diff options
Diffstat (limited to 'clang/lib/CIR')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp | 18 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 15 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 132 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 | ||||
-rw-r--r-- | clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 43 | ||||
-rw-r--r-- | clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 |
6 files changed, 213 insertions, 4 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 be66240..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. @@ -245,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/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/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index d10d058..a60efe1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1254,6 +1254,11 @@ 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); diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 3484c59..64ac970 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -473,6 +473,49 @@ LogicalResult cir::VTableAttr::verify( } //===----------------------------------------------------------------------===// +// DynamicCastInfoAtttr definitions +//===----------------------------------------------------------------------===// + +std::string DynamicCastInfoAttr::getAlias() const { + // The alias looks like: `dyn_cast_info_<src>_<dest>` + + std::string alias = "dyn_cast_info_"; + + alias.append(getSrcRtti().getSymbol().getValue()); + alias.push_back('_'); + alias.append(getDestRtti().getSymbol().getValue()); + + return alias; +} + +LogicalResult DynamicCastInfoAttr::verify( + function_ref<InFlightDiagnostic()> emitError, cir::GlobalViewAttr srcRtti, + cir::GlobalViewAttr destRtti, mlir::FlatSymbolRefAttr runtimeFunc, + mlir::FlatSymbolRefAttr badCastFunc, cir::IntAttr offsetHint) { + auto isRttiPtr = [](mlir::Type ty) { + // RTTI pointers are !cir.ptr<!u8i>. + + auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty); + if (!ptrTy) + return false; + + auto pointeeIntTy = mlir::dyn_cast<cir::IntType>(ptrTy.getPointee()); + if (!pointeeIntTy) + return false; + + return pointeeIntTy.isUnsigned() && pointeeIntTy.getWidth() == 8; + }; + + if (!isRttiPtr(srcRtti.getType())) + return emitError() << "srcRtti must be an RTTI pointer"; + + if (!isRttiPtr(destRtti.getType())) + return emitError() << "destRtti must be an RTTI pointer"; + + return success(); +} + +//===----------------------------------------------------------------------===// // CIR Dialect //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index cdd4e3c..5f88590 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -71,6 +71,10 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface { os << "bfi_" << bitfield.getName().str(); return AliasResult::FinalAlias; } + if (auto dynCastInfoAttr = mlir::dyn_cast<cir::DynamicCastInfoAttr>(attr)) { + os << dynCastInfoAttr.getAlias(); + return AliasResult::FinalAlias; + } return AliasResult::NoAlias; } }; |