Home | History | Annotate | Download | only in CodeGen
      1 // RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
      2 // RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s --check-prefix=CHECK-ARM64
      3 
      4 
      5 struct Simple {
      6   char a, b;
      7 };
      8 
      9 int test_ldrex(char *addr, long long *addr64, float *addrfloat) {
     10 // CHECK-LABEL: @test_ldrex
     11 // CHECK-ARM64-LABEL: @test_ldrex
     12   int sum = 0;
     13   sum += __builtin_arm_ldrex(addr);
     14 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
     15 // CHECK: trunc i32 [[INTRES]] to i8
     16 
     17 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i8(i8* %addr)
     18 // CHECK-ARM64: trunc i64 [[INTRES]] to i8
     19 
     20   sum += __builtin_arm_ldrex((short *)addr);
     21 // CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
     22 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0i16(i16* [[ADDR16]])
     23 // CHECK: trunc i32 [[INTRES]] to i16
     24 
     25 // CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
     26 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i16(i16* [[ADDR16]])
     27 // CHECK-ARM64: trunc i64 [[INTRES]] to i16
     28 
     29   sum += __builtin_arm_ldrex((int *)addr);
     30 // CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
     31 // CHECK: call i32 @llvm.arm.ldrex.p0i32(i32* [[ADDR32]])
     32 
     33 // CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
     34 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i32(i32* [[ADDR32]])
     35 // CHECK-ARM64: trunc i64 [[INTRES]] to i32
     36 
     37   sum += __builtin_arm_ldrex((long long *)addr);
     38 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i64*
     39 // CHECK: [[TMP5:%.*]] = bitcast i64* [[TMP4]] to i8*
     40 // CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* [[TMP5]])
     41 
     42 // CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
     43 // CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0i64(i64* [[ADDR64]])
     44 
     45   sum += __builtin_arm_ldrex(addr64);
     46 // CHECK: [[ADDR64_AS8:%.*]] = bitcast i64* %addr64 to i8*
     47 // CHECK: call { i32, i32 } @llvm.arm.ldrexd(i8* [[ADDR64_AS8]])
     48 
     49 // CHECK-ARM64: call i64 @llvm.aarch64.ldxr.p0i64(i64* %addr64)
     50 
     51   sum += __builtin_arm_ldrex(addrfloat);
     52 // CHECK: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
     53 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* [[INTADDR]])
     54 // CHECK: bitcast i32 [[INTRES]] to float
     55 
     56 // CHECK-ARM64: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
     57 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i32(i32* [[INTADDR]])
     58 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
     59 // CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float
     60 
     61   sum += __builtin_arm_ldrex((double *)addr);
     62 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to double*
     63 // CHECK: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i8*
     64 // CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldrexd(i8* [[TMP5]])
     65 // CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
     66 // CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
     67 // CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
     68 // CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
     69 // CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
     70 // CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
     71 // CHECK: bitcast i64 [[INTRES]] to double
     72 
     73 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to double*
     74 // CHECK-ARM64: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i64*
     75 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i64(i64* [[TMP5]])
     76 // CHECK-ARM64: bitcast i64 [[INTRES]] to double
     77 
     78   sum += *__builtin_arm_ldrex((int **)addr);
     79 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i32**
     80 // CHECK: [[TMP5:%.*]] = bitcast i32** [[TMP4]] to i32*
     81 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* [[TMP5]])
     82 // CHECK: inttoptr i32 [[INTRES]] to i32*
     83 
     84 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to i32**
     85 // CHECK-ARM64: [[TMP5:%.*]] = bitcast i32** [[TMP4]] to i64*
     86 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i64(i64* [[TMP5]])
     87 // CHECK-ARM64: inttoptr i64 [[INTRES]] to i32*
     88 
     89   sum += __builtin_arm_ldrex((struct Simple **)addr)->a;
     90 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
     91 // CHECK: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i32*
     92 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldrex.p0i32(i32* [[TMP5]])
     93 // CHECK: inttoptr i32 [[INTRES]] to %struct.Simple*
     94 
     95 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
     96 // CHECK-ARM64: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i64*
     97 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldxr.p0i64(i64* [[TMP5]])
     98 // CHECK-ARM64: inttoptr i64 [[INTRES]] to %struct.Simple*
     99   return sum;
    100 }
    101 
    102 int test_ldaex(char *addr, long long *addr64, float *addrfloat) {
    103 // CHECK-LABEL: @test_ldaex
    104 // CHECK-ARM64-LABEL: @test_ldaex
    105   int sum = 0;
    106   sum += __builtin_arm_ldaex(addr);
    107 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0i8(i8* %addr)
    108 // CHECK: trunc i32 [[INTRES]] to i8
    109 
    110 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i8(i8* %addr)
    111 // CHECK-ARM64: trunc i64 [[INTRES]] to i8
    112 
    113   sum += __builtin_arm_ldaex((short *)addr);
    114 // CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    115 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0i16(i16* [[ADDR16]])
    116 // CHECK: trunc i32 [[INTRES]] to i16
    117 
    118 // CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    119 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i16(i16* [[ADDR16]])
    120 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i16
    121 
    122   sum += __builtin_arm_ldaex((int *)addr);
    123 // CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    124 // CHECK:  call i32 @llvm.arm.ldaex.p0i32(i32* [[ADDR32]])
    125 
    126 // CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    127 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i32(i32* [[ADDR32]])
    128 // CHECK-ARM64: trunc i64 [[INTRES]] to i32
    129 
    130   sum += __builtin_arm_ldaex((long long *)addr);
    131 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i64*
    132 // CHECK: [[TMP5:%.*]] = bitcast i64* [[TMP4]] to i8*
    133 // CHECK: call { i32, i32 } @llvm.arm.ldaexd(i8* [[TMP5]])
    134 
    135 // CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
    136 // CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[ADDR64]])
    137 
    138   sum += __builtin_arm_ldaex(addr64);
    139 // CHECK: [[ADDR64_AS8:%.*]] = bitcast i64* %addr64 to i8*
    140 // CHECK: call { i32, i32 } @llvm.arm.ldaexd(i8* [[ADDR64_AS8]])
    141 
    142 // CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0i64(i64* %addr64)
    143 
    144   sum += __builtin_arm_ldaex(addrfloat);
    145 // CHECK: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
    146 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0i32(i32* [[INTADDR]])
    147 // CHECK: bitcast i32 [[INTRES]] to float
    148 
    149 // CHECK-ARM64: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
    150 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i32(i32* [[INTADDR]])
    151 // CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
    152 // CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float
    153 
    154   sum += __builtin_arm_ldaex((double *)addr);
    155 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to double*
    156 // CHECK: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i8*
    157 // CHECK: [[STRUCTRES:%.*]] = call { i32, i32 } @llvm.arm.ldaexd(i8* [[TMP5]])
    158 // CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
    159 // CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
    160 // CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
    161 // CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
    162 // CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
    163 // CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
    164 // CHECK: bitcast i64 [[INTRES]] to double
    165 
    166 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to double*
    167 // CHECK-ARM64: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i64*
    168 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[TMP5]])
    169 // CHECK-ARM64: bitcast i64 [[INTRES]] to double
    170 
    171   sum += *__builtin_arm_ldaex((int **)addr);
    172 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i32**
    173 // CHECK: [[TMP5:%.*]] = bitcast i32** [[TMP4]] to i32*
    174 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0i32(i32* [[TMP5]])
    175 // CHECK: inttoptr i32 [[INTRES]] to i32*
    176 
    177 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to i32**
    178 // CHECK-ARM64: [[TMP5:%.*]] = bitcast i32** [[TMP4]] to i64*
    179 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[TMP5]])
    180 // CHECK-ARM64: inttoptr i64 [[INTRES]] to i32*
    181 
    182   sum += __builtin_arm_ldaex((struct Simple **)addr)->a;
    183 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    184 // CHECK: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i32*
    185 // CHECK: [[INTRES:%.*]] = call i32 @llvm.arm.ldaex.p0i32(i32* [[TMP5]])
    186 // CHECK: inttoptr i32 [[INTRES]] to %struct.Simple*
    187 
    188 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    189 // CHECK-ARM64: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i64*
    190 // CHECK-ARM64: [[INTRES:%.*]] = call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[TMP5]])
    191 // CHECK-ARM64: inttoptr i64 [[INTRES]] to %struct.Simple*
    192   return sum;
    193 }
    194 
    195 int test_strex(char *addr) {
    196 // CHECK-LABEL: @test_strex
    197 // CHECK-ARM64-LABEL: @test_strex
    198   int res = 0;
    199   struct Simple var = {0};
    200   res |= __builtin_arm_strex(4, addr);
    201 // CHECK: call i32 @llvm.arm.strex.p0i8(i32 4, i8* %addr)
    202 
    203 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i8(i64 4, i8* %addr)
    204 
    205   res |= __builtin_arm_strex(42, (short *)addr);
    206 // CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    207 // CHECK:  call i32 @llvm.arm.strex.p0i16(i32 42, i16* [[ADDR16]])
    208 
    209 // CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    210 // CHECK-ARM64:  call i32 @llvm.aarch64.stxr.p0i16(i64 42, i16* [[ADDR16]])
    211 
    212   res |= __builtin_arm_strex(42, (int *)addr);
    213 // CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    214 // CHECK: call i32 @llvm.arm.strex.p0i32(i32 42, i32* [[ADDR32]])
    215 
    216 // CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    217 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i32(i64 42, i32* [[ADDR32]])
    218 
    219   res |= __builtin_arm_strex(42, (long long *)addr);
    220 // CHECK: store i64 42, i64* [[TMP:%.*]], align 8
    221 // CHECK: [[LOHI_ADDR:%.*]] = bitcast i64* [[TMP]] to { i32, i32 }*
    222 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, { i32, i32 }* [[LOHI_ADDR]]
    223 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    224 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    225 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i64*
    226 // CHECK: [[TMP5:%.*]] = bitcast i64* [[TMP4]] to i8*
    227 // CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], i8* [[TMP5]])
    228 
    229 // CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
    230 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i64(i64 42, i64* [[ADDR64]])
    231 
    232   res |= __builtin_arm_strex(2.71828f, (float *)addr);
    233 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to float*
    234 // CHECK: [[TMP5:%.*]] = bitcast float* [[TMP4]] to i32*
    235 // CHECK: call i32 @llvm.arm.strex.p0i32(i32 1076754509, i32* [[TMP5]])
    236 
    237 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to float*
    238 // CHECK-ARM64: [[TMP5:%.*]] = bitcast float* [[TMP4]] to i32*
    239 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i32(i64 1076754509, i32* [[TMP5]])
    240 
    241   res |= __builtin_arm_strex(3.14159, (double *)addr);
    242 // CHECK: store double 3.141590e+00, double* [[TMP:%.*]], align 8
    243 // CHECK: [[LOHI_ADDR:%.*]] = bitcast double* [[TMP]] to { i32, i32 }*
    244 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, { i32, i32 }* [[LOHI_ADDR]]
    245 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    246 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    247 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to double*
    248 // CHECK: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i8*
    249 // CHECK: call i32 @llvm.arm.strexd(i32 [[LO]], i32 [[HI]], i8* [[TMP5]])
    250 
    251 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to double*
    252 // CHECK-ARM64: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i64*
    253 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i64(i64 4614256650576692846, i64* [[TMP5]])
    254 
    255   res |= __builtin_arm_strex(&var, (struct Simple **)addr);
    256 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    257 // CHECK: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i32*
    258 // CHECK: [[INTVAL:%.*]] = ptrtoint %struct.Simple* %var to i32
    259 // CHECK: call i32 @llvm.arm.strex.p0i32(i32 [[INTVAL]], i32* [[TMP5]])
    260 
    261 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    262 // CHECK-ARM64: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i64*
    263 // CHECK-ARM64: [[INTVAL:%.*]] = ptrtoint %struct.Simple* %var to i64
    264 // CHECK-ARM64: call i32 @llvm.aarch64.stxr.p0i64(i64 [[INTVAL]], i64* [[TMP5]])
    265 
    266   return res;
    267 }
    268 
    269 int test_stlex(char *addr) {
    270 // CHECK-LABEL: @test_stlex
    271 // CHECK-ARM64-LABEL: @test_stlex
    272   int res = 0;
    273   struct Simple var = {0};
    274   res |= __builtin_arm_stlex(4, addr);
    275 // CHECK: call i32 @llvm.arm.stlex.p0i8(i32 4, i8* %addr)
    276 
    277 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i8(i64 4, i8* %addr)
    278 
    279   res |= __builtin_arm_stlex(42, (short *)addr);
    280 // CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    281 // CHECK:  call i32 @llvm.arm.stlex.p0i16(i32 42, i16* [[ADDR16]])
    282 
    283 // CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
    284 // CHECK-ARM64:  call i32 @llvm.aarch64.stlxr.p0i16(i64 42, i16* [[ADDR16]])
    285 
    286   res |= __builtin_arm_stlex(42, (int *)addr);
    287 // CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    288 // CHECK: call i32 @llvm.arm.stlex.p0i32(i32 42, i32* [[ADDR32]])
    289 
    290 // CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
    291 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i32(i64 42, i32* [[ADDR32]])
    292 
    293   res |= __builtin_arm_stlex(42, (long long *)addr);
    294 // CHECK: store i64 42, i64* [[TMP:%.*]], align 8
    295 // CHECK: [[LOHI_ADDR:%.*]] = bitcast i64* [[TMP]] to { i32, i32 }*
    296 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, { i32, i32 }* [[LOHI_ADDR]]
    297 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    298 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    299 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to i64*
    300 // CHECK: [[TMP5:%.*]] = bitcast i64* [[TMP4]] to i8*
    301 // CHECK: call i32 @llvm.arm.stlexd(i32 [[LO]], i32 [[HI]], i8* [[TMP5]])
    302 
    303 // CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
    304 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 42, i64* [[ADDR64]])
    305 
    306   res |= __builtin_arm_stlex(2.71828f, (float *)addr);
    307 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to float*
    308 // CHECK: [[TMP5:%.*]] = bitcast float* [[TMP4]] to i32*
    309 // CHECK: call i32 @llvm.arm.stlex.p0i32(i32 1076754509, i32* [[TMP5]])
    310 
    311 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to float*
    312 // CHECK-ARM64: [[TMP5:%.*]] = bitcast float* [[TMP4]] to i32*
    313 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i32(i64 1076754509, i32* [[TMP5]])
    314 
    315   res |= __builtin_arm_stlex(3.14159, (double *)addr);
    316 // CHECK: store double 3.141590e+00, double* [[TMP:%.*]], align 8
    317 // CHECK: [[LOHI_ADDR:%.*]] = bitcast double* [[TMP]] to { i32, i32 }*
    318 // CHECK: [[LOHI:%.*]] = load { i32, i32 }, { i32, i32 }* [[LOHI_ADDR]]
    319 // CHECK: [[LO:%.*]] = extractvalue { i32, i32 } [[LOHI]], 0
    320 // CHECK: [[HI:%.*]] = extractvalue { i32, i32 } [[LOHI]], 1
    321 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to double*
    322 // CHECK: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i8*
    323 // CHECK: call i32 @llvm.arm.stlexd(i32 [[LO]], i32 [[HI]], i8* [[TMP5]])
    324 
    325 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to double*
    326 // CHECK-ARM64: [[TMP5:%.*]] = bitcast double* [[TMP4]] to i64*
    327 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 4614256650576692846, i64* [[TMP5]])
    328 
    329   res |= __builtin_arm_stlex(&var, (struct Simple **)addr);
    330 // CHECK: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    331 // CHECK: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i32*
    332 // CHECK: [[INTVAL:%.*]] = ptrtoint %struct.Simple* %var to i32
    333 // CHECK: call i32 @llvm.arm.stlex.p0i32(i32 [[INTVAL]], i32* [[TMP5]])
    334 
    335 // CHECK-ARM64: [[TMP4:%.*]] = bitcast i8* %addr to %struct.Simple**
    336 // CHECK-ARM64: [[TMP5:%.*]] = bitcast %struct.Simple** [[TMP4]] to i64*
    337 // CHECK-ARM64: [[INTVAL:%.*]] = ptrtoint %struct.Simple* %var to i64
    338 // CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 [[INTVAL]], i64* [[TMP5]])
    339 
    340   return res;
    341 }
    342 
    343 void test_clrex() {
    344 // CHECK-LABEL: @test_clrex
    345 // CHECK-ARM64-LABEL: @test_clrex
    346 
    347   __builtin_arm_clrex();
    348 // CHECK: call void @llvm.arm.clrex()
    349 // CHECK-ARM64: call void @llvm.aarch64.clrex()
    350 }
    351 
    352 #ifdef __aarch64__
    353 // 128-bit tests
    354 
    355 __int128 test_ldrex_128(__int128 *addr) {
    356 // CHECK-ARM64-LABEL: @test_ldrex_128
    357 
    358   return __builtin_arm_ldrex(addr);
    359 // CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
    360 // CHECK-ARM64: [[STRUCTRES:%.*]] = call { i64, i64 } @llvm.aarch64.ldxp(i8* [[ADDR8]])
    361 // CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
    362 // CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
    363 // CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
    364 // CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
    365 // CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
    366 // CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESHIHI]], [[RESLO64]]
    367 // CHECK-ARM64: ret i128 [[INTRES]]
    368 }
    369 
    370 int test_strex_128(__int128 *addr, __int128 val) {
    371 // CHECK-ARM64-LABEL: @test_strex_128
    372 
    373   return __builtin_arm_strex(val, addr);
    374 // CHECK-ARM64: store i128 %val, i128* [[TMP:%.*]], align 16
    375 // CHECK-ARM64: [[LOHI_ADDR:%.*]] = bitcast i128* [[TMP]] to { i64, i64 }*
    376 // CHECK-ARM64: [[LOHI:%.*]] = load { i64, i64 }, { i64, i64 }* [[LOHI_ADDR]]
    377 // CHECK-ARM64: [[LO:%.*]] = extractvalue { i64, i64 } [[LOHI]], 0
    378 // CHECK-ARM64: [[HI:%.*]] = extractvalue { i64, i64 } [[LOHI]], 1
    379 // CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
    380 // CHECK-ARM64: call i32 @llvm.aarch64.stxp(i64 [[LO]], i64 [[HI]], i8* [[ADDR8]])
    381 }
    382 
    383 __int128 test_ldaex_128(__int128 *addr) {
    384 // CHECK-ARM64-LABEL: @test_ldaex_128
    385 
    386   return __builtin_arm_ldaex(addr);
    387 // CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
    388 // CHECK-ARM64: [[STRUCTRES:%.*]] = call { i64, i64 } @llvm.aarch64.ldaxp(i8* [[ADDR8]])
    389 // CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
    390 // CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
    391 // CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
    392 // CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
    393 // CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
    394 // CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESHIHI]], [[RESLO64]]
    395 // CHECK-ARM64: ret i128 [[INTRES]]
    396 }
    397 
    398 int test_stlex_128(__int128 *addr, __int128 val) {
    399 // CHECK-ARM64-LABEL: @test_stlex_128
    400 
    401   return __builtin_arm_stlex(val, addr);
    402 // CHECK-ARM64: store i128 %val, i128* [[TMP:%.*]], align 16
    403 // CHECK-ARM64: [[LOHI_ADDR:%.*]] = bitcast i128* [[TMP]] to { i64, i64 }*
    404 // CHECK-ARM64: [[LOHI:%.*]] = load { i64, i64 }, { i64, i64 }* [[LOHI_ADDR]]
    405 // CHECK-ARM64: [[LO:%.*]] = extractvalue { i64, i64 } [[LOHI]], 0
    406 // CHECK-ARM64: [[HI:%.*]] = extractvalue { i64, i64 } [[LOHI]], 1
    407 // CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
    408 // CHECK-ARM64: [[RES:%.*]] = call i32 @llvm.aarch64.stlxp(i64 [[LO]], i64 [[HI]], i8* [[ADDR8]])
    409 }
    410 
    411 #endif
    412