aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/Transforms/SafeStack
diff options
context:
space:
mode:
authorEric Christopher <echristo@gmail.com>2019-04-17 04:52:47 +0000
committerEric Christopher <echristo@gmail.com>2019-04-17 04:52:47 +0000
commitcee313d288a4faf0355d76fb6e0e927e211d08a5 (patch)
treed386075318d761197779a96e5d8fc0dc7b06342b /llvm/test/Transforms/SafeStack
parentc3d6a929fdd92fd06d4304675ade8d7210ee711a (diff)
downloadllvm-cee313d288a4faf0355d76fb6e0e927e211d08a5.zip
llvm-cee313d288a4faf0355d76fb6e0e927e211d08a5.tar.gz
llvm-cee313d288a4faf0355d76fb6e0e927e211d08a5.tar.bz2
Revert "Temporarily Revert "Add basic loop fusion pass.""
The reversion apparently deleted the test/Transforms directory. Will be re-reverting again. llvm-svn: 358552
Diffstat (limited to 'llvm/test/Transforms/SafeStack')
-rw-r--r--llvm/test/Transforms/SafeStack/AArch64/abi.ll20
-rw-r--r--llvm/test/Transforms/SafeStack/AArch64/abi_ssp.ll23
-rw-r--r--llvm/test/Transforms/SafeStack/AArch64/lit.local.cfg3
-rw-r--r--llvm/test/Transforms/SafeStack/AArch64/unreachable.ll23
-rw-r--r--llvm/test/Transforms/SafeStack/ARM/abi.ll18
-rw-r--r--llvm/test/Transforms/SafeStack/ARM/debug.ll98
-rw-r--r--llvm/test/Transforms/SafeStack/ARM/lit.local.cfg3
-rw-r--r--llvm/test/Transforms/SafeStack/ARM/setjmp.ll36
-rw-r--r--llvm/test/Transforms/SafeStack/X86/abi.ll30
-rw-r--r--llvm/test/Transforms/SafeStack/X86/abi_ssp.ll26
-rw-r--r--llvm/test/Transforms/SafeStack/X86/addr-taken.ll22
-rw-r--r--llvm/test/Transforms/SafeStack/X86/array-aligned.ll38
-rw-r--r--llvm/test/Transforms/SafeStack/X86/array.ll89
-rw-r--r--llvm/test/Transforms/SafeStack/X86/byval.ll68
-rw-r--r--llvm/test/Transforms/SafeStack/X86/call.ll178
-rw-r--r--llvm/test/Transforms/SafeStack/X86/cast.ll39
-rw-r--r--llvm/test/Transforms/SafeStack/X86/coloring-ssp.ll34
-rw-r--r--llvm/test/Transforms/SafeStack/X86/coloring.ll44
-rw-r--r--llvm/test/Transforms/SafeStack/X86/coloring2.ll521
-rw-r--r--llvm/test/Transforms/SafeStack/X86/constant-gep-call.ll26
-rw-r--r--llvm/test/Transforms/SafeStack/X86/constant-gep.ll20
-rw-r--r--llvm/test/Transforms/SafeStack/X86/constant-geps.ll28
-rw-r--r--llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll56
-rw-r--r--llvm/test/Transforms/SafeStack/X86/debug-loc.ll80
-rw-r--r--llvm/test/Transforms/SafeStack/X86/debug-loc2.ll96
-rw-r--r--llvm/test/Transforms/SafeStack/X86/dynamic-alloca.ll22
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-addr-pointer.ll23
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-bitcast-store.ll23
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll20
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-call.ll16
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-casted-pointer.ll24
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-gep-call.ll20
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-gep-invoke.ll34
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-gep-negative.ll18
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll22
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-gep-store.ll23
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-phi-call.ll36
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-select-call.ll22
-rw-r--r--llvm/test/Transforms/SafeStack/X86/escape-vector.ll21
-rw-r--r--llvm/test/Transforms/SafeStack/X86/invoke.ll33
-rw-r--r--llvm/test/Transforms/SafeStack/X86/layout-frag.ll39
-rw-r--r--llvm/test/Transforms/SafeStack/X86/layout-region-split.ll84
-rw-r--r--llvm/test/Transforms/SafeStack/X86/lit.local.cfg3
-rw-r--r--llvm/test/Transforms/SafeStack/X86/memintrinsic-oob-read.ll14
-rw-r--r--llvm/test/Transforms/SafeStack/X86/no-attr.ll27
-rw-r--r--llvm/test/Transforms/SafeStack/X86/phi-cycle.ll50
-rw-r--r--llvm/test/Transforms/SafeStack/X86/phi.ll35
-rw-r--r--llvm/test/Transforms/SafeStack/X86/ret.ll17
-rw-r--r--llvm/test/Transforms/SafeStack/X86/setjmp.ll37
-rw-r--r--llvm/test/Transforms/SafeStack/X86/setjmp2.ll43
-rw-r--r--llvm/test/Transforms/SafeStack/X86/sink-to-use.ll22
-rw-r--r--llvm/test/Transforms/SafeStack/X86/ssp.ll30
-rw-r--r--llvm/test/Transforms/SafeStack/X86/store.ll63
-rw-r--r--llvm/test/Transforms/SafeStack/X86/struct.ll40
54 files changed, 2480 insertions, 0 deletions
diff --git a/llvm/test/Transforms/SafeStack/AArch64/abi.ll b/llvm/test/Transforms/SafeStack/AArch64/abi.ll
new file mode 100644
index 0000000..bd6710d1
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/AArch64/abi.ll
@@ -0,0 +1,20 @@
+; RUN: opt -safe-stack -S -mtriple=aarch64-linux-android < %s -o - | FileCheck %s
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; 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]]
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; CHECK: store i8* %[[USP]], i8** %[[SPA]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/llvm/test/Transforms/SafeStack/AArch64/abi_ssp.ll b/llvm/test/Transforms/SafeStack/AArch64/abi_ssp.ll
new file mode 100644
index 0000000..c78b20a
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/AArch64/abi_ssp.ll
@@ -0,0 +1,23 @@
+; RUN: opt -safe-stack -S -mtriple=aarch64-linux-android < %s -o - | FileCheck --check-prefixes=TLS,ANDROID %s
+; RUN: opt -safe-stack -S -mtriple=aarch64-unknown-fuchsia < %s -o - | FileCheck --check-prefixes=TLS,FUCHSIA %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()
+; ANDROID: %[[B:.*]] = getelementptr i8, i8* %[[TP2]], i32 40
+; FUCHSIA: %[[B:.*]] = getelementptr i8, i8* %[[TP2]], i32 -16
+; 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/llvm/test/Transforms/SafeStack/AArch64/lit.local.cfg b/llvm/test/Transforms/SafeStack/AArch64/lit.local.cfg
new file mode 100644
index 0000000..cec29af
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/AArch64/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'AArch64' in config.root.targets:
+ config.unsupported = True
+
diff --git a/llvm/test/Transforms/SafeStack/AArch64/unreachable.ll b/llvm/test/Transforms/SafeStack/AArch64/unreachable.ll
new file mode 100644
index 0000000..53ed690
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/AArch64/unreachable.ll
@@ -0,0 +1,23 @@
+; RUN: opt -safe-stack -safe-stack-coloring -S -mtriple=aarch64-linux-android < %s -o - | FileCheck %s
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; 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]]
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ br label %ret
+
+ret:
+ ret void
+
+dead:
+ call void @Capture(i8* %a)
+ br label %ret
+}
+
+declare void @Capture(i8*)
diff --git a/llvm/test/Transforms/SafeStack/ARM/abi.ll b/llvm/test/Transforms/SafeStack/ARM/abi.ll
new file mode 100644
index 0000000..e33c913
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/ARM/abi.ll
@@ -0,0 +1,18 @@
+; RUN: opt -safe-stack -S -mtriple=arm-linux-android < %s -o - | FileCheck %s
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
+; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; CHECK: store i8* %[[USP]], i8** %[[SPA]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/llvm/test/Transforms/SafeStack/ARM/debug.ll b/llvm/test/Transforms/SafeStack/ARM/debug.ll
new file mode 100644
index 0000000..6728c2f
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/ARM/debug.ll
@@ -0,0 +1,98 @@
+; RUN: opt -safe-stack -safestack-use-pointer-address < %s -S | FileCheck %s
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "armv7-pc-linux-android"
+
+; Original C used to generate debug info:
+; char*** addr;
+; char** __safestack_pointer_address() {
+; return *addr;
+; }
+; void Capture(char*x);
+; void f() { char c[16]; Capture(c); }
+
+; CHECK: !35 = !DILocation(line: 3, column: 11, scope: !17, inlinedAt: !36)
+; CHECK: !36 = distinct !DILocation(line: 6, scope: !27)
+
+@addr = common local_unnamed_addr global i8*** null, align 4, !dbg !0
+
+; Function Attrs: norecurse nounwind readonly safestack
+define i8** @__safestack_pointer_address() local_unnamed_addr #0 !dbg !17 {
+entry:
+ %0 = load i8***, i8**** @addr, align 4, !dbg !20, !tbaa !21
+ %1 = load i8**, i8*** %0, align 4, !dbg !25, !tbaa !21
+ ret i8** %1, !dbg !26
+}
+
+; Function Attrs: nounwind safestack
+define void @f() local_unnamed_addr #1 !dbg !27 {
+entry:
+ %c = alloca [16 x i8], align 1
+ %0 = getelementptr inbounds [16 x i8], [16 x i8]* %c, i32 0, i32 0, !dbg !35
+ call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %0) #5, !dbg !35
+ call void @llvm.dbg.declare(metadata [16 x i8]* %c, metadata !31, metadata !DIExpression()), !dbg !36
+ call void @Capture(i8* nonnull %0) #5, !dbg !37
+ call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0) #5, !dbg !38
+ ret void, !dbg !38
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #3
+
+declare void @Capture(i8*) local_unnamed_addr #4
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2
+
+attributes #0 = { norecurse nounwind readonly safestack "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind safestack "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { argmemonly nounwind }
+attributes #3 = { nounwind readnone speculatable }
+attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #5 = { nounwind }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!11, !12, !13, !14, !15}
+!llvm.ident = !{!16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "addr", scope: !2, file: !6, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "-", directory: "/")
+!4 = !{}
+!5 = !{!0}
+!6 = !DIFile(filename: "<stdin>", directory: "/")
+!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32)
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 32)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 32)
+!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
+!11 = !{i32 2, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{i32 1, !"min_enum_size", i32 4}
+!15 = !{i32 7, !"PIC Level", i32 1}
+!16 = !{!"clang"}
+!17 = distinct !DISubprogram(name: "__safestack_pointer_address", scope: !6, file: !6, line: 2, type: !18, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !2, retainedNodes: !4)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!8}
+!20 = !DILocation(line: 3, column: 11, scope: !17)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"any pointer", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 3, column: 10, scope: !17)
+!26 = !DILocation(line: 3, column: 3, scope: !17)
+!27 = distinct !DISubprogram(name: "f", scope: !6, file: !6, line: 6, type: !28, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !2, retainedNodes: !30)
+!28 = !DISubroutineType(types: !29)
+!29 = !{null}
+!30 = !{!31}
+!31 = !DILocalVariable(name: "c", scope: !27, file: !6, line: 6, type: !32)
+!32 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, elements: !33)
+!33 = !{!34}
+!34 = !DISubrange(count: 16)
+!35 = !DILocation(line: 6, column: 12, scope: !27)
+!36 = !DILocation(line: 6, column: 17, scope: !27)
+!37 = !DILocation(line: 6, column: 24, scope: !27)
+!38 = !DILocation(line: 6, column: 36, scope: !27)
diff --git a/llvm/test/Transforms/SafeStack/ARM/lit.local.cfg b/llvm/test/Transforms/SafeStack/ARM/lit.local.cfg
new file mode 100644
index 0000000..98c6700
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/ARM/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'ARM' in config.root.targets:
+ config.unsupported = True
+
diff --git a/llvm/test/Transforms/SafeStack/ARM/setjmp.ll b/llvm/test/Transforms/SafeStack/ARM/setjmp.ll
new file mode 100644
index 0000000..20e46f8
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/ARM/setjmp.ll
@@ -0,0 +1,36 @@
+; Test stack pointer restore after setjmp() with the function-call safestack ABI.
+; RUN: opt -safe-stack -S -mtriple=arm-linux-androideabi < %s -o - | FileCheck %s
+
+@env = global [64 x i32] zeroinitializer, align 4
+
+define void @f(i32 %b) safestack {
+entry:
+; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
+; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: %[[USDP:.*]] = alloca i8*
+; CHECK: store i8* %[[USP]], i8** %[[USDP]]
+; CHECK: call i32 @setjmp
+
+ %call = call i32 @setjmp(i32* getelementptr inbounds ([64 x i32], [64 x i32]* @env, i32 0, i32 0)) returns_twice
+
+; CHECK: %[[USP2:.*]] = load i8*, i8** %[[USDP]]
+; CHECK: store i8* %[[USP2]], i8** %[[SPA]]
+
+ %tobool = icmp eq i32 %b, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then:
+ %0 = alloca [42 x i8], align 1
+ %.sub = getelementptr inbounds [42 x i8], [42 x i8]* %0, i32 0, i32 0
+ call void @_Z7CapturePv(i8* %.sub)
+ br label %if.end
+
+if.end:
+; CHECK: store i8* %[[USP:.*]], i8** %[[SPA:.*]]
+
+ ret void
+}
+
+declare i32 @setjmp(i32*) returns_twice
+
+declare void @_Z7CapturePv(i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/abi.ll b/llvm/test/Transforms/SafeStack/X86/abi.ll
new file mode 100644
index 0000000..f437c4f
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/abi.ll
@@ -0,0 +1,30 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS32
+; RUN: opt -safe-stack -S -mtriple=x86_64-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS64
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; TLS: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; TLS: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; TLS: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
+
+; DIRECT-TLS32: %[[USP:.*]] = load i8*, i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+; DIRECT-TLS32: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS32: store i8* %[[USST]], i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+
+; DIRECT-TLS64: %[[USP:.*]] = load i8*, i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+; DIRECT-TLS64: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS64: store i8* %[[USST]], i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; TLS: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+; DIRECT-TLS32: store i8* %[[USP]], i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+; DIRECT-TLS64: store i8* %[[USP]], i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/abi_ssp.ll b/llvm/test/Transforms/SafeStack/X86/abi_ssp.ll
new file mode 100644
index 0000000..b489e07
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/abi_ssp.ll
@@ -0,0 +1,26 @@
+; RUN: opt -safe-stack -S -mtriple=i686-pc-linux-gnu < %s -o - | FileCheck --check-prefixes=COMMON,TLS32 %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck --check-prefixes=COMMON,TLS64 %s
+
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android < %s -o - | FileCheck --check-prefixes=COMMON,GLOBAL32 %s
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android24 < %s -o - | FileCheck --check-prefixes=COMMON,TLS32 %s
+
+; RUN: opt -safe-stack -S -mtriple=x86_64-linux-android < %s -o - | FileCheck --check-prefixes=COMMON,TLS64 %s
+
+; RUN: opt -safe-stack -S -mtriple=x86_64-unknown-fuchsia < %s -o - | FileCheck --check-prefixes=COMMON,FUCHSIA64 %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)*)
+; FUCHSIA64: %[[StackGuard:.*]] = load i8*, i8* addrspace(257)* inttoptr (i32 16 to i8* addrspace(257)*)
+; GLOBAL32: %[[StackGuard:.*]] = load i8*, i8** @__stack_chk_guard
+; COMMON: store i8* %[[StackGuard]], i8** %[[StackGuardSlot:.*]]
+ %a = alloca i8, align 1
+ call void @Capture(i8* %a)
+
+; COMMON: %[[A:.*]] = load i8*, i8** %[[StackGuardSlot]]
+; COMMON: icmp ne i8* %[[StackGuard]], %[[A]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/addr-taken.ll b/llvm/test/Transforms/SafeStack/X86/addr-taken.ll
new file mode 100644
index 0000000..0780a01
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/addr-taken.ll
@@ -0,0 +1,22 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Address-of local taken (j = &a)
+; Requires protector.
+
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %retval = alloca i32, align 4
+ %a = alloca i32, align 4
+ %j = alloca i32*, align 8
+ store i32 0, i32* %retval
+ %0 = load i32, i32* %a, align 4
+ %add = add nsw i32 %0, 1
+ store i32 %add, i32* %a, align 4
+ store i32* %a, i32** %j, align 8
+ ret void
+}
+
diff --git a/llvm/test/Transforms/SafeStack/X86/array-aligned.ll b/llvm/test/Transforms/SafeStack/X86/array-aligned.ll
new file mode 100644
index 0000000..26558e4f
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/array-aligned.ll
@@ -0,0 +1,38 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; array of [16 x i8]
+
+define void @foo(i8* %a) nounwind uwtable safestack {
+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
+
+ %a.addr = alloca i8*, align 8
+ %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
+
+ ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8
+ %a2 = load i8*, i8** %a.addr, align 8
+
+ ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]])
+ %call = call i8* @strcpy(i8* %gep, i8* %a2)
+
+ ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+ ret void
+}
+
+declare i8* @strcpy(i8*, i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/array.ll b/llvm/test/Transforms/SafeStack/X86/array.ll
new file mode 100644
index 0000000..b699352
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/array.ll
@@ -0,0 +1,89 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=i386-pc-contiki-unknown < %s -o - | FileCheck -check-prefix=SINGLE-THREAD %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+; array [4 x i8]
+; Requires protector.
+
+; CHECK: @__safestack_unsafe_stack_ptr = external thread_local(initialexec) global i8*
+; SINGLE-THREAD: @__safestack_unsafe_stack_ptr = external global i8*
+
+define void @foo(i8* %a) nounwind uwtable safestack {
+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
+
+ %a.addr = alloca i8*, align 8
+ %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
+
+ ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8
+ %a2 = load i8*, i8** %a.addr, align 8
+
+ ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]])
+ %call = call i8* @strcpy(i8* %gep, i8* %a2)
+
+ ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+ ret void
+}
+
+; Load from an array at a fixed offset, no overflow.
+define i8 @StaticArrayFixedSafe() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayFixedSafe(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 2
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array at a fixed offset with overflow.
+define i8 @StaticArrayFixedUnsafe() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayFixedUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 5
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array at an unknown offset.
+define i8 @StaticArrayVariableUnsafe(i32 %ofs) nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayVariableUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 %ofs
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array of an unknown size.
+define i8 @DynamicArrayUnsafe(i32 %sz) nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @DynamicArrayUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 %sz, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 2
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+declare i8* @strcpy(i8*, i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/byval.ll b/llvm/test/Transforms/SafeStack/X86/byval.ll
new file mode 100644
index 0000000..1b131aa
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/byval.ll
@@ -0,0 +1,68 @@
+; 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
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.S = type { [100 x i32] }
+
+; Safe access to a byval argument.
+define i32 @ByValSafe(%struct.S* byval nocapture readonly align 8 %zzz) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValSafe
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 3
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; Unsafe access to a byval argument.
+; Argument is copied to the unsafe stack.
+define i32 @ByValUnsafe(%struct.S* byval nocapture readonly align 8 %zzz, i64 %idx) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValUnsafe
+ ; CHECK: %[[A:.*]] = load {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: store {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[B:.*]] = getelementptr i8, i8* %[[A]], i32 -400
+ ; CHECK: %[[C:.*]] = bitcast %struct.S* %zzz to i8*
+ ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[B]], i8* align 8 %[[C]], i64 400, i1 false)
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 %idx
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; Unsafe access to a byval argument.
+; Argument is copied to the unsafe stack.
+; Check that dest align of memcpy is set according to datalayout prefered alignment
+define i32 @ByValUnsafe2(%struct.S* byval nocapture readonly %zzz, i64 %idx) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValUnsafe
+ ; CHECK: %[[A:.*]] = load {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: store {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[B:.*]] = getelementptr i8, i8* %[[A]], i32 -400
+ ; CHECK: %[[C:.*]] = bitcast %struct.S* %zzz to i8*
+ ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[B]], i8* %[[C]], i64 400, i1 false)
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 %idx
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; Highly aligned byval argument.
+define i32 @ByValUnsafeAligned(%struct.S* byval nocapture readonly align 64 %zzz, i64 %idx) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValUnsafeAligned
+ ; CHECK: %[[A:.*]] = load {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[B:.*]] = ptrtoint i8* %[[A]] to i64
+ ; CHECK: and i64 %[[B]], -64
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 0
+ %0 = load i32, i32* %arrayidx, align 64
+ %arrayidx2 = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 %idx
+ %1 = load i32, i32* %arrayidx2, align 4
+ %add = add nsw i32 %1, %0
+ ret i32 %add
+}
+
diff --git a/llvm/test/Transforms/SafeStack/X86/call.ll b/llvm/test/Transforms/SafeStack/X86/call.ll
new file mode 100644
index 0000000..a7bf9ae
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/call.ll
@@ -0,0 +1,178 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; no arrays / no nested arrays
+; Requires no protector.
+
+define void @foo(i8* %a) nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define void @foo(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a.addr = alloca i8*, align 8
+ store i8* %a, i8** %a.addr, align 8
+ %0 = load i8*, i8** %a.addr, align 8
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %0)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @call_memset(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 %len, i1 false)
+ ret void
+}
+
+define void @call_constant_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_memset
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 2
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 7, i1 false)
+ ret void
+}
+
+define void @call_constant_overflow_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_overflow_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 7
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 5, i1 false)
+ ret void
+}
+
+define void @call_constant_underflow_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_underflow_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr [10 x i8], [10 x i8]* %q, i32 0, i32 -1
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 3, i1 false)
+ ret void
+}
+
+; Readnone nocapture -> safe
+define void @call_readnone(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone(i8* %arraydecay)
+ ret void
+}
+
+; Arg0 is readnone, arg1 is not. Pass alloca ptr as arg0 -> safe
+define void @call_readnone0_0(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone0_0
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone0(i8* %arraydecay, i8* zeroinitializer)
+ ret void
+}
+
+; Arg0 is readnone, arg1 is not. Pass alloca ptr as arg1 -> unsafe
+define void @call_readnone0_1(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone0_1
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone0(i8 *zeroinitializer, i8* %arraydecay)
+ ret void
+}
+
+; Readonly nocapture -> unsafe
+define void @call_readonly(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readonly
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readonly(i8* %arraydecay)
+ ret void
+}
+
+; Readonly nocapture -> unsafe
+define void @call_arg_readonly(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_arg_readonly
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @arg_readonly(i8* %arraydecay)
+ ret void
+}
+
+; Readwrite nocapture -> unsafe
+define void @call_readwrite(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readwrite
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readwrite(i8* %arraydecay)
+ ret void
+}
+
+; Captures the argument -> unsafe
+define void @call_capture(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_capture
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @capture(i8* %arraydecay)
+ ret void
+}
+
+; Lifetime intrinsics are always safe.
+define void @call_lifetime(i32* %p) {
+ ; CHECK-LABEL: define void @call_lifetime
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+entry:
+ %q = alloca [100 x i8], align 16
+ %0 = bitcast [100 x i8]* %q to i8*
+ call void @llvm.lifetime.start.p0i8(i64 100, i8* %0)
+ call void @llvm.lifetime.end.p0i8(i64 100, i8* %0)
+ ret void
+}
+
+declare void @readonly(i8* nocapture) readonly
+declare void @arg_readonly(i8* readonly nocapture)
+declare void @readwrite(i8* nocapture)
+declare void @capture(i8* readnone) readnone
+
+declare void @readnone(i8* nocapture) readnone
+declare void @readnone0(i8* nocapture readnone, i8* nocapture)
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) nounwind argmemonly
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind argmemonly
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind argmemonly
diff --git a/llvm/test/Transforms/SafeStack/X86/cast.ll b/llvm/test/Transforms/SafeStack/X86/cast.ll
new file mode 100644
index 0000000..23f525d
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/cast.ll
@@ -0,0 +1,39 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; PtrToInt/IntToPtr Cast
+
+define void @IntToPtr() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @IntToPtr(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = ptrtoint i32* %a to i64
+ %1 = inttoptr i64 %0 to i32*
+ ret void
+}
+
+define i8 @BitCastNarrow() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @BitCastNarrow(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = load i8, i8* %0, align 1
+ ret i8 %1
+}
+
+define i64 @BitCastWide() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @BitCastWide(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i64
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i64*
+ %1 = load i64, i64* %0, align 1
+ ret i64 %1
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/coloring-ssp.ll b/llvm/test/Transforms/SafeStack/X86/coloring-ssp.ll
new file mode 100644
index 0000000..040632e
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/coloring-ssp.ll
@@ -0,0 +1,34 @@
+; RUN: opt -safe-stack -safe-stack-coloring=1 -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+; %x and %y share a stack slot between them, but not with the stack guard.
+define void @f() safestack sspreq {
+; CHECK-LABEL: define void @f
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+
+; CHECK: %[[A:.*]] = getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK: %[[StackGuardSlot:.*]] = bitcast i8* %[[A]] to i8**
+; CHECK: store i8* %{{.*}}, i8** %[[StackGuardSlot]]
+
+ %x = alloca i64, align 8
+ %y = alloca i64, align 8
+ %x0 = bitcast i64* %x to i8*
+ %y0 = bitcast i64* %y to i8*
+
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+ call void @capture64(i64* %x)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0)
+
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+ call void @capture64(i64* %y)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0)
+
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @capture64(i64*)
diff --git a/llvm/test/Transforms/SafeStack/X86/coloring.ll b/llvm/test/Transforms/SafeStack/X86/coloring.ll
new file mode 100644
index 0000000..60e960e
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/coloring.ll
@@ -0,0 +1,44 @@
+; RUN: opt -safe-stack -safe-stack-coloring=1 -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -safe-stack-coloring=1 -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.p0i8(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.p0i8(i64 4, i8* %0)
+ %1 = bitcast i32* %x1 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 4, i8* %1)
+ %2 = bitcast i32* %x2 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 4, i8* %2)
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @capture(i32*)
diff --git a/llvm/test/Transforms/SafeStack/X86/coloring2.ll b/llvm/test/Transforms/SafeStack/X86/coloring2.ll
new file mode 100644
index 0000000..ef00d9b
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/coloring2.ll
@@ -0,0 +1,521 @@
+; RUN: opt -safe-stack -safe-stack-coloring=1 -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -safe-stack-coloring=1 -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.p0i8(i64 -1, i8* %z0)
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture32(i32* %z)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture32(i32* %x)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture32(i32* %y)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0)
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0)
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture64(i64* %z)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0)
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %x0)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %0)
+ %1 = bitcast i64* %x2 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %3)
+ br label %if.end
+
+if.else: ; preds = %if.then
+ %4 = bitcast i64* %y2 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %4)
+ br label %if.end
+
+if.end: ; preds = %if.else, %if.then3
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2)
+ br label %if.end9
+
+if.else4: ; preds = %entry
+ %5 = bitcast i64* %z to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %6)
+ br label %if.end8
+
+if.else7: ; preds = %if.else4
+ %7 = bitcast i64* %z2 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %7)
+ br label %if.end8
+
+if.end8: ; preds = %if.else7, %if.then6
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %5)
+ br label %if.end9
+
+if.end9: ; preds = %if.end8, %if.end
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %y0)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0)
+ ret void
+bb3:
+ call void @llvm.lifetime.end.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start.p0i8(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.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start.p0i8(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.p0i8(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.p0i8(i64 -1, i8* %x0)
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %x0)
+ br i1 %d, label %bb2, label %bb3
+bb2:
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %0)
+ %1 = bitcast [100 x i32]* %B.i to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %0)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1)
+ %2 = bitcast [100 x i32]* %A.i1 to i8*
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2)
+ %3 = bitcast [100 x i32]* %B.i2 to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %2)
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %buf1)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %buf1)
+
+ call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf1)
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %0) nounwind
+ %1 = bitcast [100 x i32]* %B.i to i8*
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %0) nounwind
+ call void @llvm.lifetime.end.p0i8(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.p0i8(i64 -1, i8* %a8)
+ call void @llvm.lifetime.start.p0i8(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.p0i8(i64 -1, i8* %a8)
+ call void @llvm.lifetime.end.p0i8(i64 -1, i8* %b8)
+ ret i32 %z3
+}
+
+define void @end_loop() safestack {
+; CHECK-LABEL: define void @end_loop()
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i8, align 4
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) nounwind
+ br label %l2
+
+l2:
+ call void @capture8(i8* %x)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x) nounwind
+ br label %l2
+}
+
+; Check that @x and @y get distinct stack slots => @x lifetime does not break
+; when control re-enters l2.
+define void @start_loop() safestack {
+; CHECK-LABEL: define void @start_loop()
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16
+ %x = alloca i8, align 4
+ %y = alloca i8, align 4
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) nounwind
+ br label %l2
+
+l2:
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %y) nounwind
+ call void @capture8(i8* %y)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %y) nounwind
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) nounwind
+ call void @capture8(i8* %x)
+ br label %l2
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @capture8(i8*)
+declare void @capture32(i32*)
+declare void @capture64(i64*)
+declare void @capture100x32([100 x i32]*)
diff --git a/llvm/test/Transforms/SafeStack/X86/constant-gep-call.ll b/llvm/test/Transforms/SafeStack/X86/constant-gep-call.ll
new file mode 100644
index 0000000..456c1cb
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/constant-gep-call.ll
@@ -0,0 +1,26 @@
+; 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
+
+%struct.nest = type { %struct.pair, %struct.pair }
+%struct.pair = type { i32, i32 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Nested structure, no arrays, no address-of expressions.
+; Verify that the resulting gep-of-gep does not incorrectly trigger
+; a safe stack protector.
+; safestack attribute
+; Requires no protector.
+; CHECK-LABEL: @foo(
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.nest, align 4
+ %b = getelementptr inbounds %struct.nest, %struct.nest* %c, i32 0, i32 1
+ %_a = getelementptr inbounds %struct.pair, %struct.pair* %b, i32 0, i32 0
+ %0 = load i32, i32* %_a, align 4
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %0)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/constant-gep.ll b/llvm/test/Transforms/SafeStack/X86/constant-gep.ll
new file mode 100644
index 0000000..6468a76
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/constant-gep.ll
@@ -0,0 +1,20 @@
+; 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
+
+%class.A = type { [2 x i8] }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; [2 x i8] in a class
+; safestack attribute
+; Requires no protector.
+; CHECK-LABEL: @foo(
+define signext i8 @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ %a = alloca %class.A, align 1
+ %array = getelementptr inbounds %class.A, %class.A* %a, i32 0, i32 0
+ %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0
+ %0 = load i8, i8* %arrayidx, align 1
+ ret i8 %0
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/constant-geps.ll b/llvm/test/Transforms/SafeStack/X86/constant-geps.ll
new file mode 100644
index 0000000..8a6f754
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/constant-geps.ll
@@ -0,0 +1,28 @@
+; 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
+
+%struct.deep = type { %union.anon }
+%union.anon = type { %struct.anon }
+%struct.anon = type { %struct.anon.0 }
+%struct.anon.0 = type { %union.anon.1 }
+%union.anon.1 = type { [2 x i8] }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; [2 x i8] nested in several layers of structs and unions
+; safestack attribute
+; Requires no protector.
+; CHECK-LABEL: @foo(
+define signext i8 @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ %x = alloca %struct.deep, align 1
+ %b = getelementptr inbounds %struct.deep, %struct.deep* %x, i32 0, i32 0
+ %c = bitcast %union.anon* %b to %struct.anon*
+ %d = getelementptr inbounds %struct.anon, %struct.anon* %c, i32 0, i32 0
+ %e = getelementptr inbounds %struct.anon.0, %struct.anon.0* %d, i32 0, i32 0
+ %array = bitcast %union.anon.1* %e to [2 x i8]*
+ %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0
+ %0 = load i8, i8* %arrayidx, align 1
+ ret i8 %0
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll
new file mode 100644
index 0000000..c944f84
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll
@@ -0,0 +1,56 @@
+; 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, 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]], metadata ![[TYPE:.*]], metadata !DIExpression(DW_OP_deref))
+; CHECK: call void @capture({{.*}} %[[VLA]])
+
+ %vla = alloca i8, i64 %0, align 16, !dbg !16
+ tail call void @llvm.dbg.value(metadata i8* %vla, 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, 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, retainedNodes: !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)
+
+!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/llvm/test/Transforms/SafeStack/X86/debug-loc.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc.ll
new file mode 100644
index 0000000..b8a7c08
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/debug-loc.ll
@@ -0,0 +1,80 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+
+; Test debug location for the local variables moved onto the unsafe stack.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.S = type { [100 x i8] }
+
+; Function Attrs: safestack uwtable
+define void @f(%struct.S* byval align 8 %zzz) #0 !dbg !12 {
+; CHECK: define void @f
+
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+
+ %xxx = alloca %struct.S, align 1
+ call void @llvm.dbg.declare(metadata %struct.S* %zzz, metadata !18, metadata !19), !dbg !20
+ call void @llvm.dbg.declare(metadata %struct.S* %xxx, metadata !21, metadata !19), !dbg !22
+
+; dbg.declare for %zzz and %xxx are gone; replaced with dbg.declare based off the unsafe stack pointer
+; CHECK-NOT: call void @llvm.dbg.declare
+; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_ARG:.*]], metadata !DIExpression(DW_OP_constu, 104, DW_OP_minus))
+; CHECK-NOT: call void @llvm.dbg.declare
+; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_LOCAL:.*]], metadata !DIExpression(DW_OP_constu, 208, DW_OP_minus))
+; CHECK-NOT: call void @llvm.dbg.declare
+
+ call void @Capture(%struct.S* %zzz), !dbg !23
+ call void @Capture(%struct.S* %xxx), !dbg !24
+
+; dbg.declare appears before the first use
+; CHECK: call void @Capture
+; CHECK: call void @Capture
+
+ ret void, !dbg !25
+}
+
+; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz"
+; 100 aligned up to 8
+
+; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx"
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare void @Capture(%struct.S*) #2
+
+attributes #0 = { safestack uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!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: 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: !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)
+!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, retainedNodes: !2)
+!13 = !DISubroutineType(types: !14)
+!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: !4)
+!19 = !DIExpression()
+!20 = !DILocation(line: 10, column: 10, scope: !12)
+!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)
+!25 = !DILocation(line: 14, column: 1, scope: !12)
diff --git a/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll b/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll
new file mode 100644
index 0000000..afa143f
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/debug-loc2.ll
@@ -0,0 +1,96 @@
+; 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:.*]], metadata !{{.*}}, metadata !{{.*}})
+ tail call void @llvm.dbg.value(metadata i32* %x1, 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]], metadata !{{.*}}, metadata !{{.*}})
+ tail call void @llvm.dbg.value(metadata i32* %x1, metadata !10, metadata !24), !dbg !16
+
+; Supported dbg.value: rewritted based on the [[USP]] value.
+; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], metadata ![[X1:.*]], metadata !DIExpression(DW_OP_deref, DW_OP_constu, 4, DW_OP_minus))
+ tail call void @llvm.dbg.value(metadata i32* %x1, 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]], metadata ![[X2:.*]], metadata !DIExpression(DW_OP_deref, DW_OP_constu, 8, DW_OP_minus))
+ call void @llvm.dbg.value(metadata i32* %x2, 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.p0i8(i64, i8* nocapture) #1
+
+declare void @capture(i32*) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, 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, retainedNodes: !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)
+
+!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_constu, 42, DW_OP_minus)
diff --git a/llvm/test/Transforms/SafeStack/X86/dynamic-alloca.ll b/llvm/test/Transforms/SafeStack/X86/dynamic-alloca.ll
new file mode 100644
index 0000000..b0571f7
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/dynamic-alloca.ll
@@ -0,0 +1,22 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Variable sized alloca
+; safestack attribute
+; Requires protector.
+define void @foo(i32 %n) nounwind uwtable safestack {
+entry:
+ ; 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
+ %0 = load i32, i32* %n.addr, align 4
+ %conv = sext i32 %0 to i64
+ %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/llvm/test/Transforms/SafeStack/X86/escape-addr-pointer.ll b/llvm/test/Transforms/SafeStack/X86/escape-addr-pointer.ll
new file mode 100644
index 0000000..615d711
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-addr-pointer.ll
@@ -0,0 +1,23 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a pointer
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %a = alloca i32*, align 8
+ %b = alloca i32**, align 8
+ %call = call i32* @getp()
+ store i32* %call, i32** %a, align 8
+ store i32** %a, i32*** %b, align 8
+ %0 = load i32**, i32*** %b, align 8
+ call void @funcall2(i32** %0)
+ ret void
+}
+
+declare void @funcall2(i32**)
+declare i32* @getp()
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store.ll b/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store.ll
new file mode 100644
index 0000000..9d556a6
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store.ll
@@ -0,0 +1,23 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a local cast to a ptr of a different type
+; (e.g., int a; ... ; float *b = &a;)
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %a = alloca i32, align 4
+ %b = alloca float*, align 8
+ store i32 0, i32* %a, align 4
+ %0 = bitcast i32* %a to float*
+ store float* %0, float** %b, align 8
+ %1 = load float*, float** %b, align 8
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), float* %1)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll b/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll
new file mode 100644
index 0000000..5f1f873
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll
@@ -0,0 +1,20 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a local cast to a ptr of a different type (optimized)
+; (e.g., int a; ... ; float *b = &a;)
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %a = alloca i32, align 4
+ store i32 0, i32* %a, align 4
+ %0 = bitcast i32* %a to float*
+ call void @funfloat(float* %0) nounwind
+ ret void
+}
+
+declare void @funfloat(float*)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-call.ll b/llvm/test/Transforms/SafeStack/X86/escape-call.ll
new file mode 100644
index 0000000..ce09780
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-call.ll
@@ -0,0 +1,16 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Passing addr-of to function call
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %b = alloca i32, align 4
+ call void @funcall(i32* %b) nounwind
+ ret void
+}
+
+declare void @funcall(i32*)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-casted-pointer.ll b/llvm/test/Transforms/SafeStack/X86/escape-casted-pointer.ll
new file mode 100644
index 0000000..bf6ce1d
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-casted-pointer.ll
@@ -0,0 +1,24 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a casted pointer
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %a = alloca i32*, align 8
+ %b = alloca float**, align 8
+ %call = call i32* @getp()
+ store i32* %call, i32** %a, align 8
+ %0 = bitcast i32** %a to float**
+ store float** %0, float*** %b, align 8
+ %1 = load float**, float*** %b, align 8
+ call void @funfloat2(float** %1)
+ ret void
+}
+
+declare void @funfloat2(float**)
+declare i32* @getp()
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-gep-call.ll b/llvm/test/Transforms/SafeStack/X86/escape-gep-call.ll
new file mode 100644
index 0000000..42b5dd5
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-gep-call.ll
@@ -0,0 +1,20 @@
+; 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
+
+%struct.pair = type { i32, i32 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of struct element, GEP followed by callinst.
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.pair, align 4
+ %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i64 0, i32 1
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %y) nounwind
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-gep-invoke.ll b/llvm/test/Transforms/SafeStack/X86/escape-gep-invoke.ll
new file mode 100644
index 0000000..8495ff9
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-gep-invoke.ll
@@ -0,0 +1,34 @@
+; 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
+
+%struct.pair = type { i32, i32 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a struct element passed into an invoke instruction.
+; (GEP followed by an invoke)
+; safestack attribute
+; Requires protector.
+define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.pair, align 4
+ %exn.slot = alloca i8*
+ %ehselector.slot = alloca i32
+ %a = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0
+ store i32 0, i32* %a, align 4
+ %a1 = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0
+ invoke void @_Z3exceptPi(i32* %a1)
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+ ret i32 0
+
+lpad:
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ ret i32 0
+}
+
+declare void @_Z3exceptPi(i32*)
+declare i32 @__gxx_personality_v0(...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-gep-negative.ll b/llvm/test/Transforms/SafeStack/X86/escape-gep-negative.ll
new file mode 100644
index 0000000..80d405d
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-gep-negative.ll
@@ -0,0 +1,18 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a local, optimized into a GEP (e.g., &a - 12)
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %a = alloca i32, align 4
+ %add.ptr5 = getelementptr inbounds i32, i32* %a, i64 -12
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %add.ptr5) nounwind
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll b/llvm/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll
new file mode 100644
index 0000000..73a8e58
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll
@@ -0,0 +1,22 @@
+; 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
+
+%struct.pair = type { i32, i32 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of struct element, GEP followed by ptrtoint.
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.pair, align 4
+ %b = alloca i32*, align 8
+ %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1
+ %0 = ptrtoint i32* %y to i64
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i64 %0)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-gep-store.ll b/llvm/test/Transforms/SafeStack/X86/escape-gep-store.ll
new file mode 100644
index 0000000..7c6c0a3
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-gep-store.ll
@@ -0,0 +1,23 @@
+; 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
+
+%struct.pair = type { i32, i32 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of struct element. (GEP followed by store).
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.pair, align 4
+ %b = alloca i32*, align 8
+ %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1
+ store i32* %y, i32** %b, align 8
+ %0 = load i32*, i32** %b, align 8
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32* %0)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-phi-call.ll b/llvm/test/Transforms/SafeStack/X86/escape-phi-call.ll
new file mode 100644
index 0000000..10b6c1f
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-phi-call.ll
@@ -0,0 +1,36 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of in phi instruction
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %x = alloca double, align 8
+ %call = call double @testi_aux() nounwind
+ store double %call, double* %x, align 8
+ %cmp = fcmp ogt double %call, 3.140000e+00
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then: ; preds = %entry
+ %call1 = call double @testi_aux() nounwind
+ store double %call1, double* %x, align 8
+ br label %if.end4
+
+if.else: ; preds = %entry
+ %cmp2 = fcmp ogt double %call, 1.000000e+00
+ br i1 %cmp2, label %if.then3, label %if.end4
+
+if.then3: ; preds = %if.else
+ br label %if.end4
+
+if.end4: ; preds = %if.else, %if.then3, %if.then
+ %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ]
+ %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind
+ ret void
+}
+
+declare double @testi_aux()
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-select-call.ll b/llvm/test/Transforms/SafeStack/X86/escape-select-call.ll
new file mode 100644
index 0000000..9e54dd8
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-select-call.ll
@@ -0,0 +1,22 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of in select instruction
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %x = alloca double, align 8
+ %call = call double @testi_aux() nounwind
+ store double %call, double* %x, align 8
+ %cmp2 = fcmp ogt double %call, 0.000000e+00
+ %y.1 = select i1 %cmp2, double* %x, double* null
+ %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), double* %y.1)
+ ret void
+}
+
+declare double @testi_aux()
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/escape-vector.ll b/llvm/test/Transforms/SafeStack/X86/escape-vector.ll
new file mode 100644
index 0000000..76b01c7
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/escape-vector.ll
@@ -0,0 +1,21 @@
+; 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
+
+%struct.vec = type { <4 x i32> }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a vector nested in a struct
+; safestack attribute
+; Requires protector.
+define void @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %c = alloca %struct.vec, align 16
+ %y = getelementptr inbounds %struct.vec, %struct.vec* %c, i64 0, i32 0
+ %add.ptr = getelementptr inbounds <4 x i32>, <4 x i32>* %y, i64 -12
+ %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), <4 x i32>* %add.ptr) nounwind
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/invoke.ll b/llvm/test/Transforms/SafeStack/X86/invoke.ll
new file mode 100644
index 0000000..bfebc33
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/invoke.ll
@@ -0,0 +1,33 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Addr-of a variable passed into an invoke instruction.
+; safestack attribute
+; Requires protector and stack restore after landing pad.
+define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16
+ %a = alloca i32, align 4
+ %exn.slot = alloca i8*
+ %ehselector.slot = alloca i32
+ store i32 0, i32* %a, align 4
+ invoke void @_Z3exceptPi(i32* %a)
+ to label %invoke.cont unwind label %lpad
+
+invoke.cont:
+ ret i32 0
+
+lpad:
+ ; CHECK: landingpad
+ ; CHECK-NEXT: catch
+ %0 = landingpad { i8*, i32 }
+ catch i8* null
+ ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr
+ ret i32 0
+}
+
+declare void @_Z3exceptPi(i32*)
+declare i32 @__gxx_personality_v0(...)
diff --git a/llvm/test/Transforms/SafeStack/X86/layout-frag.ll b/llvm/test/Transforms/SafeStack/X86/layout-frag.ll
new file mode 100644
index 0000000..b9831c2
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/layout-frag.ll
@@ -0,0 +1,39 @@
+; Test that safestack layout reuses a region w/o fragmentation.
+; RUN: opt -safe-stack -safe-stack-coloring=1 -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+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
+
+ %x0 = alloca i64, align 8
+ %x1 = alloca i8, align 1
+ %x2 = alloca i64, align 8
+
+ %x0a = bitcast i64* %x0 to i8*
+ %x2a = bitcast i64* %x2 to i8*
+
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x0a)
+ call void @capture64(i64* %x0)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x0a)
+
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x1)
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x2a)
+ call void @capture8(i8* %x1)
+ call void @capture64(i64* %x2)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x1)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x2a)
+
+; Test that i64 allocas share space.
+; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8
+; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -9
+; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8
+
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
+declare void @capture8(i8*)
+declare void @capture64(i64*)
diff --git a/llvm/test/Transforms/SafeStack/X86/layout-region-split.ll b/llvm/test/Transforms/SafeStack/X86/layout-region-split.ll
new file mode 100644
index 0000000..ceb18bb
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/layout-region-split.ll
@@ -0,0 +1,84 @@
+; Regression test for safestack layout. Used to fail with asan.
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+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 -224
+
+ %x0 = alloca i8, align 16
+ %x1 = alloca i8, align 16
+ %x2 = alloca i8, align 16
+ %x3 = alloca i8, align 16
+ %x4 = alloca i8, align 16
+ %x5 = alloca i8, align 16
+ %x6 = alloca i8, align 16
+ %x7 = alloca i8, align 16
+ %x8 = alloca i8, align 16
+ %x9 = alloca i8, align 16
+ %x10 = alloca i8, align 16
+ %x11 = alloca i8, align 16
+ %x12 = alloca i8, align 16
+ %x13 = alloca i8, align 16
+ %y0 = alloca i8, align 2
+ %y1 = alloca i8, align 2
+ %y2 = alloca i8, align 2
+ %y3 = alloca i8, align 2
+ %y4 = alloca i8, align 2
+ %y5 = alloca i8, align 2
+ %y6 = alloca i8, align 2
+ %y7 = alloca i8, align 2
+ %y8 = alloca i8, align 2
+
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -16
+ call void @capture8(i8* %x0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -32
+ call void @capture8(i8* %x1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -48
+ call void @capture8(i8* %x2)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -64
+ call void @capture8(i8* %x3)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -80
+ call void @capture8(i8* %x4)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -96
+ call void @capture8(i8* %x5)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -112
+ call void @capture8(i8* %x6)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -128
+ call void @capture8(i8* %x7)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -144
+ call void @capture8(i8* %x8)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -160
+ call void @capture8(i8* %x9)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -176
+ call void @capture8(i8* %x10)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -192
+ call void @capture8(i8* %x11)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -208
+ call void @capture8(i8* %x12)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -224
+ call void @capture8(i8* %x13)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -2
+ call void @capture8(i8* %y0)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -4
+ call void @capture8(i8* %y1)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -6
+ call void @capture8(i8* %y2)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -8
+ call void @capture8(i8* %y3)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -10
+ call void @capture8(i8* %y4)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -12
+ call void @capture8(i8* %y5)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -14
+ call void @capture8(i8* %y6)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -18
+ call void @capture8(i8* %y7)
+; CHECK: getelementptr i8, i8* %[[USP]], i32 -20
+ call void @capture8(i8* %y8)
+
+ ret void
+}
+
+declare void @capture8(i8*)
diff --git a/llvm/test/Transforms/SafeStack/X86/lit.local.cfg b/llvm/test/Transforms/SafeStack/X86/lit.local.cfg
new file mode 100644
index 0000000..e71f3cc
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'X86' in config.root.targets:
+ config.unsupported = True
+
diff --git a/llvm/test/Transforms/SafeStack/X86/memintrinsic-oob-read.ll b/llvm/test/Transforms/SafeStack/X86/memintrinsic-oob-read.ll
new file mode 100644
index 0000000..90af6b3
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/memintrinsic-oob-read.ll
@@ -0,0 +1,14 @@
+; 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
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)
+
+; CHECK: __safestack_unsafe_stack_ptr
+define void @oob_read(i8* %ptr) safestack {
+ %1 = alloca i8
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %ptr, i8* align 1 %1, i64 4, i1 false)
+ ret void
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/no-attr.ll b/llvm/test/Transforms/SafeStack/X86/no-attr.ll
new file mode 100644
index 0000000..d9bcefd
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/no-attr.ll
@@ -0,0 +1,27 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; no safestack attribute
+; Requires no protector.
+
+; CHECK-NOT: __safestack_unsafe_stack_ptr
+
+; CHECK: @foo
+define void @foo(i8* %a) nounwind uwtable {
+entry:
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ %a.addr = alloca i8*, align 8
+ %buf = alloca [16 x i8], align 16
+ store i8* %a, i8** %a.addr, align 8
+ %arraydecay = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0
+ %0 = load i8*, i8** %a.addr, align 8
+ %call = call i8* @strcpy(i8* %arraydecay, i8* %0)
+ %arraydecay1 = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0
+ %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %arraydecay1)
+ ret void
+}
+
+declare i8* @strcpy(i8*, i8*)
+declare i32 @printf(i8*, ...)
diff --git a/llvm/test/Transforms/SafeStack/X86/phi-cycle.ll b/llvm/test/Transforms/SafeStack/X86/phi-cycle.ll
new file mode 100644
index 0000000..026e887
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/phi-cycle.ll
@@ -0,0 +1,50 @@
+; 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
+
+%struct.small = type { i8 }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Address-of a structure taken in a function with a loop where
+; the alloca is an incoming value to a PHI node and a use of that PHI
+; node is also an incoming value.
+; Verify that the address-of analysis does not get stuck in infinite
+; recursion when chasing the alloca through the PHI nodes.
+; Requires protector.
+define i32 @foo(i32 %arg) nounwind uwtable safestack {
+bb:
+ ; CHECK: __safestack_unsafe_stack_ptr
+ %tmp = alloca %struct.small*, align 8
+ %tmp1 = call i32 (...) @dummy(%struct.small** %tmp) nounwind
+ %tmp2 = load %struct.small*, %struct.small** %tmp, align 8
+ %tmp3 = ptrtoint %struct.small* %tmp2 to i64
+ %tmp4 = trunc i64 %tmp3 to i32
+ %tmp5 = icmp sgt i32 %tmp4, 0
+ br i1 %tmp5, label %bb6, label %bb21
+
+bb6: ; preds = %bb17, %bb
+ %tmp7 = phi %struct.small* [ %tmp19, %bb17 ], [ %tmp2, %bb ]
+ %tmp8 = phi i64 [ %tmp20, %bb17 ], [ 1, %bb ]
+ %tmp9 = phi i32 [ %tmp14, %bb17 ], [ %tmp1, %bb ]
+ %tmp10 = getelementptr inbounds %struct.small, %struct.small* %tmp7, i64 0, i32 0
+ %tmp11 = load i8, i8* %tmp10, align 1
+ %tmp12 = icmp eq i8 %tmp11, 1
+ %tmp13 = add nsw i32 %tmp9, 8
+ %tmp14 = select i1 %tmp12, i32 %tmp13, i32 %tmp9
+ %tmp15 = trunc i64 %tmp8 to i32
+ %tmp16 = icmp eq i32 %tmp15, %tmp4
+ br i1 %tmp16, label %bb21, label %bb17
+
+bb17: ; preds = %bb6
+ %tmp18 = getelementptr inbounds %struct.small*, %struct.small** %tmp, i64 %tmp8
+ %tmp19 = load %struct.small*, %struct.small** %tmp18, align 8
+ %tmp20 = add i64 %tmp8, 1
+ br label %bb6
+
+bb21: ; preds = %bb6, %bb
+ %tmp22 = phi i32 [ %tmp1, %bb ], [ %tmp14, %bb6 ]
+ %tmp23 = call i32 (...) @dummy(i32 %tmp22) nounwind
+ ret i32 undef
+}
+
+declare i32 @dummy(...)
diff --git a/llvm/test/Transforms/SafeStack/X86/phi.ll b/llvm/test/Transforms/SafeStack/X86/phi.ll
new file mode 100644
index 0000000..3ee56aa
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/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/llvm/test/Transforms/SafeStack/X86/ret.ll b/llvm/test/Transforms/SafeStack/X86/ret.ll
new file mode 100644
index 0000000..b2b8e56
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/ret.ll
@@ -0,0 +1,17 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Returns an alloca address.
+; Requires protector.
+
+define i64 @foo() nounwind readnone safestack {
+entry:
+ ; CHECK-LABEL: define i64 @foo(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i64
+ %x = alloca [100 x i32], align 16
+ %0 = ptrtoint [100 x i32]* %x to i64
+ ret i64 %0
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/setjmp.ll b/llvm/test/Transforms/SafeStack/X86/setjmp.ll
new file mode 100644
index 0000000..e38bff6
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/setjmp.ll
@@ -0,0 +1,37 @@
+; 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
+
+%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t }
+%struct.__sigset_t = type { [16 x i64] }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16
+
+; setjmp/longjmp test.
+; Requires protector.
+define i32 @foo() nounwind uwtable safestack {
+entry:
+ ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16
+ %retval = alloca i32, align 4
+ %x = alloca i32, align 4
+ store i32 0, i32* %retval
+ store i32 42, i32* %x, align 4
+ %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice
+ ; CHECK: setjmp
+ ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr
+ %tobool = icmp ne i32 %call, 0
+ br i1 %tobool, label %if.else, label %if.then
+if.then: ; preds = %entry
+ call void @funcall(i32* %x)
+ br label %if.end
+if.else: ; preds = %entry
+ call i32 (...) @dummy()
+ br label %if.end
+if.end: ; preds = %if.else, %if.then
+ ret i32 0
+}
+
+declare i32 @_setjmp(%struct.__jmp_buf_tag*)
+declare void @funcall(i32*)
+declare i32 @dummy(...)
diff --git a/llvm/test/Transforms/SafeStack/X86/setjmp2.ll b/llvm/test/Transforms/SafeStack/X86/setjmp2.ll
new file mode 100644
index 0000000..dc83c48
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/setjmp2.ll
@@ -0,0 +1,43 @@
+; 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
+
+%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t }
+%struct.__sigset_t = type { [16 x i64] }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16
+
+; setjmp/longjmp test with dynamically sized array.
+; Requires protector.
+; CHECK: @foo(i32 %[[ARG:.*]])
+define i32 @foo(i32 %size) nounwind uwtable safestack {
+entry:
+ ; 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
+ ; CHECK-NEXT: %[[MUL:.*]] = mul i64 %[[ZEXT]], 4
+ ; CHECK-NEXT: %[[SP2:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+ ; CHECK-NEXT: %[[PTRTOINT:.*]] = ptrtoint i8* %[[SP2]] to i64
+ ; CHECK-NEXT: %[[SUB:.*]] = sub i64 %[[PTRTOINT]], %[[MUL]]
+ ; CHECK-NEXT: %[[AND:.*]] = and i64 %[[SUB]], -16
+ ; CHECK-NEXT: %[[INTTOPTR:.*]] = inttoptr i64 %[[AND]] to i8*
+ ; CHECK-NEXT: store i8* %[[INTTOPTR]], i8** @__safestack_unsafe_stack_ptr
+ ; CHECK-NEXT: store i8* %[[INTTOPTR]], i8** %unsafe_stack_dynamic_ptr
+ ; CHECK-NEXT: %[[ALLOCA:.*]] = bitcast i8* %[[INTTOPTR]] to i32*
+ %a = alloca i32, i32 %size
+
+ ; CHECK: setjmp
+ ; CHECK-NEXT: %[[LOAD:.*]] = load i8*, i8** %[[DYNPTR]]
+ ; CHECK-NEXT: store i8* %[[LOAD]], i8** @__safestack_unsafe_stack_ptr
+ %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice
+
+ ; CHECK: call void @funcall(i32* %[[ALLOCA]])
+ call void @funcall(i32* %a)
+ ; CHECK-NEXT: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr
+ ret i32 0
+}
+
+declare i32 @_setjmp(%struct.__jmp_buf_tag*)
+declare void @funcall(i32*)
diff --git a/llvm/test/Transforms/SafeStack/X86/sink-to-use.ll b/llvm/test/Transforms/SafeStack/X86/sink-to-use.ll
new file mode 100644
index 0000000..e208ce1
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/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/llvm/test/Transforms/SafeStack/X86/ssp.ll b/llvm/test/Transforms/SafeStack/X86/ssp.ll
new file mode 100644
index 0000000..0e28878
--- /dev/null
+++ b/llvm/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/llvm/test/Transforms/SafeStack/X86/store.ll b/llvm/test/Transforms/SafeStack/X86/store.ll
new file mode 100644
index 0000000..f493dd0
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/store.ll
@@ -0,0 +1,63 @@
+; 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
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+define void @bad_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @bad_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = ptrtoint i32* %a to i64
+ %1 = inttoptr i64 %0 to i64*
+ store i64 zeroinitializer, i64* %1
+ ret void
+}
+
+define void @good_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @good_store(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ store i8 zeroinitializer, i8* %0
+ ret void
+}
+
+define void @overflow_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @overflow_gep_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 4
+ store i8 zeroinitializer, i8* %1
+ ret void
+}
+
+define void @underflow_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @underflow_gep_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 -1
+ store i8 zeroinitializer, i8* %1
+ ret void
+}
+
+define void @good_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @good_gep_store(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 3
+ store i8 zeroinitializer, i8* %1
+ ret void
+}
diff --git a/llvm/test/Transforms/SafeStack/X86/struct.ll b/llvm/test/Transforms/SafeStack/X86/struct.ll
new file mode 100644
index 0000000..b64803d
--- /dev/null
+++ b/llvm/test/Transforms/SafeStack/X86/struct.ll
@@ -0,0 +1,40 @@
+; 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
+
+%struct.foo = type { [16 x i8] }
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; struct { [16 x i8] }
+
+define void @foo(i8* %a) nounwind uwtable safestack {
+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
+
+ %a.addr = alloca i8*, align 8
+ %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
+
+ ; CHECK: %[[A:.*]] = load i8*, i8** %[[AADDR]], align 8
+ %a2 = load i8*, i8** %a.addr, align 8
+
+ ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A]])
+ %call = call i8* @strcpy(i8* %gep, i8* %a2)
+
+ ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+ ret void
+}
+
+declare i8* @strcpy(i8*, i8*)