Skip to content

Commit

Permalink
CIRToLLVMLowering: Lower to LLVM FenceOp
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajveer100 committed Feb 8, 2025
1 parent 6796ee4 commit 83b33a7
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 64 deletions.
5 changes: 3 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;

Expand All @@ -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);
Expand Down
25 changes: 17 additions & 8 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<mlir::LLVM::FenceOp>(op, llvmOrder,
llvmSyncScope);

return mlir::success();
}

mlir::LogicalResult CIRToLLVMByteswapOpLowering::matchAndRewrite(
cir::ByteswapOp op, OpAdaptor adaptor,
Expand Down Expand Up @@ -4129,6 +4137,7 @@ void populateCIRToLLVMConversionPatterns(
CIRToLLVMAtomicCmpXchgLowering,
CIRToLLVMAtomicFetchLowering,
CIRToLLVMAtomicXchgLowering,
CIRToLLVMAtomicFenceLowering,
CIRToLLVMBaseClassAddrOpLowering,
CIRToLLVMBinOpLowering,
CIRToLLVMBinOpOverflowOpLowering,
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -822,15 +822,15 @@ class CIRToLLVMAtomicFetchLowering
mlir::ConversionPatternRewriter &) const override;
};

// class CIRToLLVMAtomicFenceLowering
// : public mlir::OpConversionPattern<cir::AtomicFence> {
// public:
// using mlir::OpConversionPattern<cir::AtomicFence>::OpConversionPattern;
//
// mlir::LogicalResult
// matchAndRewrite(cir::AtomicFence op, OpAdaptor,
// mlir::ConversionPatternRewriter &) const override;
// };
class CIRToLLVMAtomicFenceLowering
: public mlir::OpConversionPattern<cir::AtomicFence> {
public:
using mlir::OpConversionPattern<cir::AtomicFence>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(cir::AtomicFence op, OpAdaptor,
mlir::ConversionPatternRewriter &) const override;
};

class CIRToLLVMByteswapOpLowering
: public mlir::OpConversionPattern<cir::ByteswapOp> {
Expand Down
140 changes: 95 additions & 45 deletions clang/test/CIR/CodeGen/atomic-thread-fence.c
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -12,88 +12,138 @@ 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: 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<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// 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<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
// CIR: cir.store %2, %4 : !s32i, !cir.ptr<!s32i>
// CIR: %[[VAL_42:.*]] = cir.const #cir.int<42> : !s32i
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i>
// 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<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// 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<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
// CIR: cir.store %2, %4 : !s32i, !cir.ptr<!s32i>
// 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<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i>
// 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<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// 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<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
// CIR: %5 = cir.const #cir.int<5> : !s32i
// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr<!u64i>, !u64i
// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: cir.store %7, %8 : !u64i, !cir.ptr<!u64i>
// CIR: %9 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: %[[CASTED_DATA_VALUE:.*]] = cir.cast(bitcast, %[[DATA_VALUE]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_VALUE]] : !cir.ptr<!u64i>, !u64i
// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[ATOMIC_LOAD_PTR:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// 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<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
// 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<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
// CIR: cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst)
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
// CIR: %[[DATA_PTR:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
// CIR: %5 = cir.const #cir.int<5> : !s32i
// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr<!u64i>, !u64i
// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: cir.store %7, %8 : !u64i, !cir.ptr<!u64i>
// CIR: %9 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: %[[CASTED_DATA_PTR:.*]] = cir.cast(bitcast, %[[DATA_PTR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_PTR]] : !cir.ptr<!u64i>, !u64i
// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[LOAD_ATOMIC_TEMP:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// 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

0 comments on commit 83b33a7

Please sign in to comment.