diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -78,6 +78,7 @@ bool IsISA2_07 = false; bool IsISA3_0 = false; bool IsISA3_1 = false; + bool HasQuadwordAtomics = false; protected: std::string ABI; @@ -443,6 +444,14 @@ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } + void setMaxAtomicWidth() override { + // For layout on ELF targets, we support up to 16 bytes. + if (getTriple().isOSBinFormatELF() && hasFeature("quadword-atomics")) { + MaxAtomicPromoteWidth = 128; + MaxAtomicInlineWidth = 128; + } + } + BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -81,6 +81,8 @@ IsISA3_0 = true; } else if (Feature == "+isa-v31-instructions") { IsISA3_1 = true; + } else if (Feature == "+quadword-atomics") { + HasQuadwordAtomics = true; } // TODO: Finish this list and add an assert that we've handled them // all. @@ -544,6 +546,12 @@ Features["isa-v30-instructions"] = llvm::StringSwitch(CPU).Case("pwr9", true).Default(false); + Features["quadword-atomics"] = + getTriple().isArch64Bit() && llvm::StringSwitch(CPU) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + // Power10 includes all the same features as Power9 plus any features specific // to the Power10 core. if (CPU == "pwr10" || CPU == "power10") { @@ -654,6 +662,7 @@ .Case("isa-v207-instructions", IsISA2_07) .Case("isa-v30-instructions", IsISA3_0) .Case("isa-v31-instructions", IsISA3_1) + .Case("quadword-atomics", HasQuadwordAtomics) .Default(false); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2132,6 +2132,13 @@ CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); } + + // For ELF targets, instruct backend to inline quadword atomics if libcalls + // are not emitted in frontend. + if (T.isOSBinFormatELF() && T.isArch64Bit()) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-ppc-quadword-atomics"); + } } static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args, diff --git a/clang/test/CodeGen/PowerPC/atomic-alignment.c b/clang/test/CodeGen/PowerPC/atomic-alignment.c --- a/clang/test/CodeGen/PowerPC/atomic-alignment.c +++ b/clang/test/CodeGen/PowerPC/atomic-alignment.c @@ -2,8 +2,12 @@ // RUN: FileCheck %s --check-prefixes=PPC,PPC32 // RUN: %clang_cc1 -verify -triple powerpc64le-unknown-linux -emit-llvm -o - %s | \ // RUN: FileCheck %s --check-prefixes=PPC,PPC64 +// RUN: %clang_cc1 -verify -triple powerpc64le-unknown-linux -target-cpu pwr8 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=PPC,PPC64-PWR8 // RUN: %clang_cc1 -verify -triple powerpc64-unknown-aix -emit-llvm -o - %s | \ // RUN: FileCheck %s --check-prefixes=PPC,PPC64 +// RUN: %clang_cc1 -verify -triple powerpc64-unknown-aix -target-cpu pwr8 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefixes=PPC,PPC64 // PPC: @c = global i8 0, align 1{{$}} _Atomic(char) c; // expected-no-diagnostics @@ -16,6 +20,7 @@ // PPC32: @l = global i32 0, align 4{{$}} // PPC64: @l = global i64 0, align 8{{$}} +// PPC64-PWR8: @l = global i64 0, align 8{{$}} _Atomic(long) l; // expected-no-diagnostics // PPC: @ll = global i64 0, align 8{{$}} @@ -27,11 +32,14 @@ // PPC32: @o = global %struct.O zeroinitializer, align 1{{$}} // PPC64: @o = global %struct.O zeroinitializer, align 8{{$}} +// PPC64-PWR8: @o = global %struct.O zeroinitializer, align 8{{$}} _Atomic(O) o; // expected-no-diagnostics typedef struct { char x[16]; } Q; -// PPC: @q = global %struct.Q zeroinitializer, align 1{{$}} +// PPC32: @q = global %struct.Q zeroinitializer, align 1{{$}} +// PPC64: @q = global %struct.Q zeroinitializer, align 1{{$}} +// PPC64-PWR8: @q = global %struct.Q zeroinitializer, align 16{{$}} _Atomic(Q) q; // expected-no-diagnostics diff --git a/clang/test/CodeGen/PowerPC/quadword-atomics.c b/clang/test/CodeGen/PowerPC/quadword-atomics.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/quadword-atomics.c @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -verify -Wno-atomic-alignment -triple powerpc64le-linux-gnu \ +// RUN: -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64-PWR8 +// RUN: %clang_cc1 -verify -Wno-atomic-alignment -triple powerpc64le-linux-gnu \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64 + +typedef struct { + char x[16]; +} Q; + +typedef _Atomic(Q) AtomicQ; + +typedef __int128_t int128_t; + +// PPC64-PWR8-LABEL: @test_load( +// PPC64-PWR8: [[TMP3:%.*]] = load atomic i128, i128* [[TMP1:%.*]] acquire, align 16 +// +// PPC64-LABEL: @test_load( +// PPC64: call void @__atomic_load(i64 noundef 16, i8* noundef [[TMP3:%.*]], i8* noundef [[TMP4:%.*]], i32 noundef signext 2) +// +Q test_load(AtomicQ *ptr) { + // expected-no-diagnostics + return __c11_atomic_load(ptr, __ATOMIC_ACQUIRE); +} + +// PPC64-PWR8-LABEL: @test_store( +// PPC64-PWR8: store atomic i128 [[TMP6:%.*]], i128* [[TMP4:%.*]] release, align 16 +// +// PPC64-LABEL: @test_store( +// PPC64: call void @__atomic_store(i64 noundef 16, i8* noundef [[TMP6:%.*]], i8* noundef [[TMP7:%.*]], i32 noundef signext 3) +// +void test_store(Q val, AtomicQ *ptr) { + // expected-no-diagnostics + __c11_atomic_store(ptr, val, __ATOMIC_RELEASE); +} + +// PPC64-PWR8-LABEL: @test_add( +// PPC64-PWR8: [[TMP3:%.*]] = atomicrmw add i128* [[TMP0:%.*]], i128 [[TMP2:%.*]] monotonic, align 16 +// +// PPC64-LABEL: @test_add( +// PPC64: [[CALL:%.*]] = call i128 @__atomic_fetch_add_16(i8* noundef [[TMP2:%.*]], i128 noundef [[TMP3:%.*]], i32 noundef signext 0) +// +void test_add(int128_t *ptr, int128_t x) { + // expected-no-diagnostics + __c11_atomic_fetch_add((_Atomic(int128_t) *)ptr, x, __ATOMIC_RELAXED); +} + +// PPC64-PWR8-LABEL: @test_xchg( +// PPC64-PWR8: [[TMP8:%.*]] = atomicrmw xchg i128* [[TMP4:%.*]], i128 [[TMP7:%.*]] seq_cst, align 16 +// +// PPC64-LABEL: @test_xchg( +// PPC64: call void @__atomic_exchange(i64 noundef 16, i8* noundef [[TMP7:%.*]], i8* noundef [[TMP8:%.*]], i8* noundef [[TMP9:%.*]], i32 noundef signext 5) +// +Q test_xchg(AtomicQ *ptr, Q new) { + // expected-no-diagnostics + return __c11_atomic_exchange(ptr, new, __ATOMIC_SEQ_CST); +} + +// PPC64-PWR8-LABEL: @test_cmpxchg( +// PPC64-PWR8: [[TMP10:%.*]] = cmpxchg i128* [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 +// +// PPC64-LABEL: @test_cmpxchg( +// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, i8* noundef [[TMP8:%.*]], i8* noundef [[TMP9:%.*]], i8* noundef [[TMP10:%.*]], i32 noundef signext 5, i32 noundef signext 0) +// +int test_cmpxchg(AtomicQ *ptr, Q *cmp, Q new) { + // expected-no-diagnostics + return __c11_atomic_compare_exchange_strong(ptr, cmp, new, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); +} + +// PPC64-PWR8-LABEL: @test_cmpxchg_weak( +// PPC64-PWR8: [[TMP10:%.*]] = cmpxchg weak i128* [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 +// +// PPC64-LABEL: @test_cmpxchg_weak( +// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, i8* noundef [[TMP8:%.*]], i8* noundef [[TMP9:%.*]], i8* noundef [[TMP10:%.*]], i32 noundef signext 5, i32 noundef signext 0) +// +int test_cmpxchg_weak(AtomicQ *ptr, Q *cmp, Q new) { + // expected-no-diagnostics + return __c11_atomic_compare_exchange_weak(ptr, cmp, new, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); +} + +// PPC64-PWR8-LABEL: @is_lock_free( +// PPC64-PWR8: ret i32 1 +// +// PPC64-LABEL: @is_lock_free( +// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_is_lock_free(i64 noundef 16, i8* noundef null) +// +int is_lock_free() { + AtomicQ q; + // expected-no-diagnostics + return __c11_atomic_is_lock_free(sizeof(q)); +} diff --git a/clang/test/Driver/ppc-quadword-atomics.c b/clang/test/Driver/ppc-quadword-atomics.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/ppc-quadword-atomics.c @@ -0,0 +1,17 @@ +// RUN: %clang -### -target powerpc-unknown-unknown -S %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NO-QUADWORD-ATOMICS +// RUN: %clang -### -target powerpc64-unknown-aix -S %s 2>&1 | \ +// RUN: FileCheck %s --check-prefix=NO-QUADWORD-ATOMICS +// RUN: %clang -### -target powerpc64-unknown-unknown -S %s 2>&1 | \ +// RUN: FileCheck %s +// RUN: %clang -### -target powerpc64le-unknown-unknown -S %s 2>&1 | \ +// RUN: FileCheck %s +// RUN: %clang -### -target powerpc64le-unknown-linux -S %s 2>&1 | \ +// RUN: FileCheck %s +// RUN: %clang -### -target powerpc64-unknown-linux -S %s 2>&1 | \ +// RUN: FileCheck %s +// RUN: %clang -### -target powerpc64le-unknown-freebsd -S %s 2>&1 | \ +// RUN: FileCheck %s +// +// CHECK: "-mllvm" "-ppc-quadword-atomics" +// NO-QUADWORD-ATOMICS-NOT: "-mllvm" "-ppc-quadword-atomics" diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c --- a/clang/test/Sema/atomic-ops.c +++ b/clang/test/Sema/atomic-ops.c @@ -9,7 +9,7 @@ // RUN: -target-cpu pwr7 // RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \ // RUN: -fsyntax-only -triple=powerpc64le-linux-gnu -std=c11 \ -// RUN: -target-cpu pwr8 +// RUN: -target-cpu pwr8 -DPPC64_PWR8 // Basic parsing/Sema tests for __c11_atomic_* @@ -47,7 +47,11 @@ _Static_assert(__c11_atomic_is_lock_free(3), ""); // expected-error {{not an integral constant expression}} _Static_assert(__c11_atomic_is_lock_free(4), ""); _Static_assert(__c11_atomic_is_lock_free(8), ""); +#ifndef PPC64_PWR8 _Static_assert(__c11_atomic_is_lock_free(16), ""); // expected-error {{not an integral constant expression}} +#else +_Static_assert(__c11_atomic_is_lock_free(16), ""); // expected-no-error +#endif _Static_assert(__c11_atomic_is_lock_free(17), ""); // expected-error {{not an integral constant expression}} _Static_assert(__atomic_is_lock_free(1, 0), ""); @@ -55,15 +59,23 @@ _Static_assert(__atomic_is_lock_free(3, 0), ""); // expected-error {{not an integral constant expression}} _Static_assert(__atomic_is_lock_free(4, 0), ""); _Static_assert(__atomic_is_lock_free(8, 0), ""); +#ifndef PPC64_PWR8 _Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-error {{not an integral constant expression}} +#else +_Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-no-error +#endif _Static_assert(__atomic_is_lock_free(17, 0), ""); // expected-error {{not an integral constant expression}} _Static_assert(atomic_is_lock_free((atomic_char*)0), ""); _Static_assert(atomic_is_lock_free((atomic_short*)0), ""); _Static_assert(atomic_is_lock_free((atomic_int*)0), ""); _Static_assert(atomic_is_lock_free((atomic_long*)0), ""); +#ifndef PPC64_PWR8 // noi128-error@+1 {{__int128 is not supported on this target}} _Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-error {{not an integral constant expression}} +#else +_Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-no-error +#endif _Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), ""); char i8; @@ -88,7 +100,11 @@ _Static_assert(!__atomic_always_lock_free(3, 0), ""); _Static_assert(__atomic_always_lock_free(4, 0), ""); _Static_assert(__atomic_always_lock_free(8, 0), ""); +#ifndef PPC64_PWR8 _Static_assert(!__atomic_always_lock_free(16, 0), ""); +#else +_Static_assert(__atomic_always_lock_free(16, 0), ""); +#endif _Static_assert(!__atomic_always_lock_free(17, 0), ""); _Static_assert(__atomic_always_lock_free(1, incomplete), "");