mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
738c47313c
Based on the same for AArch64: 4751cadcca45984d7671e594ce95aed8fe030bf1 At -O0, the fast register allocator may insert spills between the ldrex and strex instructions inserted by AtomicExpandPass when expanding atomicrmw instructions in LL/SC loops. To avoid this, expand to cmpxchg loops and therefore expand the cmpxchg pseudos after register allocation. Required a tweak to ARMExpandPseudo::ExpandCMP_SWAP to use the 4-byte encoding of UXT, since the pseudo instruction can be allocated a high register (R8-R15) which the 2-byte encoding doesn't support. However, the 4-byte encodings are not present for ARM v8-M Baseline. To enable this, two new pseudos are added for Thumb which are only valid for v8mbase, tCMP_SWAP_8 and tCMP_SWAP_16. The previously committed attempt in D101164 had to be reverted due to runtime failures in the test suites. Rather than spending time fixing that implementation (adding another implementation of atomic operations and more divergence between backends) I have chosen to follow the approach taken in D101163. Differential Revision: https://reviews.llvm.org/D101898 Depends on D101912
474 lines
11 KiB
LLVM
474 lines
11 KiB
LLVM
; Test the instruction sequences produced by atomicrmw instructions. In
|
|
; particular, ensure there are no stores/spills inserted between the exclusive
|
|
; load and stores, which would invalidate the exclusive monitor.
|
|
|
|
; RUN: llc -mtriple=armv8-unknown-none-eabi -O0 -o - %s | FileCheck %s --check-prefix=COMMON --check-prefix=EXPAND32 --check-prefix=EXPAND64
|
|
; RUN: llc -mtriple=armv6-unknown-none-eabi -O0 -o - %s | FileCheck %s --check-prefix=COMMON --check-prefix=EXPAND32 --check-prefix=EXPAND64
|
|
; RUN: llc -mtriple=thumbv7-unknown-none-eabi -O0 -o - %s | FileCheck %s --check-prefix=COMMON --check-prefix=EXPAND32 --check-prefix=EXPAND64
|
|
; RUN: llc -mtriple=thumbv6-unknown-none-eabi -O0 -o - %s | FileCheck %s --check-prefix=COMMON --check-prefix=THUMB1
|
|
; RUN: llc -mtriple=thumbv8m.base-unknown-none-eabi -O0 -o - %s | FileCheck %s --check-prefix=COMMON --check-prefix=EXPAND32 --check-prefix=BASELINE64
|
|
|
|
@atomic_i8 = external global i8
|
|
@atomic_i16 = external global i16
|
|
@atomic_i32 = external global i32
|
|
@atomic_i64 = external global i64
|
|
|
|
define i8 @test_xchg_i8() {
|
|
; COMMON-LABEL: test_xchg_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_lock_test_and_set_1
|
|
entry:
|
|
%0 = atomicrmw xchg i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_add_i8() {
|
|
; COMMON-LABEL: test_add_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_add_1
|
|
entry:
|
|
%0 = atomicrmw add i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_sub_i8() {
|
|
; COMMON-LABEL: test_sub_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_sub_1
|
|
entry:
|
|
%0 = atomicrmw sub i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_and_i8() {
|
|
; COMMON-LABEL: test_and_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_and_1
|
|
entry:
|
|
%0 = atomicrmw and i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_nand_i8() {
|
|
; COMMON-LABEL: test_nand_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_nand_1
|
|
entry:
|
|
%0 = atomicrmw nand i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_or_i8() {
|
|
; COMMON-LABEL: test_or_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_or_1
|
|
entry:
|
|
%0 = atomicrmw or i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_xor_i8() {
|
|
; COMMON-LABEL: test_xor_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_xor_1
|
|
entry:
|
|
%0 = atomicrmw xor i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_max_i8() {
|
|
; COMMON-LABEL: test_max_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_max_1
|
|
entry:
|
|
%0 = atomicrmw max i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_min_i8() {
|
|
; COMMON-LABEL: test_min_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_min_1
|
|
entry:
|
|
%0 = atomicrmw min i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_umax_i8() {
|
|
; COMMON-LABEL: test_umax_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_umax_1
|
|
entry:
|
|
%0 = atomicrmw umax i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
define i8 @test_umin_i8() {
|
|
; COMMON-LABEL: test_umin_i8:
|
|
; EXPAND32: ldrexb
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexb
|
|
; THUMB1: bl __sync_fetch_and_umin_1
|
|
entry:
|
|
%0 = atomicrmw umin i8* @atomic_i8, i8 1 monotonic
|
|
ret i8 %0
|
|
}
|
|
|
|
|
|
define i16 @test_xchg_i16() {
|
|
; COMMON-LABEL: test_xchg_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_lock_test_and_set_2
|
|
entry:
|
|
%0 = atomicrmw xchg i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_add_i16() {
|
|
; COMMON-LABEL: test_add_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_add_2
|
|
entry:
|
|
%0 = atomicrmw add i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_sub_i16() {
|
|
; COMMON-LABEL: test_sub_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_sub_2
|
|
entry:
|
|
%0 = atomicrmw sub i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_and_i16() {
|
|
; COMMON-LABEL: test_and_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_and_2
|
|
entry:
|
|
%0 = atomicrmw and i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_nand_i16() {
|
|
; COMMON-LABEL: test_nand_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_nand_2
|
|
entry:
|
|
%0 = atomicrmw nand i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_or_i16() {
|
|
; COMMON-LABEL: test_or_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_or_2
|
|
entry:
|
|
%0 = atomicrmw or i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_xor_i16() {
|
|
; COMMON-LABEL: test_xor_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_xor_2
|
|
entry:
|
|
%0 = atomicrmw xor i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_max_i16() {
|
|
; COMMON-LABEL: test_max_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_max_2
|
|
entry:
|
|
%0 = atomicrmw max i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_min_i16() {
|
|
; COMMON-LABEL: test_min_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_min_2
|
|
entry:
|
|
%0 = atomicrmw min i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_umax_i16() {
|
|
; COMMON-LABEL: test_umax_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_umax_2
|
|
entry:
|
|
%0 = atomicrmw umax i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
define i16 @test_umin_i16() {
|
|
; COMMON-LABEL: test_umin_i16:
|
|
; EXPAND32: ldrexh
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strexh
|
|
; THUMB1: bl __sync_fetch_and_umin_2
|
|
entry:
|
|
%0 = atomicrmw umin i16* @atomic_i16, i16 1 monotonic
|
|
ret i16 %0
|
|
}
|
|
|
|
|
|
define i32 @test_xchg_i32() {
|
|
; COMMON-LABEL: test_xchg_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_lock_test_and_set_4
|
|
entry:
|
|
%0 = atomicrmw xchg i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_add_i32() {
|
|
; COMMON-LABEL: test_add_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_add_4
|
|
entry:
|
|
%0 = atomicrmw add i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_sub_i32() {
|
|
; COMMON-LABEL: test_sub_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_sub_4
|
|
entry:
|
|
%0 = atomicrmw sub i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_and_i32() {
|
|
; COMMON-LABEL: test_and_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_and_4
|
|
entry:
|
|
%0 = atomicrmw and i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_nand_i32() {
|
|
; COMMON-LABEL: test_nand_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_nand_4
|
|
entry:
|
|
%0 = atomicrmw nand i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_or_i32() {
|
|
; COMMON-LABEL: test_or_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_or_4
|
|
entry:
|
|
%0 = atomicrmw or i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_xor_i32() {
|
|
; COMMON-LABEL: test_xor_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_xor_4
|
|
entry:
|
|
%0 = atomicrmw xor i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_max_i32() {
|
|
; COMMON-LABEL: test_max_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_max_4
|
|
entry:
|
|
%0 = atomicrmw max i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_min_i32() {
|
|
; COMMON-LABEL: test_min_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
|
|
; THUMB1: bl __sync_fetch_and_min_4
|
|
entry:
|
|
%0 = atomicrmw min i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_umax_i32() {
|
|
; COMMON-LABEL: test_umax_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_umax_4
|
|
entry:
|
|
%0 = atomicrmw umax i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
define i32 @test_umin_i32() {
|
|
; COMMON-LABEL: test_umin_i32:
|
|
; EXPAND32: ldrex
|
|
; EXPAND32-NOT: str
|
|
; EXPAND32: strex
|
|
; THUMB1: bl __sync_fetch_and_umin_4
|
|
entry:
|
|
%0 = atomicrmw umin i32* @atomic_i32, i32 1 monotonic
|
|
ret i32 %0
|
|
}
|
|
|
|
define i64 @test_xchg_i64() {
|
|
; COMMON-LABEL: test_xchg_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_lock_test_and_set_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw xchg i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_add_i64() {
|
|
; COMMON-LABEL: test_add_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_add_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw add i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_sub_i64() {
|
|
; COMMON-LABEL: test_sub_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_sub_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw sub i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_and_i64() {
|
|
; COMMON-LABEL: test_and_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_and_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw and i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_nand_i64() {
|
|
; COMMON-LABEL: test_nand_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_nand_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw nand i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_or_i64() {
|
|
; COMMON-LABEL: test_or_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_or_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw or i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_xor_i64() {
|
|
; COMMON-LABEL: test_xor_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_xor_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw xor i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
|
|
define i64 @test_max_i64() {
|
|
; COMMON-LABEL: test_max_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_max_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw max i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_min_i64() {
|
|
; COMMON-LABEL: test_min_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_min_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw min i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_umax_i64() {
|
|
; COMMON-LABEL: test_umax_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_umax_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw umax i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|
|
define i64 @test_umin_i64() {
|
|
; COMMON-LABEL: test_umin_i64:
|
|
; EXPAND64: ldrexd
|
|
; EXPAND64-NOT: str
|
|
; EXPAND64: strexd
|
|
; THUMB1: bl __sync_fetch_and_umin_8
|
|
; BASELINE64: bl __sync_val_compare_and_swap_8
|
|
entry:
|
|
%0 = atomicrmw umin i64* @atomic_i64, i64 1 monotonic
|
|
ret i64 %0
|
|
}
|