xref: /llvm-project/clang/test/CodeGen/builtins-arm-exclusive.c (revision 5f9a82683dc13a09bdd55d88dde981552cda4ce7)
1 // RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg | FileCheck %s
2 // RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -disable-O0-optnone -emit-llvm -o - %s | opt -S -passes=mem2reg | FileCheck %s --check-prefix=CHECK-ARM64
3 
4 struct Simple {
5   char a, b;
6 };
7 
test_ldrex(char * addr,long long * addr64,float * addrfloat)8 int test_ldrex(char *addr, long long *addr64, float *addrfloat) {
9 // CHECK-LABEL: @test_ldrex
10 // CHECK-ARM64-LABEL: @test_ldrex
11   int sum = 0;
12   sum += __builtin_arm_ldrex(addr);
13 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i8) %addr)
14 // CHECK: trunc i32 [[INTRES]] to i8
15 
16 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i8) %addr)
17 // CHECK-ARM64: trunc i64 [[INTRES]] to i8
18 
19   sum += __builtin_arm_ldrex((short *)addr);
20 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i16) %addr)
21 // CHECK: trunc i32 [[INTRES]] to i16
22 
23 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i16) %addr)
24 // CHECK-ARM64: trunc i64 [[INTRES]] to i16
25 
26   sum += __builtin_arm_ldrex((int *)addr);
27 // CHECK: call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %addr)
28 
29 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %addr)
30 // CHECK-ARM64: trunc i64 [[INTRES]] to i32
31 
32   sum += __builtin_arm_ldrex((long long *)addr);
33 // CHECK: call { i32, i32 } @llvm.arm.ldrexd(ptr %addr)
34 
35 // CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr)
36 
37   sum += __builtin_arm_ldrex(addr64);
38 // CHECK: call { i32, i32 } @llvm.arm.ldrexd(ptr %addr64)
39 
40 // CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr64)
41 
42   sum += __builtin_arm_ldrex(addrfloat);
43 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %addrfloat)
44 
45 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %addrfloat)
46 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
47 // CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float
48 
49   sum += __builtin_arm_ldrex((double *)addr);
50 // CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(ptr %addr)
51 // CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
52 // CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
53 // CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
54 // CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
55 // CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
56 // CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
57 
58 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr)
59 // CHECK-ARM64: bitcast i64 [[INTRES]] to double
60 
61   sum += *__builtin_arm_ldrex((int **)addr);
62 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %addr)
63 // CHECK: inttoptr i32 [[INTRES]] to ptr
64 
65 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr)
66 // CHECK-ARM64: inttoptr i64 [[INTRES]] to ptr
67 
68   sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
69 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0(ptr elementtype(i32) %addr)
70 // CHECK: inttoptr i32 [[INTRES]] to ptr
71 
72 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr)
73 // CHECK-ARM64: inttoptr i64 [[INTRES]] to ptr
74   return sum;
75 }
76 
test_ldaex(char * addr,long long * addr64,float * addrfloat)77 int test_ldaex(char *addr, long long *addr64, float *addrfloat) {
78 // CHECK-LABEL: @test_ldaex
79 // CHECK-ARM64-LABEL: @test_ldaex
80   int sum = 0;
81   sum += __builtin_arm_ldaex(addr);
82 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0(ptr elementtype(i8) %addr)
83 // CHECK: trunc i32 [[INTRES]] to i8
84 
85 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i8) %addr)
86 // CHECK-ARM64: trunc i64 [[INTRES]] to i8
87 
88   sum += __builtin_arm_ldaex((short *)addr);
89 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0(ptr elementtype(i16) %addr)
90 // CHECK: trunc i32 [[INTRES]] to i16
91 
92 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i16) %addr)
93 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i16
94 
95   sum += __builtin_arm_ldaex((int *)addr);
96 // CHECK:  call i32 @llvm.arm.ldaex.p0(ptr elementtype(i32) %addr)
97 
98 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i32) %addr)
99 // CHECK-ARM64: trunc i64 [[INTRES]] to i32
100 
101   sum += __builtin_arm_ldaex((long long *)addr);
102 // CHECK: call { i32, i32 } @llvm.arm.ldaexd(ptr %addr)
103 
104 // CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr)
105 
106   sum += __builtin_arm_ldaex(addr64);
107 // CHECK: call { i32, i32 } @llvm.arm.ldaexd(ptr %addr64)
108 
109 // CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr64)
110 
111   sum += __builtin_arm_ldaex(addrfloat);
112 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0(ptr elementtype(i32) %addrfloat)
113 
114 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i32) %addrfloat)
115 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
116 // CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float
117 
118   sum += __builtin_arm_ldaex((double *)addr);
119 // CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldaexd(ptr %addr)
120 // CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
121 // CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
122 // CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
123 // CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
124 // CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
125 // CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
126 
127 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr)
128 // CHECK-ARM64: bitcast i64 [[INTRES]] to double
129 
130   sum += *__builtin_arm_ldaex((int **)addr);
131 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0(ptr elementtype(i32) %addr)
132 // CHECK: inttoptr i32 [[INTRES]] to ptr
133 
134 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr)
135 // CHECK-ARM64: inttoptr i64 [[INTRES]] to ptr
136 
137   sum += __builtin_arm_ldaex((struct Simple **)addr)->a;
138 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0(ptr elementtype(i32) %addr)
139 // CHECK: inttoptr i32 [[INTRES]] to ptr
140 
141 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr)
142 // CHECK-ARM64: inttoptr i64 [[INTRES]] to ptr
143   return sum;
144 }
145 
test_strex(char * addr)146 int test_strex(char *addr) {
147 // CHECK-LABEL: @test_strex
148 // CHECK-ARM64-LABEL: @test_strex
149   int res = 0;
150   struct Simple var = {0};
151   res |= __builtin_arm_strex(4, addr);
152 // CHECK: call i32 @llvm.arm.strex.p0(i32 4, ptr elementtype(i8) %addr)
153 
154 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 4, ptr elementtype(i8) %addr)
155 
156   res |= __builtin_arm_strex(42, (short *)addr);
157 // CHECK:  call i32 @llvm.arm.strex.p0(i32 42, ptr elementtype(i16) %addr)
158 
159 // CHECK-ARM64:  call i32 @llvm.aarch64.stxr.p0(i64 42, ptr elementtype(i16) %addr)
160 
161   res |= __builtin_arm_strex(42, (int *)addr);
162 // CHECK: call i32 @llvm.arm.strex.p0(i32 42, ptr elementtype(i32) %addr)
163 
164 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 42, ptr elementtype(i32) %addr)
165 
166   res |= __builtin_arm_strex(42, (long long *)addr);
167 // CHECK: store i64 42, ptr [[TMP:%.*]], align 8
168 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]]
169 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
170 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
171 // CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], ptr %addr)
172 
173 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 42, ptr elementtype(i64) %addr)
174 
175   res |= __builtin_arm_strex(2.71828f, (float *)addr);
176 // CHECK: call i32 @llvm.arm.strex.p0(i32 1076754509, ptr elementtype(i32) %addr)
177 
178 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 1076754509, ptr elementtype(i32) %addr)
179 
180   res |= __builtin_arm_strex(3.14159, (double *)addr);
181 // CHECK: store double 3.141590e+00, ptr [[TMP:%.*]], align 8
182 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]]
183 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
184 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
185 // CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], ptr %addr)
186 
187 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 4614256650576692846, ptr elementtype(i64) %addr)
188 
189   res |= __builtin_arm_strex(&var, (struct Simple **)addr);
190 // CHECK: [[INTVAL:%.*]] = ptrtoint ptr %var to i32
191 // CHECK: call i32 @llvm.arm.strex.p0(i32 [[INTVAL]], ptr elementtype(i32) %addr)
192 
193 // CHECK-ARM64: [[INTVAL:%.*]] = ptrtoint ptr %var to i64
194 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0(i64 [[INTVAL]], ptr elementtype(i64) %addr)
195 
196   return res;
197 }
198 
test_stlex(char * addr)199 int test_stlex(char *addr) {
200 // CHECK-LABEL: @test_stlex
201 // CHECK-ARM64-LABEL: @test_stlex
202   int res = 0;
203   struct Simple var = {0};
204   res |= __builtin_arm_stlex(4, addr);
205 // CHECK: call i32 @llvm.arm.stlex.p0(i32 4, ptr elementtype(i8) %addr)
206 
207 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 4, ptr elementtype(i8) %addr)
208 
209   res |= __builtin_arm_stlex(42, (short *)addr);
210 // CHECK:  call i32 @llvm.arm.stlex.p0(i32 42, ptr elementtype(i16) %addr)
211 
212 // CHECK-ARM64:  call i32 @llvm.aarch64.stlxr.p0(i64 42, ptr elementtype(i16) %addr)
213 
214   res |= __builtin_arm_stlex(42, (int *)addr);
215 // CHECK: call i32 @llvm.arm.stlex.p0(i32 42, ptr elementtype(i32) %addr)
216 
217 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 42, ptr elementtype(i32) %addr)
218 
219   res |= __builtin_arm_stlex(42, (long long *)addr);
220 // CHECK: store i64 42, ptr [[TMP:%.*]], align 8
221 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]]
222 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
223 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
224 // CHECK: call i32 @llvm.arm.stlexd(i32 [[LO]], i32 [[HI]], ptr %addr)
225 
226 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 42, ptr elementtype(i64) %addr)
227 
228   res |= __builtin_arm_stlex(2.71828f, (float *)addr);
229 // CHECK: call i32 @llvm.arm.stlex.p0(i32 1076754509, ptr elementtype(i32) %addr)
230 
231 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 1076754509, ptr elementtype(i32) %addr)
232 
233   res |= __builtin_arm_stlex(3.14159, (double *)addr);
234 // CHECK: store double 3.141590e+00, ptr [[TMP:%.*]], align 8
235 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, ptr [[TMP]]
236 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
237 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
238 // CHECK: call i32 @llvm.arm.stlexd(i32 [[LO]], i32 [[HI]], ptr %addr)
239 
240 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 4614256650576692846, ptr elementtype(i64) %addr)
241 
242   res |= __builtin_arm_stlex(&var, (struct Simple **)addr);
243 // CHECK: [[INTVAL:%.*]] = ptrtoint ptr %var to i32
244 // CHECK: call i32 @llvm.arm.stlex.p0(i32 [[INTVAL]], ptr elementtype(i32) %addr)
245 
246 // CHECK-ARM64: [[INTVAL:%.*]] = ptrtoint ptr %var to i64
247 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0(i64 [[INTVAL]], ptr elementtype(i64) %addr)
248 
249   return res;
250 }
251 
test_clrex(void)252 void test_clrex(void) {
253 // CHECK-LABEL: @test_clrex
254 // CHECK-ARM64-LABEL: @test_clrex
255 
256   __builtin_arm_clrex();
257 // CHECK: call void @llvm.arm.clrex()
258 // CHECK-ARM64: call void @llvm.aarch64.clrex()
259 }
260 
261 #ifdef __aarch64__
262 // 128-bit tests
263 
test_ldrex_128(__int128 * addr)264 __int128 test_ldrex_128(__int128 *addr) {
265 // CHECK-ARM64-LABEL: @test_ldrex_128
266 
267   return __builtin_arm_ldrex(addr);
268 // CHECK-ARM64: [[STRUCTRES:%.*]] = call { i64, i64 } @llvm.aarch64.ldxp(ptr %addr)
269 // CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
270 // CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
271 // CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
272 // CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
273 // CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
274 // CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESHIHI]], [[RESLO64]]
275 // CHECK-ARM64: ret i128 [[INTRES]]
276 }
277 
test_strex_128(__int128 * addr,__int128 val)278 int test_strex_128(__int128 *addr, __int128 val) {
279 // CHECK-ARM64-LABEL: @test_strex_128
280 
281   return __builtin_arm_strex(val, addr);
282 // CHECK-ARM64: store i128 %val, ptr [[TMP:%.*]], align 16
283 // CHECK-ARM64: [[LOHI:%.*]] = load { i64, i64 }, ptr [[TMP]]
284 // CHECK-ARM64: [[LO:%.*]] = extractvalue { i64, i64 } [[LOHI]], 0
285 // CHECK-ARM64: [[HI:%.*]] = extractvalue { i64, i64 } [[LOHI]], 1
286 // CHECK-ARM64: call i32 @llvm.aarch64.stxp(i64 [[LO]], i64 [[HI]], ptr %addr)
287 }
288 
test_ldaex_128(__int128 * addr)289 __int128 test_ldaex_128(__int128 *addr) {
290 // CHECK-ARM64-LABEL: @test_ldaex_128
291 
292   return __builtin_arm_ldaex(addr);
293 // CHECK-ARM64: [[STRUCTRES:%.*]] = call { i64, i64 } @llvm.aarch64.ldaxp(ptr %addr)
294 // CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
295 // CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
296 // CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
297 // CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
298 // CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
299 // CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESHIHI]], [[RESLO64]]
300 // CHECK-ARM64: ret i128 [[INTRES]]
301 }
302 
test_stlex_128(__int128 * addr,__int128 val)303 int test_stlex_128(__int128 *addr, __int128 val) {
304 // CHECK-ARM64-LABEL: @test_stlex_128
305 
306   return __builtin_arm_stlex(val, addr);
307 // CHECK-ARM64: store i128 %val, ptr [[TMP:%.*]], align 16
308 // CHECK-ARM64: [[LOHI:%.*]] = load { i64, i64 }, ptr [[TMP]]
309 // CHECK-ARM64: [[LO:%.*]] = extractvalue { i64, i64 } [[LOHI]], 0
310 // CHECK-ARM64: [[HI:%.*]] = extractvalue { i64, i64 } [[LOHI]], 1
311 // CHECK-ARM64: [[RES:%.*]] = call i32 @llvm.aarch64.stlxp(i64 [[LO]], i64 [[HI]], ptr %addr)
312 }
313 
314 #endif
315