aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp18
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCXXABI.h16
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenClass.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCleanup.cpp6
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCleanup.h9
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenException.cpp35
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp30
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp132
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp247
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp16
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h10
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp54
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp60
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h109
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenValue.h7
-rw-r--r--clang/lib/CIR/CodeGen/EHScopeStack.h4
16 files changed, 615 insertions, 140 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
index 5f1faab..df42af8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -15,6 +15,7 @@
#include "CIRGenFunction.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
using namespace clang;
@@ -75,3 +76,20 @@ void CIRGenCXXABI::setCXXABIThisValue(CIRGenFunction &cgf,
assert(getThisDecl(cgf) && "no 'this' variable for function");
cgf.cxxabiThisValue = thisPtr;
}
+
+CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *e) {
+ if (!requiresArrayCookie(e))
+ return CharUnits::Zero();
+
+ cgm.errorNYI(e->getSourceRange(), "CIRGenCXXABI::getArrayCookieSize");
+ return CharUnits::Zero();
+}
+
+bool CIRGenCXXABI::requiresArrayCookie(const CXXNewExpr *e) {
+ // If the class's usual deallocation function takes two arguments,
+ // it needs a cookie.
+ if (e->doesUsualArrayDeleteWantSize())
+ return true;
+
+ return e->getAllocatedType().isDestructedType();
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 1dee774..2465a68 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -28,6 +28,8 @@ protected:
CIRGenModule &cgm;
std::unique_ptr<clang::MangleContext> mangleContext;
+ virtual bool requiresArrayCookie(const CXXNewExpr *e);
+
public:
// TODO(cir): make this protected when target-specific CIRGenCXXABIs are
// implemented.
@@ -113,6 +115,7 @@ public:
CIRGenFunction &cgf) = 0;
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
+ virtual void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) = 0;
virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
QualType ty) = 0;
@@ -244,6 +247,19 @@ public:
void setStructorImplicitParamValue(CIRGenFunction &cgf, mlir::Value val) {
cgf.cxxStructorImplicitParamValue = val;
}
+
+ /**************************** Array cookies ******************************/
+
+ /// Returns the extra size required in order to store the array
+ /// cookie for the given new-expression. May return 0 to indicate that no
+ /// array cookie is required.
+ ///
+ /// Several cases are filtered out before this method is called:
+ /// - non-array allocations never need a cookie
+ /// - calls to \::operator new(size_t, void*) never need a cookie
+ ///
+ /// \param E - the new-expression being allocated.
+ virtual CharUnits getArrayCookieSize(const CXXNewExpr *e);
};
/// Creates and Itanium-family ABI
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 9d12a13..8f4377b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -690,7 +690,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
// every temporary created in a default argument expression is sequenced
// before the construction of the next array element, if any.
{
- assert(!cir::MissingFeatures::runCleanupsScope());
+ RunCleanupsScope scope(*this);
// Evaluate the constructor and its arguments in a regular
// partial-destroy cleanup.
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 4d4d10b..8700697 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -28,6 +28,12 @@ using namespace clang::CIRGen;
// CIRGenFunction cleanup related
//===----------------------------------------------------------------------===//
+/// Emits all the code to cause the given temporary to be cleaned up.
+void CIRGenFunction::emitCXXTemporary(const CXXTemporary *temporary,
+ QualType tempType, Address ptr) {
+ pushDestroy(NormalAndEHCleanup, ptr, tempType, destroyCXXObject);
+}
+
//===----------------------------------------------------------------------===//
// EHScopeStack
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.h b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
index a4ec8cc..30f5607 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.h
@@ -104,6 +104,7 @@ public:
bool isNormalCleanup() const { return cleanupBits.isNormalCleanup; }
bool isActive() const { return cleanupBits.isActive; }
+ void setActive(bool isActive) { cleanupBits.isActive = isActive; }
size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
void *getCleanupBuffer() { return this + 1; }
@@ -138,5 +139,13 @@ inline EHScopeStack::iterator EHScopeStack::begin() const {
return iterator(startOfData);
}
+inline EHScopeStack::iterator
+EHScopeStack::find(stable_iterator savePoint) const {
+ assert(savePoint.isValid() && "finding invalid savepoint");
+ assert(savePoint.size <= stable_begin().size &&
+ "finding savepoint after pop");
+ return iterator(endOfBuffer - savePoint.size);
+}
+
} // namespace clang::CIRGen
#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index 7fcb39a..6453843 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -31,11 +31,36 @@ void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) {
if (throwType->isObjCObjectPointerType()) {
cgm.errorNYI("emitCXXThrowExpr ObjCObjectPointerType");
return;
- } else {
- cgm.errorNYI("emitCXXThrowExpr with subExpr");
- return;
}
- } else {
- cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
+
+ cgm.getCXXABI().emitThrow(*this, e);
+ return;
}
+
+ cgm.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true);
+}
+
+void CIRGenFunction::emitAnyExprToExn(const Expr *e, Address addr) {
+ // Make sure the exception object is cleaned up if there's an
+ // exception during initialization.
+ assert(!cir::MissingFeatures::ehCleanupScope());
+
+ // __cxa_allocate_exception returns a void*; we need to cast this
+ // to the appropriate type for the object.
+ mlir::Type ty = convertTypeForMem(e->getType());
+ Address typedAddr = addr.withElementType(builder, ty);
+
+ // From LLVM's codegen:
+ // FIXME: this isn't quite right! If there's a final unelided call
+ // to a copy constructor, then according to [except.terminate]p1 we
+ // must call std::terminate() if that constructor throws, because
+ // technically that copy occurs after the exception expression is
+ // evaluated but before the exception is caught. But the best way
+ // to handle that is to teach EmitAggExpr to do the final copy
+ // differently if it can't be elided.
+ emitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
+ /*isInitializer=*/true);
+
+ // Deactivate the cleanup block.
+ assert(!cir::MissingFeatures::ehCleanupScope());
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 60ccf18..901b937 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -46,6 +46,12 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
return dest;
}
+ void ensureDest(mlir::Location loc, QualType ty) {
+ if (!dest.isIgnored())
+ return;
+ dest = cgf.createAggTemp(ty, loc, "agg.tmp.ensured");
+ }
+
public:
AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)
: cgf(cgf), dest(dest) {}
@@ -96,10 +102,22 @@ public:
Visit(die->getExpr());
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
- assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
+ // Ensure that we have a slot, but if we already do, remember
+ // whether it was externally destructed.
+ bool wasExternallyDestructed = dest.isExternallyDestructed();
+ ensureDest(cgf.getLoc(e->getSourceRange()), e->getType());
+
+ // We're going to push a destructor if there isn't already one.
+ dest.setExternallyDestructed();
+
Visit(e->getSubExpr());
+
+ // Push that destructor we promised.
+ if (!wasExternallyDestructed)
+ cgf.emitCXXTemporary(e->getTemporary(), e->getType(), dest.getAddress());
}
void VisitLambdaExpr(LambdaExpr *e);
+ void VisitExprWithCleanups(ExprWithCleanups *e);
// Stubs -- These should be moved up when they are implemented.
void VisitCastExpr(CastExpr *e) {
@@ -241,11 +259,6 @@ public:
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXStdInitializerListExpr");
}
-
- void VisitExprWithCleanups(ExprWithCleanups *e) {
- cgf.cgm.errorNYI(e->getSourceRange(),
- "AggExprEmitter: VisitExprWithCleanups");
- }
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXScalarValueInitExpr");
@@ -588,6 +601,11 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) {
}
}
+void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
+ CIRGenFunction::RunCleanupsScope cleanups(cgf);
+ Visit(e->getSubExpr());
+}
+
void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index 7989ad2..4eb8ca8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "CIRGenCXXABI.h"
+#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
#include "clang/AST/DeclCXX.h"
@@ -210,6 +211,19 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
}
+static CharUnits calculateCookiePadding(CIRGenFunction &cgf,
+ const CXXNewExpr *e) {
+ if (!e->isArray())
+ return CharUnits::Zero();
+
+ // No cookie is required if the operator new[] being used is the
+ // reserved placement operator new[].
+ if (e->getOperatorNew()->isReservedGlobalPlacementOperator())
+ return CharUnits::Zero();
+
+ return cgf.cgm.getCXXABI().getArrayCookieSize(e);
+}
+
static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
unsigned minElements,
mlir::Value &numElements,
@@ -224,8 +238,98 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
return sizeWithoutCookie;
}
- cgf.cgm.errorNYI(e->getSourceRange(), "emitCXXNewAllocSize: array");
- return {};
+ // The width of size_t.
+ unsigned sizeWidth = cgf.cgm.getDataLayout().getTypeSizeInBits(cgf.SizeTy);
+
+ // The number of elements can be have an arbitrary integer type;
+ // essentially, we need to multiply it by a constant factor, add a
+ // cookie size, and verify that the result is representable as a
+ // size_t. That's just a gloss, though, and it's wrong in one
+ // important way: if the count is negative, it's an error even if
+ // the cookie size would bring the total size >= 0.
+ //
+ // If the array size is constant, Sema will have prevented negative
+ // values and size overflow.
+
+ // Compute the constant factor.
+ llvm::APInt arraySizeMultiplier(sizeWidth, 1);
+ while (const ConstantArrayType *cat =
+ cgf.getContext().getAsConstantArrayType(type)) {
+ type = cat->getElementType();
+ arraySizeMultiplier *= cat->getSize();
+ }
+
+ CharUnits typeSize = cgf.getContext().getTypeSizeInChars(type);
+ llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity());
+ typeSizeMultiplier *= arraySizeMultiplier;
+
+ // Figure out the cookie size.
+ llvm::APInt cookieSize(sizeWidth,
+ calculateCookiePadding(cgf, e).getQuantity());
+
+ // This will be a size_t.
+ mlir::Value size;
+
+ // Emit the array size expression.
+ // We multiply the size of all dimensions for NumElements.
+ // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
+ const Expr *arraySize = *e->getArraySize();
+ mlir::Attribute constNumElements =
+ ConstantEmitter(cgf.cgm, &cgf)
+ .emitAbstract(arraySize, arraySize->getType());
+ if (constNumElements) {
+ // Get an APInt from the constant
+ const llvm::APInt &count =
+ mlir::cast<cir::IntAttr>(constNumElements).getValue();
+
+ unsigned numElementsWidth = count.getBitWidth();
+
+ // The equivalent code in CodeGen/CGExprCXX.cpp handles these cases as
+ // overflow, but that should never happen. The size argument is implicitly
+ // cast to a size_t, so it can never be negative and numElementsWidth will
+ // always equal sizeWidth.
+ assert(!count.isNegative() && "Expected non-negative array size");
+ assert(numElementsWidth == sizeWidth &&
+ "Expected a size_t array size constant");
+
+ // Okay, compute a count at the right width.
+ llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
+
+ // Scale numElements by that. This might overflow, but we don't
+ // care because it only overflows if allocationSize does too, and
+ // if that overflows then we shouldn't use this.
+ // This emits a constant that may not be used, but we can't tell here
+ // whether it will be needed or not.
+ numElements =
+ cgf.getBuilder().getConstInt(loc, adjustedCount * arraySizeMultiplier);
+
+ // Compute the size before cookie, and track whether it overflowed.
+ bool overflow;
+ llvm::APInt allocationSize =
+ adjustedCount.umul_ov(typeSizeMultiplier, overflow);
+
+ // Sema prevents us from hitting this case
+ assert(!overflow && "Overflow in array allocation size");
+
+ // Add in the cookie, and check whether it's overflowed.
+ if (cookieSize != 0) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitCXXNewAllocSize: array cookie");
+ }
+
+ size = cgf.getBuilder().getConstInt(loc, allocationSize);
+ } else {
+ // TODO: Handle the variable size case
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitCXXNewAllocSize: variable array size");
+ }
+
+ if (cookieSize == 0)
+ sizeWithoutCookie = size;
+ else
+ assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?");
+
+ return size;
}
static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
@@ -254,13 +358,26 @@ static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
llvm_unreachable("bad evaluation kind");
}
+void CIRGenFunction::emitNewArrayInitializer(
+ const CXXNewExpr *e, QualType elementType, mlir::Type elementTy,
+ Address beginPtr, mlir::Value numElements,
+ mlir::Value allocSizeWithoutCookie) {
+ // If we have a type with trivial initialization and no initializer,
+ // there's nothing to do.
+ if (!e->hasInitializer())
+ return;
+
+ cgm.errorNYI(e->getSourceRange(), "emitNewArrayInitializer");
+}
+
static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,
QualType elementType, mlir::Type elementTy,
Address newPtr, mlir::Value numElements,
mlir::Value allocSizeWithoutCookie) {
assert(!cir::MissingFeatures::generateDebugInfo());
if (e->isArray()) {
- cgf.cgm.errorNYI(e->getSourceRange(), "emitNewInitializer: array");
+ cgf.emitNewArrayInitializer(e, elementType, elementTy, newPtr, numElements,
+ allocSizeWithoutCookie);
} else if (const Expr *init = e->getInitializer()) {
storeAnyExprIntoOneUnit(cgf, init, e->getAllocatedType(), newPtr,
AggValueSlot::DoesNotOverlap);
@@ -536,7 +653,14 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
if (allocSize != allocSizeWithoutCookie)
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");
- mlir::Type elementTy = convertTypeForMem(allocType);
+ mlir::Type elementTy;
+ if (e->isArray()) {
+ // For array new, use the allocated type to handle multidimensional arrays
+ // correctly
+ elementTy = convertTypeForMem(e->getAllocatedType());
+ } else {
+ elementTy = convertTypeForMem(allocType);
+ }
Address result = builder.createElementBitCast(getLoc(e->getSourceRange()),
allocation, elementTy);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index e20a4fc..59aa257 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -118,6 +118,9 @@ class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
/// non-packed LLVM struct will give the correct layout.
bool naturalLayout = true;
+ bool split(size_t index, CharUnits hint);
+ std::optional<size_t> splitAt(CharUnits pos);
+
static mlir::Attribute buildFrom(CIRGenModule &cgm, ArrayRef<Element> elems,
CharUnits startOffset, CharUnits size,
bool naturalLayout, mlir::Type desiredTy,
@@ -137,6 +140,10 @@ public:
/// Update or overwrite the bits starting at \p offsetInBits with \p bits.
bool addBits(llvm::APInt bits, uint64_t offsetInBits, bool allowOverwrite);
+ /// Attempt to condense the value starting at \p offset to a constant of type
+ /// \p desiredTy.
+ void condense(CharUnits offset, mlir::Type desiredTy);
+
/// Produce a constant representing the entire accumulated value, ideally of
/// the specified type. If \p allowOversized, the constant might be larger
/// than implied by \p desiredTy (eg, if there is a flexible array member).
@@ -176,6 +183,195 @@ bool ConstantAggregateBuilder::add(mlir::TypedAttr typedAttr, CharUnits offset,
return false;
}
+bool ConstantAggregateBuilder::addBits(llvm::APInt bits, uint64_t offsetInBits,
+ bool allowOverwrite) {
+ const ASTContext &astContext = cgm.getASTContext();
+ const uint64_t charWidth = astContext.getCharWidth();
+ mlir::Type charTy = cgm.getBuilder().getUIntNTy(charWidth);
+
+ // Offset of where we want the first bit to go within the bits of the
+ // current char.
+ unsigned offsetWithinChar = offsetInBits % charWidth;
+
+ // We split bit-fields up into individual bytes. Walk over the bytes and
+ // update them.
+ for (CharUnits offsetInChars =
+ astContext.toCharUnitsFromBits(offsetInBits - offsetWithinChar);
+ /**/; ++offsetInChars) {
+ // Number of bits we want to fill in this char.
+ unsigned wantedBits =
+ std::min((uint64_t)bits.getBitWidth(), charWidth - offsetWithinChar);
+
+ // Get a char containing the bits we want in the right places. The other
+ // bits have unspecified values.
+ llvm::APInt bitsThisChar = bits;
+ if (bitsThisChar.getBitWidth() < charWidth)
+ bitsThisChar = bitsThisChar.zext(charWidth);
+ if (cgm.getDataLayout().isBigEndian()) {
+ // Figure out how much to shift by. We may need to left-shift if we have
+ // less than one byte of Bits left.
+ int shift = bits.getBitWidth() - charWidth + offsetWithinChar;
+ if (shift > 0)
+ bitsThisChar.lshrInPlace(shift);
+ else if (shift < 0)
+ bitsThisChar = bitsThisChar.shl(-shift);
+ } else {
+ bitsThisChar = bitsThisChar.shl(offsetWithinChar);
+ }
+ if (bitsThisChar.getBitWidth() > charWidth)
+ bitsThisChar = bitsThisChar.trunc(charWidth);
+
+ if (wantedBits == charWidth) {
+ // Got a full byte: just add it directly.
+ add(cir::IntAttr::get(charTy, bitsThisChar), offsetInChars,
+ allowOverwrite);
+ } else {
+ // Partial byte: update the existing integer if there is one. If we
+ // can't split out a 1-CharUnit range to update, then we can't add
+ // these bits and fail the entire constant emission.
+ std::optional<size_t> firstElemToUpdate = splitAt(offsetInChars);
+ if (!firstElemToUpdate)
+ return false;
+ std::optional<size_t> lastElemToUpdate =
+ splitAt(offsetInChars + CharUnits::One());
+ if (!lastElemToUpdate)
+ return false;
+ assert(*lastElemToUpdate - *firstElemToUpdate < 2 &&
+ "should have at most one element covering one byte");
+
+ // Figure out which bits we want and discard the rest.
+ llvm::APInt updateMask(charWidth, 0);
+ if (cgm.getDataLayout().isBigEndian())
+ updateMask.setBits(charWidth - offsetWithinChar - wantedBits,
+ charWidth - offsetWithinChar);
+ else
+ updateMask.setBits(offsetWithinChar, offsetWithinChar + wantedBits);
+ bitsThisChar &= updateMask;
+ bool isNull = false;
+ if (*firstElemToUpdate < elements.size()) {
+ auto firstEltToUpdate =
+ mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element);
+ isNull = firstEltToUpdate && firstEltToUpdate.isNullValue();
+ }
+
+ if (*firstElemToUpdate == *lastElemToUpdate || isNull) {
+ // All existing bits are either zero or undef.
+ add(cir::IntAttr::get(charTy, bitsThisChar), offsetInChars,
+ /*allowOverwrite*/ true);
+ } else {
+ cir::IntAttr ci =
+ mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element);
+ // In order to perform a partial update, we need the existing bitwise
+ // value, which we can only extract for a constant int.
+ if (!ci)
+ return false;
+ // Because this is a 1-CharUnit range, the constant occupying it must
+ // be exactly one CharUnit wide.
+ assert(ci.getBitWidth() == charWidth && "splitAt failed");
+ assert((!(ci.getValue() & updateMask) || allowOverwrite) &&
+ "unexpectedly overwriting bitfield");
+ bitsThisChar |= (ci.getValue() & ~updateMask);
+ elements[*firstElemToUpdate].element =
+ cir::IntAttr::get(charTy, bitsThisChar);
+ }
+ }
+
+ // Stop if we've added all the bits.
+ if (wantedBits == bits.getBitWidth())
+ break;
+
+ // Remove the consumed bits from Bits.
+ if (!cgm.getDataLayout().isBigEndian())
+ bits.lshrInPlace(wantedBits);
+ bits = bits.trunc(bits.getBitWidth() - wantedBits);
+
+ // The remaining bits go at the start of the following bytes.
+ offsetWithinChar = 0;
+ }
+
+ return true;
+}
+
+/// Returns a position within elements such that all elements
+/// before the returned index end before pos and all elements at or after
+/// the returned index begin at or after pos. Splits elements as necessary
+/// to ensure this. Returns std::nullopt if we find something we can't split.
+std::optional<size_t> ConstantAggregateBuilder::splitAt(CharUnits pos) {
+ if (pos >= size)
+ return elements.size();
+
+ while (true) {
+ // Find the first element that starts after pos.
+ Element *iter =
+ llvm::upper_bound(elements, pos, [](CharUnits pos, const Element &elt) {
+ return pos < elt.offset;
+ });
+
+ if (iter == elements.begin())
+ return 0;
+
+ size_t index = iter - elements.begin() - 1;
+ const Element &elt = elements[index];
+
+ // If we already have an element starting at pos, we're done.
+ if (elt.offset == pos)
+ return index;
+
+ // Check for overlap with the element that starts before pos.
+ CharUnits eltEnd = elt.offset + getSize(elt.element);
+ if (eltEnd <= pos)
+ return index + 1;
+
+ // Try to decompose it into smaller constants.
+ if (!split(index, pos))
+ return std::nullopt;
+ }
+}
+
+/// Split the constant at index, if possible. Return true if we did.
+/// Hint indicates the location at which we'd like to split, but may be
+/// ignored.
+bool ConstantAggregateBuilder::split(size_t index, CharUnits hint) {
+ cgm.errorNYI("split constant at index");
+ return false;
+}
+
+void ConstantAggregateBuilder::condense(CharUnits offset,
+ mlir::Type desiredTy) {
+ CharUnits desiredSize = getSize(desiredTy);
+
+ std::optional<size_t> firstElemToReplace = splitAt(offset);
+ if (!firstElemToReplace)
+ return;
+ size_t first = *firstElemToReplace;
+
+ std::optional<size_t> lastElemToReplace = splitAt(offset + desiredSize);
+ if (!lastElemToReplace)
+ return;
+ size_t last = *lastElemToReplace;
+
+ size_t length = last - first;
+ if (length == 0)
+ return;
+
+ if (length == 1 && elements[first].offset == offset &&
+ getSize(elements[first].element) == desiredSize) {
+ cgm.errorNYI("re-wrapping single element records");
+ return;
+ }
+
+ // Build a new constant from the elements in the range.
+ SmallVector<Element> subElems(elements.begin() + first,
+ elements.begin() + last);
+ mlir::Attribute replacement =
+ buildFrom(cgm, subElems, offset, desiredSize,
+ /*naturalLayout=*/false, desiredTy, false);
+
+ // Replace the range with the condensed constant.
+ Element newElt(mlir::cast<mlir::TypedAttr>(replacement), offset);
+ replace(elements, first, last, {newElt});
+}
+
mlir::Attribute
ConstantAggregateBuilder::buildFrom(CIRGenModule &cgm, ArrayRef<Element> elems,
CharUnits startOffset, CharUnits size,
@@ -301,6 +497,9 @@ private:
bool appendBytes(CharUnits fieldOffsetInChars, mlir::TypedAttr initCst,
bool allowOverwrite = false);
+ bool appendBitField(const FieldDecl *field, uint64_t fieldOffset,
+ cir::IntAttr ci, bool allowOverwrite = false);
+
bool build(InitListExpr *ile, bool allowOverwrite);
bool build(const APValue &val, const RecordDecl *rd, bool isPrimaryBase,
const CXXRecordDecl *vTableClass, CharUnits baseOffset);
@@ -325,6 +524,30 @@ bool ConstRecordBuilder::appendBytes(CharUnits fieldOffsetInChars,
return builder.add(initCst, startOffset + fieldOffsetInChars, allowOverwrite);
}
+bool ConstRecordBuilder::appendBitField(const FieldDecl *field,
+ uint64_t fieldOffset, cir::IntAttr ci,
+ bool allowOverwrite) {
+ const CIRGenRecordLayout &rl =
+ cgm.getTypes().getCIRGenRecordLayout(field->getParent());
+ const CIRGenBitFieldInfo &info = rl.getBitFieldInfo(field);
+ llvm::APInt fieldValue = ci.getValue();
+
+ // Promote the size of FieldValue if necessary
+ // FIXME: This should never occur, but currently it can because initializer
+ // constants are cast to bool, and because clang is not enforcing bitfield
+ // width limits.
+ if (info.size > fieldValue.getBitWidth())
+ fieldValue = fieldValue.zext(info.size);
+
+ // Truncate the size of FieldValue to the bit field size.
+ if (info.size < fieldValue.getBitWidth())
+ fieldValue = fieldValue.trunc(info.size);
+
+ return builder.addBits(fieldValue,
+ cgm.getASTContext().toBits(startOffset) + fieldOffset,
+ allowOverwrite);
+}
+
bool ConstRecordBuilder::build(InitListExpr *ile, bool allowOverwrite) {
RecordDecl *rd = ile->getType()
->castAs<clang::RecordType>()
@@ -407,12 +630,14 @@ bool ConstRecordBuilder::build(InitListExpr *ile, bool allowOverwrite) {
} else {
// Otherwise we have a bitfield.
if (auto constInt = dyn_cast<cir::IntAttr>(eltInit)) {
- assert(!cir::MissingFeatures::bitfields());
- cgm.errorNYI(field->getSourceRange(), "bitfields");
+ if (!appendBitField(field, layout.getFieldOffset(index), constInt,
+ allowOverwrite))
+ return false;
+ } else {
+ // We are trying to initialize a bitfield with a non-trivial constant,
+ // this must require run-time code.
+ return false;
}
- // We are trying to initialize a bitfield with a non-trivial constant,
- // this must require run-time code.
- return false;
}
}
@@ -510,8 +735,16 @@ bool ConstRecordBuilder::build(const APValue &val, const RecordDecl *rd,
if (field->hasAttr<NoUniqueAddressAttr>())
allowOverwrite = true;
} else {
- assert(!cir::MissingFeatures::bitfields());
- cgm.errorNYI(field->getSourceRange(), "bitfields");
+ // Otherwise we have a bitfield.
+ if (auto constInt = dyn_cast<cir::IntAttr>(eltInit)) {
+ if (!appendBitField(field, layout.getFieldOffset(index) + offsetBits,
+ constInt, allowOverwrite))
+ return false;
+ } else {
+ // We are trying to initialize a bitfield with a non-trivial constant,
+ // this must require run-time code.
+ return false;
+ }
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 768d75d..5d3496a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1099,15 +1099,17 @@ public:
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
- b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
+ mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
+ lexScope.forceCleanup();
+ cir::YieldOp::create(b, loc, res);
},
/*falseBuilder*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
- auto res = b.create<cir::ConstantOp>(loc, builder.getFalseAttr());
- b.create<cir::YieldOp>(loc, res.getRes());
+ auto res = cir::ConstantOp::create(b, loc, builder.getFalseAttr());
+ cir::YieldOp::create(b, loc, res.getRes());
});
return maybePromoteBoolResult(resOp.getResult(), resTy);
}
@@ -1143,15 +1145,17 @@ public:
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
- auto res = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
- b.create<cir::YieldOp>(loc, res.getRes());
+ auto res = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
+ cir::YieldOp::create(b, loc, res.getRes());
},
/*falseBuilder*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
- b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
+ mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
+ lexScope.forceCleanup();
+ cir::YieldOp::create(b, loc, res);
});
return maybePromoteBoolResult(resOp.getResult(), resTy);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index dfd9d2c..a60efe1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1090,6 +1090,8 @@ public:
/// even if no aggregate location is provided.
RValue emitAnyExprToTemp(const clang::Expr *e);
+ void emitAnyExprToExn(const Expr *e, Address addr);
+
void emitArrayDestroy(mlir::Value begin, mlir::Value numElements,
QualType elementType, CharUnits elementAlign,
Destroyer *destroyer);
@@ -1252,12 +1254,20 @@ public:
mlir::Value emitCXXNewExpr(const CXXNewExpr *e);
+ void emitNewArrayInitializer(const CXXNewExpr *E, QualType ElementType,
+ mlir::Type ElementTy, Address BeginPtr,
+ mlir::Value NumElements,
+ mlir::Value AllocSizeWithoutCookie);
+
RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,
const CXXMethodDecl *md,
ReturnValueSlot returnValue);
RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);
+ void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType,
+ Address ptr);
+
void emitCXXThrowExpr(const CXXThrowExpr *e);
void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index debea8af..0418174 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -70,6 +70,7 @@ public:
QualType thisTy) override;
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
+ void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
CXXDtorType dt) const override {
@@ -1544,6 +1545,59 @@ void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
}
}
+void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,
+ const CXXThrowExpr *e) {
+ // This differs a bit from LLVM codegen, CIR has native operations for some
+ // cxa functions, and defers allocation size computation, always pass the dtor
+ // symbol, etc. CIRGen also does not use getAllocateExceptionFn / getThrowFn.
+
+ // Now allocate the exception object.
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ QualType clangThrowType = e->getSubExpr()->getType();
+ cir::PointerType throwTy =
+ builder.getPointerTo(cgf.convertType(clangThrowType));
+ uint64_t typeSize =
+ cgf.getContext().getTypeSizeInChars(clangThrowType).getQuantity();
+ mlir::Location subExprLoc = cgf.getLoc(e->getSubExpr()->getSourceRange());
+
+ // Defer computing allocation size to some later lowering pass.
+ mlir::TypedValue<cir::PointerType> exceptionPtr =
+ cir::AllocExceptionOp::create(builder, subExprLoc, throwTy,
+ builder.getI64IntegerAttr(typeSize))
+ .getAddr();
+
+ // Build expression and store its result into exceptionPtr.
+ CharUnits exnAlign = cgf.getContext().getExnObjectAlignment();
+ cgf.emitAnyExprToExn(e->getSubExpr(), Address(exceptionPtr, exnAlign));
+
+ // Get the RTTI symbol address.
+ auto typeInfo = mlir::cast<cir::GlobalViewAttr>(
+ cgm.getAddrOfRTTIDescriptor(subExprLoc, clangThrowType,
+ /*forEH=*/true));
+ assert(!typeInfo.getIndices() && "expected no indirection");
+
+ // The address of the destructor.
+ //
+ // Note: LLVM codegen already optimizes out the dtor if the
+ // type is a record with trivial dtor (by passing down a
+ // null dtor). In CIR, we forward this info and allow for
+ // Lowering pass to skip passing the trivial function.
+ //
+ if (const RecordType *recordTy = clangThrowType->getAs<RecordType>()) {
+ CXXRecordDecl *rec =
+ cast<CXXRecordDecl>(recordTy->getOriginalDecl()->getDefinition());
+ assert(!cir::MissingFeatures::isTrivialCtorOrDtor());
+ if (!rec->hasTrivialDestructor()) {
+ cgm.errorNYI("emitThrow: non-trivial destructor");
+ return;
+ }
+ }
+
+ // Now throw the exception.
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol());
+}
+
CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
switch (cgm.getASTContext().getCXXABIKind()) {
case TargetCXXABI::GenericItanium:
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
index bbc45e5..24a5fc2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
@@ -221,10 +221,9 @@ mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
return initialAlloca;
}
-mlir::Value
-OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
- mlir::Value bound,
- mlir::Location loc, bool inverse) {
+std::pair<mlir::Value, mlir::Value> OpenACCRecipeBuilderBase::createBoundsLoop(
+ mlir::Value subscriptedValue, mlir::Value subscriptedValue2,
+ mlir::Value bound, mlir::Location loc, bool inverse) {
mlir::Operation *bodyInsertLoc;
mlir::Type itrTy = cgf.cgm.convertType(cgf.getContext().UnsignedLongLongTy);
@@ -249,7 +248,6 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
return cir::PtrStrideOp::create(builder, loc, eltLoad.getType(), eltLoad,
idxLoad);
-
};
auto forStmtBuilder = [&]() {
@@ -303,6 +301,8 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
if (subscriptedValue)
subscriptedValue = doSubscriptOp(subscriptedValue, load);
+ if (subscriptedValue2)
+ subscriptedValue2 = doSubscriptOp(subscriptedValue2, load);
bodyInsertLoc = builder.createYield(loc);
},
/*stepBuilder=*/
@@ -325,7 +325,7 @@ OpenACCRecipeBuilderBase::createBoundsLoop(mlir::Value subscriptedValue,
// Leave the insertion point to be inside the body, so we can loop over
// these things.
builder.setInsertionPoint(bodyInsertLoc);
- return subscriptedValue;
+ return {subscriptedValue, subscriptedValue2};
}
mlir::acc::ReductionOperator
@@ -434,7 +434,7 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
mlir::Location loc, mlir::Location locEnd, SourceRange exprRange,
mlir::Value mainOp, mlir::Region &recipeInitRegion, size_t numBounds,
llvm::ArrayRef<QualType> boundTypes, const VarDecl *allocaDecl,
- QualType origType) {
+ QualType origType, bool emitInitExpr) {
assert(allocaDecl && "Required recipe variable not set?");
CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, allocaDecl};
@@ -464,14 +464,15 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
// initialize this variable correctly.
CIRGenFunction::AutoVarEmission tempDeclEmission =
cgf.emitAutoVarAlloca(*allocaDecl, builder.saveInsertionPoint());
- cgf.emitAutoVarInit(tempDeclEmission);
+ if (emitInitExpr)
+ cgf.emitAutoVarInit(tempDeclEmission);
} else {
mlir::Value alloca = makeBoundsAlloca(
block, exprRange, loc, allocaDecl->getName(), numBounds, boundTypes);
// If the initializer is trivial, there is nothing to do here, so save
// ourselves some effort.
- if (allocaDecl->getInit() &&
+ if (emitInitExpr && allocaDecl->getInit() &&
(!cgf.isTrivialInitializer(allocaDecl->getInit()) ||
cgf.getContext().getLangOpts().getTrivialAutoVarInit() !=
LangOptions::TrivialAutoVarInitKind::Uninitialized))
@@ -484,35 +485,42 @@ void OpenACCRecipeBuilderBase::createInitRecipe(
void OpenACCRecipeBuilderBase::createFirstprivateRecipeCopy(
mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
- CIRGenFunction::AutoVarEmission tempDeclEmission,
- mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
- const VarDecl *temporary) {
- mlir::Block *block =
- createRecipeBlock(recipe.getCopyRegion(), mainOp.getType(), loc,
- /*numBounds=*/0, /*isInit=*/false);
- builder.setInsertionPointToEnd(&recipe.getCopyRegion().back());
+ const VarDecl *allocaDecl, const VarDecl *temporary,
+ mlir::Region &copyRegion, size_t numBounds) {
+ mlir::Block *block = createRecipeBlock(copyRegion, mainOp.getType(), loc,
+ numBounds, /*isInit=*/false);
+ builder.setInsertionPointToEnd(&copyRegion.back());
CIRGenFunction::LexicalScope ls(cgf, loc, block);
- mlir::BlockArgument fromArg = block->getArgument(0);
- mlir::BlockArgument toArg = block->getArgument(1);
+ mlir::Value fromArg = block->getArgument(0);
+ mlir::Value toArg = block->getArgument(1);
- mlir::Type elementTy =
- mlir::cast<cir::PointerType>(mainOp.getType()).getPointee();
+ llvm::MutableArrayRef<mlir::BlockArgument> boundsRange =
+ block->getArguments().drop_front(2);
- // Set the address of the emission to be the argument, so that we initialize
- // that instead of the variable in the other block.
- tempDeclEmission.setAllocatedAddress(
- Address{toArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
+ for (mlir::BlockArgument boundArg : llvm::reverse(boundsRange))
+ std::tie(fromArg, toArg) =
+ createBoundsLoop(fromArg, toArg, boundArg, loc, /*inverse=*/false);
+
+ // Set up the 'to' address.
+ mlir::Type elementTy =
+ mlir::cast<cir::PointerType>(toArg.getType()).getPointee();
+ CIRGenFunction::AutoVarEmission tempDeclEmission(*allocaDecl);
tempDeclEmission.emittedAsOffload = true;
+ tempDeclEmission.setAllocatedAddress(
+ Address{toArg, elementTy, cgf.getContext().getDeclAlign(allocaDecl)});
+ // Set up the 'from' address from the temporary.
CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, temporary};
cgf.setAddrOfLocalVar(
temporary,
- Address{fromArg, elementTy, cgf.getContext().getDeclAlign(varRecipe)});
-
+ Address{fromArg, elementTy, cgf.getContext().getDeclAlign(allocaDecl)});
cgf.emitAutoVarInit(tempDeclEmission);
+
+ builder.setInsertionPointToEnd(&copyRegion.back());
mlir::acc::YieldOp::create(builder, locEnd);
}
+
// This function generates the 'combiner' section for a reduction recipe. Note
// 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
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
index 21707ad..a5da744 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h
@@ -49,14 +49,16 @@ protected:
// Creates a loop through an 'acc.bounds', leaving the 'insertion' point to be
// the inside of the loop body. Traverses LB->UB UNLESS `inverse` is set.
// Returns the 'subscriptedValue' changed with the new bounds subscript.
+ std::pair<mlir::Value, mlir::Value>
+ createBoundsLoop(mlir::Value subscriptedValue, mlir::Value subscriptedValue2,
+ mlir::Value bound, mlir::Location loc, bool inverse);
+
mlir::Value createBoundsLoop(mlir::Value subscriptedValue, mlir::Value bound,
- mlir::Location loc, bool inverse);
+ mlir::Location loc, bool inverse) {
+ return createBoundsLoop(subscriptedValue, {}, bound, loc, inverse).first;
+ }
+
mlir::acc::ReductionOperator convertReductionOp(OpenACCReductionOperator op);
- void createFirstprivateRecipeCopy(
- mlir::Location loc, mlir::Location locEnd, mlir::Value mainOp,
- CIRGenFunction::AutoVarEmission tempDeclEmission,
- mlir::acc::FirstprivateRecipeOp recipe, const VarDecl *varRecipe,
- const VarDecl *temporary);
// This function generates the 'combiner' section for a reduction recipe. Note
// that this function is not 'insertion point' clean, in that it alters the
@@ -66,11 +68,19 @@ protected:
mlir::Value mainOp,
mlir::acc::ReductionRecipeOp recipe,
size_t numBounds);
+
void createInitRecipe(mlir::Location loc, mlir::Location locEnd,
SourceRange exprRange, mlir::Value mainOp,
mlir::Region &recipeInitRegion, size_t numBounds,
llvm::ArrayRef<QualType> boundTypes,
- const VarDecl *allocaDecl, QualType origType);
+ const VarDecl *allocaDecl, QualType origType,
+ bool emitInitExpr);
+
+ void createFirstprivateRecipeCopy(mlir::Location loc, mlir::Location locEnd,
+ mlir::Value mainOp,
+ const VarDecl *allocaDecl,
+ const VarDecl *temporary,
+ mlir::Region &copyRegion, size_t numBounds);
void createRecipeDestroySection(mlir::Location loc, mlir::Location locEnd,
mlir::Value mainOp, CharUnits alignment,
@@ -150,63 +160,6 @@ class OpenACCRecipeBuilder : OpenACCRecipeBuilderBase {
return recipeName;
}
- // Create the 'init' section of the recipe, including the 'copy' section for
- // 'firstprivate'. Note that this function is not 'insertion point' clean, in
- // that it alters the insertion point to be inside of the 'destroy' section of
- // the recipe, but doesn't restore it aftewards.
- void createRecipeInitCopy(mlir::Location loc, mlir::Location locEnd,
- SourceRange exprRange, mlir::Value mainOp,
- RecipeTy recipe, const VarDecl *varRecipe,
- const VarDecl *temporary) {
- // TODO: OpenACC: when we get the 'pointer' variants for
- // firstprivate/reduction, this probably should be removed/split into
- // functions for the BuilderBase.
- assert(varRecipe && "Required recipe variable not set?");
-
- CIRGenFunction::AutoVarEmission tempDeclEmission{
- CIRGenFunction::AutoVarEmission::invalid()};
- CIRGenFunction::DeclMapRevertingRAII declMapRAII{cgf, varRecipe};
-
- // Do the 'init' section of the recipe IR, which does an alloca, then the
- // initialization (except for firstprivate).
- mlir::Block *block =
- createRecipeBlock(recipe.getInitRegion(), mainOp.getType(), loc,
- /*numBounds=*/0, /*isInit=*/true);
- builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
- CIRGenFunction::LexicalScope ls(cgf, loc, block);
-
- tempDeclEmission =
- cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint());
-
- // 'firstprivate' doesn't do its initialization in the 'init' section,
- // instead it does it in the 'copy' section. SO, only do 'init' here for
- // reduction.
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::ReductionRecipeOp>) {
- // Unlike Private, the recipe here is always required as it has to do
- // init, not just 'default' init.
- if (!varRecipe->getInit())
- cgf.cgm.errorNYI(exprRange, "reduction init recipe");
- cgf.emitAutoVarInit(tempDeclEmission);
- }
-
- mlir::acc::YieldOp::create(builder, locEnd);
-
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
- if (!varRecipe->getInit()) {
- // If we don't have any initialization recipe, we failed during Sema to
- // initialize this correctly. If we disable the
- // Sema::TentativeAnalysisScopes in SemaOpenACC::CreateInitRecipe, it'll
- // emit an error to tell us. However, emitting those errors during
- // production is a violation of the standard, so we cannot do them.
- cgf.cgm.errorNYI(
- exprRange, "firstprivate copy-init recipe not properly generated");
- }
-
- createFirstprivateRecipeCopy(loc, locEnd, mainOp, tempDeclEmission,
- recipe, varRecipe, temporary);
- }
- }
-
public:
OpenACCRecipeBuilder(CIRGen::CIRGenFunction &cgf,
CIRGen::CIRGenBuilderTy &builder)
@@ -221,19 +174,6 @@ public:
BuiltinType::ArraySection) &&
"array section shouldn't make it to recipe creation");
- // TODO: OpenACC: This is a bit of a hackery to get this to not change for
- // the non-private recipes. This will be removed soon, when we get this
- // 'right' for firstprivate and reduction.
- if constexpr (std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>) {
- if (numBounds) {
- cgf.cgm.errorNYI(varRef->getSourceRange(),
- "firstprivate-init with bounds");
- }
- boundTypes = {};
- numBounds = 0;
- origType = baseType;
- }
-
mlir::ModuleOp mod = builder.getBlock()
->getParent()
->template getParentOfType<mlir::ModuleOp>();
@@ -262,21 +202,20 @@ public:
if constexpr (std::is_same_v<RecipeTy, mlir::acc::PrivateRecipeOp>) {
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
- origType);
+ origType, /*emitInitExpr=*/true);
} else if constexpr (std::is_same_v<RecipeTy,
mlir::acc::ReductionRecipeOp>) {
createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
- origType);
+ origType, /*emitInitExpr=*/true);
createReductionRecipeCombiner(loc, locEnd, mainOp, recipe, numBounds);
} else {
static_assert(std::is_same_v<RecipeTy, mlir::acc::FirstprivateRecipeOp>);
- // TODO: OpenACC: we probably want this to call createInitRecipe as well,
- // but do so in a way that omits the 'initialization', so that we can do
- // it separately, since it belongs in the 'copy' region. It also might
- // need a way of getting the tempDeclEmission out of it for that purpose.
- createRecipeInitCopy(loc, locEnd, varRef->getSourceRange(), mainOp,
- recipe, varRecipe, temporary);
+ createInitRecipe(loc, locEnd, varRef->getSourceRange(), mainOp,
+ recipe.getInitRegion(), numBounds, boundTypes, varRecipe,
+ origType, /*emitInitExpr=*/false);
+ createFirstprivateRecipeCopy(loc, locEnd, mainOp, varRecipe, temporary,
+ recipe.getCopyRegion(), numBounds);
}
if (origType.isDestructedType())
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index ea8625a..25b6ecb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -371,6 +371,13 @@ public:
mayOverlap, isZeroed);
}
+ IsDestructed_t isExternallyDestructed() const {
+ return IsDestructed_t(destructedFlag);
+ }
+ void setExternallyDestructed(bool destructed = true) {
+ destructedFlag = destructed;
+ }
+
clang::Qualifiers getQualifiers() const { return quals; }
Address getAddress() const { return addr; }
diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h b/clang/lib/CIR/CodeGen/EHScopeStack.h
index c87a6ef..66c1f76 100644
--- a/clang/lib/CIR/CodeGen/EHScopeStack.h
+++ b/clang/lib/CIR/CodeGen/EHScopeStack.h
@@ -175,6 +175,10 @@ public:
return stable_iterator(endOfBuffer - startOfData);
}
+ /// Turn a stable reference to a scope depth into a unstable pointer
+ /// to the EH stack.
+ iterator find(stable_iterator savePoint) const;
+
/// Create a stable reference to the bottom of the EH stack.
static stable_iterator stable_end() { return stable_iterator(0); }
};