summaryrefslogtreecommitdiff
path: root/test/Transforms/SafeStack
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/SafeStack')
-rw-r--r--test/Transforms/SafeStack/AArch64/abi.ll2
-rw-r--r--test/Transforms/SafeStack/AArch64/abi_ssp.ll22
-rw-r--r--test/Transforms/SafeStack/ARM/setjmp.ll4
-rw-r--r--test/Transforms/SafeStack/X86/abi_ssp.ll19
-rw-r--r--test/Transforms/SafeStack/X86/ssp.ll30
-rw-r--r--test/Transforms/SafeStack/array-aligned.ll7
-rw-r--r--test/Transforms/SafeStack/array.ll7
-rw-r--r--test/Transforms/SafeStack/coloring.ll44
-rw-r--r--test/Transforms/SafeStack/coloring2.ll482
-rw-r--r--test/Transforms/SafeStack/debug-loc-dynamic.ll57
-rw-r--r--test/Transforms/SafeStack/debug-loc.ll13
-rw-r--r--test/Transforms/SafeStack/debug-loc2.ll98
-rw-r--r--test/Transforms/SafeStack/dynamic-alloca.ll3
-rw-r--r--test/Transforms/SafeStack/phi.ll35
-rw-r--r--test/Transforms/SafeStack/setjmp2.ll5
-rw-r--r--test/Transforms/SafeStack/sink-to-use.ll22
-rw-r--r--test/Transforms/SafeStack/struct.ll7
17 files changed, 833 insertions, 24 deletions
diff --git a/test/Transforms/SafeStack/AArch64/abi.ll b/test/Transforms/SafeStack/AArch64/abi.ll
index cdec923eb74ce..bd6710d160c55 100644
--- a/test/Transforms/SafeStack/AArch64/abi.ll
+++ b/test/Transforms/SafeStack/AArch64/abi.ll
@@ -3,7 +3,7 @@
define void @foo() nounwind uwtable safestack {
entry:
-; CHECK: %[[TP:.*]] = call i8* @llvm.aarch64.thread.pointer()
+; CHECK: %[[TP:.*]] = call i8* @llvm.thread.pointer()
; CHECK: %[[SPA0:.*]] = getelementptr i8, i8* %[[TP]], i32 72
; CHECK: %[[SPA:.*]] = bitcast i8* %[[SPA0]] to i8**
; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
diff --git a/test/Transforms/SafeStack/AArch64/abi_ssp.ll b/test/Transforms/SafeStack/AArch64/abi_ssp.ll
new file mode 100644
index 0000000000000..5d584d0a76b9d
--- /dev/null
+++ b/test/Transforms/SafeStack/AArch64/abi_ssp.ll
@@ -0,0 +1,22 @@
+; RUN: opt -safe-stack -S -mtriple=aarch64-linux-android < %s -o - | FileCheck --check-prefix=TLS %s
+
+
+define void @foo() nounwind uwtable safestack sspreq {
+entry:
+; The first @llvm.thread.pointer is for the unsafe stack pointer, skip it.
+; TLS: call i8* @llvm.thread.pointer()
+
+; TLS: %[[TP2:.*]] = call i8* @llvm.thread.pointer()
+; TLS: %[[B:.*]] = getelementptr i8, i8* %[[TP2]], i32 40
+; TLS: %[[C:.*]] = bitcast i8* %[[B]] to i8**
+; TLS: %[[StackGuard:.*]] = load i8*, i8** %[[C]]
+; TLS: store i8* %[[StackGuard]], i8** %[[StackGuardSlot:.*]]
+ %a = alloca i128, align 16
+ call void @Capture(i128* %a)
+
+; TLS: %[[A:.*]] = load i8*, i8** %[[StackGuardSlot]]
+; TLS: icmp ne i8* %[[StackGuard]], %[[A]]
+ ret void
+}
+
+declare void @Capture(i128*)
diff --git a/test/Transforms/SafeStack/ARM/setjmp.ll b/test/Transforms/SafeStack/ARM/setjmp.ll
index 8c57908bbe4bd..20e46f8f0e215 100644
--- a/test/Transforms/SafeStack/ARM/setjmp.ll
+++ b/test/Transforms/SafeStack/ARM/setjmp.ll
@@ -6,8 +6,8 @@
define void @f(i32 %b) safestack {
entry:
; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
-; CHECK: %[[USDP:.*]] = alloca i8*
; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: %[[USDP:.*]] = alloca i8*
; CHECK: store i8* %[[USP]], i8** %[[USDP]]
; CHECK: call i32 @setjmp
@@ -26,6 +26,8 @@ if.then:
br label %if.end
if.end:
+; CHECK: store i8* %[[USP:.*]], i8** %[[SPA:.*]]
+
ret void
}
diff --git a/test/Transforms/SafeStack/X86/abi_ssp.ll b/test/Transforms/SafeStack/X86/abi_ssp.ll
new file mode 100644
index 0000000000000..ba4ced5b88204
--- /dev/null
+++ b/test/Transforms/SafeStack/X86/abi_ssp.ll
@@ -0,0 +1,19 @@
+; RUN: opt -safe-stack -S -mtriple=i686-pc-linux-gnu < %s -o - | FileCheck --check-prefix=TLS --check-prefix=TLS32 %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck --check-prefix=TLS --check-prefix=TLS64 %s
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android < %s -o - | FileCheck --check-prefix=TLS --check-prefix=TLS32 %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-linux-android < %s -o - | FileCheck --check-prefix=TLS --check-prefix=TLS64 %s
+
+define void @foo() safestack sspreq {
+entry:
+; TLS32: %[[StackGuard:.*]] = load i8*, i8* addrspace(256)* inttoptr (i32 20 to i8* addrspace(256)*)
+; TLS64: %[[StackGuard:.*]] = load i8*, i8* addrspace(257)* inttoptr (i32 40 to i8* addrspace(257)*)
+; TLS: store i8* %[[StackGuard]], i8** %[[StackGuardSlot:.*]]
+ %a = alloca i8, align 1
+ call void @Capture(i8* %a)
+
+; TLS: %[[A:.*]] = load i8*, i8** %[[StackGuardSlot]]
+; TLS: icmp ne i8* %[[StackGuard]], %[[A]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/test/Transforms/SafeStack/X86/ssp.ll b/test/Transforms/SafeStack/X86/ssp.ll
new file mode 100644
index 0000000000000..0e28878c5477a
--- /dev/null
+++ b/test/Transforms/SafeStack/X86/ssp.ll
@@ -0,0 +1,30 @@
+; RUN: opt -safe-stack -S -mtriple=x86_64-unknown < %s -o - | FileCheck %s
+
+define void @foo() safestack sspreq {
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
+
+; CHECK: %[[A:.*]] = getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK: %[[StackGuardSlot:.*]] = bitcast i8* %[[A]] to i8**
+; CHECK: %[[StackGuard:.*]] = load i8*, i8** @__stack_chk_guard
+; CHECK: store i8* %[[StackGuard]], i8** %[[StackGuardSlot]]
+ %a = alloca i8, align 1
+
+; CHECK: call void @Capture
+ call void @Capture(i8* %a)
+
+; CHECK: %[[B:.*]] = load i8*, i8** %[[StackGuardSlot]]
+; CHECK: %[[COND:.*]] = icmp ne i8* %[[StackGuard]], %[[B]]
+; CHECK: br i1 %[[COND]], {{.*}} !prof
+
+; CHECK: call void @__stack_chk_fail()
+; CHECK-NEXT: unreachable
+
+; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: ret void
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/test/Transforms/SafeStack/array-aligned.ll b/test/Transforms/SafeStack/array-aligned.ll
index 4676903ec7724..26558e4fa812e 100644
--- a/test/Transforms/SafeStack/array-aligned.ll
+++ b/test/Transforms/SafeStack/array-aligned.ll
@@ -13,16 +13,15 @@ entry:
; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
- ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8
-
- ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
- ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]*
%buf = alloca [16 x i8], align 16
+ ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8
+ ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+ ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]*
; CHECK: %[[GEP:.*]] = getelementptr inbounds [16 x i8], [16 x i8]* %[[BUFPTR2]], i32 0, i32 0
%gep = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0
diff --git a/test/Transforms/SafeStack/array.ll b/test/Transforms/SafeStack/array.ll
index 564213e6d58fa..7dcf7fa50d949 100644
--- a/test/Transforms/SafeStack/array.ll
+++ b/test/Transforms/SafeStack/array.ll
@@ -17,16 +17,15 @@ entry:
; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
- ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8
-
- ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
- ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]*
%buf = alloca [4 x i8], align 1
+ ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8
+ ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+ ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]*
; CHECK: %[[GEP:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUFPTR2]], i32 0, i32 0
%gep = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i32 0, i32 0
diff --git a/test/Transforms/SafeStack/coloring.ll b/test/Transforms/SafeStack/coloring.ll
new file mode 100644
index 0000000000000..3ed9ccb43f39e
--- /dev/null
+++ b/test/Transforms/SafeStack/coloring.ll
@@ -0,0 +1,44 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+define void @f() safestack {
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+
+ %x = alloca i32, align 4
+ %x1 = alloca i32, align 4
+ %x2 = alloca i32, align 4
+ %0 = bitcast i32* %x to i8*
+ call void @llvm.lifetime.start(i64 4, i8* %0)
+
+; CHECK: %[[A1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: %[[A2:.*]] = bitcast i8* %[[A1]] to i32*
+; CHECK: call void @capture(i32* nonnull %[[A2]])
+
+ call void @capture(i32* nonnull %x)
+ call void @llvm.lifetime.end(i64 4, i8* %0)
+ %1 = bitcast i32* %x1 to i8*
+ call void @llvm.lifetime.start(i64 4, i8* %1)
+
+; CHECK: %[[B1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: %[[B2:.*]] = bitcast i8* %[[B1]] to i32*
+; CHECK: call void @capture(i32* nonnull %[[B2]])
+
+ call void @capture(i32* nonnull %x1)
+ call void @llvm.lifetime.end(i64 4, i8* %1)
+ %2 = bitcast i32* %x2 to i8*
+ call void @llvm.lifetime.start(i64 4, i8* %2)
+
+; CHECK: %[[C1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: %[[C2:.*]] = bitcast i8* %[[C1]] to i32*
+; CHECK: call void @capture(i32* nonnull %[[C2]])
+
+ call void @capture(i32* nonnull %x2)
+ call void @llvm.lifetime.end(i64 4, i8* %2)
+ ret void
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+declare void @capture(i32*)
diff --git a/test/Transforms/SafeStack/coloring2.ll b/test/Transforms/SafeStack/coloring2.ll
new file mode 100644
index 0000000000000..54ed812cfe281
--- /dev/null
+++ b/test/Transforms/SafeStack/coloring2.ll
@@ -0,0 +1,482 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+; x and y share the stack slot.
+define void @f() safestack {
+; CHECK-LABEL: define void @f
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ %z0 = bitcast i32* %z to i8*
+
+ call void @llvm.lifetime.start(i64 -1, i8* %z0)
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture32(i32* %z)
+ call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+ ret void
+}
+
+define void @no_markers() safestack {
+; CHECK-LABEL: define void @no_markers(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture32(i32* %y)
+
+ ret void
+}
+
+; x and y can't share memory, but they can split z's storage.
+define void @g() safestack {
+; CHECK-LABEL: define void @g
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i64, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ %z0 = bitcast i64* %z to i8*
+
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end(i64 -1, i8* %y0)
+ call void @llvm.lifetime.start(i64 -1, i8* %z0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture64(i64* %z)
+ call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+ ret void
+}
+
+; Both y and z fit in x's alignment gap.
+define void @h() safestack {
+; CHECK-LABEL: define void @h
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+
+ %x = alloca i32, align 16
+ %z = alloca i64, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ %z0 = bitcast i64* %z to i8*
+
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+ call void @llvm.lifetime.start(i64 -1, i8* %z0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+ call void @capture32(i32* %x)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -12
+ call void @capture32(i32* %y)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture64(i64* %z)
+
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ call void @llvm.lifetime.end(i64 -1, i8* %y0)
+ call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+ ret void
+}
+
+; void f(bool a, bool b) {
+; long x1, x2; capture64(&x1); capture64(&x2);
+; if (a) {
+; long y; capture64(&y);
+; if (b) {
+; long y1; capture64(&y1);
+; } else {
+; long y2; capture64(&y2);
+; }
+; } else {
+; long z; capture64(&z);
+; if (b) {
+; long z1; capture64(&z1);
+; } else {
+; long z2; capture64(&z2);
+; }
+; }
+; }
+; Everything fits in 4 x 64-bit slots.
+define void @i(i1 zeroext %a, i1 zeroext %b) safestack {
+; CHECK-LABEL: define void @i
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -32
+ %x1 = alloca i64, align 8
+ %x2 = alloca i64, align 8
+ %y = alloca i64, align 8
+ %y1 = alloca i64, align 8
+ %y2 = alloca i64, align 8
+ %z = alloca i64, align 8
+ %z1 = alloca i64, align 8
+ %z2 = alloca i64, align 8
+ %0 = bitcast i64* %x1 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %0)
+ %1 = bitcast i64* %x2 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %x1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %x2)
+ br i1 %a, label %if.then, label %if.else4
+
+if.then: ; preds = %entry
+ %2 = bitcast i64* %y to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %2)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -24
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %y)
+ br i1 %b, label %if.then3, label %if.else
+
+if.then3: ; preds = %if.then
+ %3 = bitcast i64* %y1 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %3)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %y1)
+ call void @llvm.lifetime.end(i64 -1, i8* %3)
+ br label %if.end
+
+if.else: ; preds = %if.then
+ %4 = bitcast i64* %y2 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %4)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %y2)
+ call void @llvm.lifetime.end(i64 -1, i8* %4)
+ br label %if.end
+
+if.end: ; preds = %if.else, %if.then3
+ call void @llvm.lifetime.end(i64 -1, i8* %2)
+ br label %if.end9
+
+if.else4: ; preds = %entry
+ %5 = bitcast i64* %z to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %5)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -24
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %z)
+ br i1 %b, label %if.then6, label %if.else7
+
+if.then6: ; preds = %if.else4
+ %6 = bitcast i64* %z1 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %6)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %z1)
+ call void @llvm.lifetime.end(i64 -1, i8* %6)
+ br label %if.end8
+
+if.else7: ; preds = %if.else4
+ %7 = bitcast i64* %z2 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %7)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK: call void @capture64(
+ call void @capture64(i64* nonnull %z2)
+ call void @llvm.lifetime.end(i64 -1, i8* %7)
+ br label %if.end8
+
+if.end8: ; preds = %if.else7, %if.then6
+ call void @llvm.lifetime.end(i64 -1, i8* %5)
+ br label %if.end9
+
+if.end9: ; preds = %if.end8, %if.end
+ call void @llvm.lifetime.end(i64 -1, i8* %1)
+ call void @llvm.lifetime.end(i64 -1, i8* %0)
+ ret void
+}
+
+; lifetime for x ends in 2 different BBs
+define void @no_merge1(i1 %d) safestack {
+; CHECK-LABEL: define void @no_merge1(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %x)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK: call void @capture32(
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end(i64 -1, i8* %y0)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ ret void
+bb3:
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ ret void
+}
+
+define void @merge1(i1 %d) safestack {
+; CHECK-LABEL: define void @merge1(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end(i64 -1, i8* %y0)
+ ret void
+bb3:
+ ret void
+}
+
+; Missing lifetime.end
+define void @merge2_noend(i1 %d) safestack {
+; CHECK-LABEL: define void @merge2_noend(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %y)
+ ret void
+bb3:
+ ret void
+}
+
+; Missing lifetime.end
+define void @merge3_noend(i1 %d) safestack {
+; CHECK-LABEL: define void @merge3_noend(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %x)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %y)
+ ret void
+bb3:
+ ret void
+}
+
+; Missing lifetime.start
+define void @nomerge4_nostart(i1 %d) safestack {
+; CHECK-LABEL: define void @nomerge4_nostart(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %x0 = bitcast i32* %x to i8*
+ %y0 = bitcast i32* %y to i8*
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK: call void @capture32(
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK: call void @capture32(
+ call void @capture32(i32* %y)
+ ret void
+bb3:
+ ret void
+}
+
+define void @array_merge() safestack {
+; CHECK-LABEL: define void @array_merge(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800
+ %A.i1 = alloca [100 x i32], align 4
+ %B.i2 = alloca [100 x i32], align 4
+ %A.i = alloca [100 x i32], align 4
+ %B.i = alloca [100 x i32], align 4
+ %0 = bitcast [100 x i32]* %A.i to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %0)
+ %1 = bitcast [100 x i32]* %B.i to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -400
+; CHECK: call void @capture100x32(
+ call void @capture100x32([100 x i32]* %A.i)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -800
+; CHECK: call void @capture100x32(
+ call void @capture100x32([100 x i32]* %B.i)
+ call void @llvm.lifetime.end(i64 -1, i8* %0)
+ call void @llvm.lifetime.end(i64 -1, i8* %1)
+ %2 = bitcast [100 x i32]* %A.i1 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %2)
+ %3 = bitcast [100 x i32]* %B.i2 to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %3)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -400
+; CHECK: call void @capture100x32(
+ call void @capture100x32([100 x i32]* %A.i1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -800
+; CHECK: call void @capture100x32(
+ call void @capture100x32([100 x i32]* %B.i2)
+ call void @llvm.lifetime.end(i64 -1, i8* %2)
+ call void @llvm.lifetime.end(i64 -1, i8* %3)
+ ret void
+}
+
+define void @myCall_pr15707() safestack {
+; CHECK-LABEL: define void @myCall_pr15707(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -200000
+ %buf1 = alloca i8, i32 100000, align 16
+ %buf2 = alloca i8, i32 100000, align 16
+
+ call void @llvm.lifetime.start(i64 -1, i8* %buf1)
+ call void @llvm.lifetime.end(i64 -1, i8* %buf1)
+
+ call void @llvm.lifetime.start(i64 -1, i8* %buf1)
+ call void @llvm.lifetime.start(i64 -1, i8* %buf2)
+ call void @capture8(i8* %buf1)
+ call void @capture8(i8* %buf2)
+ ret void
+}
+
+; Check that we don't assert and crash even when there are allocas
+; outside the declared lifetime regions.
+define void @bad_range() safestack {
+; CHECK-LABEL: define void @bad_range(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; A.i and B.i unsafe, not merged
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800
+; A.i1 and B.i2 safe
+; CHECK: = alloca [100 x i32], align 4
+; CHECK: = alloca [100 x i32], align 4
+
+ %A.i1 = alloca [100 x i32], align 4
+ %B.i2 = alloca [100 x i32], align 4
+ %A.i = alloca [100 x i32], align 4
+ %B.i = alloca [100 x i32], align 4
+ %0 = bitcast [100 x i32]* %A.i to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %0) nounwind
+ %1 = bitcast [100 x i32]* %B.i to i8*
+ call void @llvm.lifetime.start(i64 -1, i8* %1) nounwind
+ call void @capture100x32([100 x i32]* %A.i)
+ call void @capture100x32([100 x i32]* %B.i)
+ call void @llvm.lifetime.end(i64 -1, i8* %0) nounwind
+ call void @llvm.lifetime.end(i64 -1, i8* %1) nounwind
+ br label %block2
+
+block2:
+ ; I am used outside the marked lifetime.
+ call void @capture100x32([100 x i32]* %A.i)
+ call void @capture100x32([100 x i32]* %B.i)
+ ret void
+}
+
+%struct.Klass = type { i32, i32 }
+
+define i32 @shady_range(i32 %argc, i8** nocapture %argv) safestack {
+; CHECK-LABEL: define i32 @shady_range(
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -64
+ %a.i = alloca [4 x %struct.Klass], align 16
+ %b.i = alloca [4 x %struct.Klass], align 16
+ %a8 = bitcast [4 x %struct.Klass]* %a.i to i8*
+ %b8 = bitcast [4 x %struct.Klass]* %b.i to i8*
+ ; I am used outside the lifetime zone below:
+ %z2 = getelementptr inbounds [4 x %struct.Klass], [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0
+ call void @llvm.lifetime.start(i64 -1, i8* %a8)
+ call void @llvm.lifetime.start(i64 -1, i8* %b8)
+ call void @capture8(i8* %a8)
+ call void @capture8(i8* %b8)
+ %z3 = load i32, i32* %z2, align 16
+ call void @llvm.lifetime.end(i64 -1, i8* %a8)
+ call void @llvm.lifetime.end(i64 -1, i8* %b8)
+ ret i32 %z3
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+declare void @capture8(i8*)
+declare void @capture32(i32*)
+declare void @capture64(i64*)
+declare void @capture100x32([100 x i32]*)
diff --git a/test/Transforms/SafeStack/debug-loc-dynamic.ll b/test/Transforms/SafeStack/debug-loc-dynamic.ll
new file mode 100644
index 0000000000000..280d010774e18
--- /dev/null
+++ b/test/Transforms/SafeStack/debug-loc-dynamic.ll
@@ -0,0 +1,57 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+
+; Test llvm.dbg.value for dynamic allocas moved onto the unsafe stack.
+; In the dynamic alloca case, the dbg.value does not change with the exception
+; of the alloca pointer in the first argument being replaced with the new stack
+; top address.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f(i32 %n) safestack !dbg !6 {
+entry:
+ tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !11, metadata !14), !dbg !15
+ %0 = zext i32 %n to i64, !dbg !16
+
+; CHECK: store i8* %[[VLA:.*]], i8** @__safestack_unsafe_stack_ptr
+; CHECK: tail call void @llvm.dbg.value(metadata i8* %[[VLA]], i64 0, metadata ![[TYPE:.*]], metadata ![[EXPR:.*]])
+; CHECK: call void @capture({{.*}} %[[VLA]])
+
+ %vla = alloca i8, i64 %0, align 16, !dbg !16
+ tail call void @llvm.dbg.value(metadata i8* %vla, i64 0, metadata !12, metadata !17), !dbg !18
+ call void @capture(i8* nonnull %vla), !dbg !19
+ ret void, !dbg !20
+}
+
+declare void @capture(i8*)
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "../llvm/1.cc", directory: "/code/build-llvm")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)"}
+!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fi", scope: !1, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !10)
+!7 = !DISubroutineType(types: !8)
+!8 = !{null, !9}
+!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!10 = !{!11, !12}
+!11 = !DILocalVariable(name: "n", arg: 1, scope: !6, file: !1, line: 2, type: !9)
+
+; CHECK-DAG: ![[TYPE]] = !DILocalVariable(name: "x",
+!12 = !DILocalVariable(name: "x", scope: !6, file: !1, line: 3, type: !13)
+!13 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!14 = !DIExpression()
+!15 = !DILocation(line: 2, column: 12, scope: !6)
+!16 = !DILocation(line: 3, column: 3, scope: !6)
+
+; CHECK-DAG: ![[EXPR]] = !DIExpression(DW_OP_deref)
+!17 = !DIExpression(DW_OP_deref)
+!18 = !DILocation(line: 3, column: 8, scope: !6)
+!19 = !DILocation(line: 4, column: 3, scope: !6)
+!20 = !DILocation(line: 5, column: 1, scope: !6)
diff --git a/test/Transforms/SafeStack/debug-loc.ll b/test/Transforms/SafeStack/debug-loc.ll
index e72d0e9d2ff25..fc0b6f911f7ee 100644
--- a/test/Transforms/SafeStack/debug-loc.ll
+++ b/test/Transforms/SafeStack/debug-loc.ll
@@ -55,28 +55,27 @@ attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-
!llvm.module.flags = !{!15, !16}
!llvm.ident = !{!17}
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !11)
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm")
!2 = !{}
!3 = !{!4}
!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !1, line: 4, size: 800, align: 8, elements: !5, identifier: "_ZTS1S")
!5 = !{!6}
-!6 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !"_ZTS1S", file: !1, line: 5, baseType: !7, size: 800, align: 8)
+!6 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !4, file: !1, line: 5, baseType: !7, size: 800, align: 8)
!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 800, align: 8, elements: !9)
!8 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
!9 = !{!10}
!10 = !DISubrange(count: 100)
-!11 = !{!12}
-!12 = distinct !DISubprogram(name: "f", linkageName: "_Z1f1S", scope: !1, file: !1, line: 10, type: !13, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!12 = distinct !DISubprogram(name: "f", linkageName: "_Z1f1S", scope: !1, file: !1, line: 10, type: !13, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
!13 = !DISubroutineType(types: !14)
-!14 = !{null, !"_ZTS1S"}
+!14 = !{null, !4}
!15 = !{i32 2, !"Dwarf Version", i32 4}
!16 = !{i32 2, !"Debug Info Version", i32 3}
!17 = !{!"clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)"}
-!18 = !DILocalVariable(name: "zzz", arg: 1, scope: !12, file: !1, line: 10, type: !"_ZTS1S")
+!18 = !DILocalVariable(name: "zzz", arg: 1, scope: !12, file: !1, line: 10, type: !4)
!19 = !DIExpression()
!20 = !DILocation(line: 10, column: 10, scope: !12)
-!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !"_ZTS1S")
+!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !4)
!22 = !DILocation(line: 11, column: 5, scope: !12)
!23 = !DILocation(line: 12, column: 3, scope: !12)
!24 = !DILocation(line: 13, column: 3, scope: !12)
diff --git a/test/Transforms/SafeStack/debug-loc2.ll b/test/Transforms/SafeStack/debug-loc2.ll
new file mode 100644
index 0000000000000..35e9b7711d2f7
--- /dev/null
+++ b/test/Transforms/SafeStack/debug-loc2.ll
@@ -0,0 +1,98 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+
+; Test llvm.dbg.value for the local variables moved onto the unsafe stack.
+; SafeStack rewrites them relative to the unsafe stack pointer (base address of
+; the unsafe stack frame).
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline safestack uwtable
+define void @f() #0 !dbg !6 {
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ %x1 = alloca i32, align 4
+ %x2 = alloca i32, align 4
+ %0 = bitcast i32* %x1 to i8*, !dbg !13
+ %1 = bitcast i32* %x2 to i8*, !dbg !14
+
+; Unhandled dbg.value: expression does not start with OP_DW_deref
+; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY:.*]], i64 0, metadata !{{.*}}, metadata !{{.*}})
+ tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !23), !dbg !16
+
+; Unhandled dbg.value: expression does not start with OP_DW_deref
+; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY]], i64 0, metadata !{{.*}}, metadata !{{.*}})
+ tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !24), !dbg !16
+
+; Supported dbg.value: rewritted based on the [[USP]] value.
+; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X1:.*]], metadata ![[X1_EXPR:.*]])
+ tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !15), !dbg !16
+ call void @capture(i32* nonnull %x1), !dbg !17
+
+; An extra non-dbg.value metadata use of %x2. Replaced with an empty metadata.
+; CHECK: call void @llvm.random.metadata.use(metadata ![[EMPTY]])
+ call void @llvm.random.metadata.use(metadata i32* %x2)
+
+; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X2:.*]], metadata ![[X2_EXPR:.*]])
+ call void @llvm.dbg.value(metadata i32* %x2, i64 0, metadata !12, metadata !15), !dbg !18
+ call void @capture(i32* nonnull %x2), !dbg !19
+ ret void, !dbg !20
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #1
+
+declare void @capture(i32*) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #3
+
+declare void @llvm.random.metadata.use(metadata)
+
+attributes #0 = { noinline safestack uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone }
+attributes #4 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm")
+
+; CHECK-DAG: ![[EMPTY]] = !{}
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)"}
+!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !1, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !9)
+!7 = !DISubroutineType(types: !8)
+!8 = !{null}
+!9 = !{!10, !12}
+
+; CHECK-DAG: ![[X1]] = !DILocalVariable(name: "x1",
+!10 = !DILocalVariable(name: "x1", scope: !6, file: !1, line: 5, type: !11)
+!11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+
+; CHECK-DAG: ![[X2]] = !DILocalVariable(name: "x2",
+!12 = !DILocalVariable(name: "x2", scope: !6, file: !1, line: 6, type: !11)
+!13 = !DILocation(line: 5, column: 3, scope: !6)
+!14 = !DILocation(line: 6, column: 3, scope: !6)
+
+; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 4)
+; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 8)
+!15 = !DIExpression(DW_OP_deref)
+!16 = !DILocation(line: 5, column: 7, scope: !6)
+!17 = !DILocation(line: 8, column: 3, scope: !6)
+!18 = !DILocation(line: 6, column: 7, scope: !6)
+!19 = !DILocation(line: 9, column: 3, scope: !6)
+!20 = !DILocation(line: 10, column: 1, scope: !6)
+!21 = !DILocation(line: 10, column: 1, scope: !22)
+!22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 1)
+!23 = !DIExpression()
+!24 = !DIExpression(DW_OP_minus, 42)
diff --git a/test/Transforms/SafeStack/dynamic-alloca.ll b/test/Transforms/SafeStack/dynamic-alloca.ll
index bfec66f82a2f9..b0571f72f1aaf 100644
--- a/test/Transforms/SafeStack/dynamic-alloca.ll
+++ b/test/Transforms/SafeStack/dynamic-alloca.ll
@@ -8,7 +8,7 @@
; Requires protector.
define void @foo(i32 %n) nounwind uwtable safestack {
entry:
- ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
%n.addr = alloca i32, align 4
%a = alloca i32*, align 8
store i32 %n, i32* %n.addr, align 4
@@ -17,5 +17,6 @@ entry:
%1 = alloca i8, i64 %conv
%2 = bitcast i8* %1 to i32*
store i32* %2, i32** %a, align 8
+ ; CHECK: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr
ret void
}
diff --git a/test/Transforms/SafeStack/phi.ll b/test/Transforms/SafeStack/phi.ll
new file mode 100644
index 0000000000000..3ee56aa0f566b
--- /dev/null
+++ b/test/Transforms/SafeStack/phi.ll
@@ -0,0 +1,35 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+define void @f(i1 %d1, i1 %d2) safestack {
+entry:
+; CHECK-LABEL: define void @f(
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: br i1 %d1, label %[[BB0:.*]], label %[[BB1:.*]]
+ %a = alloca i32, align 8
+ %b = alloca i32, align 8
+ br i1 %d1, label %bb0, label %bb1
+
+bb0:
+; CHECK: [[BB0]]:
+; CHECK: %[[Ai8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32
+; CHECK: %[[AUNSAFE:.*]] = bitcast i8* %[[Ai8]] to i32*
+; CHECK: br i1
+ br i1 %d2, label %bb2, label %bb2
+
+bb1:
+; CHECK: [[BB1]]:
+; CHECK: %[[Bi8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32
+; CHECK: %[[BUNSAFE:.*]] = bitcast i8* %[[Bi8]] to i32*
+; CHECK: br label
+ br label %bb2
+
+bb2:
+; CHECK: phi i32* [ %[[AUNSAFE]], %[[BB0]] ], [ %[[AUNSAFE]], %[[BB0]] ], [ %[[BUNSAFE]], %[[BB1]] ]
+ %c = phi i32* [ %a, %bb0 ], [ %a, %bb0 ], [ %b, %bb1 ]
+ call void @capture(i32* %c)
+ ret void
+}
+
+declare void @capture(i32*)
diff --git a/test/Transforms/SafeStack/setjmp2.ll b/test/Transforms/SafeStack/setjmp2.ll
index bb15d7e03ace7..dc83c48242075 100644
--- a/test/Transforms/SafeStack/setjmp2.ll
+++ b/test/Transforms/SafeStack/setjmp2.ll
@@ -12,8 +12,8 @@
; CHECK: @foo(i32 %[[ARG:.*]])
define i32 @foo(i32 %size) nounwind uwtable safestack {
entry:
- ; CHECK: %[[DYNPTR:.*]] = alloca i8*
- ; CHECK-NEXT: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ ; CHECK-NEXT: %[[DYNPTR:.*]] = alloca i8*
; CHECK-NEXT: store i8* %[[SP]], i8** %[[DYNPTR]]
; CHECK-NEXT: %[[ZEXT:.*]] = zext i32 %[[ARG]] to i64
@@ -35,6 +35,7 @@ entry:
; CHECK: call void @funcall(i32* %[[ALLOCA]])
call void @funcall(i32* %a)
+ ; CHECK-NEXT: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr
ret i32 0
}
diff --git a/test/Transforms/SafeStack/sink-to-use.ll b/test/Transforms/SafeStack/sink-to-use.ll
new file mode 100644
index 0000000000000..e208ce1da9d45
--- /dev/null
+++ b/test/Transforms/SafeStack/sink-to-use.ll
@@ -0,0 +1,22 @@
+; Test that unsafe alloca address calculation is done immediately before each use.
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+
+define void @f() safestack {
+entry:
+ %x0 = alloca i32, align 4
+ %x1 = alloca i32, align 4
+
+; CHECK: %[[A:.*]] = getelementptr i8, i8* %{{.*}}, i32 -4
+; CHECK: %[[X0:.*]] = bitcast i8* %[[A]] to i32*
+; CHECK: call void @use(i32* %[[X0]])
+ call void @use(i32* %x0)
+
+; CHECK: %[[B:.*]] = getelementptr i8, i8* %{{.*}}, i32 -8
+; CHECK: %[[X1:.*]] = bitcast i8* %[[B]] to i32*
+; CHECK: call void @use(i32* %[[X1]])
+ call void @use(i32* %x1)
+ ret void
+}
+
+declare void @use(i32*)
diff --git a/test/Transforms/SafeStack/struct.ll b/test/Transforms/SafeStack/struct.ll
index 12a0085a2cc34..b64803d160c66 100644
--- a/test/Transforms/SafeStack/struct.ll
+++ b/test/Transforms/SafeStack/struct.ll
@@ -15,16 +15,15 @@ entry:
; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
- ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8
-
- ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
- ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo*
%buf = alloca %struct.foo, align 1
+ ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8
+ ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+ ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo*
; CHECK: %[[GEP:.*]] = getelementptr inbounds %struct.foo, %struct.foo* %[[BUFPTR2]], i32 0, i32 0, i32 0
%gep = getelementptr inbounds %struct.foo, %struct.foo* %buf, i32 0, i32 0, i32 0