Skip to content

Commit 2ca4d32

Browse files
jiang1997lanza
authored andcommitted
[CIR] Add syncscope support for atomic load operations (#1958)
Fix #1868
1 parent 37da690 commit 2ca4d32

File tree

14 files changed

+151
-78
lines changed

14 files changed

+151
-78
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+
/*sync_scope=*/cir::SyncScopeKindAttr{},
179+
/*mem_order=*/cir::MemOrderAttr{},
180180
/*tbaa=*/cir::TBAAAttr{});
181181
}
182182

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,15 @@ def CIR_MemOrder : CIR_I32EnumAttr<
538538
I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">
539539
]>;
540540

541+
//===----------------------------------------------------------------------===//
542+
// C/C++ sync scope definitions
543+
//===----------------------------------------------------------------------===//
544+
545+
def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [
546+
I32EnumAttrCase<"SingleThread", 0, "single_thread">,
547+
I32EnumAttrCase<"System", 1, "system">
548+
]>;
549+
541550
//===----------------------------------------------------------------------===//
542551
// AllocaOp
543552
//===----------------------------------------------------------------------===//
@@ -675,7 +684,8 @@ def CIR_LoadOp : CIR_Op<"load", [
675684
%4 = cir.load volatile %0 : !cir.ptr<i32>, i32
676685

677686
// Others
678-
%x = cir.load align(16) atomic(seq_cst) %0 : !cir.ptr<i32>, i32
687+
%x = cir.load align(16) syncscope(single_thread) atomic(seq_cst)
688+
%0 : !cir.ptr<i32>, i32
679689
```
680690
}];
681691

@@ -684,6 +694,7 @@ def CIR_LoadOp : CIR_Op<"load", [
684694
UnitAttr:$is_volatile,
685695
UnitAttr:$is_nontemporal,
686696
OptionalAttr<I64Attr>:$alignment,
697+
OptionalAttr<CIR_SyncScopeKind>:$sync_scope,
687698
OptionalAttr<CIR_MemOrder>:$mem_order,
688699
OptionalAttr<CIR_AnyTBAAAttr>:$tbaa
689700
);
@@ -694,6 +705,7 @@ def CIR_LoadOp : CIR_Op<"load", [
694705
(`volatile` $is_volatile^)?
695706
(`nontemporal` $is_nontemporal^)?
696707
(`align` `(` $alignment^ `)`)?
708+
(`syncscope` `(` $sync_scope^ `)`)?
697709
(`atomic` `(` $mem_order^ `)`)?
698710
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
699711
(`tbaa` `(` $tbaa^ `)`)?
@@ -703,7 +715,8 @@ def CIR_LoadOp : CIR_Op<"load", [
703715
// TODO(CIR): The final interface here should include an argument for the
704716
// SyncScope::ID.
705717
// This should be used over the ODS generated setMemOrder.
706-
void setAtomic(cir::MemOrder order);
718+
void setAtomic(cir::MemOrder order,
719+
cir::SyncScopeKind scope);
707720
}];
708721

709722
// FIXME: add verifier.
@@ -6091,11 +6104,6 @@ def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [
60916104
let hasVerifier = 1;
60926105
}
60936106

6094-
def CIR_MemScopeKind : CIR_I32EnumAttr<"MemScopeKind", "memory scope kind", [
6095-
I32EnumAttrCase<"SingleThread", 0, "single_thread">,
6096-
I32EnumAttrCase<"System", 1, "system">
6097-
]>;
6098-
60996107
def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [
61006108
AllTypesMatch<["old", "expected", "desired"]>
61016109
]> {
@@ -6119,7 +6127,7 @@ def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [
61196127
CIR_AnyType:$desired,
61206128
Arg<CIR_MemOrder, "success memory order">:$succ_order,
61216129
Arg<CIR_MemOrder, "failure memory order">:$fail_order,
6122-
OptionalAttr<CIR_MemScopeKind>:$syncscope,
6130+
OptionalAttr<CIR_SyncScopeKind>:$sync_scope,
61236131
OptionalAttr<I64Attr>:$alignment,
61246132
UnitAttr:$weak,
61256133
UnitAttr:$is_volatile);
@@ -6132,7 +6140,7 @@ def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [
61326140
`success` `=` $succ_order `,`
61336141
`failure` `=` $fail_order
61346142
`)`
6135-
(`syncscope` `(` $syncscope^ `)`)?
6143+
(`syncscope` `(` $sync_scope^ `)`)?
61366144
(`align` `(` $alignment^ `)`)?
61376145
(`weak` $weak^)?
61386146
(`volatile` $is_volatile^)?
@@ -6162,7 +6170,7 @@ def CIR_AtomicTestAndSetOp : CIR_Op<"atomic.test_and_set"> {
61626170
let arguments = (ins
61636171
Arg<CIR_PtrToType<CIR_SInt8>, "", [MemRead, MemWrite]>:$ptr,
61646172
Arg<CIR_MemOrder, "memory order">:$mem_order,
6165-
OptionalAttr<CIR_MemScopeKind>:$syncscope,
6173+
OptionalAttr<CIR_SyncScopeKind>:$sync_scope,
61666174
OptionalAttr<I64Attr>:$alignment,
61676175
UnitAttr:$is_volatile);
61686176

@@ -6193,7 +6201,7 @@ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> {
61936201
let arguments = (ins
61946202
Arg<CIR_PtrToType<CIR_SInt8>, "", [MemRead, MemWrite]>:$ptr,
61956203
Arg<CIR_MemOrder, "memory order">:$mem_order,
6196-
OptionalAttr<CIR_MemScopeKind>:$syncscope,
6204+
OptionalAttr<CIR_SyncScopeKind>:$sync_scope,
61976205
OptionalAttr<I64Attr>:$alignment,
61986206
UnitAttr:$is_volatile);
61996207

@@ -6227,11 +6235,11 @@ def CIR_AtomicFence : CIR_Op<"atomic.fence"> {
62276235

62286236
let arguments = (ins
62296237
Arg<CIR_MemOrder, "memory order">:$ordering,
6230-
OptionalAttr<CIR_MemScopeKind>:$syncscope
6238+
OptionalAttr<CIR_SyncScopeKind>:$sync_scope
62316239
);
62326240

62336241
let assemblyFormat = [{
6234-
(`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict
6242+
(`syncscope` `(` $sync_scope^ `)`)? $ordering attr-dict
62356243
}];
62366244
}
62376245

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ struct MissingFeatures {
189189
// Type qualifiers.
190190
static bool atomicTypes() { return false; }
191191
static bool volatileTypes() { return false; }
192-
static bool syncScopeID() { return false; }
193192

194193
// ABIInfo queries.
195194
static bool useTargetLoweringABIInfo() { return false; }

clang/lib/CIR/CodeGen/CIRGenAtomic.cpp

Lines changed: 28 additions & 16 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 SyncScopeKind::SingleThread,
355+
// SyncScope::SystemScope to SyncScopeKind::System,
356+
// and asserts (llvm_unreachable) for anything else.
357+
static cir::SyncScopeKind convertSyncScopeToCIR(clang::SyncScope scope) {
358+
switch (scope) {
359+
case clang::SyncScope::SingleScope:
360+
return cir::SyncScopeKind::SingleThread;
361+
case clang::SyncScope::SystemScope:
362+
return cir::SyncScopeKind::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
@@ -418,7 +433,7 @@ static void emitAtomicCmpXchg(CIRGenFunction &CGF, AtomicExpr *E, bool IsWeak,
418433
Address Val2, uint64_t Size,
419434
cir::MemOrder SuccessOrder,
420435
cir::MemOrder FailureOrder,
421-
cir::MemScopeKind Scope) {
436+
cir::SyncScopeKind Scope) {
422437
auto &builder = CGF.getBuilder();
423438
auto loc = CGF.getLoc(E->getSourceRange());
424439
auto Expected = builder.createLoad(loc, Val1);
@@ -428,7 +443,7 @@ static void emitAtomicCmpXchg(CIRGenFunction &CGF, AtomicExpr *E, bool IsWeak,
428443
builder, loc, Expected.getType(), boolTy, Ptr.getPointer(), Expected,
429444
Desired, cir::MemOrderAttr::get(&CGF.getMLIRContext(), SuccessOrder),
430445
cir::MemOrderAttr::get(&CGF.getMLIRContext(), FailureOrder),
431-
cir::MemScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
446+
cir::SyncScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
432447
builder.getI64IntegerAttr(Ptr.getAlignment().getAsAlign().value()));
433448
cmpxchg.setIsVolatile(E->isVolatile());
434449
cmpxchg.setWeak(IsWeak);
@@ -456,7 +471,7 @@ static void emitAtomicCmpXchg(CIRGenFunction &CGF, AtomicExpr *E, bool IsWeak,
456471
static void emitAtomicCmpXchgFailureSet(
457472
CIRGenFunction &CGF, AtomicExpr *E, bool IsWeak, Address Dest, Address Ptr,
458473
Address Val1, Address Val2, mlir::Value FailureOrderVal, uint64_t Size,
459-
cir::MemOrder SuccessOrder, cir::MemScopeKind Scope) {
474+
cir::MemOrder SuccessOrder, cir::SyncScopeKind Scope) {
460475

461476
cir::MemOrder FailureOrder;
462477
if (auto ordAttr = extractIntAttr(FailureOrderVal)) {
@@ -546,8 +561,7 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
546561
Address Ptr, Address Val1, Address Val2,
547562
mlir::Value IsWeak, mlir::Value FailureOrder,
548563
uint64_t Size, cir::MemOrder Order,
549-
cir::MemScopeKind Scope) {
550-
assert(!cir::MissingFeatures::syncScopeID());
564+
cir::SyncScopeKind Scope) {
551565
StringRef Op;
552566

553567
auto &builder = CGF.getBuilder();
@@ -594,9 +608,7 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
594608
case AtomicExpr::AO__scoped_atomic_load_n:
595609
case AtomicExpr::AO__scoped_atomic_load: {
596610
auto load = builder.createLoad(loc, Ptr);
597-
// FIXME(cir): add scope information.
598-
assert(!cir::MissingFeatures::syncScopeID());
599-
load.setMemOrder(Order);
611+
load.setAtomic(Order, Scope);
600612
load.setIsVolatile(E->isVolatile());
601613

602614
// TODO(cir): this logic should be part of createStore, but doing so
@@ -619,7 +631,6 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
619631
case AtomicExpr::AO__scoped_atomic_store_n: {
620632
auto loadVal1 = builder.createLoad(loc, Val1);
621633
// FIXME(cir): add scope information.
622-
assert(!cir::MissingFeatures::syncScopeID());
623634
builder.createStore(loc, loadVal1, Ptr, E->isVolatile(),
624635
/*isNontemporal=*/false,
625636
/*alignment=*/mlir::IntegerAttr{}, orderAttr);
@@ -748,7 +759,7 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
748759
case AtomicExpr::AO__atomic_test_and_set: {
749760
auto op = cir::AtomicTestAndSetOp::create(
750761
builder, loc, Ptr.getPointer(), Order,
751-
cir::MemScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
762+
cir::SyncScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
752763
builder.getI64IntegerAttr(Ptr.getAlignment().getQuantity()),
753764
E->isVolatile());
754765
builder.createStore(loc, op, Dest);
@@ -758,7 +769,7 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *E, Address Dest,
758769
case AtomicExpr::AO__atomic_clear: {
759770
cir::AtomicClearOp::create(
760771
builder, loc, Ptr.getPointer(), Order,
761-
cir::MemScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
772+
cir::SyncScopeKindAttr::get(&CGF.getMLIRContext(), Scope),
762773
builder.getI64IntegerAttr(Ptr.getAlignment().getQuantity()),
763774
E->isVolatile());
764775
return;
@@ -811,16 +822,17 @@ static void emitAtomicOp(CIRGenFunction &CGF, AtomicExpr *Expr, Address Dest,
811822
// LLVM atomic instructions always have synch scope. If clang atomic
812823
// expression has no scope operand, use default LLVM synch scope.
813824
if (!ScopeModel) {
814-
assert(!cir::MissingFeatures::syncScopeID());
815825
emitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
816-
Order, cir::MemScopeKind::System);
826+
Order, cir::SyncScopeKind::System);
817827
return;
818828
}
819829

820830
// Handle constant scope.
821-
if (extractIntAttr(Scope)) {
822-
assert(!cir::MissingFeatures::syncScopeID());
823-
llvm_unreachable("NYI");
831+
if (auto scopeAttr = extractIntAttr(Scope)) {
832+
auto mappedScope =
833+
convertSyncScopeToCIR(ScopeModel->map(scopeAttr.getUInt()));
834+
emitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
835+
Order, mappedScope);
824836
return;
825837
}
826838

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+
/*sync_scope=*/cir::SyncScopeKindAttr{},
873874
/*mem_order=*/cir::MemOrderAttr{}, /*tbaa=*/cir::TBAAAttr{});
874875
}
875876

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -370,15 +370,15 @@ static mlir::Value makeAtomicCmpXchgValue(CIRGenFunction &cgf,
370370
cir::MemOrder::SequentiallyConsistent),
371371
MemOrderAttr::get(&cgf.getMLIRContext(),
372372
cir::MemOrder::SequentiallyConsistent),
373-
MemScopeKindAttr::get(&cgf.getMLIRContext(), cir::MemScopeKind::System),
373+
SyncScopeKindAttr::get(&cgf.getMLIRContext(), cir::SyncScopeKind::System),
374374
builder.getI64IntegerAttr(destAddr.getAlignment().getAsAlign().value()));
375375

376376
return returnBool ? op.getResult(1) : op.getResult(0);
377377
}
378378

379379
static mlir::Value makeAtomicFenceValue(CIRGenFunction &cgf,
380380
const CallExpr *expr,
381-
cir::MemScopeKind syncScope) {
381+
cir::SyncScopeKind syncScope) {
382382
auto &builder = cgf.getBuilder();
383383
mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0));
384384

@@ -392,7 +392,7 @@ static mlir::Value makeAtomicFenceValue(CIRGenFunction &cgf,
392392

393393
cir::AtomicFence::create(
394394
builder, cgf.getLoc(expr->getSourceRange()), ordering,
395-
MemScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
395+
SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
396396
}
397397

398398
return mlir::Value();
@@ -2155,10 +2155,10 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
21552155

21562156
case Builtin::BI__atomic_thread_fence:
21572157
return RValue::get(
2158-
makeAtomicFenceValue(*this, E, cir::MemScopeKind::System));
2158+
makeAtomicFenceValue(*this, E, cir::SyncScopeKind::System));
21592159
case Builtin::BI__atomic_signal_fence:
21602160
return RValue::get(
2161-
makeAtomicFenceValue(*this, E, cir::MemScopeKind::SingleThread));
2161+
makeAtomicFenceValue(*this, E, cir::SyncScopeKind::SingleThread));
21622162
case Builtin::BI__c11_atomic_thread_fence:
21632163
case Builtin::BI__c11_atomic_signal_fence:
21642164
llvm_unreachable("BI__c11_atomic_thread_fence like NYI");

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
@@ -4489,7 +4490,7 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
44894490
case NEON::BI__builtin_neon_vldap1q_lane_s64: {
44904491
cir::LoadOp Load = builder.createAlignedLoad(
44914492
Ops[0].getLoc(), vTy.getElementType(), Ops[0], PtrOp0.getAlignment());
4492-
Load.setAtomic(cir::MemOrder::Acquire);
4493+
Load.setAtomic(cir::MemOrder::Acquire, cir::SyncScopeKind::System);
44934494
return cir::VecInsertOp::create(builder, getLoc(E->getExprLoc()),
44944495
builder.createBitcast(Ops[1], vTy), Load,
44954496
Ops[2]);

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,12 +1013,9 @@ LogicalResult cir::ComplexImagPtrOp::verify() {
10131013
// LoadOp
10141014
//===----------------------------------------------------------------------===//
10151015

1016-
// TODO(CIR): The final interface here should include an argument for the
1017-
// SyncScope::ID.
1018-
void cir::LoadOp::setAtomic(cir::MemOrder order) {
1016+
void cir::LoadOp::setAtomic(cir::MemOrder order, cir::SyncScopeKind scope) {
10191017
setMemOrder(order);
1020-
if (cir::MissingFeatures::syncScopeID())
1021-
llvm_unreachable("NYI");
1018+
setSyncScope(scope);
10221019
}
10231020

10241021
//===----------------------------------------------------------------------===//
@@ -1027,11 +1024,7 @@ void cir::LoadOp::setAtomic(cir::MemOrder order) {
10271024

10281025
// TODO(CIR): The final interface here should include an argument for the
10291026
// SyncScope::ID.
1030-
void cir::StoreOp::setAtomic(cir::MemOrder order) {
1031-
setMemOrder(order);
1032-
if (cir::MissingFeatures::syncScopeID())
1033-
llvm_unreachable("NYI");
1034-
}
1027+
void cir::StoreOp::setAtomic(cir::MemOrder order) { setMemOrder(order); }
10351028

10361029
//===----------------------------------------------------------------------===//
10371030
// VecCreateOp

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,9 @@ void ItaniumCXXABI::lowerGetMethod(
386386
rewriter, op.getLoc(), vtablePtrPtr, /*isDeref=*/false,
387387
/*isVolatile=*/false,
388388
/*isNontemporal=*/false,
389-
/*alignment=*/mlir::IntegerAttr(), /*mem_order=*/cir::MemOrderAttr(),
389+
/*alignment=*/mlir::IntegerAttr(),
390+
/*sync_scope=*/cir::SyncScopeKindAttr{},
391+
/*mem_order=*/cir::MemOrderAttr(),
390392
/*tbaa=*/mlir::ArrayAttr());
391393

392394
// Get the vtable offset.
@@ -421,6 +423,7 @@ void ItaniumCXXABI::lowerGetMethod(
421423
/*isDeref=*/false, /*isVolatile=*/false,
422424
/*isNontemporal=*/false,
423425
/*alignment=*/mlir::IntegerAttr(),
426+
/*sync_scope=*/cir::SyncScopeKindAttr{},
424427
/*mem_order=*/cir::MemOrderAttr(),
425428
/*tbaa=*/mlir::ArrayAttr());
426429
}

0 commit comments

Comments
 (0)