1 ; RUN: opt < %s -passes=asan -S | FileCheck %s
3 ; Source (-O0 -fsanitize=address -fsanitize-address-use-after-scope):
4 ;; struct S { int x, y; };
5 ;; void swap(S *a, S *b, bool doit) {
13 target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
14 target triple = "x86_64-apple-macosx10.14.0"
16 %struct.S = type { i32, i32 }
18 ; CHECK-LABEL: define {{.*}} @_Z4swapP1SS0_b(
20 ; First come the argument allocas.
21 ; CHECK: [[argA:%.*]] = alloca ptr,
22 ; CHECK-NEXT: [[argB:%.*]] = alloca ptr,
23 ; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
25 ; Next, the stores into the argument allocas.
26 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argA]]
27 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argB]]
28 ; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8
29 ; CHECK-NEXT: store i8 [[frombool]], ptr [[argDoit]]
31 define void @_Z4swapP1SS0_b(ptr %a, ptr %b, i1 zeroext %doit) sanitize_address {
33 %a.addr = alloca ptr, align 8
34 %b.addr = alloca ptr, align 8
35 %doit.addr = alloca i8, align 1
36 %tmp = alloca %struct.S, align 4
37 store ptr %a, ptr %a.addr, align 8
38 store ptr %b, ptr %b.addr, align 8
39 %frombool = zext i1 %doit to i8
40 store i8 %frombool, ptr %doit.addr, align 1
41 %0 = load i8, ptr %doit.addr, align 1
42 %tobool = trunc i8 %0 to i1
43 br i1 %tobool, label %if.end, label %if.then
45 if.then: ; preds = %entry
48 if.end: ; preds = %entry
49 %1 = load ptr, ptr %a.addr, align 8
50 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %tmp, ptr align 4 %1, i64 8, i1 false)
51 %2 = load ptr, ptr %b.addr, align 8
52 %3 = load ptr, ptr %a.addr, align 8
53 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %3, ptr align 4 %2, i64 8, i1 false)
54 %4 = load ptr, ptr %b.addr, align 8
55 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %4, ptr align 4 %tmp, i64 8, i1 false)
58 return: ; preds = %if.end, %if.then
62 ; Synthetic test case, meant to check that we do not reorder instructions past
63 ; a load when attempting to hoist argument init insts.
64 ; CHECK-LABEL: define {{.*}} @func_with_load_in_arginit_sequence
65 ; CHECK: [[argA:%.*]] = alloca ptr,
66 ; CHECK-NEXT: [[argB:%.*]] = alloca ptr,
67 ; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
68 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argA]]
69 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argB]]
70 ; CHECK-NEXT: [[stack_base:%.*]] = alloca i64
71 define void @func_with_load_in_arginit_sequence(ptr %a, ptr %b, i1 zeroext %doit) sanitize_address {
73 %a.addr = alloca ptr, align 8
74 %b.addr = alloca ptr, align 8
75 %doit.addr = alloca i8, align 1
76 %tmp = alloca %struct.S, align 4
77 store ptr %a, ptr %a.addr, align 8
78 store ptr %b, ptr %b.addr, align 8
80 ; This load prevents the next argument init sequence from being moved.
81 %0 = load i8, ptr %doit.addr, align 1
83 %frombool = zext i1 %doit to i8
84 store i8 %frombool, ptr %doit.addr, align 1
85 %tobool = trunc i8 %0 to i1
86 br i1 %tobool, label %if.end, label %if.then
88 if.then: ; preds = %entry
91 if.end: ; preds = %entry
92 %1 = load ptr, ptr %a.addr, align 8
93 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %tmp, ptr align 4 %1, i64 8, i1 false)
94 %2 = load ptr, ptr %b.addr, align 8
95 %3 = load ptr, ptr %a.addr, align 8
96 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %3, ptr align 4 %2, i64 8, i1 false)
97 %4 = load ptr, ptr %b.addr, align 8
98 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %4, ptr align 4 %tmp, i64 8, i1 false)
101 return: ; preds = %if.end, %if.then
105 ; Synthetic test case, meant to check that we can handle functions with more
106 ; than one interesting alloca.
107 ; CHECK-LABEL: define {{.*}} @func_with_multiple_interesting_allocas
108 ; CHECK: [[argA:%.*]] = alloca ptr,
109 ; CHECK-NEXT: [[argB:%.*]] = alloca ptr,
110 ; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
111 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argA]]
112 ; CHECK-NEXT: store ptr {{.*}}, ptr [[argB]]
113 ; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8
114 ; CHECK-NEXT: store i8 [[frombool]], ptr [[argDoit]]
115 define void @func_with_multiple_interesting_allocas(ptr %a, ptr %b, i1 zeroext %doit) sanitize_address {
117 %a.addr = alloca ptr, align 8
118 %b.addr = alloca ptr, align 8
119 %doit.addr = alloca i8, align 1
120 %tmp = alloca %struct.S, align 4
121 %tmp2 = alloca %struct.S, align 4
122 store ptr %a, ptr %a.addr, align 8
123 store ptr %b, ptr %b.addr, align 8
124 %frombool = zext i1 %doit to i8
125 store i8 %frombool, ptr %doit.addr, align 1
126 %0 = load i8, ptr %doit.addr, align 1
127 %tobool = trunc i8 %0 to i1
128 br i1 %tobool, label %if.end, label %if.then
130 if.then: ; preds = %entry
133 if.end: ; preds = %entry
134 %1 = load ptr, ptr %a.addr, align 8
135 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %tmp, ptr align 4 %1, i64 8, i1 false)
136 %2 = load ptr, ptr %b.addr, align 8
137 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %tmp2, ptr align 4 %2, i64 8, i1 false)
138 %3 = load ptr, ptr %b.addr, align 8
139 %4 = load ptr, ptr %a.addr, align 8
140 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %4, ptr align 4 %3, i64 8, i1 false)
141 %5 = load ptr, ptr %b.addr, align 8
142 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %5, ptr align 4 %tmp, i64 8, i1 false)
143 %6 = load ptr, ptr %a.addr, align 8
144 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %6, ptr align 4 %tmp2, i64 8, i1 false)
147 return: ; preds = %if.end, %if.then
151 declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)