[clang] [libcxx] [Clang] Support atomic operations on _BitInt(N) (PR #204815)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 26 10:00:14 PDT 2026
================
@@ -558,6 +559,195 @@ static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
return Builder.CreateSelect(Cmp, OldVal, RHS, "newval");
}
+/// Classify an atomic op as an arithmetic/bitwise read-modify-write (one that
+/// normally lowers to a single `atomicrmw`), mapping it to the matching
+/// `AtomicRMWInst::BinOp` and reporting whether the builtin returns the new
+/// value (`<op>_fetch`) rather than the old value (`fetch_<op>`). \p IsSigned
+/// selects signed vs unsigned min/max. Returns false for exchange, load, store,
+/// compare-exchange, and any non-RMW op, none of which need the _BitInt loop.
+static bool classifyBitIntRMW(AtomicExpr::AtomicOp Op, bool IsSigned,
+ llvm::AtomicRMWInst::BinOp &BinOp,
+ bool &ReturnsNew) {
+ using RMW = llvm::AtomicRMWInst;
+ switch (Op) {
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__hip_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__scoped_atomic_fetch_add:
+ BinOp = RMW::Add, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__scoped_atomic_add_fetch:
+ BinOp = RMW::Add, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__hip_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__scoped_atomic_fetch_sub:
+ BinOp = RMW::Sub, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_sub_fetch:
+ case AtomicExpr::AO__scoped_atomic_sub_fetch:
+ BinOp = RMW::Sub, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__hip_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__scoped_atomic_fetch_and:
+ BinOp = RMW::And, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__scoped_atomic_and_fetch:
+ BinOp = RMW::And, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__hip_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__scoped_atomic_fetch_or:
+ BinOp = RMW::Or, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__scoped_atomic_or_fetch:
+ BinOp = RMW::Or, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__hip_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__scoped_atomic_fetch_xor:
+ BinOp = RMW::Xor, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__scoped_atomic_xor_fetch:
+ BinOp = RMW::Xor, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__scoped_atomic_fetch_nand:
+ BinOp = RMW::Nand, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_nand_fetch:
+ case AtomicExpr::AO__scoped_atomic_nand_fetch:
+ BinOp = RMW::Nand, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_min:
+ case AtomicExpr::AO__hip_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__atomic_fetch_min:
+ case AtomicExpr::AO__scoped_atomic_fetch_min:
+ BinOp = IsSigned ? RMW::Min : RMW::UMin, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_min_fetch:
+ case AtomicExpr::AO__scoped_atomic_min_fetch:
+ BinOp = IsSigned ? RMW::Min : RMW::UMin, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__hip_atomic_fetch_max:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
+ case AtomicExpr::AO__atomic_fetch_max:
+ case AtomicExpr::AO__scoped_atomic_fetch_max:
+ BinOp = IsSigned ? RMW::Max : RMW::UMax, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_max_fetch:
+ case AtomicExpr::AO__scoped_atomic_max_fetch:
+ BinOp = IsSigned ? RMW::Max : RMW::UMax, ReturnsNew = true;
+ return true;
+ case AtomicExpr::AO__atomic_fetch_uinc:
+ case AtomicExpr::AO__scoped_atomic_fetch_uinc:
+ BinOp = RMW::UIncWrap, ReturnsNew = false;
+ return true;
+ case AtomicExpr::AO__atomic_fetch_udec:
+ case AtomicExpr::AO__scoped_atomic_fetch_udec:
+ BinOp = RMW::UDecWrap, ReturnsNew = false;
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// True for a `_BitInt(N)` whose value width N differs from its in-memory width
+/// (e.g. `_BitInt(37)` occupies 64 bits), so the high bits are padding.
+static bool hasBitIntPadding(QualType T, const ASTContext &C) {
+ if (const auto *BIT = T->getAs<BitIntType>())
+ return BIT->getNumBits() != C.getTypeSize(T);
+ return false;
+}
+
+/// Map a constant C ABI memory order to an llvm ordering. A non-constant order
+/// is handled conservatively with the strongest ordering.
+static llvm::AtomicOrdering atomicOrderOrSeqCst(llvm::Value *Order) {
+ auto *C = dyn_cast<llvm::ConstantInt>(Order);
+ if (!C || !llvm::isValidAtomicOrderingCABI(C->getZExtValue()))
+ return llvm::AtomicOrdering::SequentiallyConsistent;
+ switch ((llvm::AtomicOrderingCABI)C->getZExtValue()) {
----------------
erichkeane wrote:
don't use C style casts.
https://github.com/llvm/llvm-project/pull/204815
More information about the cfe-commits
mailing list