aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenAtomic.cpp4
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenBuilder.h8
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenClass.cpp5
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenDecl.cpp98
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExpr.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.cpp58
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h32
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp28
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp6
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp132
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h15
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenStmt.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenTypeCache.h3
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenTypes.cpp15
-rw-r--r--clang/lib/CIR/Dialect/IR/CIRDialect.cpp14
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp22
18 files changed, 364 insertions, 94 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 0f4d6d2..a9983f8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -255,7 +255,7 @@ static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak,
mlir::Value expected = builder.createLoad(loc, val1);
mlir::Value desired = builder.createLoad(loc, val2);
- auto cmpxchg = cir::AtomicCmpXchg::create(
+ auto cmpxchg = cir::AtomicCmpXchgOp::create(
builder, loc, expected.getType(), builder.getBoolTy(), ptr.getPointer(),
expected, desired,
cir::MemOrderAttr::get(&cgf.getMLIRContext(), successOrder),
@@ -404,7 +404,7 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
case AtomicExpr::AO__c11_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
case AtomicExpr::AO__atomic_exchange:
- opName = cir::AtomicXchg::getOperationName();
+ opName = cir::AtomicXchgOp::getOperationName();
break;
case AtomicExpr::AO__opencl_atomic_init:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index a6f10e6..84acc74 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -519,6 +519,14 @@ public:
return createGlobal(module, loc, uniqueName, type, isConstant, linkage);
}
+ cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) {
+ return cir::StackSaveOp::create(*this, loc, ty);
+ }
+
+ cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) {
+ return cir::StackRestoreOp::create(*this, loc, v);
+ }
+
mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
Address dstAddr, mlir::Type storageType,
mlir::Value src, const CIRGenBitFieldInfo &info,
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index dd357ce..89f4926 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -478,8 +478,7 @@ void CIRGenFunction::getVTablePointers(BaseSubobject base,
for (const auto &nextBase : rd->bases()) {
const auto *baseDecl =
- cast<CXXRecordDecl>(
- nextBase.getType()->castAs<RecordType>()->getOriginalDecl())
+ cast<CXXRecordDecl>(nextBase.getType()->castAs<RecordType>()->getDecl())
->getDefinitionOrSelf();
// Ignore classes without a vtable.
@@ -1025,7 +1024,7 @@ void CIRGenFunction::enterDtorCleanups(const CXXDestructorDecl *dd,
// Anonymous union members do not have their destructors called.
const RecordType *rt = type->getAsUnionType();
- if (rt && rt->getOriginalDecl()->isAnonymousStructOrUnion())
+ if (rt && rt->getDecl()->isAnonymousStructOrUnion())
continue;
CleanupKind cleanupKind = getCleanupKind(dtorKind);
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 039d290..4a19d91 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -44,38 +44,70 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d,
// If the type is variably-modified, emit all the VLA sizes for it.
if (ty->isVariablyModifiedType())
- cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
+ emitVariablyModifiedType(ty);
assert(!cir::MissingFeatures::openMP());
Address address = Address::invalid();
- if (!ty->isConstantSizeType())
- cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");
-
- // A normal fixed sized variable becomes an alloca in the entry block,
- // unless:
- // - it's an NRVO variable.
- // - we are compiling OpenMP and it's an OpenMP local variable.
- if (nrvo) {
- // The named return value optimization: allocate this variable in the
- // return slot, so that we can elide the copy when returning this
- // variable (C++0x [class.copy]p34).
- address = returnValue;
-
- if (const RecordDecl *rd = ty->getAsRecordDecl()) {
- if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
- (cxxrd && !cxxrd->hasTrivialDestructor()) ||
- rd->isNonTrivialToPrimitiveDestroy())
- cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
+ if (ty->isConstantSizeType()) {
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ // unless:
+ // - it's an NRVO variable.
+ // - we are compiling OpenMP and it's an OpenMP local variable.
+ if (nrvo) {
+ // The named return value optimization: allocate this variable in the
+ // return slot, so that we can elide the copy when returning this
+ // variable (C++0x [class.copy]p34).
+ address = returnValue;
+
+ if (const RecordDecl *rd = ty->getAsRecordDecl()) {
+ if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
+ (cxxrd && !cxxrd->hasTrivialDestructor()) ||
+ rd->isNonTrivialToPrimitiveDestroy())
+ cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
+ }
+ } else {
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ mlir::Type allocaTy = convertTypeForMem(ty);
+ // Create the temp alloca and declare variable using it.
+ address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
+ /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
+ declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
+ alignment);
}
} else {
- // A normal fixed sized variable becomes an alloca in the entry block,
- mlir::Type allocaTy = convertTypeForMem(ty);
- // Create the temp alloca and declare variable using it.
- address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
- /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
- declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
- alignment);
+ // Non-constant size type
+ assert(!cir::MissingFeatures::openMP());
+ if (!didCallStackSave) {
+ // Save the stack.
+ cir::PointerType defaultTy = AllocaInt8PtrTy;
+ CharUnits align = CharUnits::fromQuantity(
+ cgm.getDataLayout().getAlignment(defaultTy, false));
+ Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");
+
+ mlir::Value v = builder.createStackSave(loc, defaultTy);
+ assert(v.getType() == AllocaInt8PtrTy);
+ builder.createStore(loc, v, stack);
+
+ didCallStackSave = true;
+
+ // Push a cleanup block and restore the stack there.
+ // FIXME: in general circumstances, this should be an EH cleanup.
+ pushStackRestore(NormalCleanup, stack);
+ }
+
+ VlaSizePair vlaSize = getVLASize(ty);
+ mlir::Type memTy = convertTypeForMem(vlaSize.type);
+
+ // Allocate memory for the array.
+ address =
+ createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
+ /*alloca=*/nullptr, builder.saveInsertionPoint());
+
+ // If we have debug info enabled, properly describe the VLA dimensions for
+ // this type by registering the vla size expression for each of the
+ // dimensions.
+ assert(!cir::MissingFeatures::generateDebugInfo());
}
emission.addr = address;
@@ -696,6 +728,16 @@ struct DestroyObject final : EHScopeStack::Cleanup {
cgf.emitDestroy(addr, type, destroyer);
}
};
+
+struct CallStackRestore final : EHScopeStack::Cleanup {
+ Address stack;
+ CallStackRestore(Address stack) : stack(stack) {}
+ void emit(CIRGenFunction &cgf) override {
+ mlir::Location loc = stack.getPointer().getLoc();
+ mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
+ cgf.getBuilder().createStackRestore(loc, v);
+ }
+};
} // namespace
void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
@@ -805,6 +847,10 @@ CIRGenFunction::getDestroyer(QualType::DestructionKind kind) {
llvm_unreachable("Unknown DestructionKind");
}
+void CIRGenFunction::pushStackRestore(CleanupKind kind, Address spMem) {
+ ehStack.pushCleanup<CallStackRestore>(kind, spMem);
+}
+
/// Enter a destroy cleanup for the given local variable.
void CIRGenFunction::emitAutoVarTypeCleanup(
const CIRGenFunction::AutoVarEmission &emission,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f416571..4897c29 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2068,7 +2068,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
mlir::OpBuilder::InsertionGuard guard(builder);
builder.restoreInsertionPoint(ip);
addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy,
- /*var type*/ ty, name, alignIntAttr);
+ /*var type*/ ty, name, alignIntAttr, arraySize);
assert(!cir::MissingFeatures::astVarDeclInterface());
}
return addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 89e9ec4..81e5fe2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -614,7 +614,7 @@ bool ConstRecordBuilder::applyZeroInitPadding(const ASTRecordLayout &layout,
bool ConstRecordBuilder::build(InitListExpr *ile, bool allowOverwrite) {
RecordDecl *rd = ile->getType()
->castAs<clang::RecordType>()
- ->getOriginalDecl()
+ ->getDecl()
->getDefinitionOrSelf();
const ASTRecordLayout &layout = cgm.getASTContext().getASTRecordLayout(rd);
@@ -817,9 +817,8 @@ bool ConstRecordBuilder::build(const APValue &val, const RecordDecl *rd,
mlir::Attribute ConstRecordBuilder::finalize(QualType type) {
type = type.getNonReferenceType();
- RecordDecl *rd = type->castAs<clang::RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ RecordDecl *rd =
+ type->castAs<clang::RecordType>()->getDecl()->getDefinitionOrSelf();
mlir::Type valTy = cgm.convertType(type);
return builder.build(valTy, rd->hasFlexibleArrayMember());
}
@@ -842,9 +841,8 @@ mlir::Attribute ConstRecordBuilder::buildRecord(ConstantEmitter &emitter,
ConstantAggregateBuilder constant(emitter.cgm);
ConstRecordBuilder builder(emitter, constant, CharUnits::Zero());
- const RecordDecl *rd = valTy->castAs<clang::RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ const RecordDecl *rd =
+ valTy->castAs<clang::RecordType>()->getDecl()->getDefinitionOrSelf();
const CXXRecordDecl *cd = dyn_cast<CXXRecordDecl>(rd);
if (!builder.build(val, rd, false, cd, CharUnits::Zero()))
return nullptr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 01a43a99..ba36cbe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -410,6 +410,8 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
curFn = fn;
const Decl *d = gd.getDecl();
+
+ didCallStackSave = false;
curCodeDecl = d;
const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
curFuncDecl = d->getNonClosureContext();
@@ -1006,6 +1008,41 @@ mlir::Value CIRGenFunction::emitAlignmentAssumption(
offsetValue);
}
+CIRGenFunction::VlaSizePair CIRGenFunction::getVLASize(QualType type) {
+ const VariableArrayType *vla =
+ cgm.getASTContext().getAsVariableArrayType(type);
+ assert(vla && "type was not a variable array type!");
+ return getVLASize(vla);
+}
+
+CIRGenFunction::VlaSizePair
+CIRGenFunction::getVLASize(const VariableArrayType *type) {
+ // The number of elements so far; always size_t.
+ mlir::Value numElements;
+
+ QualType elementType;
+ do {
+ elementType = type->getElementType();
+ mlir::Value vlaSize = vlaSizeMap[type->getSizeExpr()];
+ assert(vlaSize && "no size for VLA!");
+ assert(vlaSize.getType() == SizeTy);
+
+ if (!numElements) {
+ numElements = vlaSize;
+ } else {
+ // It's undefined behavior if this wraps around, so mark it that way.
+ // FIXME: Teach -fsanitize=undefined to trap this.
+
+ numElements =
+ builder.createMul(numElements.getLoc(), numElements, vlaSize,
+ cir::OverflowBehavior::NoUnsignedWrap);
+ }
+ } while ((type = getContext().getAsVariableArrayType(elementType)));
+
+ assert(numElements && "Undefined elements number");
+ return {numElements, elementType};
+}
+
// TODO(cir): Most of this function can be shared between CIRGen
// and traditional LLVM codegen
void CIRGenFunction::emitVariablyModifiedType(QualType type) {
@@ -1086,7 +1123,26 @@ void CIRGenFunction::emitVariablyModifiedType(QualType type) {
break;
case Type::VariableArray: {
- cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType VLA");
+ // Losing element qualification here is fine.
+ const VariableArrayType *vat = cast<clang::VariableArrayType>(ty);
+
+ // Unknown size indication requires no size computation.
+ // Otherwise, evaluate and record it.
+ if (const Expr *sizeExpr = vat->getSizeExpr()) {
+ // It's possible that we might have emitted this already,
+ // e.g. with a typedef and a pointer to it.
+ mlir::Value &entry = vlaSizeMap[sizeExpr];
+ if (!entry) {
+ mlir::Value size = emitScalarExpr(sizeExpr);
+ assert(!cir::MissingFeatures::sanitizers());
+
+ // Always zexting here would be wrong if it weren't
+ // undefined behavior to have a negative bound.
+ // FIXME: What about when size's type is larger than size_t?
+ entry = builder.createIntCast(size, SizeTy);
+ }
+ }
+ type = vat->getElementType();
break;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index d71de2f..0d64c31 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -149,6 +149,10 @@ public:
using SymTableTy = llvm::ScopedHashTable<const clang::Decl *, mlir::Value>;
SymTableTy symbolTable;
+ /// Whether a cir.stacksave operation has been added. Used to avoid
+ /// inserting cir.stacksave for multiple VLAs in the same scope.
+ bool didCallStackSave = false;
+
/// Whether or not a Microsoft-style asm block has been processed within
/// this fuction. These can potentially set the return value.
bool sawAsmBlock = false;
@@ -188,6 +192,14 @@ public:
llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues;
llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues;
+ // This keeps track of the associated size for each VLA type.
+ // We track this by the size expression rather than the type itself because
+ // in certain situations, like a const qualifier applied to an VLA typedef,
+ // multiple VLA types can share the same size expression.
+ // FIXME: Maybe this could be a stack of maps that is pushed/popped as we
+ // enter/leave scopes.
+ llvm::DenseMap<const Expr *, mlir::Value> vlaSizeMap;
+
public:
/// A non-RAII class containing all the information about a bound
/// opaque value. OpaqueValueMapping, below, is a RAII wrapper for
@@ -436,6 +448,20 @@ public:
}
};
+ struct VlaSizePair {
+ mlir::Value numElts;
+ QualType type;
+
+ VlaSizePair(mlir::Value num, QualType ty) : numElts(num), type(ty) {}
+ };
+
+ /// Returns an MLIR::Value+QualType pair that corresponds to the size,
+ /// in non-variably-sized elements, of a variable length array type,
+ /// plus that largest non-variably-sized element type. Assumes that
+ /// the type has already been emitted with emitVariablyModifiedType.
+ VlaSizePair getVLASize(const VariableArrayType *type);
+ VlaSizePair getVLASize(QualType type);
+
void finishFunction(SourceLocation endLoc);
/// Determine whether the given initializer is trivial in the sense
@@ -583,6 +609,8 @@ public:
return needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup;
}
+ void pushStackRestore(CleanupKind kind, Address spMem);
+
/// Set the address of a local variable.
void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) {
assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!");
@@ -854,6 +882,7 @@ public:
protected:
bool performCleanup;
+ bool oldDidCallStackSave;
private:
RunCleanupsScope(const RunCleanupsScope &) = delete;
@@ -867,6 +896,8 @@ public:
explicit RunCleanupsScope(CIRGenFunction &cgf)
: performCleanup(true), cgf(cgf) {
cleanupStackDepth = cgf.ehStack.stable_begin();
+ oldDidCallStackSave = cgf.didCallStackSave;
+ cgf.didCallStackSave = false;
oldCleanupStackDepth = cgf.currentCleanupStackDepth;
cgf.currentCleanupStackDepth = cleanupStackDepth;
}
@@ -883,6 +914,7 @@ public:
assert(performCleanup && "Already forced cleanup");
{
mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder());
+ cgf.didCallStackSave = oldDidCallStackSave;
cgf.popCleanupBlocks(cleanupStackDepth);
performCleanup = false;
cgf.currentCleanupStackDepth = oldCleanupStackDepth;
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index d30c975..1b85a53 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -744,8 +744,8 @@ static bool shouldUseExternalRttiDescriptor(CIRGenModule &cgm, QualType ty) {
return false;
if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
- const CXXRecordDecl *rd =
- cast<CXXRecordDecl>(recordTy->getOriginalDecl())->getDefinitionOrSelf();
+ const auto *rd =
+ cast<CXXRecordDecl>(recordTy->getDecl())->getDefinitionOrSelf();
if (!rd->hasDefinition())
return false;
@@ -859,9 +859,7 @@ static bool canUseSingleInheritance(const CXXRecordDecl *rd) {
/// IsIncompleteClassType - Returns whether the given record type is incomplete.
static bool isIncompleteClassType(const RecordType *recordTy) {
- return !recordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isCompleteDefinition();
+ return !recordTy->getDecl()->getDefinitionOrSelf()->isCompleteDefinition();
}
/// Returns whether the given type contains an
@@ -939,8 +937,7 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
case Type::Atomic:
// FIXME: GCC treats block pointers as fundamental types?!
case Type::BlockPointer:
- cgm.errorNYI("VTableClassNameForType: __fundamental_type_info");
- break;
+ return "_ZTVN10__cxxabiv123__fundamental_type_infoE";
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
@@ -957,9 +954,8 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
break;
case Type::Record: {
- const CXXRecordDecl *rd =
- cast<CXXRecordDecl>(cast<RecordType>(ty)->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
+ ->getDefinitionOrSelf();
if (!rd->hasDefinition() || !rd->getNumBases()) {
return classTypeInfo;
@@ -1031,8 +1027,8 @@ static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
return cir::GlobalLinkageKind::LinkOnceODRLinkage;
if (const RecordType *record = dyn_cast<RecordType>(ty)) {
- const CXXRecordDecl *rd =
- cast<CXXRecordDecl>(record->getOriginalDecl())->getDefinitionOrSelf();
+ const auto *rd =
+ cast<CXXRecordDecl>(record->getDecl())->getDefinitionOrSelf();
if (rd->hasAttr<WeakAttr>())
return cir::GlobalLinkageKind::WeakODRLinkage;
@@ -1382,9 +1378,8 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
break;
case Type::Record: {
- const auto *rd =
- cast<CXXRecordDecl>(cast<RecordType>(ty)->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
+ ->getDefinitionOrSelf();
if (!rd->hasDefinition() || !rd->getNumBases()) {
// We don't need to emit any fields.
break;
@@ -1651,8 +1646,7 @@ void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,
// Lowering pass to skip passing the trivial function.
//
if (const RecordType *recordTy = clangThrowType->getAs<RecordType>()) {
- CXXRecordDecl *rec =
- cast<CXXRecordDecl>(recordTy->getOriginalDecl()->getDefinition());
+ auto *rec = cast<CXXRecordDecl>(recordTy->getDecl()->getDefinition());
assert(!cir::MissingFeatures::isTrivialCtorOrDtor());
if (!rec->hasTrivialDestructor()) {
cgm.errorNYI("emitThrow: non-trivial destructor");
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 82b1051..57c7a44 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -88,6 +88,8 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
FP80Ty = cir::FP80Type::get(&getMLIRContext());
FP128Ty = cir::FP128Type::get(&getMLIRContext());
+ AllocaInt8PtrTy = cir::PointerType::get(UInt8Ty, cirAllocaAddressSpace);
+
PointerAlignInBytes =
astContext
.toCharUnitsFromBits(
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 3d86f71..ce4ae7e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -1005,7 +1005,7 @@ public:
/*temporary=*/nullptr, OpenACCReductionOperator::Invalid,
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
- privateOp);
+ privateOp, /*reductionCombinerRecipes=*/{});
// TODO: OpenACC: The dialect is going to change in the near future to
// have these be on a different operation, so when that changes, we
// probably need to change these here.
@@ -1046,7 +1046,7 @@ public:
OpenACCReductionOperator::Invalid,
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
- firstPrivateOp);
+ firstPrivateOp, /*reductionCombinerRecipe=*/{});
// TODO: OpenACC: The dialect is going to change in the near future to
// have these be on a different operation, so when that changes, we
@@ -1088,7 +1088,7 @@ public:
/*temporary=*/nullptr, clause.getReductionOp(),
Decl::castToDeclContext(cgf.curFuncDecl), opInfo.origType,
opInfo.bounds.size(), opInfo.boundTypes, opInfo.baseType,
- reductionOp);
+ reductionOp, varRecipe.CombinerRecipes);
operation.addReduction(builder.getContext(), reductionOp, recipe);
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
index 24a5fc2..ce14aa8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
@@ -527,16 +527,142 @@ void OpenACCRecipeBuilderBase::createFirstprivateRecipeCopy(
// doesn't restore it aftewards.
void OpenACCRecipeBuilderBase::createReductionRecipeCombiner(
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
- mlir::acc::ReductionRecipeOp recipe, size_t numBounds) {
+ mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType,
+ llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe> combinerRecipes) {
mlir::Block *block =
createRecipeBlock(recipe.getCombinerRegion(), mainOp.getType(), loc,
numBounds, /*isInit=*/false);
builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
CIRGenFunction::LexicalScope ls(cgf, loc, block);
- mlir::BlockArgument lhsArg = block->getArgument(0);
+ mlir::Value lhsArg = block->getArgument(0);
+ mlir::Value rhsArg = block->getArgument(1);
+ llvm::MutableArrayRef<mlir::BlockArgument> boundsRange =
+ block->getArguments().drop_front(2);
+
+ if (llvm::any_of(combinerRecipes, [](auto &r) { return r.Op == nullptr; })) {
+ cgf.cgm.errorNYI(loc, "OpenACC Reduction combiner not generated");
+ mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0));
+ return;
+ }
+
+ // apply the bounds so that we can get our bounds emitted correctly.
+ for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
+ std::tie(lhsArg, rhsArg) =
+ createBoundsLoop(lhsArg, rhsArg, boundArg, loc, /*inverse=*/false);
+
+ // Emitter for when we know this isn't a struct or array we have to loop
+ // through. This should work for the 'field' once the get-element call has
+ // been made.
+ auto emitSingleCombiner =
+ [&](mlir::Value lhsArg, mlir::Value rhsArg,
+ const OpenACCReductionRecipe::CombinerRecipe &combiner) {
+ mlir::Type elementTy =
+ mlir::cast<cir::PointerType>(lhsArg.getType()).getPointee();
+ CIRGenFunction::DeclMapRevertingRAII declMapRAIILhs{cgf, combiner.LHS};
+ cgf.setAddrOfLocalVar(
+ combiner.LHS, Address{lhsArg, elementTy,
+ cgf.getContext().getDeclAlign(combiner.LHS)});
+ CIRGenFunction::DeclMapRevertingRAII declMapRAIIRhs{cgf, combiner.RHS};
+ cgf.setAddrOfLocalVar(
+ combiner.RHS, Address{rhsArg, elementTy,
+ cgf.getContext().getDeclAlign(combiner.RHS)});
+
+ [[maybe_unused]] mlir::LogicalResult stmtRes =
+ cgf.emitStmt(combiner.Op, /*useCurrentScope=*/true);
+ };
+
+ // Emitter for when we know this is either a non-array or element of an array
+ // (which also shouldn't be an array type?). This function should generate the
+ // initialization code for an entire 'array-element'/non-array, including
+ // diving into each element of a struct (if necessary).
+ auto emitCombiner = [&](mlir::Value lhsArg, mlir::Value rhsArg, QualType ty) {
+ assert(!ty->isArrayType() && "Array type shouldn't get here");
+ if (const auto *rd = ty->getAsRecordDecl()) {
+ if (combinerRecipes.size() == 1 &&
+ cgf.getContext().hasSameType(ty, combinerRecipes[0].LHS->getType())) {
+ // If this is a 'top level' operator on the type we can just emit this
+ // as a simple one.
+ emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
+ } else {
+ // else we have to handle each individual field after after a
+ // get-element.
+ for (const auto &[field, combiner] :
+ llvm::zip_equal(rd->fields(), combinerRecipes)) {
+ mlir::Type fieldType = cgf.convertType(field->getType());
+ auto fieldPtr = cir::PointerType::get(fieldType);
+
+ mlir::Value lhsField = builder.createGetMember(
+ loc, fieldPtr, lhsArg, field->getName(), field->getFieldIndex());
+ mlir::Value rhsField = builder.createGetMember(
+ loc, fieldPtr, rhsArg, field->getName(), field->getFieldIndex());
+
+ emitSingleCombiner(lhsField, rhsField, combiner);
+ }
+ }
+
+ } else {
+ // if this is a single-thing (because we should know this isn't an array,
+ // as Sema wouldn't let us get here), we can just do a normal emit call.
+ emitSingleCombiner(lhsArg, rhsArg, combinerRecipes[0]);
+ }
+ };
+
+ if (const auto *cat = cgf.getContext().getAsConstantArrayType(origType)) {
+ // If we're in an array, we have to emit the combiner for each element of
+ // the array.
+ auto itrTy = mlir::cast<cir::IntType>(cgf.PtrDiffTy);
+ auto itrPtrTy = cir::PointerType::get(itrTy);
+
+ mlir::Value zero =
+ builder.getConstInt(loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), 0);
+ mlir::Value itr =
+ cir::AllocaOp::create(builder, loc, itrPtrTy, itrTy, "itr",
+ cgf.cgm.getSize(cgf.getPointerAlign()));
+ builder.CIRBaseBuilderTy::createStore(loc, zero, itr);
+
+ builder.setInsertionPointAfter(builder.createFor(
+ loc,
+ /*condBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ auto loadItr = cir::LoadOp::create(builder, loc, {itr});
+ mlir::Value arraySize = builder.getConstInt(
+ loc, mlir::cast<cir::IntType>(cgf.PtrDiffTy), cat->getZExtSize());
+ auto cmp = builder.createCompare(loc, cir::CmpOpKind::lt, loadItr,
+ arraySize);
+ builder.createCondition(cmp);
+ },
+ /*bodyBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ auto loadItr = cir::LoadOp::create(builder, loc, {itr});
+ auto lhsElt = builder.getArrayElement(
+ loc, loc, lhsArg, cgf.convertType(cat->getElementType()), loadItr,
+ /*shouldDecay=*/true);
+ auto rhsElt = builder.getArrayElement(
+ loc, loc, rhsArg, cgf.convertType(cat->getElementType()), loadItr,
+ /*shouldDecay=*/true);
+
+ emitCombiner(lhsElt, rhsElt, cat->getElementType());
+ builder.createYield(loc);
+ },
+ /*stepBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ auto loadItr = cir::LoadOp::create(builder, loc, {itr});
+ auto inc = cir::UnaryOp::create(builder, loc, loadItr.getType(),
+ cir::UnaryOpKind::Inc, loadItr);
+ builder.CIRBaseBuilderTy::createStore(loc, inc, itr);
+ builder.createYield(loc);
+ }));
- mlir::acc::YieldOp::create(builder, locEnd, lhsArg);
+ } else if (origType->isArrayType()) {
+ cgf.cgm.errorNYI(loc,
+ "OpenACC Reduction combiner non-constant array recipe");
+ } else {
+ emitCombiner(lhsArg, rhsArg, origType);
+ }
+
+ builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back());
+ mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0));
}
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
index a5da744..745d424 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -64,10 +64,10 @@ protected:
// that this function is not 'insertion point' clean, in that it alters the
// insertion point to be inside of the 'combiner' section of the recipe, but
// doesn't restore it aftewards.
- void createReductionRecipeCombiner(mlir::Location loc, mlir::Location locEnd,
- mlir::Value mainOp,
- mlir::acc::ReductionRecipeOp recipe,
- size_t numBounds);
+ void createReductionRecipeCombiner(
+ mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
+ mlir::acc::ReductionRecipeOp recipe, size_t numBounds, QualType origType,
+ llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe> combinerRecipes);
void createInitRecipe(mlir::Location loc, mlir::Location locEnd,
SourceRange exprRange, mlir::Value mainOp,
@@ -169,7 +169,9 @@ public:
const Expr *varRef, const VarDecl *varRecipe, const VarDecl *temporary,
OpenACCReductionOperator reductionOp, DeclContext *dc, QualType origType,
size_t numBounds, llvm::ArrayRef<QualType> boundTypes, QualType baseType,
- mlir::Value mainOp) {
+ mlir::Value mainOp,
+ llvm::ArrayRef<OpenACCReductionRecipe::CombinerRecipe>
+ reductionCombinerRecipes) {
assert(!varRecipe->getType()->isSpecificBuiltinType(
BuiltinType::ArraySection) &&
"array section shouldn't make it to recipe creation");
@@ -208,7 +210,8 @@ public:
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
origType, /*emitInitExpr=*/true);
- createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds);
+ createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds,
+ origType, reductionCombinerRecipes);
} else {
static_assert(std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>);
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index cfd48a2..5ba64dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -536,7 +536,7 @@ mlir::LogicalResult CIRGenFunction::emitLabel(const clang::LabelDecl &d) {
mlir::Block *currBlock = builder.getBlock();
mlir::Block *labelBlock = currBlock;
- if (!currBlock->empty()) {
+ if (!currBlock->empty() || currBlock->isEntryBlock()) {
{
mlir::OpBuilder::InsertionGuard guard(builder);
labelBlock = builder.createBlock(builder.getBlock()->getParent());
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index 273ec7f..b5612d9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -65,6 +65,9 @@ struct CIRGenTypeCache {
cir::PointerType VoidPtrTy;
cir::PointerType UInt8PtrTy;
+ /// void* in alloca address space
+ cir::PointerType AllocaInt8PtrTy;
+
/// The size and alignment of a pointer into the generic address space.
union {
unsigned char PointerAlignInBytes;
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 2ab1ea0c..d1b91d0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -159,7 +159,7 @@ isSafeToConvert(const RecordDecl *rd, CIRGenTypes &cgt,
for (const clang::CXXBaseSpecifier &i : crd->bases())
if (!isSafeToConvert(i.getType()
->castAs<RecordType>()
- ->getOriginalDecl()
+ ->getDecl()
->getDefinitionOrSelf(),
cgt, alreadyChecked))
return false;
@@ -279,8 +279,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
// Process record types before the type cache lookup.
if (const auto *recordType = dyn_cast<RecordType>(type))
- return convertRecordDeclType(
- recordType->getOriginalDecl()->getDefinitionOrSelf());
+ return convertRecordDeclType(recordType->getDecl()->getDefinitionOrSelf());
// Has the type already been processed?
TypeCacheTy::iterator tci = typeCache.find(ty);
@@ -421,6 +420,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
break;
}
+ case Type::VariableArray: {
+ const VariableArrayType *a = cast<VariableArrayType>(ty);
+ if (a->getIndexTypeCVRQualifiers() != 0)
+ cgm.errorNYI(SourceLocation(), "non trivial array types", type);
+ // VLAs resolve to the innermost element type; this matches
+ // the return of alloca, and there isn't any obviously better choice.
+ resultType = convertTypeForMem(a->getElementType());
+ break;
+ }
+
case Type::IncompleteArray: {
const IncompleteArrayType *arrTy = cast<IncompleteArrayType>(ty);
if (arrTy->getIndexTypeCVRQualifiers() != 0)
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 12837d9..7af3dc1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2901,20 +2901,6 @@ mlir::LogicalResult cir::ThrowOp::verify() {
}
//===----------------------------------------------------------------------===//
-// AtomicCmpXchg
-//===----------------------------------------------------------------------===//
-
-LogicalResult cir::AtomicCmpXchg::verify() {
- mlir::Type pointeeType = getPtr().getType().getPointee();
-
- if (pointeeType != getExpected().getType() ||
- pointeeType != getDesired().getType())
- return emitOpError("ptr, expected and desired types must match");
-
- return success();
-}
-
-//===----------------------------------------------------------------------===//
// TypeInfoAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index f0d73ac..e61b65f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -694,8 +694,8 @@ getLLVMMemOrder(std::optional<cir::MemOrder> memorder) {
llvm_unreachable("unknown memory order");
}
-mlir::LogicalResult CIRToLLVMAtomicCmpXchgLowering::matchAndRewrite(
- cir::AtomicCmpXchg op, OpAdaptor adaptor,
+mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(
+ cir::AtomicCmpXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
mlir::Value expected = adaptor.getExpected();
mlir::Value desired = adaptor.getDesired();
@@ -719,8 +719,8 @@ mlir::LogicalResult CIRToLLVMAtomicCmpXchgLowering::matchAndRewrite(
return mlir::success();
}
-mlir::LogicalResult CIRToLLVMAtomicXchgLowering::matchAndRewrite(
- cir::AtomicXchg op, OpAdaptor adaptor,
+mlir::LogicalResult CIRToLLVMAtomicXchgOpLowering::matchAndRewrite(
+ cir::AtomicXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
assert(!cir::MissingFeatures::atomicSyncScopeID());
mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getMemOrder());
@@ -1793,12 +1793,20 @@ CIRToLLVMGlobalOpLowering::getComdatAttr(cir::GlobalOp &op,
if (!comdatOp) {
builder.setInsertionPointToStart(module.getBody());
comdatOp =
- builder.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
+ mlir::LLVM::ComdatOp::create(builder, module.getLoc(), comdatName);
+ }
+
+ if (auto comdatSelector = comdatOp.lookupSymbol<mlir::LLVM::ComdatSelectorOp>(
+ op.getSymName())) {
+ return mlir::SymbolRefAttr::get(
+ builder.getContext(), comdatName,
+ mlir::FlatSymbolRefAttr::get(comdatSelector.getSymNameAttr()));
}
builder.setInsertionPointToStart(&comdatOp.getBody().back());
- auto selectorOp = builder.create<mlir::LLVM::ComdatSelectorOp>(
- comdatOp.getLoc(), op.getSymName(), mlir::LLVM::comdat::Comdat::Any);
+ auto selectorOp = mlir::LLVM::ComdatSelectorOp::create(
+ builder, comdatOp.getLoc(), op.getSymName(),
+ mlir::LLVM::comdat::Comdat::Any);
return mlir::SymbolRefAttr::get(
builder.getContext(), comdatName,
mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr()));