diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 79fa38784932..100910f1e391 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5410,7 +5410,7 @@ def AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", } def MemScope_SingleThread : I32EnumAttrCase<"MemScope_SingleThread", - 0, "single_thread">; + 0, "singlethread">; def MemScope_System : I32EnumAttrCase<"MemScope_System", 1, "system">; @@ -5435,7 +5435,8 @@ def AtomicFence : CIR_Op<"atomic.fence"> { - `__c11_atomic_signal_fence` Example: - + cir.atomic.fence(sync_scope = system, ordering = seq_cst) + cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst) }]; let results = (outs); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 455f8d859533..e58da6d86b5c 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" @@ -3189,9 +3190,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, @@ -3360,11 +3362,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, @@ -4129,6 +4137,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 da57785012d4..8fc736cfac81 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..67164ab80432 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,7 +12,7 @@ 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 @@ -20,80 +20,130 @@ void applyThreadFence() { // CIR: cir.atomic.fence(sync_scope = system, ordering = 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: cir.atomic.fence(sync_scope = singlethread, ordering = 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: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.store %arg0, %[[DATA]] : !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: %[[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: store ptr %0, ptr %[[DATA]], 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: %[[DATA:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["d", init] {alignment = 8 : i64} +// CIR: cir.store %arg0, %[[DATA]] : !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.atomic.fence(sync_scope = singlethread, ordering = 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: store ptr %0, ptr %[[DATA]], 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: %[[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.store %arg0, %[[DATA]] : !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: %[[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: %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: %[[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: store ptr %0, ptr %[[DATA]], align 8 +// LLVM: fence seq_cst +// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %2, 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: %[[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.store %arg0, %[[DATA]] : !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: cir.atomic.fence(sync_scope = singlethread, ordering = 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: %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: %[[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: store ptr %0, ptr %[[DATA]], 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