[clang] 6855d70 - [CIR] Add support for atomic-to-non-atomic cast (#193784)

via cfe-commits cfe-commits at lists.llvm.org
Sat Apr 25 09:33:06 PDT 2026


Author: Sirui Mu
Date: 2026-04-26T00:33:01+08:00
New Revision: 6855d70d0153bc1b238a781db0211bdb581cfa4a

URL: https://github.com/llvm/llvm-project/commit/6855d70d0153bc1b238a781db0211bdb581cfa4a
DIFF: https://github.com/llvm/llvm-project/commit/6855d70d0153bc1b238a781db0211bdb581cfa4a.diff

LOG: [CIR] Add support for atomic-to-non-atomic cast (#193784)

This patch adds support for atomic-to-non-atomic casts in CIR.

Related to #192319 .

Assisted-by: Github Copilot / GPT-5.4

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
    clang/lib/CIR/CodeGen/CIRGenExpr.cpp
    clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/test/CIR/CodeGen/atomic.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 4b5c5325d0486..e9bf89c91627f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -113,6 +113,10 @@ class AtomicInfo {
   /// Converts a rvalue to integer value.
   mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
 
+  RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
+                                SourceLocation loc, bool asValue,
+                                bool cmpxchg = false) const;
+
   /// Copy an atomic r-value into atomic-layout memory.
   void emitCopyIntoMemory(RValue rvalue) const;
 
@@ -128,11 +132,20 @@ class AtomicInfo {
     return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
   }
 
+  /// Emits atomic load.
+  /// \returns Loaded value.
+  RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
+                        bool asValue, cir::MemOrder order, bool isVolatile);
+
   /// Creates temp alloca for intermediate operations on atomic value.
   Address createTempAlloca() const;
 
 private:
   bool requiresMemSetZero(mlir::Type ty) const;
+
+  /// Emits atomic load as a CIR operation.
+  mlir::Value emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
+                               bool cmpxchg = false);
 };
 } // namespace
 
@@ -189,6 +202,28 @@ Address AtomicInfo::convertToAtomicIntPointer(Address addr) const {
   return castToAtomicIntPointer(addr);
 }
 
+RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
+                                  bool asValue, cir::MemOrder order,
+                                  bool isVolatile) {
+  // Check whether we should use a library call.
+  if (shouldUseLibCall()) {
+    assert(!cir::MissingFeatures::atomicUseLibCall());
+    cgf.cgm.errorNYI(loc, "emitAtomicLoad: emit atomic lib call");
+    return RValue::get(nullptr);
+  }
+
+  // Okay, we're doing this natively.
+  mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
+
+  // If we're ignoring an aggregate return, don't do anything.
+  if (getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
+    return RValue::getAggregate(Address::invalid(), false);
+
+  // Okay, turn that back into the original value or atomic (for non-simple
+  // lvalues) type.
+  return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
+}
+
 Address AtomicInfo::createTempAlloca() const {
   Address tempAlloca = cgf.createMemTemp(
       (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits) ? valueTy
@@ -240,6 +275,20 @@ static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
   return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
 }
 
+mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
+                                         bool cmpxchg) {
+  Address addr = getAtomicAddress();
+  if (shouldCastToInt(addr.getElementType(), cmpxchg))
+    addr = castToAtomicIntPointer(addr);
+
+  cir::LoadOp op =
+      cgf.getBuilder().createLoad(loc, addr, /*isVolatile=*/isVolatile);
+  op.setMemOrder(order);
+
+  assert(!cir::MissingFeatures::opTBAA());
+  return op;
+}
+
 mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
   // If we've got a scalar value of the right size, try to avoid going
   // through memory. Floats get casted if needed by AtomicExpandPass.
@@ -257,6 +306,35 @@ mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
   return nullptr;
 }
 
+RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
+                                          AggValueSlot resultSlot,
+                                          SourceLocation loc, bool asValue,
+                                          bool cmpxchg) const {
+  // Try not to in some easy cases.
+  assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
+             intVal.getType())) &&
+         "Expected integer, pointer or floating point value when converting "
+         "result.");
+  bool isWholeValue =
+      !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
+  if (getEvaluationKind() == TEK_Scalar &&
+      ((isWholeValue && !hasPadding()) || !asValue)) {
+    mlir::Type valTy = asValue ? cgf.convertTypeForMem(valueTy)
+                               : getAtomicAddress().getElementType();
+    if (!shouldCastToInt(valTy, cmpxchg)) {
+      assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
+             "Different integer types.");
+      return RValue::get(cgf.emitFromMemory(intVal, valueTy));
+    }
+
+    cgf.cgm.errorNYI("convertToValueOrAtomic: convert through bitcast");
+    return RValue::get(nullptr);
+  }
+
+  cgf.cgm.errorNYI("convertToValueOrAtomic: convert through temp");
+  return RValue::get(nullptr);
+}
+
 /// Copy an r-value into memory as part of storing to an atomic type.
 /// This needs to create a bit-pattern suitable for atomic operations.
 void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
@@ -1163,6 +1241,22 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
       e->getExprLoc());
 }
 
+RValue CIRGenFunction::emitAtomicLoad(LValue lvalue, SourceLocation loc,
+                                      AggValueSlot slot) {
+  if (lvalue.getType()->isAtomicType())
+    return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
+                          /*isVolatile=*/lvalue.isVolatileQualified(), slot);
+  return emitAtomicLoad(lvalue, loc, cir::MemOrder::Acquire,
+                        /*isVolatile=*/true, slot);
+}
+
+RValue CIRGenFunction::emitAtomicLoad(LValue lvalue, SourceLocation loc,
+                                      cir::MemOrder order, bool isVolatile,
+                                      AggValueSlot slot) {
+  AtomicInfo info(*this, lvalue, getLoc(loc));
+  return info.emitAtomicLoad(slot, loc, /*asValue=*/true, order, isVolatile);
+}
+
 void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
   bool isVolatile = dest.isVolatileQualified();
   auto order = cir::MemOrder::SequentiallyConsistent;

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 37f2d030024df..65c218f0f78c7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -676,7 +676,7 @@ mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,
   assert(!cir::MissingFeatures::opLoadStoreTbaa());
   LValue atomicLValue = LValue::makeAddr(addr, ty, baseInfo);
   if (ty->isAtomicType() || isLValueSuitableForInlineAtomic(atomicLValue))
-    cgm.errorNYI("emitLoadOfScalar: load atomic");
+    return emitAtomicLoad(atomicLValue, loc).getValue();
 
   if (mlir::isa<cir::VoidType>(eltTy))
     cgm.errorNYI(loc, "emitLoadOfScalar: void type");

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 9c03279352357..aef3decf4d2ae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2225,12 +2225,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
     return cgf.performAddrSpaceCast(Visit(subExpr), convertType(destTy));
   }
 
-  case CK_AtomicToNonAtomic: {
-    cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
-                                   "CastExpr: ", ce->getCastKindName());
-    mlir::Location loc = cgf.getLoc(subExpr->getSourceRange());
-    return cgf.createDummyValue(loc, destTy);
-  }
+  case CK_AtomicToNonAtomic:
   case CK_NonAtomicToAtomic:
   case CK_UserDefinedConversion:
     return Visit(const_cast<Expr *>(subExpr));

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c5106caa52cb2..f3eb5982c041f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -546,6 +546,12 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   bool isLValueSuitableForInlineAtomic(LValue lv);
 
+  RValue emitAtomicLoad(LValue lvalue, SourceLocation loc,
+                        AggValueSlot slot = AggValueSlot::ignored());
+  RValue emitAtomicLoad(LValue lvalue, SourceLocation loc, cir::MemOrder order,
+                        bool isVolatile = false,
+                        AggValueSlot slot = AggValueSlot::ignored());
+
   /// An abstract representation of regular/ObjC call/message targets.
   class AbstractCallee {
     /// The function declaration of the callee.

diff  --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 50ed62cc9d7d1..abce1166cf9a2 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -72,6 +72,22 @@ void f4(_Atomic(float) *p) {
 // OGCG-LABEL: @f4
 // OGCG: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4
 
+void atomic_to_non_atomic(_Atomic int *ptr, _Atomic volatile int *vptr) {
+  // CIR-LABEL: @atomic_to_non_atomic
+  // LLVM-LABEL: @atomic_to_non_atomic
+  // OGCG-LABEL: @atomic_to_non_atomic
+
+  int a = *ptr;
+  // CIR: %{{.+}} = cir.load align(4) atomic(seq_cst) %{{.+}} : !cir.ptr<!s32i>, !s32i
+  // LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+  // OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+
+  int b = *vptr;
+  // CIR: %{{.+}} = cir.load volatile align(4) atomic(seq_cst) %{{.+}} : !cir.ptr<!s32i>, !s32i
+  // LLVM: %{{.+}} = load atomic volatile i32, ptr %{{.+}} seq_cst, align 4
+  // OGCG: %{{.+}} = load atomic volatile i32, ptr %{{.+}} seq_cst, align 4
+}
+
 void load(int *ptr) {
   int x;
   __atomic_load(ptr, &x, __ATOMIC_RELAXED);


        


More information about the cfe-commits mailing list