brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · 1d6a32c Raw
233 lines · plain
1; RUN: opt -S %s -passes=atomic-expand | FileCheck %s2 3;;; NOTE: this test is actually target-independent -- any target which4;;; doesn't support inline atomics can be used. (E.g. X86 i386 would5;;; 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"9target datalayout = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"10target triple = "sparc-unknown-unknown"11 12;; First, check the sized calls. Except for cmpxchg, these are fairly13;; straightforward.14 15; CHECK-LABEL: @test_load_i16(16; CHECK:  %1 = call i16 @__atomic_load_2(ptr %arg, i32 5)17; CHECK:  ret i16 %118define i16 @test_load_i16(ptr %arg) {19  %ret = load atomic i16, ptr %arg seq_cst, align 420  ret i16 %ret21}22 23; CHECK-LABEL: @test_store_i16(24; CHECK:  call void @__atomic_store_2(ptr %arg, i16 %val, i32 5)25; CHECK:  ret void26define void @test_store_i16(ptr %arg, i16 %val) {27  store atomic i16 %val, ptr %arg seq_cst, align 428  ret void29}30 31; CHECK-LABEL: @test_exchange_i16(32; CHECK:  %1 = call i16 @__atomic_exchange_2(ptr %arg, i16 %val, i32 5)33; CHECK:  ret i16 %134define i16 @test_exchange_i16(ptr %arg, i16 %val) {35  %ret = atomicrmw xchg ptr %arg, i16 %val seq_cst36  ret i16 %ret37}38 39; CHECK-LABEL: @test_cmpxchg_i16(40; CHECK:  %1 = alloca i16, align 241; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)42; CHECK:  store i16 %old, ptr %1, align 243; CHECK:  %2 = call zeroext i1 @__atomic_compare_exchange_2(ptr %arg, ptr %1, i16 %new, i32 5, i32 0)44; CHECK:  %3 = load i16, ptr %1, align 245; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)46; CHECK:  %4 = insertvalue { i16, i1 } poison, i16 %3, 047; CHECK:  %5 = insertvalue { i16, i1 } %4, i1 %2, 148; CHECK:  %ret = extractvalue { i16, i1 } %5, 049; CHECK:  ret i16 %ret50define i16 @test_cmpxchg_i16(ptr %arg, i16 %old, i16 %new) {51  %ret_succ = cmpxchg ptr %arg, i16 %old, i16 %new seq_cst monotonic52  %ret = extractvalue { i16, i1 } %ret_succ, 053  ret i16 %ret54}55 56; CHECK-LABEL: @test_add_i16(57; CHECK:  %1 = call i16 @__atomic_fetch_add_2(ptr %arg, i16 %val, i32 5)58; CHECK:  ret i16 %159define i16 @test_add_i16(ptr %arg, i16 %val) {60  %ret = atomicrmw add ptr %arg, i16 %val seq_cst61  ret i16 %ret62}63 64 65;; Now, check the output for the unsized libcalls. i128 is used for66;; these tests because the "16" suffixed functions aren't available on67;; 32-bit i386.68 69; CHECK-LABEL: @test_load_i128(70; CHECK:  %1 = alloca i128, align 871; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)72; CHECK:  call void @__atomic_load(i32 16, ptr %arg, ptr %1, i32 5)73; CHECK:  %2 = load i128, ptr %1, align 874; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)75; CHECK:  ret i128 %276define i128 @test_load_i128(ptr %arg) {77  %ret = load atomic i128, ptr %arg seq_cst, align 1678  ret i128 %ret79}80 81; CHECK-LABEL: @test_store_i128(82; CHECK:  %1 = alloca i128, align 883; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)84; CHECK:  store i128 %val, ptr %1, align 885; CHECK:  call void @__atomic_store(i32 16, ptr %arg, ptr %1, i32 5)86; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)87; CHECK:  ret void88define void @test_store_i128(ptr %arg, i128 %val) {89  store atomic i128 %val, ptr %arg seq_cst, align 1690  ret void91}92 93; CHECK-LABEL: @test_exchange_i128(94; CHECK:  %1 = alloca i128, align 895; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)96; CHECK:  store i128 %val, ptr %1, align 897; CHECK:  %2 = alloca i128, align 898; CHECK:  call void @llvm.lifetime.start.p0(ptr %2)99; CHECK:  call void @__atomic_exchange(i32 16, ptr %arg, ptr %1, ptr %2, i32 5)100; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)101; CHECK:  %3 = load i128, ptr %2, align 8102; CHECK:  call void @llvm.lifetime.end.p0(ptr %2)103; CHECK:  ret i128 %3104define i128 @test_exchange_i128(ptr %arg, i128 %val) {105  %ret = atomicrmw xchg ptr %arg, i128 %val seq_cst106  ret i128 %ret107}108 109; CHECK-LABEL: @test_cmpxchg_i128(110; CHECK:  %1 = alloca i128, align 8111; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)112; CHECK:  store i128 %old, ptr %1, align 8113; CHECK:  %2 = alloca i128, align 8114; CHECK:  call void @llvm.lifetime.start.p0(ptr %2)115; CHECK:  store i128 %new, ptr %2, align 8116; CHECK:  %3 = call zeroext i1 @__atomic_compare_exchange(i32 16, ptr %arg, ptr %1, ptr %2, i32 5, i32 0)117; CHECK:  call void @llvm.lifetime.end.p0(ptr %2)118; CHECK:  %4 = load i128, ptr %1, align 8119; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)120; CHECK:  %5 = insertvalue { i128, i1 } poison, i128 %4, 0121; CHECK:  %6 = insertvalue { i128, i1 } %5, i1 %3, 1122; CHECK:  %ret = extractvalue { i128, i1 } %6, 0123; CHECK:  ret i128 %ret124define i128 @test_cmpxchg_i128(ptr %arg, i128 %old, i128 %new) {125  %ret_succ = cmpxchg ptr %arg, i128 %old, i128 %new seq_cst monotonic126  %ret = extractvalue { i128, i1 } %ret_succ, 0127  ret i128 %ret128}129 130; This one is a verbose expansion, as there is no generic131; __atomic_fetch_add function, so it needs to expand to a cmpxchg132; loop, which then itself expands into a libcall.133 134; CHECK-LABEL: @test_add_i128(135; CHECK:  %1 = alloca i128, align 8136; CHECK:  %2 = alloca i128, align 8137; CHECK:  %3 = load i128, ptr %arg, align 16138; CHECK:  br label %atomicrmw.start139; CHECK:atomicrmw.start:140; CHECK:  %loaded = phi i128 [ %3, %0 ], [ %newloaded, %atomicrmw.start ]141; CHECK:  %new = add i128 %loaded, %val142; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)143; CHECK:  store i128 %loaded, ptr %1, align 8144; CHECK:  call void @llvm.lifetime.start.p0(ptr %2)145; CHECK:  store i128 %new, ptr %2, align 8146; CHECK:  %4 = call zeroext i1 @__atomic_compare_exchange(i32 16, ptr %arg, ptr %1, ptr %2, i32 5, i32 5)147; CHECK:  call void @llvm.lifetime.end.p0(ptr %2)148; CHECK:  %5 = load i128, ptr %1, align 8149; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)150; CHECK:  %6 = insertvalue { i128, i1 } poison, i128 %5, 0151; CHECK:  %7 = insertvalue { i128, i1 } %6, i1 %4, 1152; CHECK:  %success = extractvalue { i128, i1 } %7, 1153; CHECK:  %newloaded = extractvalue { i128, i1 } %7, 0154; CHECK:  br i1 %success, label %atomicrmw.end, label %atomicrmw.start155; CHECK:atomicrmw.end:156; CHECK:  ret i128 %newloaded157define i128 @test_add_i128(ptr %arg, i128 %val) {158  %ret = atomicrmw add ptr %arg, i128 %val seq_cst159  ret i128 %ret160}161 162;; Ensure that non-integer types get bitcast correctly on the way in and out of a libcall:163 164; CHECK-LABEL: @test_load_double(165; CHECK:  %1 = call i64 @__atomic_load_8(ptr %arg, i32 5)166; CHECK:  %2 = bitcast i64 %1 to double167; CHECK:  ret double %2168define double @test_load_double(ptr %arg, double %val) {169  %1 = load atomic double, ptr %arg seq_cst, align 16170  ret double %1171}172 173; CHECK-LABEL: @test_store_double(174; CHECK:  %1 = bitcast double %val to i64175; CHECK:  call void @__atomic_store_8(ptr %arg, i64 %1, i32 5)176; CHECK:  ret void177define void @test_store_double(ptr %arg, double %val) {178  store atomic double %val, ptr %arg seq_cst, align 16179  ret void180}181 182; CHECK-LABEL: @test_cmpxchg_ptr(183; CHECK:   %1 = alloca ptr, align 4184; CHECK:   call void @llvm.lifetime.start.p0(ptr %1)185; CHECK:   store ptr %old, ptr %1, align 4186; CHECK:   %2 = ptrtoint ptr %new to i32187; CHECK:   %3 = call zeroext i1 @__atomic_compare_exchange_4(ptr %arg, ptr %1, i32 %2, i32 5, i32 2)188; CHECK:   %4 = load ptr, ptr %1, align 4189; CHECK:   call void @llvm.lifetime.end.p0(ptr %1)190; CHECK:   %5 = insertvalue { ptr, i1 } poison, ptr %4, 0191; CHECK:   %6 = insertvalue { ptr, i1 } %5, i1 %3, 1192; CHECK:   %ret = extractvalue { ptr, i1 } %6, 0193; CHECK:   ret ptr %ret194; CHECK: }195define ptr @test_cmpxchg_ptr(ptr %arg, ptr %old, ptr %new) {196  %ret_succ = cmpxchg ptr %arg, ptr %old, ptr %new seq_cst acquire197  %ret = extractvalue { ptr, i1 } %ret_succ, 0198  ret ptr %ret199}200 201;; ...and for a non-integer type of large size too.202 203; CHECK-LABEL: @test_store_fp128204; CHECK:  %1 = alloca fp128, align 8205; CHECK:  call void @llvm.lifetime.start.p0(ptr %1)206; CHECK:  store fp128 %val, ptr %1, align 8207; CHECK:  call void @__atomic_store(i32 16, ptr %arg, ptr %1, i32 5)208; CHECK:  call void @llvm.lifetime.end.p0(ptr %1)209; CHECK:  ret void210define void @test_store_fp128(ptr %arg, fp128 %val) {211  store atomic fp128 %val, ptr %arg seq_cst, align 16212  ret void213}214 215;; Unaligned loads and stores should be expanded to the generic216;; libcall, just like large loads/stores, and not a specialized one.217;; NOTE: atomicrmw and cmpxchg don't yet support an align attribute;218;; when such support is added, they should also be tested here.219 220; CHECK-LABEL: @test_unaligned_load_i16(221; CHECK:  __atomic_load(222define i16 @test_unaligned_load_i16(ptr %arg) {223  %ret = load atomic i16, ptr %arg seq_cst, align 1224  ret i16 %ret225}226 227; CHECK-LABEL: @test_unaligned_store_i16(228; CHECK: __atomic_store(229define void @test_unaligned_store_i16(ptr %arg, i16 %val) {230  store atomic i16 %val, ptr %arg seq_cst, align 1231  ret void232}233