atomic-expansion-v7.ll 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. ; RUN: opt -S -o - -mtriple=armv7-apple-ios7.0 -atomic-expand %s | FileCheck %s
  2. define i8 @test_atomic_xchg_i8(i8* %ptr, i8 %xchgend) {
  3. ; CHECK-LABEL: @test_atomic_xchg_i8
  4. ; CHECK-NOT: dmb
  5. ; CHECK: br label %[[LOOP:.*]]
  6. ; CHECK: [[LOOP]]:
  7. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  8. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  9. ; CHECK: [[NEWVAL32:%.*]] = zext i8 %xchgend to i32
  10. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  11. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  12. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  13. ; CHECK: [[END]]:
  14. ; CHECK-NOT: dmb
  15. ; CHECK: ret i8 [[OLDVAL]]
  16. %res = atomicrmw xchg i8* %ptr, i8 %xchgend monotonic
  17. ret i8 %res
  18. }
  19. define i16 @test_atomic_add_i16(i16* %ptr, i16 %addend) {
  20. ; CHECK-LABEL: @test_atomic_add_i16
  21. ; CHECK: call void @llvm.arm.dmb(i32 11)
  22. ; CHECK: br label %[[LOOP:.*]]
  23. ; CHECK: [[LOOP]]:
  24. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
  25. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
  26. ; CHECK: [[NEWVAL:%.*]] = add i16 [[OLDVAL]], %addend
  27. ; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
  28. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
  29. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  30. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  31. ; CHECK: [[END]]:
  32. ; CHECK: call void @llvm.arm.dmb(i32 11)
  33. ; CHECK: ret i16 [[OLDVAL]]
  34. %res = atomicrmw add i16* %ptr, i16 %addend seq_cst
  35. ret i16 %res
  36. }
  37. define i32 @test_atomic_sub_i32(i32* %ptr, i32 %subend) {
  38. ; CHECK-LABEL: @test_atomic_sub_i32
  39. ; CHECK-NOT: dmb
  40. ; CHECK: br label %[[LOOP:.*]]
  41. ; CHECK: [[LOOP]]:
  42. ; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %ptr)
  43. ; CHECK: [[NEWVAL:%.*]] = sub i32 [[OLDVAL]], %subend
  44. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i32(i32 [[NEWVAL]], i32* %ptr)
  45. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  46. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  47. ; CHECK: [[END]]:
  48. ; CHECK: call void @llvm.arm.dmb(i32 11)
  49. ; CHECK: ret i32 [[OLDVAL]]
  50. %res = atomicrmw sub i32* %ptr, i32 %subend acquire
  51. ret i32 %res
  52. }
  53. define i8 @test_atomic_and_i8(i8* %ptr, i8 %andend) {
  54. ; CHECK-LABEL: @test_atomic_and_i8
  55. ; CHECK: call void @llvm.arm.dmb(i32 11)
  56. ; CHECK: br label %[[LOOP:.*]]
  57. ; CHECK: [[LOOP]]:
  58. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  59. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  60. ; CHECK: [[NEWVAL:%.*]] = and i8 [[OLDVAL]], %andend
  61. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  62. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  63. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  64. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  65. ; CHECK: [[END]]:
  66. ; CHECK-NOT: dmb
  67. ; CHECK: ret i8 [[OLDVAL]]
  68. %res = atomicrmw and i8* %ptr, i8 %andend release
  69. ret i8 %res
  70. }
  71. define i16 @test_atomic_nand_i16(i16* %ptr, i16 %nandend) {
  72. ; CHECK-LABEL: @test_atomic_nand_i16
  73. ; CHECK: call void @llvm.arm.dmb(i32 11)
  74. ; CHECK: br label %[[LOOP:.*]]
  75. ; CHECK: [[LOOP]]:
  76. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
  77. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i16
  78. ; CHECK: [[NEWVAL_TMP:%.*]] = and i16 [[OLDVAL]], %nandend
  79. ; CHECK: [[NEWVAL:%.*]] = xor i16 [[NEWVAL_TMP]], -1
  80. ; CHECK: [[NEWVAL32:%.*]] = zext i16 [[NEWVAL]] to i32
  81. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
  82. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  83. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  84. ; CHECK: [[END]]:
  85. ; CHECK: call void @llvm.arm.dmb(i32 11)
  86. ; CHECK: ret i16 [[OLDVAL]]
  87. %res = atomicrmw nand i16* %ptr, i16 %nandend seq_cst
  88. ret i16 %res
  89. }
  90. define i64 @test_atomic_or_i64(i64* %ptr, i64 %orend) {
  91. ; CHECK-LABEL: @test_atomic_or_i64
  92. ; CHECK: call void @llvm.arm.dmb(i32 11)
  93. ; CHECK: br label %[[LOOP:.*]]
  94. ; CHECK: [[LOOP]]:
  95. ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
  96. ; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[PTR8]])
  97. ; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
  98. ; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
  99. ; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
  100. ; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
  101. ; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
  102. ; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
  103. ; CHECK: [[NEWVAL:%.*]] = or i64 [[OLDVAL]], %orend
  104. ; CHECK: [[NEWLO:%.*]] = trunc i64 [[NEWVAL]] to i32
  105. ; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 [[NEWVAL]], 32
  106. ; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
  107. ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
  108. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], i8* [[PTR8]])
  109. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  110. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  111. ; CHECK: [[END]]:
  112. ; CHECK: call void @llvm.arm.dmb(i32 11)
  113. ; CHECK: ret i64 [[OLDVAL]]
  114. %res = atomicrmw or i64* %ptr, i64 %orend seq_cst
  115. ret i64 %res
  116. }
  117. define i8 @test_atomic_xor_i8(i8* %ptr, i8 %xorend) {
  118. ; CHECK-LABEL: @test_atomic_xor_i8
  119. ; CHECK: call void @llvm.arm.dmb(i32 11)
  120. ; CHECK: br label %[[LOOP:.*]]
  121. ; CHECK: [[LOOP]]:
  122. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  123. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  124. ; CHECK: [[NEWVAL:%.*]] = xor i8 [[OLDVAL]], %xorend
  125. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  126. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  127. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  128. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  129. ; CHECK: [[END]]:
  130. ; CHECK: call void @llvm.arm.dmb(i32 11)
  131. ; CHECK: ret i8 [[OLDVAL]]
  132. %res = atomicrmw xor i8* %ptr, i8 %xorend seq_cst
  133. ret i8 %res
  134. }
  135. define i8 @test_atomic_max_i8(i8* %ptr, i8 %maxend) {
  136. ; CHECK-LABEL: @test_atomic_max_i8
  137. ; CHECK: call void @llvm.arm.dmb(i32 11)
  138. ; CHECK: br label %[[LOOP:.*]]
  139. ; CHECK: [[LOOP]]:
  140. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  141. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  142. ; CHECK: [[WANT_OLD:%.*]] = icmp sgt i8 [[OLDVAL]], %maxend
  143. ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %maxend
  144. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  145. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  146. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  147. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  148. ; CHECK: [[END]]:
  149. ; CHECK: call void @llvm.arm.dmb(i32 11)
  150. ; CHECK: ret i8 [[OLDVAL]]
  151. %res = atomicrmw max i8* %ptr, i8 %maxend seq_cst
  152. ret i8 %res
  153. }
  154. define i8 @test_atomic_min_i8(i8* %ptr, i8 %minend) {
  155. ; CHECK-LABEL: @test_atomic_min_i8
  156. ; CHECK: call void @llvm.arm.dmb(i32 11)
  157. ; CHECK: br label %[[LOOP:.*]]
  158. ; CHECK: [[LOOP]]:
  159. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  160. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  161. ; CHECK: [[WANT_OLD:%.*]] = icmp sle i8 [[OLDVAL]], %minend
  162. ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %minend
  163. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  164. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  165. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  166. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  167. ; CHECK: [[END]]:
  168. ; CHECK: call void @llvm.arm.dmb(i32 11)
  169. ; CHECK: ret i8 [[OLDVAL]]
  170. %res = atomicrmw min i8* %ptr, i8 %minend seq_cst
  171. ret i8 %res
  172. }
  173. define i8 @test_atomic_umax_i8(i8* %ptr, i8 %umaxend) {
  174. ; CHECK-LABEL: @test_atomic_umax_i8
  175. ; CHECK: call void @llvm.arm.dmb(i32 11)
  176. ; CHECK: br label %[[LOOP:.*]]
  177. ; CHECK: [[LOOP]]:
  178. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  179. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  180. ; CHECK: [[WANT_OLD:%.*]] = icmp ugt i8 [[OLDVAL]], %umaxend
  181. ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %umaxend
  182. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  183. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  184. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  185. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  186. ; CHECK: [[END]]:
  187. ; CHECK: call void @llvm.arm.dmb(i32 11)
  188. ; CHECK: ret i8 [[OLDVAL]]
  189. %res = atomicrmw umax i8* %ptr, i8 %umaxend seq_cst
  190. ret i8 %res
  191. }
  192. define i8 @test_atomic_umin_i8(i8* %ptr, i8 %uminend) {
  193. ; CHECK-LABEL: @test_atomic_umin_i8
  194. ; CHECK: call void @llvm.arm.dmb(i32 11)
  195. ; CHECK: br label %[[LOOP:.*]]
  196. ; CHECK: [[LOOP]]:
  197. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  198. ; CHECK: [[OLDVAL:%.*]] = trunc i32 [[OLDVAL32]] to i8
  199. ; CHECK: [[WANT_OLD:%.*]] = icmp ule i8 [[OLDVAL]], %uminend
  200. ; CHECK: [[NEWVAL:%.*]] = select i1 [[WANT_OLD]], i8 [[OLDVAL]], i8 %uminend
  201. ; CHECK: [[NEWVAL32:%.*]] = zext i8 [[NEWVAL]] to i32
  202. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  203. ; CHECK: [[TST:%.*]] = icmp ne i32 [[TRYAGAIN]], 0
  204. ; CHECK: br i1 [[TST]], label %[[LOOP]], label %[[END:.*]]
  205. ; CHECK: [[END]]:
  206. ; CHECK: call void @llvm.arm.dmb(i32 11)
  207. ; CHECK: ret i8 [[OLDVAL]]
  208. %res = atomicrmw umin i8* %ptr, i8 %uminend seq_cst
  209. ret i8 %res
  210. }
  211. define i8 @test_cmpxchg_i8_seqcst_seqcst(i8* %ptr, i8 %desired, i8 %newval) {
  212. ; CHECK-LABEL: @test_cmpxchg_i8_seqcst_seqcst
  213. ; CHECK: call void @llvm.arm.dmb(i32 11)
  214. ; CHECK: br label %[[LOOP:.*]]
  215. ; CHECK: [[LOOP]]:
  216. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %ptr)
  217. ; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i8
  218. ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i8 [[OLDVAL]], %desired
  219. ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
  220. ; CHECK: [[TRY_STORE]]:
  221. ; CHECK: [[NEWVAL32:%.*]] = zext i8 %newval to i32
  222. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i8(i32 [[NEWVAL32]], i8* %ptr)
  223. ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
  224. ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
  225. ; CHECK: [[SUCCESS_BB]]:
  226. ; CHECK: call void @llvm.arm.dmb(i32 11)
  227. ; CHECK: br label %[[DONE:.*]]
  228. ; CHECK: [[FAILURE_BB]]:
  229. ; CHECK: call void @llvm.arm.dmb(i32 11)
  230. ; CHECK: br label %[[DONE]]
  231. ; CHECK: [[DONE]]:
  232. ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
  233. ; CHECK: ret i8 [[OLDVAL]]
  234. %pairold = cmpxchg i8* %ptr, i8 %desired, i8 %newval seq_cst seq_cst
  235. %old = extractvalue { i8, i1 } %pairold, 0
  236. ret i8 %old
  237. }
  238. define i16 @test_cmpxchg_i16_seqcst_monotonic(i16* %ptr, i16 %desired, i16 %newval) {
  239. ; CHECK-LABEL: @test_cmpxchg_i16_seqcst_monotonic
  240. ; CHECK: call void @llvm.arm.dmb(i32 11)
  241. ; CHECK: br label %[[LOOP:.*]]
  242. ; CHECK: [[LOOP]]:
  243. ; CHECK: [[OLDVAL32:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* %ptr)
  244. ; CHECK: [[OLDVAL:%.*]] = trunc i32 %1 to i16
  245. ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i16 [[OLDVAL]], %desired
  246. ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
  247. ; CHECK: [[TRY_STORE]]:
  248. ; CHECK: [[NEWVAL32:%.*]] = zext i16 %newval to i32
  249. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i16(i32 [[NEWVAL32]], i16* %ptr)
  250. ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
  251. ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
  252. ; CHECK: [[SUCCESS_BB]]:
  253. ; CHECK: call void @llvm.arm.dmb(i32 11)
  254. ; CHECK: br label %[[DONE:.*]]
  255. ; CHECK: [[FAILURE_BB]]:
  256. ; CHECK-NOT: dmb
  257. ; CHECK: br label %[[DONE]]
  258. ; CHECK: [[DONE]]:
  259. ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
  260. ; CHECK: ret i16 [[OLDVAL]]
  261. %pairold = cmpxchg i16* %ptr, i16 %desired, i16 %newval seq_cst monotonic
  262. %old = extractvalue { i16, i1 } %pairold, 0
  263. ret i16 %old
  264. }
  265. define i32 @test_cmpxchg_i32_acquire_acquire(i32* %ptr, i32 %desired, i32 %newval) {
  266. ; CHECK-LABEL: @test_cmpxchg_i32_acquire_acquire
  267. ; CHECK-NOT: dmb
  268. ; CHECK: br label %[[LOOP:.*]]
  269. ; CHECK: [[LOOP]]:
  270. ; CHECK: [[OLDVAL:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* %ptr)
  271. ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i32 [[OLDVAL]], %desired
  272. ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
  273. ; CHECK: [[TRY_STORE]]:
  274. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strex.p0i32(i32 %newval, i32* %ptr)
  275. ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
  276. ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
  277. ; CHECK: [[SUCCESS_BB]]:
  278. ; CHECK: call void @llvm.arm.dmb(i32 11)
  279. ; CHECK: br label %[[DONE:.*]]
  280. ; CHECK: [[FAILURE_BB]]:
  281. ; CHECK: call void @llvm.arm.dmb(i32 11)
  282. ; CHECK: br label %[[DONE]]
  283. ; CHECK: [[DONE]]:
  284. ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
  285. ; CHECK: ret i32 [[OLDVAL]]
  286. %pairold = cmpxchg i32* %ptr, i32 %desired, i32 %newval acquire acquire
  287. %old = extractvalue { i32, i1 } %pairold, 0
  288. ret i32 %old
  289. }
  290. define i64 @test_cmpxchg_i64_monotonic_monotonic(i64* %ptr, i64 %desired, i64 %newval) {
  291. ; CHECK-LABEL: @test_cmpxchg_i64_monotonic_monotonic
  292. ; CHECK-NOT: dmb
  293. ; CHECK: br label %[[LOOP:.*]]
  294. ; CHECK: [[LOOP]]:
  295. ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
  296. ; CHECK: [[LOHI:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[PTR8]])
  297. ; CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
  298. ; CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
  299. ; CHECK: [[LO64:%.*]] = zext i32 [[LO]] to i64
  300. ; CHECK: [[HI64_TMP:%.*]] = zext i32 [[HI]] to i64
  301. ; CHECK: [[HI64:%.*]] = shl i64 [[HI64_TMP]], 32
  302. ; CHECK: [[OLDVAL:%.*]] = or i64 [[LO64]], [[HI64]]
  303. ; CHECK: [[SHOULD_STORE:%.*]] = icmp eq i64 [[OLDVAL]], %desired
  304. ; CHECK: br i1 [[SHOULD_STORE]], label %[[TRY_STORE:.*]], label %[[FAILURE_BB:.*]]
  305. ; CHECK: [[TRY_STORE]]:
  306. ; CHECK: [[NEWLO:%.*]] = trunc i64 %newval to i32
  307. ; CHECK: [[NEWHI_TMP:%.*]] = lshr i64 %newval, 32
  308. ; CHECK: [[NEWHI:%.*]] = trunc i64 [[NEWHI_TMP]] to i32
  309. ; CHECK: [[PTR8:%.*]] = bitcast i64* %ptr to i8*
  310. ; CHECK: [[TRYAGAIN:%.*]] = call i32 @llvm.arm.strexd(i32 [[NEWLO]], i32 [[NEWHI]], i8* [[PTR8]])
  311. ; CHECK: [[TST:%.*]] = icmp eq i32 [[TRYAGAIN]], 0
  312. ; CHECK: br i1 [[TST]], label %[[SUCCESS_BB:.*]], label %[[LOOP]]
  313. ; CHECK: [[SUCCESS_BB]]:
  314. ; CHECK-NOT: dmb
  315. ; CHECK: br label %[[DONE:.*]]
  316. ; CHECK: [[FAILURE_BB]]:
  317. ; CHECK-NOT: dmb
  318. ; CHECK: br label %[[DONE]]
  319. ; CHECK: [[DONE]]:
  320. ; CHECK: [[SUCCESS:%.*]] = phi i1 [ true, %[[SUCCESS_BB]] ], [ false, %[[FAILURE_BB]] ]
  321. ; CHECK: ret i64 [[OLDVAL]]
  322. %pairold = cmpxchg i64* %ptr, i64 %desired, i64 %newval monotonic monotonic
  323. %old = extractvalue { i64, i1 } %pairold, 0
  324. ret i64 %old
  325. }