Skip to content

Commit af464b6

Browse files
committed
[CIR] Add syncscope support for atomic load operations
1 parent 58135ea commit af464b6

File tree

12 files changed

+102
-38
lines changed

12 files changed

+102
-38
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
175175
return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false, isVolatile,
176176
isNontemporal,
177177
/*alignment=*/alignmentAttr,
178-
/*mem_order=*/
179-
cir::MemOrderAttr{},
178+
/*syncscope=*/cir::MemScopeKindAttr{},
179+
/*mem_order=*/cir::MemOrderAttr{},
180180
/*tbaa=*/cir::TBAAAttr{});
181181
}
182182

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,15 @@ def CIR_MemOrder : CIR_I32EnumAttr<
533533
I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">
534534
]>;
535535

536+
//===----------------------------------------------------------------------===//
537+
// C/C++ sync scope definitions
538+
//===----------------------------------------------------------------------===//
539+
540+
def CIR_MemScopeKind : CIR_I32EnumAttr<"MemScopeKind", "memory scope kind", [
541+
I32EnumAttrCase<"SingleThread", 0, "single_thread">,
542+
I32EnumAttrCase<"System", 1, "system">
543+
]>;
544+
536545
//===----------------------------------------------------------------------===//
537546
// AllocaOp
538547
//===----------------------------------------------------------------------===//
@@ -670,17 +679,19 @@ def CIR_LoadOp : CIR_Op<"load", [
670679
%4 = cir.load volatile %0 : !cir.ptr<i32>, i32
671680

672681
// Others
673-
%x = cir.load align(16) atomic(seq_cst) %0 : !cir.ptr<i32>, i32
682+
%x = cir.load align(16) syncscope(single_thread) atomic(seq_cst)
683+
%0 : !cir.ptr<i32>, i32
674684
```
675685
}];
676686

677687
let arguments = (ins Arg<CIR_PointerType, "the address to load from",
678688
[MemRead]>:$addr, UnitAttr:$isDeref,
679689
UnitAttr:$is_volatile,
680690
UnitAttr:$is_nontemporal,
681-
OptionalAttr<I64Attr>:$alignment,
682-
OptionalAttr<CIR_MemOrder>:$mem_order,
683-
OptionalAttr<CIR_AnyTBAAAttr>:$tbaa
691+
OptionalAttr<I64Attr>:$alignment,
692+
OptionalAttr<CIR_MemScopeKind>:$syncscope,
693+
OptionalAttr<CIR_MemOrder>:$mem_order,
694+
OptionalAttr<CIR_AnyTBAAAttr>:$tbaa
684695
);
685696
let results = (outs CIR_AnyType:$result);
686697

@@ -689,6 +700,7 @@ def CIR_LoadOp : CIR_Op<"load", [
689700
(`volatile` $is_volatile^)?
690701
(`nontemporal` $is_nontemporal^)?
691702
(`align` `(` $alignment^ `)`)?
703+
(`syncscope` `(` $syncscope^ `)`)?
692704
(`atomic` `(` $mem_order^ `)`)?
693705
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
694706
(`tbaa` `(` $tbaa^ `)`)?
@@ -698,7 +710,8 @@ def CIR_LoadOp : CIR_Op<"load", [
698710
// TODO(CIR): The final interface here should include an argument for the
699711
// SyncScope::ID.
700712
// This should be used over the ODS generated setMemOrder.
701-
void setAtomic(cir::MemOrder order);
713+
void setAtomic(cir::MemOrder order,
714+
cir::MemScopeKind scope);
702715
}];
703716

704717
// FIXME: add verifier.
@@ -6012,11 +6025,6 @@ def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [
60126025
let hasVerifier = 1;
60136026
}
60146027

6015-
def CIR_MemScopeKind : CIR_I32EnumAttr<"MemScopeKind", "memory scope kind", [
6016-
I32EnumAttrCase<"SingleThread", 0, "single_thread">,
6017-
I32EnumAttrCase<"System", 1, "system">
6018-
]>;
6019-
60206028
def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [
60216029
AllTypesMatch<["old", "expected", "desired"]>
60226030
]> {

clang/lib/CIR/CodeGen/CIRGenAtomic.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "CIRGenOpenMPRuntime.h"
1818
#include "TargetInfo.h"
1919
#include "clang/AST/ASTContext.h"
20+
#include "clang/Basic/SyncScope.h"
2021
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
2122
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
2223
#include "clang/CIR/Dialect/IR/CIRDialect.h"
@@ -350,6 +351,20 @@ static cir::IntAttr extractIntAttr(mlir::Value v) {
350351
return {};
351352
}
352353

354+
// Maps SyncScope::SingleScope to MemScopeKind::SingleThread,
355+
// SyncScope::SystemScope to MemScopeKind::System,
356+
// and asserts (llvm_unreachable) for anything else.
357+
static cir::MemScopeKind convertSyncScopeToCIR(clang::SyncScope scope) {
358+
switch (scope) {
359+
case clang::SyncScope::SingleScope:
360+
return cir::MemScopeKind::SingleThread;
361+
case clang::SyncScope::SystemScope:
362+
return cir::MemScopeKind::System;
363+
default:
364+
llvm_unreachable("NYI");
365+
}
366+
}
367+
353368
// Inspect a value that is the strong/weak flag for a compare-exchange. If it
354369
// is a constant of intergral or boolean type, set `val` to the constant's
355370
// boolean value and return true. Otherwise leave `val` unchanged and return
@@ -555,6 +570,10 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
555570
auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), Order);
556571
cir::AtomicFetchKindAttr fetchAttr;
557572
bool fetchFirst = true;
573+
auto scopeAttr = cir::MemScopeKindAttr::get(builder.getContext(), Scope);
574+
std::optional<cir::MemScopeKind> scopeOpt;
575+
if (Scope != cir::MemScopeKind::System)
576+
scopeOpt = Scope;
558577

559578
switch (E->getOp()) {
560579
case AtomicExpr::AO__c11_atomic_init:
@@ -594,9 +613,7 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
594613
case AtomicExpr::AO__scoped_atomic_load_n:
595614
case AtomicExpr::AO__scoped_atomic_load: {
596615
auto load = builder.createLoad(loc, Ptr);
597-
// FIXME(cir): add scope information.
598-
assert(!cir::MissingFeatures::syncScopeID());
599-
load.setMemOrder(Order);
616+
load.setAtomic(Order, Scope);
600617
load.setIsVolatile(E->isVolatile());
601618

602619
// TODO(cir): this logic should be part of createStore, but doing so
@@ -818,9 +835,12 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *Expr, Address Dest,
818835
}
819836

820837
// Handle constant scope.
821-
if (extractIntAttr(Scope)) {
838+
if (auto scopeAttr = extractIntAttr(Scope)) {
822839
assert(!cir::MissingFeatures::syncScopeID());
823-
llvm_unreachable("NYI");
840+
auto mappedScope =
841+
convertSyncScopeToCIR(ScopeModel->map(scopeAttr.getUInt()));
842+
emitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
843+
Order, mappedScope);
824844
return;
825845
}
826846

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
870870
return cir::LoadOp::create(
871871
*this, loc, addr.getElementType(), addr.getPointer(), /*isDeref=*/false,
872872
/*is_volatile=*/isVolatile, /*is_nontemporal=*/isNontemporal, align,
873+
/*syncscope=*/cir::MemScopeKindAttr{},
873874
/*mem_order=*/cir::MemOrderAttr{}, /*tbaa=*/cir::TBAAAttr{});
874875
}
875876

clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "CIRGenFunction.h"
1919
#include "CIRGenModule.h"
2020
#include "TargetInfo.h"
21+
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
2122
#include "clang/CIR/MissingFeatures.h"
2223

2324
// TODO(cir): once all builtins are covered, decide whether we still
@@ -4485,7 +4486,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
44854486
case NEON::BI__builtin_neon_vldap1q_lane_s64: {
44864487
cir::LoadOp Load = builder.createAlignedLoad(
44874488
Ops[0].getLoc(), vTy.getElementType(), Ops[0], PtrOp0.getAlignment());
4488-
Load.setAtomic(cir::MemOrder::Acquire);
4489+
Load.setAtomic(cir::MemOrder::Acquire, cir::MemScopeKind::System);
44894490
return builder.create<cir::VecInsertOp>(getLoc(E->getExprLoc()),
44904491
builder.createBitcast(Ops[1], vTy),
44914492
Load, Ops[2]);

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,12 +1012,9 @@ LogicalResult cir::ComplexImagPtrOp::verify() {
10121012
// LoadOp
10131013
//===----------------------------------------------------------------------===//
10141014

1015-
// TODO(CIR): The final interface here should include an argument for the
1016-
// SyncScope::ID.
1017-
void cir::LoadOp::setAtomic(cir::MemOrder order) {
1015+
void cir::LoadOp::setAtomic(cir::MemOrder order, cir::MemScopeKind scope) {
10181016
setMemOrder(order);
1019-
if (cir::MissingFeatures::syncScopeID())
1020-
llvm_unreachable("NYI");
1017+
setSyncscope(scope);
10211018
}
10221019

10231020
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/Transforms/TargetLowering/ItaniumCXXABI.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,9 @@ void ItaniumCXXABI::lowerGetMethod(
383383
mlir::Value vtablePtr = rewriter.create<cir::LoadOp>(
384384
op.getLoc(), vtablePtrPtr, /*isDeref=*/false, /*isVolatile=*/false,
385385
/*isNontemporal=*/false,
386-
/*alignment=*/mlir::IntegerAttr(), /*mem_order=*/cir::MemOrderAttr(),
386+
/*alignment=*/mlir::IntegerAttr(),
387+
/*syncscope=*/cir::MemScopeKindAttr{},
388+
/*mem_order=*/cir::MemOrderAttr(),
387389
/*tbaa=*/mlir::ArrayAttr());
388390

389391
// Get the vtable offset.
@@ -418,6 +420,7 @@ void ItaniumCXXABI::lowerGetMethod(
418420
op.getLoc(), vfpPtr, /*isDeref=*/false, /*isVolatile=*/false,
419421
/*isNontemporal=*/false,
420422
/*alignment=*/mlir::IntegerAttr(),
423+
/*syncscope=*/cir::MemScopeKindAttr{},
421424
/*mem_order=*/cir::MemOrderAttr(),
422425
/*tbaa=*/mlir::ArrayAttr());
423426
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,8 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(
18241824
op->getLoc(), llvmTy, adaptor.getAddr(), /* alignment */ alignment,
18251825
op.getIsVolatile(), /* nontemporal */ op.getIsNontemporal(),
18261826
/* invariant */ false, /* invariantGroup */ invariant, ordering);
1827+
if (auto scope = op.getSyncscope())
1828+
newLoad.setSyncscope(getLLVMSyncScope(scope));
18271829

18281830
// Convert adapted result to its original type if needed.
18291831
mlir::Value result =

clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ class CIRWhileOpLowering : public mlir::OpConversionPattern<cir::WhileOp> {
482482
auto cond = rewriter.create<LoadOp>(
483483
loc, boolTy, condAlloca, /*isDeref=*/false,
484484
/*volatile=*/false, /*nontemporal=*/false, alignment,
485+
/*syncscope=*/cir::MemScopeKindAttr{},
485486
/*memorder=*/cir::MemOrderAttr{}, /*tbaa=*/cir::TBAAAttr{});
486487
auto ifnot =
487488
rewriter.create<IfOp>(loc, cond, /*withElseRegion=*/false,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -x c -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
// CHECK-LABEL: @scoped_load_thread
5+
// CHECK: %[[ATOMIC_LOAD:.*]] = cir.load align(4) syncscope(single_thread) atomic(relaxed) %{{.*}} : !cir.ptr<!s32i>, !s32i
6+
// CHECK: cir.store align(4) %[[ATOMIC_LOAD]], %{{.*}} : !s32i, !cir.ptr<!s32i>
7+
int scoped_load_thread(int *ptr) {
8+
return __scoped_atomic_load_n(ptr, __ATOMIC_RELAXED, __MEMORY_SCOPE_SINGLE);
9+
}
10+
11+
// CHECK-LABEL: @scoped_load_system
12+
// CHECK: cir.load align(4) syncscope(system) atomic(seq_cst) %{{.*}} : !cir.ptr<!s32i>, !s32i
13+
int scoped_load_system(int *ptr) {
14+
return __scoped_atomic_load_n(ptr, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM);
15+
}
16+

0 commit comments

Comments
 (0)