1; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s 2; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL 3 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 5target triple = "x86_64-unknown-linux-gnu" 6 7declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile) 8declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile) 9declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 10declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 11 12define void @MemsetInBounds() { 13; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}} 14; CHECK-NEXT: args uses: 15; CHECK-NEXT: allocas uses: 16; CHECK-NEXT: x[4]: [0,4){{$}} 17; GLOBAL-NEXT: safe accesses: 18; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false) 19; CHECK-EMPTY: 20entry: 21 %x = alloca i32, align 4 22 %x1 = bitcast i32* %x to i8* 23 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false) 24 ret void 25} 26 27; Volatile does not matter for access bounds. 28define void @VolatileMemsetInBounds() { 29; CHECK-LABEL: VolatileMemsetInBounds dso_preemptable{{$}} 30; CHECK-NEXT: args uses: 31; CHECK-NEXT: allocas uses: 32; CHECK-NEXT: x[4]: [0,4){{$}} 33; GLOBAL-NEXT: safe accesses: 34; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true) 35; CHECK-EMPTY: 36entry: 37 %x = alloca i32, align 4 38 %x1 = bitcast i32* %x to i8* 39 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true) 40 ret void 41} 42 43define void @MemsetOutOfBounds() { 44; CHECK-LABEL: MemsetOutOfBounds dso_preemptable{{$}} 45; CHECK-NEXT: args uses: 46; CHECK-NEXT: allocas uses: 47; CHECK-NEXT: x[4]: [0,5){{$}} 48; GLOBAL-NEXT: safe accesses: 49; CHECK-EMPTY: 50entry: 51 %x = alloca i32, align 4 52 %x1 = bitcast i32* %x to i8* 53 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 5, i1 false) 54 ret void 55} 56 57define void @MemsetNonConst(i32 %size) { 58; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}} 59; CHECK-NEXT: args uses: 60; CHECK-NEXT: allocas uses: 61; CHECK-NEXT: x[4]: [0,4294967295){{$}} 62; GLOBAL-NEXT: safe accesses: 63; CHECK-EMPTY: 64entry: 65 %x = alloca i32, align 4 66 %x1 = bitcast i32* %x to i8* 67 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false) 68 ret void 69} 70 71; FIXME: memintrinsics should look at size range when possible 72; Right now we refuse any non-constant size. 73define void @MemsetNonConstInBounds(i1 zeroext %z) { 74; CHECK-LABEL: MemsetNonConstInBounds dso_preemptable{{$}} 75; CHECK-NEXT: args uses: 76; CHECK-NEXT: allocas uses: 77; CHECK-NEXT: x[4]: [0,7){{$}} 78; GLOBAL-NEXT: safe accesses: 79; CHECK-EMPTY: 80entry: 81 %x = alloca i32, align 4 82 %x1 = bitcast i32* %x to i8* 83 %size = select i1 %z, i32 3, i32 4 84 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false) 85 ret void 86} 87 88define void @MemsetNonConstSize() { 89; CHECK-LABEL: MemsetNonConstSize dso_preemptable{{$}} 90; CHECK-NEXT: args uses: 91; CHECK-NEXT: allocas uses: 92; CHECK-NEXT: x[4]: [0,4294967295){{$}} 93; CHECK-NEXT: y[4]: empty-set{{$}} 94; GLOBAL-NEXT: safe accesses: 95; CHECK-EMPTY: 96entry: 97 %x = alloca i32, align 4 98 %y = alloca i32, align 4 99 %x1 = bitcast i32* %x to i8* 100 %xint = ptrtoint i32* %x to i32 101 %yint = ptrtoint i32* %y to i32 102 %d = sub i32 %xint, %yint 103 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %d, i1 false) 104 ret void 105} 106 107define void @MemcpyInBounds() { 108; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}} 109; CHECK-NEXT: args uses: 110; CHECK-NEXT: allocas uses: 111; CHECK-NEXT: x[4]: [0,4){{$}} 112; CHECK-NEXT: y[4]: [0,4){{$}} 113; GLOBAL-NEXT: safe accesses: 114; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false) 115; CHECK-EMPTY: 116entry: 117 %x = alloca i32, align 4 118 %y = alloca i32, align 4 119 %x1 = bitcast i32* %x to i8* 120 %y1 = bitcast i32* %y to i8* 121 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false) 122 ret void 123} 124 125define void @MemcpySrcOutOfBounds() { 126; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}} 127; CHECK-NEXT: args uses: 128; CHECK-NEXT: allocas uses: 129; CHECK-NEXT: x[8]: [0,5){{$}} 130; CHECK-NEXT: y[4]: [0,5){{$}} 131; GLOBAL-NEXT: safe accesses 132; CHECK-EMPTY: 133entry: 134 %x = alloca i64, align 4 135 %y = alloca i32, align 4 136 %x1 = bitcast i64* %x to i8* 137 %y1 = bitcast i32* %y to i8* 138 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false) 139 ret void 140} 141 142define void @MemcpyDstOutOfBounds() { 143; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}} 144; CHECK-NEXT: args uses: 145; CHECK-NEXT: allocas uses: 146; CHECK-NEXT: x[4]: [0,5){{$}} 147; CHECK-NEXT: y[8]: [0,5){{$}} 148; GLOBAL-NEXT: safe accesses 149; CHECK-EMPTY: 150entry: 151 %x = alloca i32, align 4 152 %y = alloca i64, align 4 153 %x1 = bitcast i32* %x to i8* 154 %y1 = bitcast i64* %y to i8* 155 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false) 156 ret void 157} 158 159define void @MemcpyBothOutOfBounds() { 160; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}} 161; CHECK-NEXT: args uses: 162; CHECK-NEXT: allocas uses: 163; CHECK-NEXT: x[4]: [0,9){{$}} 164; CHECK-NEXT: y[8]: [0,9){{$}} 165; GLOBAL-NEXT: safe accesses 166; CHECK-EMPTY: 167entry: 168 %x = alloca i32, align 4 169 %y = alloca i64, align 4 170 %x1 = bitcast i32* %x to i8* 171 %y1 = bitcast i64* %y to i8* 172 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 9, i1 false) 173 ret void 174} 175 176define void @MemcpySelfInBounds() { 177; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}} 178; CHECK-NEXT: args uses: 179; CHECK-NEXT: allocas uses: 180; CHECK-NEXT: x[8]: [0,8){{$}} 181; GLOBAL-NEXT: safe accesses 182; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false) 183; CHECK-EMPTY: 184entry: 185 %x = alloca i64, align 4 186 %x1 = bitcast i64* %x to i8* 187 %x2 = getelementptr i8, i8* %x1, i64 5 188 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false) 189 ret void 190} 191 192define void @MemcpySelfSrcOutOfBounds() { 193; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}} 194; CHECK-NEXT: args uses: 195; CHECK-NEXT: allocas uses: 196; CHECK-NEXT: x[8]: [0,9){{$}} 197; GLOBAL-NEXT: safe accesses: 198; CHECK-EMPTY: 199entry: 200 %x = alloca i64, align 4 201 %x1 = bitcast i64* %x to i8* 202 %x2 = getelementptr i8, i8* %x1, i64 5 203 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 4, i1 false) 204 ret void 205} 206 207define void @MemcpySelfDstOutOfBounds() { 208; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}} 209; CHECK-NEXT: args uses: 210; CHECK-NEXT: allocas uses: 211; CHECK-NEXT: x[8]: [0,9){{$}} 212; GLOBAL-NEXT: safe accesses: 213; CHECK-EMPTY: 214entry: 215 %x = alloca i64, align 4 216 %x1 = bitcast i64* %x to i8* 217 %x2 = getelementptr i8, i8* %x1, i64 5 218 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x2, i8* %x1, i32 4, i1 false) 219 ret void 220} 221 222define void @MemmoveSelfBothOutOfBounds() { 223; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}} 224; CHECK-NEXT: args uses: 225; CHECK-NEXT: allocas uses: 226; CHECK-NEXT: x[8]: [0,14){{$}} 227; GLOBAL-NEXT: safe accesses: 228; CHECK-EMPTY: 229entry: 230 %x = alloca i64, align 4 231 %x1 = bitcast i64* %x to i8* 232 %x2 = getelementptr i8, i8* %x1, i64 5 233 call void @llvm.memmove.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 9, i1 false) 234 ret void 235} 236 237define void @MemsetInBoundsCast() { 238; CHECK-LABEL: MemsetInBoundsCast dso_preemptable{{$}} 239; CHECK-NEXT: args uses: 240; CHECK-NEXT: allocas uses: 241; CHECK-NEXT: x[4]: [0,4){{$}} 242; CHECK-NEXT: y[1]: empty-set{{$}} 243; GLOBAL-NEXT: safe accesses: 244; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 %yint, i32 4, i1 false) 245; CHECK-EMPTY: 246entry: 247 %x = alloca i32, align 4 248 %y = alloca i8, align 1 249 %x1 = bitcast i32* %x to i8* 250 %yint = ptrtoint i8* %y to i8 251 call void @llvm.memset.p0i8.i32(i8* %x1, i8 %yint, i32 4, i1 false) 252 ret void 253} 254 255define void @MemcpyInBoundsCast2(i8 %zint8) { 256; CHECK-LABEL: MemcpyInBoundsCast2 dso_preemptable{{$}} 257; CHECK-NEXT: args uses: 258; CHECK-NEXT: allocas uses: 259; CHECK-NEXT: x[256]: [0,255){{$}} 260; CHECK-NEXT: y[256]: [0,255){{$}} 261; CHECK-NEXT: z[1]: empty-set{{$}} 262; GLOBAL-NEXT: safe accesses: 263; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 %zint32, i1 false) 264; CHECK-EMPTY: 265entry: 266 %x = alloca [256 x i8], align 4 267 %y = alloca [256 x i8], align 4 268 %z = alloca i8, align 1 269 %x1 = bitcast [256 x i8]* %x to i8* 270 %y1 = bitcast [256 x i8]* %y to i8* 271 %zint32 = zext i8 %zint8 to i32 272 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 %zint32, i1 false) 273 ret void 274} 275