https://github.com/Lancern updated 
https://github.com/llvm/llvm-project/pull/152923

>From 2aca18e40471552400218f0bf6f50a02209509da Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlanc...@gmail.com>
Date: Sun, 10 Aug 2025 23:53:29 +0800
Subject: [PATCH] [CIR] Add initial support for atomic types

This patch adds the initial support for C11 atomic types, including:

- Convert QualType that represents atomic types to CIR types;
- Start emitting code for atomic value initializers.
---
 clang/include/clang/CIR/MissingFeatures.h  |  13 ++
 clang/lib/CIR/CodeGen/CIRGenAtomic.cpp     | 227 +++++++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp       |   7 +-
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp |   4 +
 clang/lib/CIR/CodeGen/CIRGenFunction.h     |   5 +-
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp      |  10 +
 clang/lib/CIR/CodeGen/CIRGenValue.h        |   1 +
 clang/lib/CIR/CodeGen/CMakeLists.txt       |   1 +
 clang/test/CIR/CodeGen/atomic.c            |  47 +++++
 9 files changed, 312 insertions(+), 3 deletions(-)
 create mode 100644 clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
 create mode 100644 clang/test/CIR/CodeGen/atomic.c

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index fcc8ce7caf111..11461d3693d44 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -162,6 +162,17 @@ struct MissingFeatures {
   static bool addressIsKnownNonNull() { return false; }
   static bool addressPointerAuthInfo() { return false; }
 
+  // Atomic
+  static bool convertAtomicType() { return false; }
+  static bool atomicExpr() { return false; }
+  static bool atomicInitComplex() { return false; }
+  static bool atomicInitAggregate() { return false; }
+  static bool atomicCopyAggregateIntoAtomic() { return false; }
+  static bool atomicCopyComplexIntoAtomic() { return false; }
+  static bool atomicInfo() { return false; }
+  static bool atomicInfoGetAtomicPointer() { return false; }
+  static bool atomicInfoGetAtomicAddress() { return false; }
+
   // Misc
   static bool abiArgInfo() { return false; }
   static bool addHeapAllocSiteMetadata() { return false; }
@@ -197,6 +208,7 @@ struct MissingFeatures {
   static bool cudaSupport() { return false; }
   static bool cxxRecordStaticMembers() { return false; }
   static bool dataLayoutTypeAllocSize() { return false; }
+  static bool dataLayoutTypeStoreSize() { return false; }
   static bool deferredCXXGlobalInit() { return false; }
   static bool ehCleanupFlags() { return false; }
   static bool ehCleanupScope() { return false; }
@@ -232,6 +244,7 @@ struct MissingFeatures {
   static bool objCBlocks() { return false; }
   static bool objCGC() { return false; }
   static bool objCLifetime() { return false; }
+  static bool openCL() { return false; }
   static bool openMP() { return false; }
   static bool opGlobalViewAttr() { return false; }
   static bool opTBAA() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp 
b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
new file mode 100644
index 0000000000000..0cd9a22b1b7cc
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -0,0 +1,227 @@
+//===--- CIRGenAtomic.cpp - Emit CIR for atomic operations 
----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the code for emitting atomic operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenFunction.h"
+#include "clang/CIR/MissingFeatures.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+using namespace cir;
+
+namespace {
+class AtomicInfo {
+  CIRGenFunction &cgf;
+  QualType atomicTy;
+  QualType valueTy;
+  uint64_t atomicSizeInBits = 0;
+  uint64_t valueSizeInBits = 0;
+  CharUnits atomicAlign;
+  CharUnits valueAlign;
+  TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
+  LValue lvalue;
+  mlir::Location loc;
+
+public:
+  AtomicInfo(CIRGenFunction &cgf, LValue &lvalue, mlir::Location loc)
+      : cgf(cgf), loc(loc) {
+    assert(!lvalue.isGlobalReg());
+    ASTContext &ctx = cgf.getContext();
+    if (lvalue.isSimple()) {
+      atomicTy = lvalue.getType();
+      if (auto *ty = atomicTy->getAs<AtomicType>())
+        valueTy = ty->getValueType();
+      else
+        valueTy = atomicTy;
+      evaluationKind = cgf.getEvaluationKind(valueTy);
+
+      TypeInfo valueTypeInfo = ctx.getTypeInfo(valueTy);
+      TypeInfo atomicTypeInfo = ctx.getTypeInfo(atomicTy);
+      uint64_t valueAlignInBits = valueTypeInfo.Align;
+      uint64_t atomicAlignInBits = atomicTypeInfo.Align;
+      valueSizeInBits = valueTypeInfo.Width;
+      atomicSizeInBits = atomicTypeInfo.Width;
+      assert(valueSizeInBits <= atomicSizeInBits);
+      assert(valueAlignInBits <= atomicAlignInBits);
+
+      atomicAlign = ctx.toCharUnitsFromBits(atomicAlignInBits);
+      valueAlign = ctx.toCharUnitsFromBits(valueAlignInBits);
+      if (lvalue.getAlignment().isZero())
+        lvalue.setAlignment(atomicAlign);
+
+      this->lvalue = lvalue;
+    } else {
+      assert(!cir::MissingFeatures::atomicInfo());
+    }
+
+    assert(!cir::MissingFeatures::atomicInfo());
+  }
+
+  QualType getValueType() const { return valueTy; }
+  CharUnits getAtomicAlignment() const { return atomicAlign; }
+  TypeEvaluationKind getEvaluationKind() const { return evaluationKind; }
+  mlir::Value getAtomicPointer() const {
+    if (lvalue.isSimple())
+      return lvalue.getPointer();
+    assert(!cir::MissingFeatures::atomicInfoGetAtomicPointer());
+    return nullptr;
+  }
+  Address getAtomicAddress() const {
+    mlir::Type elemTy;
+    if (lvalue.isSimple()) {
+      elemTy = lvalue.getAddress().getElementType();
+    } else {
+      assert(!cir::MissingFeatures::atomicInfoGetAtomicAddress());
+    }
+    return Address(getAtomicPointer(), elemTy, getAtomicAlignment());
+  }
+
+  /// Is the atomic size larger than the underlying value type?
+  ///
+  /// Note that the absence of padding does not mean that atomic
+  /// objects are completely interchangeable with non-atomic
+  /// objects: we might have promoted the alignment of a type
+  /// without making it bigger.
+  bool hasPadding() const { return (valueSizeInBits != atomicSizeInBits); }
+
+  bool emitMemSetZeroIfNecessary() const;
+
+  /// Copy an atomic r-value into atomic-layout memory.
+  void emitCopyIntoMemory(RValue rvalue) const;
+
+  /// Project an l-value down to the value field.
+  LValue projectValue() const {
+    assert(lvalue.isSimple());
+    Address addr = getAtomicAddress();
+    if (hasPadding())
+      llvm_unreachable("NYI");
+
+    assert(!cir::MissingFeatures::opTBAA());
+    return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
+  }
+
+private:
+  bool requiresMemSetZero(mlir::Type ty) const;
+};
+} // namespace
+
+/// Does a store of the given IR type modify the full expected width?
+static bool isFullSizeType(CIRGenModule &cgm, mlir::Type ty,
+                           uint64_t expectedSize) {
+  assert(!cir::MissingFeatures::dataLayoutTypeStoreSize());
+  return true;
+}
+
+/// Does the atomic type require memsetting to zero before initialization?
+///
+/// The IR type is provided as a way of making certain queries faster.
+bool AtomicInfo::requiresMemSetZero(mlir::Type ty) const {
+  // If the atomic type has size padding, we definitely need a memset.
+  if (hasPadding())
+    return true;
+
+  // Otherwise, do some simple heuristics to try to avoid it:
+  switch (getEvaluationKind()) {
+  // For scalars and complexes, check whether the store size of the
+  // type uses the full size.
+  case cir::TEK_Scalar:
+    return !isFullSizeType(cgf.cgm, ty, atomicSizeInBits);
+  case cir::TEK_Complex:
+    llvm_unreachable("NYI");
+
+  // Padding in structs has an undefined bit pattern.  User beware.
+  case cir::TEK_Aggregate:
+    return false;
+  }
+  llvm_unreachable("bad evaluation kind");
+}
+
+bool AtomicInfo::emitMemSetZeroIfNecessary() const {
+  assert(lvalue.isSimple());
+  Address addr = lvalue.getAddress();
+  if (!requiresMemSetZero(addr.getElementType()))
+    return false;
+
+  llvm_unreachable("NYI");
+}
+
+/// 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 {
+  assert(lvalue.isSimple());
+
+  // If we have an r-value, the rvalue should be of the atomic type,
+  // which means that the caller is responsible for having zeroed
+  // any padding.  Just do an aggregate copy of that type.
+  if (rvalue.isAggregate()) {
+    assert(!cir::MissingFeatures::atomicCopyAggregateIntoAtomic());
+    cgf.cgm.errorNYI("copying aggregate into atomic lvalue is NYI");
+    return;
+  }
+
+  // Okay, otherwise we're copying stuff.
+
+  // Zero out the buffer if necessary.
+  emitMemSetZeroIfNecessary();
+
+  // Drill past the padding if present.
+  LValue tempLValue = projectValue();
+
+  // Okay, store the rvalue in.
+  if (rvalue.isScalar()) {
+    cgf.emitStoreOfScalar(rvalue.getValue(), tempLValue, /*isInit=*/true);
+  } else {
+    assert(!cir::MissingFeatures::atomicCopyComplexIntoAtomic());
+    cgf.cgm.errorNYI("copying complex into atomic lvalue is NYI");
+  }
+}
+
+RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
+  QualType atomicTy = e->getPtr()->getType()->getPointeeType();
+  QualType memTy = atomicTy;
+  if (const auto *ty = atomicTy->getAs<AtomicType>())
+    memTy = ty->getValueType();
+
+  Address ptr = emitPointerWithAlignment(e->getPtr());
+
+  assert(!cir::MissingFeatures::openCL());
+  if (e->getOp() == AtomicExpr::AO__c11_atomic_init) {
+    LValue lvalue = makeAddrLValue(ptr, atomicTy);
+    emitAtomicInit(e->getVal1(), lvalue);
+    return RValue::get(nullptr);
+  }
+
+  assert(!cir::MissingFeatures::atomicExpr());
+  cgm.errorNYI(e->getSourceRange(), "atomic expr is NYI");
+  return RValue::get(nullptr);
+}
+
+void CIRGenFunction::emitAtomicInit(Expr *init, LValue dest) {
+  AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));
+
+  switch (atomics.getEvaluationKind()) {
+  case cir::TEK_Scalar: {
+    mlir::Value value = emitScalarExpr(init);
+    atomics.emitCopyIntoMemory(RValue::get(value));
+    return;
+  }
+
+  case cir::TEK_Complex:
+    assert(!cir::MissingFeatures::atomicInitComplex());
+    return;
+
+  case cir::TEK_Aggregate:
+    assert(!cir::MissingFeatures::atomicInitAggregate());
+    return;
+  }
+
+  llvm_unreachable("bad evaluation kind");
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index c437b14dd8d1c..a53857c019b0d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -184,8 +184,11 @@ Address CIRGenFunction::emitPointerWithAlignment(const 
Expr *expr,
   if (const UnaryOperator *uo = dyn_cast<UnaryOperator>(expr)) {
     // TODO(cir): maybe we should use cir.unary for pointers here instead.
     if (uo->getOpcode() == UO_AddrOf) {
-      cgm.errorNYI(expr->getSourceRange(), "emitPointerWithAlignment: unary 
&");
-      return Address::invalid();
+      LValue lv = emitLValue(uo->getSubExpr());
+      if (baseInfo)
+        *baseInfo = lv.getBaseInfo();
+      assert(!cir::MissingFeatures::opTBAA());
+      return lv.getAddress();
     }
   }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3e06513bb6cf0..e0015f505e9ed 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1060,6 +1060,10 @@ class ScalarExprEmitter : public 
StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
     return maybePromoteBoolResult(resOp.getResult(), resTy);
   }
+
+  mlir::Value VisitAtomicExpr(AtomicExpr *e) {
+    return cgf.emitAtomicExpr(e).getValue();
+  }
 };
 
 LValue ScalarExprEmitter::emitCompoundAssignLValue(
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 065039ec041e0..37f5c1a35198e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -893,6 +893,9 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   Address emitArrayToPointerDecay(const Expr *array);
 
+  RValue emitAtomicExpr(AtomicExpr *e);
+  void emitAtomicInit(Expr *init, LValue dest);
+
   AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
                                     mlir::OpBuilder::InsertPoint ip = {});
 
@@ -1197,7 +1200,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// reasonable to just ignore the returned alignment when it isn't from an
   /// explicit source.
   Address emitPointerWithAlignment(const clang::Expr *expr,
-                                   LValueBaseInfo *baseInfo);
+                                   LValueBaseInfo *baseInfo = nullptr);
 
   /// Emits a reference binding to the passed in expression.
   RValue emitReferenceBindingToExpr(const Expr *e);
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 2084b6d9e8989..baaf7cb50b96f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -491,6 +491,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
     break;
   }
 
+  case Type::Atomic: {
+    QualType valueType = cast<AtomicType>(ty)->getValueType();
+    resultType = convertTypeForMem(valueType);
+
+    // Pad out to the inflated size if necessary.
+    assert(!cir::MissingFeatures::convertAtomicType());
+
+    break;
+  }
+
   default:
     cgm.errorNYI(SourceLocation(), "processing of type",
                  type->getTypeClassName());
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h 
b/clang/lib/CIR/CodeGen/CIRGenValue.h
index 0832c4141a10f..661cecf8416b6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -190,6 +190,7 @@ class LValue {
   bool isSimple() const { return lvType == Simple; }
   bool isVectorElt() const { return lvType == VectorElt; }
   bool isBitField() const { return lvType == BitField; }
+  bool isGlobalReg() const { return lvType == GlobalReg; }
   bool isVolatile() const { return quals.hasVolatile(); }
 
   bool isVolatileQualified() const { return quals.hasVolatile(); }
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt 
b/clang/lib/CIR/CodeGen/CMakeLists.txt
index ca3a329d0c56d..29aa5372c66f1 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 
 add_clang_library(clangCIR
   CIRGenerator.cpp
+  CIRGenAtomic.cpp
   CIRGenBuilder.cpp
   CIRGenCall.cpp
   CIRGenClass.cpp
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
new file mode 100644
index 0000000000000..8db4ae43d7389
--- /dev/null
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void f1(void) {
+  _Atomic(int) x = 42;
+}
+
+// CIR-LABEL: @f1
+// CIR:         %[[SLOT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] 
{alignment = 4 : i64}
+// CIR-NEXT:    %[[INIT:.+]] = cir.const #cir.int<42> : !s32i
+// CIR-NEXT:    cir.store align(4) %[[INIT]], %[[SLOT]] : !s32i, 
!cir.ptr<!s32i>
+// CIR:       }
+
+// LLVM-LABEL: @f1
+// LLVM:         %[[SLOT:.+]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:    store i32 42, ptr %[[SLOT]], align 4
+// LLVM:       }
+
+// OGCG-LABEL: @f1
+// OGCG:         %[[SLOT:.+]] = alloca i32, align 4
+// OGCG-NEXT:    store i32 42, ptr %[[SLOT]], align 4
+// OGCG:       }
+
+void f2(void) {
+  _Atomic(int) x;
+  __c11_atomic_init(&x, 42);
+}
+
+// CIR-LABEL: @f2
+// CIR:         %[[SLOT:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] 
{alignment = 4 : i64}
+// CIR-NEXT:    %[[INIT:.+]] = cir.const #cir.int<42> : !s32i
+// CIR-NEXT:    cir.store align(4) %[[INIT]], %[[SLOT]] : !s32i, 
!cir.ptr<!s32i>
+// CIR:       }
+
+// LLVM-LABEL: @f2
+// LLVM:         %[[SLOT:.+]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:    store i32 42, ptr %[[SLOT]], align 4
+// LLVM:       }
+
+// OGCG-LABEL: @f2
+// OGCG:         %[[SLOT:.+]] = alloca i32, align 4
+// OGCG-NEXT:    store i32 42, ptr %[[SLOT]], align 4
+// OGCG:       }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to