Home | History | Annotate | Download | only in SPARC
      1 ; RUN: opt -S %s -atomic-expand | FileCheck %s
      2 
      3 ;;; NOTE: this test is actually target-independent -- any target which
      4 ;;; doesn't support inline atomics can be used. (E.g. X86 i386 would
      5 ;;; work, if LLVM is properly taught about what it's missing vs i586.)
      6 
      7 ;target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"
      8 ;target triple = "i386-unknown-unknown"
      9 target datalayout = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"
     10 target triple = "sparc-unknown-unknown"
     11 
     12 ;; First, check the sized calls. Except for cmpxchg, these are fairly
     13 ;; straightforward.
     14 
     15 ; CHECK-LABEL: @test_load_i16(
     16 ; CHECK:  %1 = bitcast i16* %arg to i8*
     17 ; CHECK:  %2 = call i16 @__atomic_load_2(i8* %1, i32 5)
     18 ; CHECK:  ret i16 %2
     19 define i16 @test_load_i16(i16* %arg) {
     20   %ret = load atomic i16, i16* %arg seq_cst, align 4
     21   ret i16 %ret
     22 }
     23 
     24 ; CHECK-LABEL: @test_store_i16(
     25 ; CHECK:  %1 = bitcast i16* %arg to i8*
     26 ; CHECK:  call void @__atomic_store_2(i8* %1, i16 %val, i32 5)
     27 ; CHECK:  ret void
     28 define void @test_store_i16(i16* %arg, i16 %val) {
     29   store atomic i16 %val, i16* %arg seq_cst, align 4
     30   ret void
     31 }
     32 
     33 ; CHECK-LABEL: @test_exchange_i16(
     34 ; CHECK:  %1 = bitcast i16* %arg to i8*
     35 ; CHECK:  %2 = call i16 @__atomic_exchange_2(i8* %1, i16 %val, i32 5)
     36 ; CHECK:  ret i16 %2
     37 define i16 @test_exchange_i16(i16* %arg, i16 %val) {
     38   %ret = atomicrmw xchg i16* %arg, i16 %val seq_cst
     39   ret i16 %ret
     40 }
     41 
     42 ; CHECK-LABEL: @test_cmpxchg_i16(
     43 ; CHECK:  %1 = bitcast i16* %arg to i8*
     44 ; CHECK:  %2 = alloca i16, align 2
     45 ; CHECK:  %3 = bitcast i16* %2 to i8*
     46 ; CHECK:  call void @llvm.lifetime.start(i64 2, i8* %3)
     47 ; CHECK:  store i16 %old, i16* %2, align 2
     48 ; CHECK:  %4 = call zeroext i1 @__atomic_compare_exchange_2(i8* %1, i8* %3, i16 %new, i32 5, i32 0)
     49 ; CHECK:  %5 = load i16, i16* %2, align 2
     50 ; CHECK:  call void @llvm.lifetime.end(i64 2, i8* %3)
     51 ; CHECK:  %6 = insertvalue { i16, i1 } undef, i16 %5, 0
     52 ; CHECK:  %7 = insertvalue { i16, i1 } %6, i1 %4, 1
     53 ; CHECK:  %ret = extractvalue { i16, i1 } %7, 0
     54 ; CHECK:  ret i16 %ret
     55 define i16 @test_cmpxchg_i16(i16* %arg, i16 %old, i16 %new) {
     56   %ret_succ = cmpxchg i16* %arg, i16 %old, i16 %new seq_cst monotonic
     57   %ret = extractvalue { i16, i1 } %ret_succ, 0
     58   ret i16 %ret
     59 }
     60 
     61 ; CHECK-LABEL: @test_add_i16(
     62 ; CHECK:  %1 = bitcast i16* %arg to i8*
     63 ; CHECK:  %2 = call i16 @__atomic_fetch_add_2(i8* %1, i16 %val, i32 5)
     64 ; CHECK:  ret i16 %2
     65 define i16 @test_add_i16(i16* %arg, i16 %val) {
     66   %ret = atomicrmw add i16* %arg, i16 %val seq_cst
     67   ret i16 %ret
     68 }
     69 
     70 
     71 ;; Now, check the output for the unsized libcalls. i128 is used for
     72 ;; these tests because the "16" suffixed functions aren't available on
     73 ;; 32-bit i386.
     74 
     75 ; CHECK-LABEL: @test_load_i128(
     76 ; CHECK:  %1 = bitcast i128* %arg to i8*
     77 ; CHECK:  %2 = alloca i128, align 8
     78 ; CHECK:  %3 = bitcast i128* %2 to i8*
     79 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %3)
     80 ; CHECK:  call void @__atomic_load(i32 16, i8* %1, i8* %3, i32 5)
     81 ; CHECK:  %4 = load i128, i128* %2, align 8
     82 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %3)
     83 ; CHECK:  ret i128 %4
     84 define i128 @test_load_i128(i128* %arg) {
     85   %ret = load atomic i128, i128* %arg seq_cst, align 16
     86   ret i128 %ret
     87 }
     88 
     89 ; CHECK-LABEL @test_store_i128(
     90 ; CHECK:  %1 = bitcast i128* %arg to i8*
     91 ; CHECK:  %2 = alloca i128, align 8
     92 ; CHECK:  %3 = bitcast i128* %2 to i8*
     93 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %3)
     94 ; CHECK:  store i128 %val, i128* %2, align 8
     95 ; CHECK:  call void @__atomic_store(i32 16, i8* %1, i8* %3, i32 5)
     96 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %3)
     97 ; CHECK:  ret void
     98 define void @test_store_i128(i128* %arg, i128 %val) {
     99   store atomic i128 %val, i128* %arg seq_cst, align 16
    100   ret void
    101 }
    102 
    103 ; CHECK-LABEL: @test_exchange_i128(
    104 ; CHECK:  %1 = bitcast i128* %arg to i8*
    105 ; CHECK:  %2 = alloca i128, align 8
    106 ; CHECK:  %3 = bitcast i128* %2 to i8*
    107 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %3)
    108 ; CHECK:  store i128 %val, i128* %2, align 8
    109 ; CHECK:  %4 = alloca i128, align 8
    110 ; CHECK:  %5 = bitcast i128* %4 to i8*
    111 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %5)
    112 ; CHECK:  call void @__atomic_exchange(i32 16, i8* %1, i8* %3, i8* %5, i32 5)
    113 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %3)
    114 ; CHECK:  %6 = load i128, i128* %4, align 8
    115 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %5)
    116 ; CHECK:  ret i128 %6
    117 define i128 @test_exchange_i128(i128* %arg, i128 %val) {
    118   %ret = atomicrmw xchg i128* %arg, i128 %val seq_cst
    119   ret i128 %ret
    120 }
    121 
    122 ; CHECK-LABEL: @test_cmpxchg_i128(
    123 ; CHECK:  %1 = bitcast i128* %arg to i8*
    124 ; CHECK:  %2 = alloca i128, align 8
    125 ; CHECK:  %3 = bitcast i128* %2 to i8*
    126 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %3)
    127 ; CHECK:  store i128 %old, i128* %2, align 8
    128 ; CHECK:  %4 = alloca i128, align 8
    129 ; CHECK:  %5 = bitcast i128* %4 to i8*
    130 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %5)
    131 ; CHECK:  store i128 %new, i128* %4, align 8
    132 ; CHECK:  %6 = call zeroext i1 @__atomic_compare_exchange(i32 16, i8* %1, i8* %3, i8* %5, i32 5, i32 0)
    133 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %5)
    134 ; CHECK:  %7 = load i128, i128* %2, align 8
    135 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %3)
    136 ; CHECK:  %8 = insertvalue { i128, i1 } undef, i128 %7, 0
    137 ; CHECK:  %9 = insertvalue { i128, i1 } %8, i1 %6, 1
    138 ; CHECK:  %ret = extractvalue { i128, i1 } %9, 0
    139 ; CHECK:  ret i128 %ret
    140 define i128 @test_cmpxchg_i128(i128* %arg, i128 %old, i128 %new) {
    141   %ret_succ = cmpxchg i128* %arg, i128 %old, i128 %new seq_cst monotonic
    142   %ret = extractvalue { i128, i1 } %ret_succ, 0
    143   ret i128 %ret
    144 }
    145 
    146 ; This one is a verbose expansion, as there is no generic
    147 ; __atomic_fetch_add function, so it needs to expand to a cmpxchg
    148 ; loop, which then itself expands into a libcall.
    149 
    150 ; CHECK-LABEL: @test_add_i128(
    151 ; CHECK:  %1 = alloca i128, align 8
    152 ; CHECK:  %2 = alloca i128, align 8
    153 ; CHECK:  %3 = load i128, i128* %arg, align 16
    154 ; CHECK:  br label %atomicrmw.start
    155 ; CHECK:atomicrmw.start:
    156 ; CHECK:  %loaded = phi i128 [ %3, %0 ], [ %newloaded, %atomicrmw.start ]
    157 ; CHECK:  %new = add i128 %loaded, %val
    158 ; CHECK:  %4 = bitcast i128* %arg to i8*
    159 ; CHECK:  %5 = bitcast i128* %1 to i8*
    160 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %5)
    161 ; CHECK:  store i128 %loaded, i128* %1, align 8
    162 ; CHECK:  %6 = bitcast i128* %2 to i8*
    163 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %6)
    164 ; CHECK:  store i128 %new, i128* %2, align 8
    165 ; CHECK:  %7 = call zeroext i1 @__atomic_compare_exchange(i32 16, i8* %4, i8* %5, i8* %6, i32 5, i32 5)
    166 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %6)
    167 ; CHECK:  %8 = load i128, i128* %1, align 8
    168 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %5)
    169 ; CHECK:  %9 = insertvalue { i128, i1 } undef, i128 %8, 0
    170 ; CHECK:  %10 = insertvalue { i128, i1 } %9, i1 %7, 1
    171 ; CHECK:  %success = extractvalue { i128, i1 } %10, 1
    172 ; CHECK:  %newloaded = extractvalue { i128, i1 } %10, 0
    173 ; CHECK:  br i1 %success, label %atomicrmw.end, label %atomicrmw.start
    174 ; CHECK:atomicrmw.end:
    175 ; CHECK:  ret i128 %newloaded
    176 define i128 @test_add_i128(i128* %arg, i128 %val) {
    177   %ret = atomicrmw add i128* %arg, i128 %val seq_cst
    178   ret i128 %ret
    179 }
    180 
    181 ;; Ensure that non-integer types get bitcast correctly on the way in and out of a libcall:
    182 
    183 ; CHECK-LABEL: @test_load_double(
    184 ; CHECK:  %1 = bitcast double* %arg to i8*
    185 ; CHECK:  %2 = call i64 @__atomic_load_8(i8* %1, i32 5)
    186 ; CHECK:  %3 = bitcast i64 %2 to double
    187 ; CHECK:  ret double %3
    188 define double @test_load_double(double* %arg, double %val) {
    189   %1 = load atomic double, double* %arg seq_cst, align 16
    190   ret double %1
    191 }
    192 
    193 ; CHECK-LABEL: @test_store_double(
    194 ; CHECK:  %1 = bitcast double* %arg to i8*
    195 ; CHECK:  %2 = bitcast double %val to i64
    196 ; CHECK:  call void @__atomic_store_8(i8* %1, i64 %2, i32 5)
    197 ; CHECK:  ret void
    198 define void @test_store_double(double* %arg, double %val) {
    199   store atomic double %val, double* %arg seq_cst, align 16
    200   ret void
    201 }
    202 
    203 ; CHECK-LABEL: @test_cmpxchg_ptr(
    204 ; CHECK:   %1 = bitcast i16** %arg to i8*
    205 ; CHECK:   %2 = alloca i16*, align 4
    206 ; CHECK:   %3 = bitcast i16** %2 to i8*
    207 ; CHECK:   call void @llvm.lifetime.start(i64 4, i8* %3)
    208 ; CHECK:   store i16* %old, i16** %2, align 4
    209 ; CHECK:   %4 = ptrtoint i16* %new to i32
    210 ; CHECK:   %5 = call zeroext i1 @__atomic_compare_exchange_4(i8* %1, i8* %3, i32 %4, i32 5, i32 2)
    211 ; CHECK:   %6 = load i16*, i16** %2, align 4
    212 ; CHECK:   call void @llvm.lifetime.end(i64 4, i8* %3)
    213 ; CHECK:   %7 = insertvalue { i16*, i1 } undef, i16* %6, 0
    214 ; CHECK:   %8 = insertvalue { i16*, i1 } %7, i1 %5, 1
    215 ; CHECK:   %ret = extractvalue { i16*, i1 } %8, 0
    216 ; CHECK:   ret i16* %ret
    217 ; CHECK: }
    218 define i16* @test_cmpxchg_ptr(i16** %arg, i16* %old, i16* %new) {
    219   %ret_succ = cmpxchg i16** %arg, i16* %old, i16* %new seq_cst acquire
    220   %ret = extractvalue { i16*, i1 } %ret_succ, 0
    221   ret i16* %ret
    222 }
    223 
    224 ;; ...and for a non-integer type of large size too.
    225 
    226 ; CHECK-LABEL: @test_store_fp128
    227 ; CHECK:   %1 = bitcast fp128* %arg to i8*
    228 ; CHECK:  %2 = alloca fp128, align 8
    229 ; CHECK:  %3 = bitcast fp128* %2 to i8*
    230 ; CHECK:  call void @llvm.lifetime.start(i64 16, i8* %3)
    231 ; CHECK:  store fp128 %val, fp128* %2, align 8
    232 ; CHECK:  call void @__atomic_store(i32 16, i8* %1, i8* %3, i32 5)
    233 ; CHECK:  call void @llvm.lifetime.end(i64 16, i8* %3)
    234 ; CHECK:  ret void
    235 define void @test_store_fp128(fp128* %arg, fp128 %val) {
    236   store atomic fp128 %val, fp128* %arg seq_cst, align 16
    237   ret void
    238 }
    239 
    240 ;; Unaligned loads and stores should be expanded to the generic
    241 ;; libcall, just like large loads/stores, and not a specialized one.
    242 ;; NOTE: atomicrmw and cmpxchg don't yet support an align attribute;
    243 ;; when such support is added, they should also be tested here.
    244 
    245 ; CHECK-LABEL: @test_unaligned_load_i16(
    246 ; CHECK:  __atomic_load(
    247 define i16 @test_unaligned_load_i16(i16* %arg) {
    248   %ret = load atomic i16, i16* %arg seq_cst, align 1
    249   ret i16 %ret
    250 }
    251 
    252 ; CHECK-LABEL: @test_unaligned_store_i16(
    253 ; CHECK: __atomic_store(
    254 define void @test_unaligned_store_i16(i16* %arg, i16 %val) {
    255   store atomic i16 %val, i16* %arg seq_cst, align 1
    256   ret void
    257 }
    258