1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 2; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-SD 3; RUN: llc < %s -mtriple=arm64-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI 4 5%0 = type { i64, i64 } 6 7define dso_local i128 @f0(ptr %p) nounwind readonly { 8; CHECK-LABEL: f0: 9; CHECK: // %bb.0: // %entry 10; CHECK-NEXT: ldxp x0, x1, [x0] 11; CHECK-NEXT: ret 12entry: 13 %ldrexd = tail call %0 @llvm.aarch64.ldxp(ptr %p) 14 %0 = extractvalue %0 %ldrexd, 1 15 %1 = extractvalue %0 %ldrexd, 0 16 %2 = zext i64 %0 to i128 17 %3 = zext i64 %1 to i128 18 %shl = shl nuw i128 %2, 64 19 %4 = or i128 %shl, %3 20 ret i128 %4 21} 22 23define dso_local i32 @f1(ptr %ptr, i128 %val) nounwind { 24; CHECK-LABEL: f1: 25; CHECK: // %bb.0: // %entry 26; CHECK-NEXT: stxp w8, x2, x3, [x0] 27; CHECK-NEXT: mov w0, w8 28; CHECK-NEXT: ret 29entry: 30 %tmp4 = trunc i128 %val to i64 31 %tmp6 = lshr i128 %val, 64 32 %tmp7 = trunc i128 %tmp6 to i64 33 %strexd = tail call i32 @llvm.aarch64.stxp(i64 %tmp4, i64 %tmp7, ptr %ptr) 34 ret i32 %strexd 35} 36 37declare %0 @llvm.aarch64.ldxp(ptr) nounwind 38declare i32 @llvm.aarch64.stxp(i64, i64, ptr) nounwind 39 40@var = dso_local global i64 0, align 8 41 42define dso_local void @test_load_i8(ptr %addr) { 43; CHECK-SD-LABEL: test_load_i8: 44; CHECK-SD: // %bb.0: 45; CHECK-SD-NEXT: ldxrb w8, [x0] 46; CHECK-SD-NEXT: adrp x9, var 47; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 48; CHECK-SD-NEXT: ret 49; 50; CHECK-GI-LABEL: test_load_i8: 51; CHECK-GI: // %bb.0: 52; CHECK-GI-NEXT: ldxrb w9, [x0] 53; CHECK-GI-NEXT: adrp x8, var 54; CHECK-GI-NEXT: and x9, x9, #0xff 55; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 56; CHECK-GI-NEXT: ret 57 58 %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i8) %addr) 59 %shortval = trunc i64 %val to i8 60 %extval = zext i8 %shortval to i64 61 store i64 %extval, ptr @var, align 8 62 ret void 63} 64 65define dso_local void @test_load_i16(ptr %addr) { 66; CHECK-SD-LABEL: test_load_i16: 67; CHECK-SD: // %bb.0: 68; CHECK-SD-NEXT: ldxrh w8, [x0] 69; CHECK-SD-NEXT: adrp x9, var 70; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 71; CHECK-SD-NEXT: ret 72; 73; CHECK-GI-LABEL: test_load_i16: 74; CHECK-GI: // %bb.0: 75; CHECK-GI-NEXT: ldxrh w9, [x0] 76; CHECK-GI-NEXT: adrp x8, var 77; CHECK-GI-NEXT: and x9, x9, #0xffff 78; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 79; CHECK-GI-NEXT: ret 80 81 %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i16) %addr) 82 %shortval = trunc i64 %val to i16 83 %extval = zext i16 %shortval to i64 84 store i64 %extval, ptr @var, align 8 85 ret void 86} 87 88define dso_local void @test_load_i32(ptr %addr) { 89; CHECK-SD-LABEL: test_load_i32: 90; CHECK-SD: // %bb.0: 91; CHECK-SD-NEXT: ldxr w8, [x0] 92; CHECK-SD-NEXT: adrp x9, var 93; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 94; CHECK-SD-NEXT: ret 95; 96; CHECK-GI-LABEL: test_load_i32: 97; CHECK-GI: // %bb.0: 98; CHECK-GI-NEXT: ldxr w9, [x0] 99; CHECK-GI-NEXT: adrp x8, var 100; CHECK-GI-NEXT: mov w9, w9 101; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 102; CHECK-GI-NEXT: ret 103 104 %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %addr) 105 %shortval = trunc i64 %val to i32 106 %extval = zext i32 %shortval to i64 107 store i64 %extval, ptr @var, align 8 108 ret void 109} 110 111define dso_local void @test_load_i64(ptr %addr) { 112; CHECK-LABEL: test_load_i64: 113; CHECK: // %bb.0: 114; CHECK-NEXT: ldxr x8, [x0] 115; CHECK-NEXT: adrp x9, var 116; CHECK-NEXT: str x8, [x9, :lo12:var] 117; CHECK-NEXT: ret 118 119 %val = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i64) %addr) 120 store i64 %val, ptr @var, align 8 121 ret void 122} 123 124 125declare i64 @llvm.aarch64.ldxr.p0(ptr) nounwind 126 127define dso_local i32 @test_store_i8(i32, i8 %val, ptr %addr) { 128; CHECK-LABEL: test_store_i8: 129; CHECK: // %bb.0: 130; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 131; CHECK-NEXT: stxrb w0, w1, [x2] 132; CHECK-NEXT: ret 133 %extval = zext i8 %val to i64 134 %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i8) %addr) 135 ret i32 %res 136} 137 138define dso_local i32 @test_store_i16(i32, i16 %val, ptr %addr) { 139; CHECK-LABEL: test_store_i16: 140; CHECK: // %bb.0: 141; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 142; CHECK-NEXT: stxrh w0, w1, [x2] 143; CHECK-NEXT: ret 144 %extval = zext i16 %val to i64 145 %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i16) %addr) 146 ret i32 %res 147} 148 149define dso_local i32 @test_store_i32(i32, i32 %val, ptr %addr) { 150; CHECK-LABEL: test_store_i32: 151; CHECK: // %bb.0: 152; CHECK-NEXT: stxr w0, w1, [x2] 153; CHECK-NEXT: ret 154 %extval = zext i32 %val to i64 155 %res = call i32 @llvm.aarch64.stxr.p0(i64 %extval, ptr elementtype(i32) %addr) 156 ret i32 %res 157} 158 159define dso_local i32 @test_store_i64(i32, i64 %val, ptr %addr) { 160; CHECK-LABEL: test_store_i64: 161; CHECK: // %bb.0: 162; CHECK-NEXT: stxr w0, x1, [x2] 163; CHECK-NEXT: ret 164 %res = call i32 @llvm.aarch64.stxr.p0(i64 %val, ptr elementtype(i64) %addr) 165 ret i32 %res 166} 167 168declare i32 @llvm.aarch64.stxr.p0(i64, ptr) nounwind 169 170define dso_local void @test_clear() { 171; CHECK-LABEL: test_clear: 172; CHECK: // %bb.0: 173; CHECK-NEXT: clrex 174; CHECK-NEXT: ret 175 call void @llvm.aarch64.clrex() 176 ret void 177} 178 179declare void @llvm.aarch64.clrex() nounwind 180 181define dso_local i128 @test_load_acquire_i128(ptr %p) nounwind readonly { 182; CHECK-LABEL: test_load_acquire_i128: 183; CHECK: // %bb.0: // %entry 184; CHECK-NEXT: ldaxp x0, x1, [x0] 185; CHECK-NEXT: ret 186entry: 187 %ldrexd = tail call %0 @llvm.aarch64.ldaxp(ptr %p) 188 %0 = extractvalue %0 %ldrexd, 1 189 %1 = extractvalue %0 %ldrexd, 0 190 %2 = zext i64 %0 to i128 191 %3 = zext i64 %1 to i128 192 %shl = shl nuw i128 %2, 64 193 %4 = or i128 %shl, %3 194 ret i128 %4 195} 196 197define dso_local i32 @test_store_release_i128(ptr %ptr, i128 %val) nounwind { 198; CHECK-LABEL: test_store_release_i128: 199; CHECK: // %bb.0: // %entry 200; CHECK-NEXT: stlxp w8, x2, x3, [x0] 201; CHECK-NEXT: mov w0, w8 202; CHECK-NEXT: ret 203entry: 204 %tmp4 = trunc i128 %val to i64 205 %tmp6 = lshr i128 %val, 64 206 %tmp7 = trunc i128 %tmp6 to i64 207 %strexd = tail call i32 @llvm.aarch64.stlxp(i64 %tmp4, i64 %tmp7, ptr %ptr) 208 ret i32 %strexd 209} 210 211declare %0 @llvm.aarch64.ldaxp(ptr) nounwind 212declare i32 @llvm.aarch64.stlxp(i64, i64, ptr) nounwind 213 214define dso_local void @test_load_acquire_i8(ptr %addr) { 215; CHECK-SD-LABEL: test_load_acquire_i8: 216; CHECK-SD: // %bb.0: 217; CHECK-SD-NEXT: ldaxrb w8, [x0] 218; CHECK-SD-NEXT: adrp x9, var 219; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 220; CHECK-SD-NEXT: ret 221; 222; CHECK-GI-LABEL: test_load_acquire_i8: 223; CHECK-GI: // %bb.0: 224; CHECK-GI-NEXT: ldaxrb w9, [x0] 225; CHECK-GI-NEXT: adrp x8, var 226; CHECK-GI-NEXT: and x9, x9, #0xff 227; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 228; CHECK-GI-NEXT: ret 229 230 %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i8) %addr) 231 %shortval = trunc i64 %val to i8 232 %extval = zext i8 %shortval to i64 233 store i64 %extval, ptr @var, align 8 234 ret void 235} 236 237define dso_local void @test_load_acquire_i16(ptr %addr) { 238; CHECK-SD-LABEL: test_load_acquire_i16: 239; CHECK-SD: // %bb.0: 240; CHECK-SD-NEXT: ldaxrh w8, [x0] 241; CHECK-SD-NEXT: adrp x9, var 242; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 243; CHECK-SD-NEXT: ret 244; 245; CHECK-GI-LABEL: test_load_acquire_i16: 246; CHECK-GI: // %bb.0: 247; CHECK-GI-NEXT: ldaxrh w9, [x0] 248; CHECK-GI-NEXT: adrp x8, var 249; CHECK-GI-NEXT: and x9, x9, #0xffff 250; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 251; CHECK-GI-NEXT: ret 252 253 %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i16) %addr) 254 %shortval = trunc i64 %val to i16 255 %extval = zext i16 %shortval to i64 256 store i64 %extval, ptr @var, align 8 257 ret void 258} 259 260define dso_local void @test_load_acquire_i32(ptr %addr) { 261; CHECK-SD-LABEL: test_load_acquire_i32: 262; CHECK-SD: // %bb.0: 263; CHECK-SD-NEXT: ldaxr w8, [x0] 264; CHECK-SD-NEXT: adrp x9, var 265; CHECK-SD-NEXT: str x8, [x9, :lo12:var] 266; CHECK-SD-NEXT: ret 267; 268; CHECK-GI-LABEL: test_load_acquire_i32: 269; CHECK-GI: // %bb.0: 270; CHECK-GI-NEXT: ldaxr w9, [x0] 271; CHECK-GI-NEXT: adrp x8, var 272; CHECK-GI-NEXT: mov w9, w9 273; CHECK-GI-NEXT: str x9, [x8, :lo12:var] 274; CHECK-GI-NEXT: ret 275 276 %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i32) %addr) 277 %shortval = trunc i64 %val to i32 278 %extval = zext i32 %shortval to i64 279 store i64 %extval, ptr @var, align 8 280 ret void 281} 282 283define dso_local void @test_load_acquire_i64(ptr %addr) { 284; CHECK-LABEL: test_load_acquire_i64: 285; CHECK: // %bb.0: 286; CHECK-NEXT: ldaxr x8, [x0] 287; CHECK-NEXT: adrp x9, var 288; CHECK-NEXT: str x8, [x9, :lo12:var] 289; CHECK-NEXT: ret 290 291 %val = call i64 @llvm.aarch64.ldaxr.p0(ptr elementtype(i64) %addr) 292 store i64 %val, ptr @var, align 8 293 ret void 294} 295 296 297declare i64 @llvm.aarch64.ldaxr.p0(ptr) nounwind 298 299define dso_local i32 @test_store_release_i8(i32, i8 %val, ptr %addr) { 300; CHECK-LABEL: test_store_release_i8: 301; CHECK: // %bb.0: 302; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 303; CHECK-NEXT: stlxrb w0, w1, [x2] 304; CHECK-NEXT: ret 305 %extval = zext i8 %val to i64 306 %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i8) %addr) 307 ret i32 %res 308} 309 310define dso_local i32 @test_store_release_i16(i32, i16 %val, ptr %addr) { 311; CHECK-LABEL: test_store_release_i16: 312; CHECK: // %bb.0: 313; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 314; CHECK-NEXT: stlxrh w0, w1, [x2] 315; CHECK-NEXT: ret 316 %extval = zext i16 %val to i64 317 %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i16) %addr) 318 ret i32 %res 319} 320 321define dso_local i32 @test_store_release_i32(i32, i32 %val, ptr %addr) { 322; CHECK-LABEL: test_store_release_i32: 323; CHECK: // %bb.0: 324; CHECK-NEXT: stlxr w0, w1, [x2] 325; CHECK-NEXT: ret 326 %extval = zext i32 %val to i64 327 %res = call i32 @llvm.aarch64.stlxr.p0(i64 %extval, ptr elementtype(i32) %addr) 328 ret i32 %res 329} 330 331define dso_local i32 @test_store_release_i64(i32, i64 %val, ptr %addr) { 332; CHECK-LABEL: test_store_release_i64: 333; CHECK: // %bb.0: 334; CHECK-NEXT: stlxr w0, x1, [x2] 335; CHECK-NEXT: ret 336 %res = call i32 @llvm.aarch64.stlxr.p0(i64 %val, ptr elementtype(i64) %addr) 337 ret i32 %res 338} 339 340; The stxp result cannot be allocated to the same register as the inputs. 341define dso_local i32 @test_stxp_undef(ptr %p, i64 %x) nounwind { 342; CHECK-LABEL: test_stxp_undef: 343; CHECK: // %bb.0: 344; CHECK-NEXT: stxp w8, x9, x1, [x0] 345; CHECK-NEXT: mov w0, w8 346; CHECK-NEXT: ret 347 %res = call i32 @llvm.aarch64.stxp(i64 undef, i64 %x, ptr %p) 348 ret i32 %res 349} 350 351; Same as previous test, but using inline asm. 352define dso_local i32 @test_stxp_undef_inline_asm(ptr %p, i64 %x) nounwind { 353; CHECK-LABEL: test_stxp_undef_inline_asm: 354; CHECK: // %bb.0: 355; CHECK-NEXT: //APP 356; CHECK-NEXT: stxp w8, x9, x1, [x0] 357; CHECK-NEXT: //NO_APP 358; CHECK-NEXT: mov w0, w8 359; CHECK-NEXT: ret 360 %res = call i32 asm sideeffect "stxp ${0:w}, ${2}, ${3}, [${1}]", "=&r,r,r,r,~{memory}"(ptr %p, i64 undef, i64 %x) 361 ret i32 %res 362} 363 364declare i32 @llvm.aarch64.stlxr.p0(i64, ptr) nounwind 365