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