From 9e8d54fe2e72730b0a7dcc7d8ad9bee207212cd6 Mon Sep 17 00:00:00 2001 From: Rajveer Date: Tue, 28 Jan 2025 16:52:09 +0530 Subject: [PATCH 1/2] [CIR][CIRGen] Support for builtin __atomic_thread_fence Resolves #1274 Implements atomic thread fence synchronization primitive corresponding to `atomic.thread_fence` CIR. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 41 ++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 36 ++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 14 +++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 11 +++ clang/test/CIR/CodeGen/atomic-thread-fence.c | 99 +++++++++++++++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGen/atomic-thread-fence.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7994cd282d83..edf44c5a2d7d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5411,6 +5411,47 @@ def AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", let hasVerifier = 0; } +def MemScope_SingleThread : I32EnumAttrCase<"MemScope_SingleThread", + 0, "single_thread">; +def MemScope_System : I32EnumAttrCase<"MemScope_System", + 1, "system">; + +def MemScopeKind : I32EnumAttr< + "MemScopeKind", + "Memory Scope Enumeration", + [MemScope_SingleThread, MemScope_System]> { + let cppNamespace = "::cir"; +} + +def AtomicFence : CIR_Op<"atomic.fence"> { + let summary = "Atomic thread fence"; + let description = [{ + C/C++ Atomic thread fence synchronization primitive. Implements the builtin + `__atomic_thread_fence` which enforces memory ordering constraints across + threads within the specified synchronization scope. + + This handles all variations including: + - `__atomic_thread_fence` + - `__atomic_signal_fence` + - `__c11_atomic_thread_fence` + - `__c11_atomic_signal_fence` + + Example: + + + }]; + let results = (outs); + let arguments = (ins Arg:$sync_scope, + Arg:$ordering); + + let assemblyFormat = [{ + `(` `sync_scope` `=` $sync_scope `,` + `ordering` `=` $ordering `)` attr-dict + }]; + + let hasVerifier = 0; +} + def SignBitOp : CIR_Op<"signbit", [Pure]> { let summary = "Checks the sign of a floating-point number"; let description = [{ diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index b3807cba5828..e32c055f365f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -16,7 +16,11 @@ #include "CIRGenCstEmitter.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" +#include "CIRGenValue.h" #include "TargetInfo.h" +#include "clang/AST/Expr.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/MissingFeatures.h" // TODO(cir): we shouldn't need this but we currently reuse intrinsic IDs for @@ -30,7 +34,9 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Value.h" +#include "mlir/Support/LLVM.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "llvm/Support/ErrorHandling.h" @@ -333,6 +339,30 @@ static mlir::Value MakeAtomicCmpXchgValue(CIRGenFunction &cgf, return returnBool ? op.getResult(1) : op.getResult(0); } +static mlir::Value MakeAtomicFenceValue(CIRGenFunction &cgf, + const CallExpr *expr, + cir::MemScopeKind syncScope) { + auto &builder = cgf.getBuilder(); + mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0)); + + auto constOrdering = + mlir::dyn_cast(orderingVal.getDefiningOp()); + if (!constOrdering) + llvm_unreachable("NYI: variable ordering not supported"); + + auto constOrderingAttr = + mlir::dyn_cast(constOrdering.getValue()); + if (constOrderingAttr) { + cir::MemOrder ordering = + static_cast(constOrderingAttr.getUInt()); + + builder.create(cgf.getLoc(expr->getSourceRange()), + syncScope, ordering); + } + + return mlir::Value(); +} + static bool typeRequiresBuiltinLaunderImp(const ASTContext &astContext, QualType ty, llvm::SmallPtrSetImpl &seen) { @@ -1863,10 +1893,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm_unreachable("BI__atomic_clear NYI"); case Builtin::BI__atomic_thread_fence: + return RValue::get( + MakeAtomicFenceValue(*this, E, cir::MemScopeKind::MemScope_System)); case Builtin::BI__atomic_signal_fence: + return RValue::get(MakeAtomicFenceValue( + *this, E, cir::MemScopeKind::MemScope_SingleThread)); case Builtin::BI__c11_atomic_thread_fence: case Builtin::BI__c11_atomic_signal_fence: - llvm_unreachable("BI__atomic_thread_fence like NYI"); + llvm_unreachable("BI__c11_atomic_thread_fence like NYI"); case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 5d8cf071927b..50c9a64d0a6b 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -18,6 +18,7 @@ #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/Transforms/Passes.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/Builders.h" @@ -41,6 +42,9 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" +#include "clang/CIR/Dialect/IR/CIRAttrVisitor.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/LoweringHelpers.h" #include "clang/CIR/MissingFeatures.h" @@ -3198,6 +3202,10 @@ mlir::LLVM::AtomicOrdering getLLVMAtomicOrder(cir::MemOrder memo) { llvm_unreachable("shouldn't get here"); } +// mlir::LLVM::AtomicSyncScope getLLVMSyncScope(cir::MemScopeKind syncScope) { +// +// } + mlir::LogicalResult CIRToLLVMAtomicCmpXchgLowering::matchAndRewrite( cir::AtomicCmpXchg op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -3366,6 +3374,12 @@ mlir::LogicalResult CIRToLLVMAtomicFetchLowering::matchAndRewrite( return mlir::success(); } +// mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite( +// cir::AtomicFence op, OpAdaptor adaptor, +// mlir::ConversionPatternRewriter &rewriter) const { +// return mlir::success(); +// } + mlir::LogicalResult CIRToLLVMByteswapOpLowering::matchAndRewrite( cir::ByteswapOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 629d148427fd..62bc64fbd66b 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -16,6 +16,7 @@ #include "mlir/IR/MLIRContext.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" namespace cir { namespace direct { @@ -821,6 +822,16 @@ class CIRToLLVMAtomicFetchLowering mlir::ConversionPatternRewriter &) const override; }; +// class CIRToLLVMAtomicFenceLowering +// : public mlir::OpConversionPattern { +// public: +// using mlir::OpConversionPattern::OpConversionPattern; +// +// mlir::LogicalResult +// matchAndRewrite(cir::AtomicFence op, OpAdaptor, +// mlir::ConversionPatternRewriter &) const override; +// }; + class CIRToLLVMByteswapOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/atomic-thread-fence.c b/clang/test/CIR/CodeGen/atomic-thread-fence.c new file mode 100644 index 000000000000..cd97e3ecb93a --- /dev/null +++ b/clang/test/CIR/CodeGen/atomic-thread-fence.c @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// UN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// UN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + + +struct Data { + int value; + void *ptr; +}; + +typedef struct Data *DataPtr; + +void applyThreadFence() { + __atomic_thread_fence(5); +} + +// CIR-LABEL: cir.func no_proto @applyThreadFence +// CIR: %0 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) +// CIR: cir.return + +void applySignalFence() { + __atomic_signal_fence(5); +} +// CIR-LABEL: cir.func no_proto @applySignalFence +// CIR: %0 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) +// CIR: cir.return + +void modifyWithThreadFence(DataPtr d) { + __atomic_thread_fence(5); + d->value = 42; +} +// CIR-LABEL: cir.func @modifyWithThreadFence +// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR: %1 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) +// CIR: %2 = cir.const #cir.int<42> : !s32i +// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr -> !cir.ptr +// CIR: cir.store %2, %4 : !s32i, !cir.ptr +// CIR: cir.return + +void modifyWithSignalFence(DataPtr d) { + __atomic_signal_fence(5); + d->value = 24; +} +// CIR-LABEL: cir.func @modifyWithSignalFence +// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR: %1 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) +// CIR: %2 = cir.const #cir.int<24> : !s32i +// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr -> !cir.ptr +// CIR: cir.store %2, %4 : !s32i, !cir.ptr +// CIR: cir.return + +void loadWithThreadFence(DataPtr d) { + __atomic_thread_fence(5); + __atomic_load_n(&d->ptr, 5); +} +// CIR-LABEL: cir.func @loadWithThreadFence +// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: %1 = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} +// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR: %2 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) +// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr -> !cir.ptr> +// CIR: %5 = cir.const #cir.int<5> : !s32i +// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr>), !cir.ptr +// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr, !u64i +// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr +// CIR: cir.store %7, %8 : !u64i, !cir.ptr +// CIR: %9 = cir.load %1 : !cir.ptr>, !cir.ptr +// CIR: cir.return + +void loadWithSignalFence(DataPtr d) { + __atomic_signal_fence(5); + __atomic_load_n(&d->ptr, 5); +} +// CIR-LABEL: cir.func @loadWithSignalFence +// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: %1 = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} +// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR: %2 = cir.const #cir.int<5> : !s32i +// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) +// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr -> !cir.ptr> +// CIR: %5 = cir.const #cir.int<5> : !s32i +// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr>), !cir.ptr +// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr, !u64i +// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr +// CIR: cir.store %7, %8 : !u64i, !cir.ptr +// CIR: %9 = cir.load %1 : !cir.ptr>, !cir.ptr +// CIR: cir.return From 0ed0cb6ff2c3c696cfa3c4c8b7e099198131fe0f Mon Sep 17 00:00:00 2001 From: Rajveer Date: Fri, 7 Feb 2025 17:02:30 +0530 Subject: [PATCH 2/2] CIRToLLVMLowering: Lower to LLVM FenceOp --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 +- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 6 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 26 ++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 18 +- clang/test/CIR/CodeGen/atomic-thread-fence.c | 158 +++++++++++------- 5 files changed, 130 insertions(+), 86 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index edf44c5a2d7d..523222085db4 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5437,7 +5437,10 @@ def AtomicFence : CIR_Op<"atomic.fence"> { - `__c11_atomic_signal_fence` Example: - + ```mlir + cir.atomic.fence system seq_cst + cir.atomic.fence single_thread seq_cst + ``` }]; let results = (outs); @@ -5445,8 +5448,7 @@ def AtomicFence : CIR_Op<"atomic.fence"> { Arg:$ordering); let assemblyFormat = [{ - `(` `sync_scope` `=` $sync_scope `,` - `ordering` `=` $ordering `)` attr-dict + $sync_scope $ordering attr-dict }]; let hasVerifier = 0; diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index e32c055f365f..a5f899320a86 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -339,7 +339,7 @@ static mlir::Value MakeAtomicCmpXchgValue(CIRGenFunction &cgf, return returnBool ? op.getResult(1) : op.getResult(0); } -static mlir::Value MakeAtomicFenceValue(CIRGenFunction &cgf, +static mlir::Value makeAtomicFenceValue(CIRGenFunction &cgf, const CallExpr *expr, cir::MemScopeKind syncScope) { auto &builder = cgf.getBuilder(); @@ -1894,9 +1894,9 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__atomic_thread_fence: return RValue::get( - MakeAtomicFenceValue(*this, E, cir::MemScopeKind::MemScope_System)); + makeAtomicFenceValue(*this, E, cir::MemScopeKind::MemScope_System)); case Builtin::BI__atomic_signal_fence: - return RValue::get(MakeAtomicFenceValue( + return RValue::get(makeAtomicFenceValue( *this, E, cir::MemScopeKind::MemScope_SingleThread)); case Builtin::BI__c11_atomic_thread_fence: case Builtin::BI__c11_atomic_signal_fence: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 50c9a64d0a6b..b8386a038e6d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -19,6 +19,7 @@ #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/LLVMIR/Transforms/Passes.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/Builders.h" @@ -42,7 +43,6 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" -#include "clang/CIR/Dialect/IR/CIRAttrVisitor.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h" @@ -3202,9 +3202,10 @@ mlir::LLVM::AtomicOrdering getLLVMAtomicOrder(cir::MemOrder memo) { llvm_unreachable("shouldn't get here"); } -// mlir::LLVM::AtomicSyncScope getLLVMSyncScope(cir::MemScopeKind syncScope) { -// -// } +llvm::StringRef getLLVMSyncScope(cir::MemScopeKind syncScope) { + return syncScope == cir::MemScopeKind::MemScope_SingleThread ? "singlethread" + : ""; +} mlir::LogicalResult CIRToLLVMAtomicCmpXchgLowering::matchAndRewrite( cir::AtomicCmpXchg op, OpAdaptor adaptor, @@ -3374,11 +3375,17 @@ mlir::LogicalResult CIRToLLVMAtomicFetchLowering::matchAndRewrite( return mlir::success(); } -// mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite( -// cir::AtomicFence op, OpAdaptor adaptor, -// mlir::ConversionPatternRewriter &rewriter) const { -// return mlir::success(); -// } +mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite( + cir::AtomicFence op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto llvmOrder = getLLVMAtomicOrder(adaptor.getOrdering()); + auto llvmSyncScope = getLLVMSyncScope(adaptor.getSyncScope()); + + rewriter.replaceOpWithNewOp(op, llvmOrder, + llvmSyncScope); + + return mlir::success(); +} mlir::LogicalResult CIRToLLVMByteswapOpLowering::matchAndRewrite( cir::ByteswapOp op, OpAdaptor adaptor, @@ -4141,6 +4148,7 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMAtomicCmpXchgLowering, CIRToLLVMAtomicFetchLowering, CIRToLLVMAtomicXchgLowering, + CIRToLLVMAtomicFenceLowering, CIRToLLVMBaseClassAddrOpLowering, CIRToLLVMBinOpLowering, CIRToLLVMBinOpOverflowOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 62bc64fbd66b..7bb14c432d07 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -822,15 +822,15 @@ class CIRToLLVMAtomicFetchLowering mlir::ConversionPatternRewriter &) const override; }; -// class CIRToLLVMAtomicFenceLowering -// : public mlir::OpConversionPattern { -// public: -// using mlir::OpConversionPattern::OpConversionPattern; -// -// mlir::LogicalResult -// matchAndRewrite(cir::AtomicFence op, OpAdaptor, -// mlir::ConversionPatternRewriter &) const override; -// }; +class CIRToLLVMAtomicFenceLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::AtomicFence op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; class CIRToLLVMByteswapOpLowering : public mlir::OpConversionPattern { diff --git a/clang/test/CIR/CodeGen/atomic-thread-fence.c b/clang/test/CIR/CodeGen/atomic-thread-fence.c index cd97e3ecb93a..4c71c3c83966 100644 --- a/clang/test/CIR/CodeGen/atomic-thread-fence.c +++ b/clang/test/CIR/CodeGen/atomic-thread-fence.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s -// UN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -// UN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s struct Data { @@ -12,88 +12,122 @@ struct Data { typedef struct Data *DataPtr; void applyThreadFence() { - __atomic_thread_fence(5); + __atomic_thread_fence(__ATOMIC_SEQ_CST); } -// CIR-LABEL: cir.func no_proto @applyThreadFence -// CIR: %0 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) +// CIR-LABEL: @applyThreadFence +// CIR: cir.atomic.fence system seq_cst // CIR: cir.return +// LLVM-LABEL: @applyThreadFence +// LLVM: fence seq_cst +// LLVM: ret void + void applySignalFence() { - __atomic_signal_fence(5); + __atomic_signal_fence(__ATOMIC_SEQ_CST); } -// CIR-LABEL: cir.func no_proto @applySignalFence -// CIR: %0 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) +// CIR-LABEL: @applySignalFence +// CIR: cir.atomic.fence single_thread seq_cst // CIR: cir.return +// LLVM-LABEL: @applySignalFence +// LLVM: fence syncscope("singlethread") seq_cst +// LLVM: ret void + void modifyWithThreadFence(DataPtr d) { - __atomic_thread_fence(5); + __atomic_thread_fence(__ATOMIC_SEQ_CST); d->value = 42; } -// CIR-LABEL: cir.func @modifyWithThreadFence -// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} -// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> -// CIR: %1 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) -// CIR: %2 = cir.const #cir.int<42> : !s32i -// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr -// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr -> !cir.ptr -// CIR: cir.store %2, %4 : !s32i, !cir.ptr +// CIR-LABEL: @modifyWithThreadFence +// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.atomic.fence system seq_cst +// CIR: %[[VAL_42:.*]] = cir.const #cir.int<42> : !s32i +// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr>, !cir.ptr +// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr -> !cir.ptr +// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr // CIR: cir.return +// LLVM-LABEL: @modifyWithThreadFence +// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: fence seq_cst +// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 +// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 +// LLVM: store i32 42, ptr %[[DATA_VALUE]], align 4 +// LLVM: ret void + void modifyWithSignalFence(DataPtr d) { - __atomic_signal_fence(5); + __atomic_signal_fence(__ATOMIC_SEQ_CST); d->value = 24; } -// CIR-LABEL: cir.func @modifyWithSignalFence -// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} -// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> -// CIR: %1 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) -// CIR: %2 = cir.const #cir.int<24> : !s32i -// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr -// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr -> !cir.ptr -// CIR: cir.store %2, %4 : !s32i, !cir.ptr +// CIR-LABEL: @modifyWithSignalFence +// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.atomic.fence single_thread seq_cst +// CIR: %[[VAL_42:.*]] = cir.const #cir.int<24> : !s32i +// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr>, !cir.ptr +// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr -> !cir.ptr +// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr // CIR: cir.return +// LLVM-LABEL: @modifyWithSignalFence +// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: fence syncscope("singlethread") seq_cst +// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 +// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0 +// LLVM: store i32 24, ptr %[[DATA_VALUE]], align 4 +// LLVM: ret void + void loadWithThreadFence(DataPtr d) { - __atomic_thread_fence(5); - __atomic_load_n(&d->ptr, 5); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + __atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST); } -// CIR-LABEL: cir.func @loadWithThreadFence -// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} -// CIR: %1 = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} -// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> -// CIR: %2 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst) -// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr -// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr -> !cir.ptr> -// CIR: %5 = cir.const #cir.int<5> : !s32i -// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr>), !cir.ptr -// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr, !u64i -// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr -// CIR: cir.store %7, %8 : !u64i, !cir.ptr -// CIR: %9 = cir.load %1 : !cir.ptr>, !cir.ptr +// CIR-LABEL: @loadWithThreadFence +// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} +// CIR: cir.atomic.fence system seq_cst +// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr>, !cir.ptr +// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr -> !cir.ptr> +// CIR: %[[CASTED_DATA_VALUE:.*]] = cir.cast(bitcast, %[[DATA_VALUE]] : !cir.ptr>), !cir.ptr +// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_VALUE]] : !cir.ptr, !u64i +// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr>), !cir.ptr +// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr +// CIR: %[[ATOMIC_LOAD_PTR:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr>, !cir.ptr // CIR: cir.return +// LLVM-LABEL: @loadWithThreadFence +// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: fence seq_cst +// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 +// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 +// LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 +// LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 +// LLVM: %[[DATA_TEMP_LOAD:.*]] = load ptr, ptr %[[DATA_TEMP]], align 8 +// LLVM: ret void + void loadWithSignalFence(DataPtr d) { - __atomic_signal_fence(5); - __atomic_load_n(&d->ptr, 5); + __atomic_signal_fence(__ATOMIC_SEQ_CST); + __atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST); } -// CIR-LABEL: cir.func @loadWithSignalFence -// CIR: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} -// CIR: %1 = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} -// CIR: cir.store %arg0, %0 : !cir.ptr, !cir.ptr> -// CIR: %2 = cir.const #cir.int<5> : !s32i -// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst) -// CIR: %3 = cir.load %0 : !cir.ptr>, !cir.ptr -// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr -> !cir.ptr> -// CIR: %5 = cir.const #cir.int<5> : !s32i -// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr>), !cir.ptr -// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr, !u64i -// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr -// CIR: cir.store %7, %8 : !u64i, !cir.ptr -// CIR: %9 = cir.load %1 : !cir.ptr>, !cir.ptr +// CIR-LABEL: @loadWithSignalFence +// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["atomic-temp"] {alignment = 8 : i64} +// CIR: cir.atomic.fence single_thread seq_cst +// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr>, !cir.ptr +// CIR: %[[DATA_PTR:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr -> !cir.ptr> +// CIR: %[[CASTED_DATA_PTR:.*]] = cir.cast(bitcast, %[[DATA_PTR]] : !cir.ptr>), !cir.ptr +// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_PTR]] : !cir.ptr, !u64i +// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr>), !cir.ptr +// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr +// CIR: %[[LOAD_ATOMIC_TEMP:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr>, !cir.ptr // CIR: cir.return + +// LLVM-LABEL: @loadWithSignalFence +// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8 +// LLVM: fence syncscope("singlethread") seq_cst +// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8 +// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1 +// LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8 +// LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8 +// LLVM: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8 +// LLVM: ret void