[clang] [CIR] Implement 'simple' atomic inc/dec. (PR #222730)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 11:48:32 PDT 2026
================
@@ -628,10 +628,88 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value value;
mlir::Value input;
- if (type->getAs<AtomicType>()) {
+ if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
+ QualType valType = atomicTy->getValueType();
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ bool isInc = e->isIncrementOp();
+ bool isPre = e->isPrefix();
+
+ // Bools are always set-to-true, as decrement isn't legal on bools.
+ if (valType->isBooleanType()) {
+ assert(isInc);
+ // Atomic operations require an integer type; reinterpret the bool
+ // pointer as a pointer to its underlying storage integer type.
+ cir::IntType intTy = builder.getUInt8Ty();
+ mlir::Value one = builder.getConstInt(loc, intTy, 1);
+ Address intAddr = lv.getAddress().withElementType(builder, intTy);
+
+ if (isPre) {
+ // Pre-increment: atomically store true, return true.
+ cir::StoreOp store = builder.createStore(loc, one, intAddr);
+ store.setMemOrder(cir::MemOrder::SequentiallyConsistent);
+ if (lv.isVolatileQualified())
+ store.setIsVolatile(true);
+ return builder.getTrue(loc);
+ }
+ // Post-increment: atomically exchange with true, return old value.
+ auto xchg = cir::AtomicXchgOp::create(
+ builder, loc, intAddr.getPointer(), one,
+ cir::MemOrder::SequentiallyConsistent, cir::SyncScopeKind::System,
+ lv.isVolatileQualified());
+ return builder.createCast(cir::CastKind::int_to_bool, xchg.getResult(),
+ builder.getBoolTy());
+ }
+
+ // Special case for atomic increment / decrement on integers, emit
+ // atomicrmw instructions. We skip this if we want to be doing overflow
+ // checking, and fall into the slow path with the atomic cmpxchg loop.
+ if (!valType->isBooleanType() && valType->isIntegerType() &&
+ !(valType->isUnsignedIntegerType() &&
+ cgf.sanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
+ cgf.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ mlir::Type intTy = cgf.convertType(valType);
+ mlir::Value one = builder.getConstInt(loc, intTy, 1);
+ cir::AtomicFetchKind kind =
+ isInc ? cir::AtomicFetchKind::Add : cir::AtomicFetchKind::Sub;
+ auto rmw = cir::AtomicFetchOp::create(
+ builder, loc, lv.getPointer(), one, kind,
+ cir::MemOrder::SequentiallyConsistent, cir::SyncScopeKind::System,
+ lv.isVolatileQualified(), /*fetch_first=*/true);
+ mlir::Value oldVal = rmw->getResult(0);
+ // Prefix returns new value; postfix returns old value.
+ return isPre ? emitIncOrDec(e, oldVal) : oldVal;
+ }
+
+ // Special case for atomic increment/decrement on floats.
+ // Bail out non-power-of-2-sized floating point types (e.g., x86_fp80).
+ if (valType->isFloatingType()) {
+ CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, e);
----------------
andykaylor wrote:
Interesting. It looks like classic codegen doesn't do this. In theory it should, but there doesn't seem to be a way to represent a constrained atomicrmw (or add fast-math flags to it). CIR could (but currently doesn't), so I think it makes sense to have this.
Should you sink this below the power-of-2 check?
https://github.com/llvm/llvm-project/pull/222730
More information about the cfe-commits
mailing list