-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[CIR] Add initial support for atomic types #152923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Sirui Mu (Lancern) ChangesThis patch adds the initial support for C11 atomic types, including:
Full diff: https://github.com/llvm/llvm-project/pull/152923.diff 8 Files Affected:
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/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..544b9ad473b2e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -0,0 +1,26 @@
+// 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: }
|
@llvm/pr-subscribers-clangir Author: Sirui Mu (Lancern) ChangesThis patch adds the initial support for C11 atomic types, including:
Full diff: https://github.com/llvm/llvm-project/pull/152923.diff 8 Files Affected:
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/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..544b9ad473b2e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -0,0 +1,26 @@
+// 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: }
|
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.
|
||
this->lvalue = lvalue; | ||
} else { | ||
assert(!cir::MissingFeatures::atomicInfo()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use errorNYI()
wherever the implementation can't perform any kind of reasonably complete handling without the omitted code.
assert(!cir::MissingFeatures::atomicInfo()); | ||
} | ||
|
||
assert(!cir::MissingFeatures::atomicInfo()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert(!cir::MissingFeatures::atomicInfo()); | |
assert(!cir::MissingFeatures::atomicUseLibCall()); |
if (lvalue.isSimple()) { | ||
elemTy = lvalue.getAddress().getElementType(); | ||
} else { | ||
assert(!cir::MissingFeatures::atomicInfoGetAtomicAddress()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
assert(lvalue.isSimple()); | ||
Address addr = getAtomicAddress(); | ||
if (hasPadding()) | ||
llvm_unreachable("NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
/// 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()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you include an implementation for this?
cgf.emitStoreOfScalar(rvalue.getValue(), tempLValue, /*isInit=*/true); | ||
} else { | ||
assert(!cir::MissingFeatures::atomicCopyComplexIntoAtomic()); | ||
cgf.cgm.errorNYI("copying complex into atomic lvalue is NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cgf.cgm.errorNYI("copying complex into atomic lvalue is NYI"); | |
cgf.cgm.errorNYI("copying complex into atomic lvalue"); |
if (rvalue.isScalar()) { | ||
cgf.emitStoreOfScalar(rvalue.getValue(), tempLValue, /*isInit=*/true); | ||
} else { | ||
assert(!cir::MissingFeatures::atomicCopyComplexIntoAtomic()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The missing feature isn't really needed since there is an errorNYI call here.
} | ||
|
||
case cir::TEK_Complex: | ||
assert(!cir::MissingFeatures::atomicInitComplex()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
return; | ||
|
||
case cir::TEK_Aggregate: | ||
assert(!cir::MissingFeatures::atomicInitAggregate()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
resultType = convertTypeForMem(valueType); | ||
|
||
// Pad out to the inflated size if necessary. | ||
assert(!cir::MissingFeatures::convertAtomicType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert(!cir::MissingFeatures::convertAtomicType()); | |
uint64_t valueSize = astContext.getTypeSize(valueType); | |
uint64_t atomicSize = astContext.getTypeSize(ty); | |
if (valueSize != atomicSize) { | |
cgm.errorNYI("value size != atomic size"); | |
} |
This patch adds the initial support for C11 atomic types, including:
QualType
that represents atomic types to CIR types;