1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s 2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s 3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s 4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s 5 6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 7target triple = "x86_64-unknown-linux-gnu" 8 9declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile) 10declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile) 11declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 12declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 13 14define void @MemsetInBounds() { 15; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}} 16; CHECK-NEXT: args uses: 17; CHECK-NEXT: allocas uses: 18; CHECK-NEXT: x[4]: [0,4){{$}} 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; CHECK-EMPTY: 34entry: 35 %x = alloca i32, align 4 36 %x1 = bitcast i32* %x to i8* 37 call void @llvm.memset.p0i8.i32(i8* %x1, 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; CHECK-EMPTY: 47entry: 48 %x = alloca i32, align 4 49 %x1 = bitcast i32* %x to i8* 50 call void @llvm.memset.p0i8.i32(i8* %x1, 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; CHECK-EMPTY: 60entry: 61 %x = alloca i32, align 4 62 %x1 = bitcast i32* %x to i8* 63 call void @llvm.memset.p0i8.i32(i8* %x1, 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,4294967295){{$}} 74; CHECK-EMPTY: 75entry: 76 %x = alloca i32, align 4 77 %x1 = bitcast i32* %x to i8* 78 %size = select i1 %z, i32 3, i32 4 79 call void @llvm.memset.p0i8.i32(i8* %x1, 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; CHECK-EMPTY: 90entry: 91 %x = alloca i32, align 4 92 %y = alloca i32, align 4 93 %x1 = bitcast i32* %x to i8* 94 %xint = ptrtoint i32* %x to i32 95 %yint = ptrtoint i32* %y to i32 96 %d = sub i32 %xint, %yint 97 call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %d, i1 false) 98 ret void 99} 100 101define void @MemcpyInBounds() { 102; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}} 103; CHECK-NEXT: args uses: 104; CHECK-NEXT: allocas uses: 105; CHECK-NEXT: x[4]: [0,4){{$}} 106; CHECK-NEXT: y[4]: [0,4){{$}} 107; CHECK-EMPTY: 108entry: 109 %x = alloca i32, align 4 110 %y = alloca i32, align 4 111 %x1 = bitcast i32* %x to i8* 112 %y1 = bitcast i32* %y to i8* 113 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false) 114 ret void 115} 116 117define void @MemcpySrcOutOfBounds() { 118; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}} 119; CHECK-NEXT: args uses: 120; CHECK-NEXT: allocas uses: 121; CHECK-NEXT: x[8]: [0,5){{$}} 122; CHECK-NEXT: y[4]: [0,5){{$}} 123; CHECK-EMPTY: 124entry: 125 %x = alloca i64, align 4 126 %y = alloca i32, align 4 127 %x1 = bitcast i64* %x to i8* 128 %y1 = bitcast i32* %y to i8* 129 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false) 130 ret void 131} 132 133define void @MemcpyDstOutOfBounds() { 134; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}} 135; CHECK-NEXT: args uses: 136; CHECK-NEXT: allocas uses: 137; CHECK-NEXT: x[4]: [0,5){{$}} 138; CHECK-NEXT: y[8]: [0,5){{$}} 139; CHECK-EMPTY: 140entry: 141 %x = alloca i32, align 4 142 %y = alloca i64, align 4 143 %x1 = bitcast i32* %x to i8* 144 %y1 = bitcast i64* %y to i8* 145 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false) 146 ret void 147} 148 149define void @MemcpyBothOutOfBounds() { 150; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}} 151; CHECK-NEXT: args uses: 152; CHECK-NEXT: allocas uses: 153; CHECK-NEXT: x[4]: [0,9){{$}} 154; CHECK-NEXT: y[8]: [0,9){{$}} 155; CHECK-EMPTY: 156entry: 157 %x = alloca i32, align 4 158 %y = alloca i64, align 4 159 %x1 = bitcast i32* %x to i8* 160 %y1 = bitcast i64* %y to i8* 161 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 9, i1 false) 162 ret void 163} 164 165define void @MemcpySelfInBounds() { 166; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}} 167; CHECK-NEXT: args uses: 168; CHECK-NEXT: allocas uses: 169; CHECK-NEXT: x[8]: [0,8){{$}} 170; CHECK-EMPTY: 171entry: 172 %x = alloca i64, align 4 173 %x1 = bitcast i64* %x to i8* 174 %x2 = getelementptr i8, i8* %x1, i64 5 175 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false) 176 ret void 177} 178 179define void @MemcpySelfSrcOutOfBounds() { 180; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}} 181; CHECK-NEXT: args uses: 182; CHECK-NEXT: allocas uses: 183; CHECK-NEXT: x[8]: [0,9){{$}} 184; CHECK-EMPTY: 185entry: 186 %x = alloca i64, align 4 187 %x1 = bitcast i64* %x to i8* 188 %x2 = getelementptr i8, i8* %x1, i64 5 189 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 4, i1 false) 190 ret void 191} 192 193define void @MemcpySelfDstOutOfBounds() { 194; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}} 195; CHECK-NEXT: args uses: 196; CHECK-NEXT: allocas uses: 197; CHECK-NEXT: x[8]: [0,9){{$}} 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* %x2, i8* %x1, i32 4, i1 false) 204 ret void 205} 206 207define void @MemmoveSelfBothOutOfBounds() { 208; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}} 209; CHECK-NEXT: args uses: 210; CHECK-NEXT: allocas uses: 211; CHECK-NEXT: x[8]: [0,14){{$}} 212; CHECK-EMPTY: 213entry: 214 %x = alloca i64, align 4 215 %x1 = bitcast i64* %x to i8* 216 %x2 = getelementptr i8, i8* %x1, i64 5 217 call void @llvm.memmove.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 9, i1 false) 218 ret void 219} 220