Skip to content

Commit 1ced565

Browse files
authored
[Clang] Add support for scoped atomic thread fence (#115545)
Summary: Previously we added support for all of the atomic GNU extensions with optional memory scoped except for `__atomic_thread_fence`. This patch adds support for that. This should ideally allow us to generically emit these LLVM scopes.
1 parent 36d47f8 commit 1ced565

File tree

3 files changed

+393
-0
lines changed

3 files changed

+393
-0
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,12 @@ def AtomicThreadFence : Builtin {
19951995
let Prototype = "void(int)";
19961996
}
19971997

1998+
def ScopedAtomicThreadFence : Builtin {
1999+
let Spellings = ["__scoped_atomic_thread_fence"];
2000+
let Attributes = [NoThrow];
2001+
let Prototype = "void(int, int)";
2002+
}
2003+
19982004
def AtomicSignalFence : Builtin {
19992005
let Spellings = ["__atomic_signal_fence"];
20002006
let Attributes = [NoThrow];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5213,6 +5213,136 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52135213
Builder.SetInsertPoint(ContBB);
52145214
return RValue::get(nullptr);
52155215
}
5216+
case Builtin::BI__scoped_atomic_thread_fence: {
5217+
auto ScopeModel = AtomicScopeModel::create(AtomicScopeModelKind::Generic);
5218+
5219+
Value *Order = EmitScalarExpr(E->getArg(0));
5220+
Value *Scope = EmitScalarExpr(E->getArg(1));
5221+
auto Ord = dyn_cast<llvm::ConstantInt>(Order);
5222+
auto Scp = dyn_cast<llvm::ConstantInt>(Scope);
5223+
if (Ord && Scp) {
5224+
SyncScope SS = ScopeModel->isValid(Scp->getZExtValue())
5225+
? ScopeModel->map(Scp->getZExtValue())
5226+
: ScopeModel->map(ScopeModel->getFallBackValue());
5227+
switch (Ord->getZExtValue()) {
5228+
case 0: // memory_order_relaxed
5229+
default: // invalid order
5230+
break;
5231+
case 1: // memory_order_consume
5232+
case 2: // memory_order_acquire
5233+
Builder.CreateFence(
5234+
llvm::AtomicOrdering::Acquire,
5235+
getTargetHooks().getLLVMSyncScopeID(getLangOpts(), SS,
5236+
llvm::AtomicOrdering::Acquire,
5237+
getLLVMContext()));
5238+
break;
5239+
case 3: // memory_order_release
5240+
Builder.CreateFence(
5241+
llvm::AtomicOrdering::Release,
5242+
getTargetHooks().getLLVMSyncScopeID(getLangOpts(), SS,
5243+
llvm::AtomicOrdering::Release,
5244+
getLLVMContext()));
5245+
break;
5246+
case 4: // memory_order_acq_rel
5247+
Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease,
5248+
getTargetHooks().getLLVMSyncScopeID(
5249+
getLangOpts(), SS,
5250+
llvm::AtomicOrdering::AcquireRelease,
5251+
getLLVMContext()));
5252+
break;
5253+
case 5: // memory_order_seq_cst
5254+
Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
5255+
getTargetHooks().getLLVMSyncScopeID(
5256+
getLangOpts(), SS,
5257+
llvm::AtomicOrdering::SequentiallyConsistent,
5258+
getLLVMContext()));
5259+
break;
5260+
}
5261+
return RValue::get(nullptr);
5262+
}
5263+
5264+
llvm::BasicBlock *ContBB = createBasicBlock("atomic.scope.continue", CurFn);
5265+
5266+
llvm::SmallVector<std::pair<llvm::BasicBlock *, llvm::AtomicOrdering>>
5267+
OrderBBs;
5268+
if (Ord) {
5269+
switch (Ord->getZExtValue()) {
5270+
case 0: // memory_order_relaxed
5271+
default: // invalid order
5272+
ContBB->eraseFromParent();
5273+
return RValue::get(nullptr);
5274+
case 1: // memory_order_consume
5275+
case 2: // memory_order_acquire
5276+
OrderBBs.emplace_back(Builder.GetInsertBlock(),
5277+
llvm::AtomicOrdering::Acquire);
5278+
break;
5279+
case 3: // memory_order_release
5280+
OrderBBs.emplace_back(Builder.GetInsertBlock(),
5281+
llvm::AtomicOrdering::Release);
5282+
break;
5283+
case 4: // memory_order_acq_rel
5284+
OrderBBs.emplace_back(Builder.GetInsertBlock(),
5285+
llvm::AtomicOrdering::AcquireRelease);
5286+
break;
5287+
case 5: // memory_order_seq_cst
5288+
OrderBBs.emplace_back(Builder.GetInsertBlock(),
5289+
llvm::AtomicOrdering::SequentiallyConsistent);
5290+
break;
5291+
}
5292+
} else {
5293+
llvm::BasicBlock *AcquireBB = createBasicBlock("acquire", CurFn);
5294+
llvm::BasicBlock *ReleaseBB = createBasicBlock("release", CurFn);
5295+
llvm::BasicBlock *AcqRelBB = createBasicBlock("acqrel", CurFn);
5296+
llvm::BasicBlock *SeqCstBB = createBasicBlock("seqcst", CurFn);
5297+
5298+
Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
5299+
llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
5300+
SI->addCase(Builder.getInt32(1), AcquireBB);
5301+
SI->addCase(Builder.getInt32(2), AcquireBB);
5302+
SI->addCase(Builder.getInt32(3), ReleaseBB);
5303+
SI->addCase(Builder.getInt32(4), AcqRelBB);
5304+
SI->addCase(Builder.getInt32(5), SeqCstBB);
5305+
5306+
OrderBBs.emplace_back(AcquireBB, llvm::AtomicOrdering::Acquire);
5307+
OrderBBs.emplace_back(ReleaseBB, llvm::AtomicOrdering::Release);
5308+
OrderBBs.emplace_back(AcqRelBB, llvm::AtomicOrdering::AcquireRelease);
5309+
OrderBBs.emplace_back(SeqCstBB,
5310+
llvm::AtomicOrdering::SequentiallyConsistent);
5311+
}
5312+
5313+
for (auto &[OrderBB, Ordering] : OrderBBs) {
5314+
Builder.SetInsertPoint(OrderBB);
5315+
if (Scp) {
5316+
SyncScope SS = ScopeModel->isValid(Scp->getZExtValue())
5317+
? ScopeModel->map(Scp->getZExtValue())
5318+
: ScopeModel->map(ScopeModel->getFallBackValue());
5319+
Builder.CreateFence(Ordering,
5320+
getTargetHooks().getLLVMSyncScopeID(
5321+
getLangOpts(), SS, Ordering, getLLVMContext()));
5322+
Builder.CreateBr(ContBB);
5323+
} else {
5324+
llvm::DenseMap<unsigned, llvm::BasicBlock *> BBs;
5325+
for (unsigned Scp : ScopeModel->getRuntimeValues())
5326+
BBs[Scp] = createBasicBlock(getAsString(ScopeModel->map(Scp)), CurFn);
5327+
5328+
auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false);
5329+
llvm::SwitchInst *SI = Builder.CreateSwitch(SC, ContBB);
5330+
for (unsigned Scp : ScopeModel->getRuntimeValues()) {
5331+
auto *B = BBs[Scp];
5332+
SI->addCase(Builder.getInt32(Scp), B);
5333+
5334+
Builder.SetInsertPoint(B);
5335+
Builder.CreateFence(Ordering, getTargetHooks().getLLVMSyncScopeID(
5336+
getLangOpts(), ScopeModel->map(Scp),
5337+
Ordering, getLLVMContext()));
5338+
Builder.CreateBr(ContBB);
5339+
}
5340+
}
5341+
}
5342+
5343+
Builder.SetInsertPoint(ContBB);
5344+
return RValue::get(nullptr);
5345+
}
52165346

52175347
case Builtin::BI__builtin_signbit:
52185348
case Builtin::BI__builtin_signbitf:

0 commit comments

Comments
 (0)