diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 16 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenClass.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCleanup.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCleanup.h | 9 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenException.cpp | 35 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 30 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 132 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 247 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 16 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.h | 10 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 54 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp | 60 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.h | 109 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenValue.h | 7 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/EHScopeStack.h | 4 |
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 ©Region, size_t numBounds) { + mlir::Block *block = createRecipeBlock(copyRegion, mainOp.getType(), loc, + numBounds, /*isInit=*/false); + builder.setInsertionPointToEnd(©Region.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(©Region.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 ©Region, 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); } }; |