Skip to content

Commit 83b33a7

Browse files
committed
CIRToLLVMLowering: Lower to LLVM FenceOp
1 parent 6796ee4 commit 83b33a7

File tree

4 files changed

+124
-64
lines changed

4 files changed

+124
-64
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

+3-2
Original file line numberDiff line numberDiff line change
@@ -5410,7 +5410,7 @@ def AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg",
54105410
}
54115411

54125412
def MemScope_SingleThread : I32EnumAttrCase<"MemScope_SingleThread",
5413-
0, "single_thread">;
5413+
0, "singlethread">;
54145414
def MemScope_System : I32EnumAttrCase<"MemScope_System",
54155415
1, "system">;
54165416

@@ -5435,7 +5435,8 @@ def AtomicFence : CIR_Op<"atomic.fence"> {
54355435
- `__c11_atomic_signal_fence`
54365436

54375437
Example:
5438-
5438+
cir.atomic.fence(sync_scope = system, ordering = seq_cst)
5439+
cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst)
54395440

54405441
}];
54415442
let results = (outs);

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

+17-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "mlir/Dialect/DLTI/DLTI.h"
2020
#include "mlir/Dialect/Func/IR/FuncOps.h"
2121
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
22+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
2223
#include "mlir/Dialect/LLVMIR/Transforms/Passes.h"
2324
#include "mlir/IR/Attributes.h"
2425
#include "mlir/IR/Builders.h"
@@ -3189,9 +3190,10 @@ mlir::LLVM::AtomicOrdering getLLVMAtomicOrder(cir::MemOrder memo) {
31893190
llvm_unreachable("shouldn't get here");
31903191
}
31913192

3192-
// mlir::LLVM::AtomicSyncScope getLLVMSyncScope(cir::MemScopeKind syncScope) {
3193-
//
3194-
// }
3193+
llvm::StringRef getLLVMSyncScope(cir::MemScopeKind syncScope) {
3194+
return syncScope == cir::MemScopeKind::MemScope_SingleThread ? "singlethread"
3195+
: "";
3196+
}
31953197

31963198
mlir::LogicalResult CIRToLLVMAtomicCmpXchgLowering::matchAndRewrite(
31973199
cir::AtomicCmpXchg op, OpAdaptor adaptor,
@@ -3360,11 +3362,17 @@ mlir::LogicalResult CIRToLLVMAtomicFetchLowering::matchAndRewrite(
33603362
return mlir::success();
33613363
}
33623364

3363-
// mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite(
3364-
// cir::AtomicFence op, OpAdaptor adaptor,
3365-
// mlir::ConversionPatternRewriter &rewriter) const {
3366-
// return mlir::success();
3367-
// }
3365+
mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite(
3366+
cir::AtomicFence op, OpAdaptor adaptor,
3367+
mlir::ConversionPatternRewriter &rewriter) const {
3368+
auto llvmOrder = getLLVMAtomicOrder(adaptor.getOrdering());
3369+
auto llvmSyncScope = getLLVMSyncScope(adaptor.getSyncScope());
3370+
3371+
rewriter.replaceOpWithNewOp<mlir::LLVM::FenceOp>(op, llvmOrder,
3372+
llvmSyncScope);
3373+
3374+
return mlir::success();
3375+
}
33683376

33693377
mlir::LogicalResult CIRToLLVMByteswapOpLowering::matchAndRewrite(
33703378
cir::ByteswapOp op, OpAdaptor adaptor,
@@ -4129,6 +4137,7 @@ void populateCIRToLLVMConversionPatterns(
41294137
CIRToLLVMAtomicCmpXchgLowering,
41304138
CIRToLLVMAtomicFetchLowering,
41314139
CIRToLLVMAtomicXchgLowering,
4140+
CIRToLLVMAtomicFenceLowering,
41324141
CIRToLLVMBaseClassAddrOpLowering,
41334142
CIRToLLVMBinOpLowering,
41344143
CIRToLLVMBinOpOverflowOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

+9-9
Original file line numberDiff line numberDiff line change
@@ -822,15 +822,15 @@ class CIRToLLVMAtomicFetchLowering
822822
mlir::ConversionPatternRewriter &) const override;
823823
};
824824

825-
// class CIRToLLVMAtomicFenceLowering
826-
// : public mlir::OpConversionPattern<cir::AtomicFence> {
827-
// public:
828-
// using mlir::OpConversionPattern<cir::AtomicFence>::OpConversionPattern;
829-
//
830-
// mlir::LogicalResult
831-
// matchAndRewrite(cir::AtomicFence op, OpAdaptor,
832-
// mlir::ConversionPatternRewriter &) const override;
833-
// };
825+
class CIRToLLVMAtomicFenceLowering
826+
: public mlir::OpConversionPattern<cir::AtomicFence> {
827+
public:
828+
using mlir::OpConversionPattern<cir::AtomicFence>::OpConversionPattern;
829+
830+
mlir::LogicalResult
831+
matchAndRewrite(cir::AtomicFence op, OpAdaptor,
832+
mlir::ConversionPatternRewriter &) const override;
833+
};
834834

835835
class CIRToLLVMByteswapOpLowering
836836
: public mlir::OpConversionPattern<cir::ByteswapOp> {
+95-45
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
22
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3-
// UN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4-
// UN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
55

66

77
struct Data {
@@ -12,88 +12,138 @@ struct Data {
1212
typedef struct Data *DataPtr;
1313

1414
void applyThreadFence() {
15-
__atomic_thread_fence(5);
15+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
1616
}
1717

1818
// CIR-LABEL: cir.func no_proto @applyThreadFence
1919
// CIR: %0 = cir.const #cir.int<5> : !s32i
2020
// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst)
2121
// CIR: cir.return
2222

23+
// LLVM-LABEL: @applyThreadFence
24+
// LLVM: fence seq_cst
25+
// LLVM: ret void
26+
2327
void applySignalFence() {
24-
__atomic_signal_fence(5);
28+
__atomic_signal_fence(__ATOMIC_SEQ_CST);
2529
}
2630
// CIR-LABEL: cir.func no_proto @applySignalFence
2731
// CIR: %0 = cir.const #cir.int<5> : !s32i
28-
// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst)
32+
// CIR: cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst)
2933
// CIR: cir.return
3034

35+
// LLVM-LABEL: @applySignalFence
36+
// LLVM: fence syncscope("singlethread") seq_cst
37+
// LLVM: ret void
38+
3139
void modifyWithThreadFence(DataPtr d) {
32-
__atomic_thread_fence(5);
40+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
3341
d->value = 42;
3442
}
3543
// CIR-LABEL: cir.func @modifyWithThreadFence
36-
// CIR: %0 = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
37-
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
44+
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
45+
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
3846
// CIR: %1 = cir.const #cir.int<5> : !s32i
3947
// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst)
40-
// CIR: %2 = cir.const #cir.int<42> : !s32i
41-
// CIR: %3 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
42-
// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
43-
// CIR: cir.store %2, %4 : !s32i, !cir.ptr<!s32i>
48+
// CIR: %[[VAL_42:.*]] = cir.const #cir.int<42> : !s32i
49+
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
50+
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
51+
// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i>
4452
// CIR: cir.return
4553

54+
// LLVM-LABEL: @modifyWithThreadFence
55+
// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8
56+
// LLVM: store ptr %0, ptr %[[DATA]], align 8
57+
// LLVM: fence seq_cst
58+
// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8
59+
// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0
60+
// LLVM: store i32 42, ptr %[[DATA_VALUE]], align 4
61+
// LLVM: ret void
62+
4663
void modifyWithSignalFence(DataPtr d) {
47-
__atomic_signal_fence(5);
64+
__atomic_signal_fence(__ATOMIC_SEQ_CST);
4865
d->value = 24;
4966
}
5067
// CIR-LABEL: cir.func @modifyWithSignalFence
51-
// CIR: %0 = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
52-
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
68+
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
69+
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
5370
// CIR: %1 = cir.const #cir.int<5> : !s32i
54-
// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst)
55-
// CIR: %2 = cir.const #cir.int<24> : !s32i
56-
// CIR: %3 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
57-
// CIR: %4 = cir.get_member %3[0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
58-
// CIR: cir.store %2, %4 : !s32i, !cir.ptr<!s32i>
71+
// CIR: cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst)
72+
// CIR: %[[VAL_42:.*]] = cir.const #cir.int<24> : !s32i
73+
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
74+
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][0] {name = "value"} : !cir.ptr<!ty_Data> -> !cir.ptr<!s32i>
75+
// CIR: cir.store %[[VAL_42]], %[[DATA_VALUE]] : !s32i, !cir.ptr<!s32i>
5976
// CIR: cir.return
6077

78+
// LLVM-LABEL: @modifyWithSignalFence
79+
// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8
80+
// LLVM: store ptr %0, ptr %[[DATA]], align 8
81+
// LLVM: fence syncscope("singlethread") seq_cst
82+
// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8
83+
// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 0
84+
// LLVM: store i32 24, ptr %[[DATA_VALUE]], align 4
85+
// LLVM: ret void
86+
6187
void loadWithThreadFence(DataPtr d) {
62-
__atomic_thread_fence(5);
63-
__atomic_load_n(&d->ptr, 5);
88+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
89+
__atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST);
6490
}
6591
// CIR-LABEL: cir.func @loadWithThreadFence
66-
// CIR: %0 = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
67-
// CIR: %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
68-
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
92+
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
93+
// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
94+
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
6995
// CIR: %2 = cir.const #cir.int<5> : !s32i
7096
// CIR: cir.atomic.fence(sync_scope = system, ordering = seq_cst)
71-
// CIR: %3 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
72-
// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
97+
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
98+
// CIR: %[[DATA_VALUE:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
7399
// CIR: %5 = cir.const #cir.int<5> : !s32i
74-
// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
75-
// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr<!u64i>, !u64i
76-
// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
77-
// CIR: cir.store %7, %8 : !u64i, !cir.ptr<!u64i>
78-
// CIR: %9 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
100+
// CIR: %[[CASTED_DATA_VALUE:.*]] = cir.cast(bitcast, %[[DATA_VALUE]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
101+
// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_VALUE]] : !cir.ptr<!u64i>, !u64i
102+
// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
103+
// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i>
104+
// CIR: %[[ATOMIC_LOAD_PTR:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
79105
// CIR: cir.return
80106

107+
// LLVM-LABEL: @loadWithThreadFence
108+
// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8
109+
// LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8
110+
// LLVM: store ptr %0, ptr %[[DATA]], align 8
111+
// LLVM: fence seq_cst
112+
// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %2, align 8
113+
// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1
114+
// LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8
115+
// LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8
116+
// LLVM: %[[DATA_TEMP_LOAD:.*]] = load ptr, ptr %[[DATA_TEMP]], align 8
117+
// LLVM: ret void
118+
81119
void loadWithSignalFence(DataPtr d) {
82-
__atomic_signal_fence(5);
83-
__atomic_load_n(&d->ptr, 5);
120+
__atomic_signal_fence(__ATOMIC_SEQ_CST);
121+
__atomic_load_n(&d->ptr, __ATOMIC_SEQ_CST);
84122
}
85123
// CIR-LABEL: cir.func @loadWithSignalFence
86-
// CIR: %0 = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
87-
// CIR: %1 = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
88-
// CIR: cir.store %arg0, %0 : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
124+
// CIR: %[[DATA:.*]] = cir.alloca !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>, ["d", init] {alignment = 8 : i64}
125+
// CIR: %[[ATOMIC_TEMP:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["atomic-temp"] {alignment = 8 : i64}
126+
// CIR: cir.store %arg0, %[[DATA]] : !cir.ptr<!ty_Data>, !cir.ptr<!cir.ptr<!ty_Data>>
89127
// CIR: %2 = cir.const #cir.int<5> : !s32i
90-
// CIR: cir.atomic.fence(sync_scope = single_thread, ordering = seq_cst)
91-
// CIR: %3 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
92-
// CIR: %4 = cir.get_member %3[1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
128+
// CIR: cir.atomic.fence(sync_scope = singlethread, ordering = seq_cst)
129+
// CIR: %[[LOAD_DATA:.*]] = cir.load %[[DATA]] : !cir.ptr<!cir.ptr<!ty_Data>>, !cir.ptr<!ty_Data>
130+
// CIR: %[[DATA_PTR:.*]] = cir.get_member %[[LOAD_DATA]][1] {name = "ptr"} : !cir.ptr<!ty_Data> -> !cir.ptr<!cir.ptr<!void>>
93131
// CIR: %5 = cir.const #cir.int<5> : !s32i
94-
// CIR: %6 = cir.cast(bitcast, %4 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
95-
// CIR: %7 = cir.load atomic(seq_cst) %6 : !cir.ptr<!u64i>, !u64i
96-
// CIR: %8 = cir.cast(bitcast, %1 : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
97-
// CIR: cir.store %7, %8 : !u64i, !cir.ptr<!u64i>
98-
// CIR: %9 = cir.load %1 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
132+
// CIR: %[[CASTED_DATA_PTR:.*]] = cir.cast(bitcast, %[[DATA_PTR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
133+
// CIR: %[[ATOMIC_LOAD:.*]] = cir.load atomic(seq_cst) %[[CASTED_DATA_PTR]] : !cir.ptr<!u64i>, !u64i
134+
// CIR: %[[CASTED_ATOMIC_TEMP:.*]] = cir.cast(bitcast, %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!u64i>
135+
// CIR: cir.store %[[ATOMIC_LOAD]], %[[CASTED_ATOMIC_TEMP]] : !u64i, !cir.ptr<!u64i>
136+
// CIR: %[[LOAD_ATOMIC_TEMP:.*]] = cir.load %[[ATOMIC_TEMP]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
99137
// CIR: cir.return
138+
139+
// LLVM-LABEL: @loadWithSignalFence
140+
// LLVM: %[[DATA:.*]] = alloca ptr, i64 1, align 8
141+
// LLVM: %[[DATA_TEMP:.*]] = alloca ptr, i64 1, align 8
142+
// LLVM: store ptr %0, ptr %[[DATA]], align 8
143+
// LLVM: fence syncscope("singlethread") seq_cst
144+
// LLVM: %[[DATA_PTR:.*]] = load ptr, ptr %[[DATA]], align 8
145+
// LLVM: %[[DATA_VALUE:.*]] = getelementptr %struct.Data, ptr %[[DATA_PTR]], i32 0, i32 1
146+
// LLVM: %[[ATOMIC_LOAD:.*]] = load atomic i64, ptr %[[DATA_VALUE]] seq_cst, align 8
147+
// LLVM: store i64 %[[ATOMIC_LOAD]], ptr %[[DATA_TEMP]], align 8
148+
// LLVM: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8
149+
// LLVM: ret void

0 commit comments

Comments
 (0)