diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 3257d180c44e..71fadd74f6b2 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -118,6 +118,15 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return createBinop(lhs, mlir::cir::BinOpKind::Or, rhs); } + mlir::Value createMul(mlir::Value lhs, mlir::Value rhs) { + return createBinop(lhs, mlir::cir::BinOpKind::Mul, rhs); + } + + mlir::Value createMul(mlir::Value lhs, llvm::APInt rhs) { + auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs); + return createBinop(lhs, mlir::cir::BinOpKind::Mul, val); + } + //===--------------------------------------------------------------------===// // Cast/Conversion Operators //===--------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 9ef1be205ad7..ce0c3c4cfa93 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -40,7 +40,6 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D, // getLangOpts().OpenCL)) assert(!UnimplementedFeature::openCL()); assert(Ty.getAddressSpace() == LangAS::Default); - assert(!Ty->isVariablyModifiedType() && "not implemented"); assert(!D.hasAttr() && "not implemented"); auto loc = getLoc(D.getSourceRange()); @@ -51,6 +50,11 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D, emission.IsEscapingByRef = isEscapingByRef; CharUnits alignment = getContext().getDeclAlign(&D); + + // If the type is variably-modified, emit all the VLA sizes for it. + if (Ty->isVariablyModifiedType()) + buildVariablyModifiedType(Ty); + assert(!UnimplementedFeature::generateDebugInfo()); assert(!UnimplementedFeature::cxxABI()); @@ -146,7 +150,41 @@ CIRGenFunction::buildAutoVarAlloca(const VarDecl &D, assert(!UnimplementedFeature::shouldEmitLifetimeMarkers()); } } else { // not openmp nor constant sized type - llvm_unreachable("NYI"); + bool VarAllocated = false; + if (getLangOpts().OpenMPIsTargetDevice) + llvm_unreachable("NYI"); + + if (!VarAllocated) { + if (!DidCallStackSave) { + // Save the stack. + auto defaultTy = AllocaInt8PtrTy; + CharUnits Align = CharUnits::fromQuantity( + CGM.getDataLayout().getAlignment(defaultTy, false)); + Address Stack = CreateTempAlloca(defaultTy, Align, loc, "saved_stack"); + + mlir::Value V = builder.createStackSave(loc, defaultTy); + assert(V.getType() == AllocaInt8PtrTy); + builder.createStore(loc, V, Stack); + + DidCallStackSave = true; + + // Push a cleanup block and restore the stack there. + // FIXME: in general circumstances, this should be an EH cleanup. + pushStackRestore(NormalCleanup, Stack); + } + + auto VlaSize = getVLASize(Ty); + mlir::Type mTy = convertTypeForMem(VlaSize.Type); + + // Allocate memory for the array. + address = CreateTempAlloca(mTy, alignment, loc, "vla", VlaSize.NumElts, + &allocaAddr, builder.saveInsertionPoint()); + } + + // If we have debug info enabled, properly describe the VLA dimensions for + // this type by registering the vla size expression for each of the + // dimensions. + assert(!UnimplementedFeature::generateDebugInfo()); } emission.Addr = address; @@ -858,7 +896,9 @@ struct CallStackRestore final : EHScopeStack::Cleanup { CallStackRestore(Address Stack) : Stack(Stack) {} bool isRedundantBeforeReturn() override { return true; } void Emit(CIRGenFunction &CGF, Flags flags) override { - llvm_unreachable("NYI"); + auto loc = Stack.getPointer().getLoc(); + mlir::Value V = CGF.getBuilder().createLoad(loc, Stack); + CGF.getBuilder().createStackRestore(loc, V); } }; @@ -941,6 +981,10 @@ CIRGenFunction::getDestroyer(QualType::DestructionKind kind) { llvm_unreachable("Unknown DestructionKind"); } +void CIRGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) { + EHStack.pushCleanup(Kind, SPMem); +} + /// Enter a destroy cleanup for the given local variable. void CIRGenFunction::buildAutoVarTypeCleanup( const CIRGenFunction::AutoVarEmission &emission, diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 15d5b9e8f6cd..430f4232b1f0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/DiagnosticCategories.h" #include "clang/Basic/TargetInfo.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/FPEnv.h" @@ -1394,3 +1395,176 @@ void CIRGenFunction::checkTargetFeatures(SourceLocation Loc, } } } + +CIRGenFunction::VlaSizePair CIRGenFunction::getVLASize(QualType type) { + const VariableArrayType *vla = + CGM.getASTContext().getAsVariableArrayType(type); + assert(vla && "type was not a variable array type!"); + return getVLASize(vla); +} + +CIRGenFunction::VlaSizePair +CIRGenFunction::getVLASize(const VariableArrayType *type) { + // The number of elements so far; always size_t. + mlir::Value numElements; + + QualType elementType; + do { + elementType = type->getElementType(); + mlir::Value vlaSize = VLASizeMap[type->getSizeExpr()]; + assert(vlaSize && "no size for VLA!"); + assert(vlaSize.getType() == SizeTy); + + if (!numElements) { + numElements = vlaSize; + } else { + // It's undefined behavior if this wraps around, so mark it that way. + // FIXME: Teach -fsanitize=undefined to trap this. + + numElements = builder.createMul(numElements, vlaSize); + } + } while ((type = getContext().getAsVariableArrayType(elementType))); + + assert(numElements && "Undefined elements number"); + return {numElements, elementType}; +} + +// TODO(cir): most part of this function can be shared between CIRGen +// and traditional LLVM codegen +void CIRGenFunction::buildVariablyModifiedType(QualType type) { + assert(type->isVariablyModifiedType() && + "Must pass variably modified type to EmitVLASizes!"); + + // We're going to walk down into the type and look for VLA + // expressions. + do { + assert(type->isVariablyModifiedType()); + + const Type *ty = type.getTypePtr(); + switch (ty->getTypeClass()) { + case clang::Type::CountAttributed: + case clang::Type::PackIndexing: + llvm_unreachable("NYI"); + +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.inc" + llvm_unreachable("unexpected dependent type!"); + + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::ConstantMatrix: + case Type::Record: + case Type::Enum: + case Type::Using: + case Type::TemplateSpecialization: + case Type::ObjCTypeParam: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::BitInt: + llvm_unreachable("type class is never variably-modified!"); + + case Type::Elaborated: + type = cast(ty)->getNamedType(); + break; + + case Type::Adjusted: + type = cast(ty)->getAdjustedType(); + break; + + case Type::Decayed: + type = cast(ty)->getPointeeType(); + break; + + case Type::Pointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::BlockPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::LValueReference: + case Type::RValueReference: + type = cast(ty)->getPointeeType(); + break; + + case Type::MemberPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + type = cast(ty)->getElementType(); + break; + + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *vat = cast(ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (const Expr *sizeExpr = vat->getSizeExpr()) { + // It's possible that we might have emitted this already, + // e.g. with a typedef and a pointer to it. + mlir::Value &entry = VLASizeMap[sizeExpr]; + if (!entry) { + mlir::Value size = buildScalarExpr(sizeExpr); + assert(!UnimplementedFeature::sanitizeVLABound()); + + // Always zexting here would be wrong if it weren't + // undefined behavior to have a negative bound. + // FIXME: What about when size's type is larger than size_t? + entry = builder.createIntCast(size, SizeTy); + } + } + type = vat->getElementType(); + break; + } + + case Type::FunctionProto: + case Type::FunctionNoProto: + type = cast(ty)->getReturnType(); + break; + + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::BTFTagAttributed: + case Type::SubstTemplateTypeParm: + case Type::MacroQualified: + // Keep walking after single level desugaring. + type = type.getSingleStepDesugaredType(getContext()); + break; + + case Type::Typedef: + case Type::Decltype: + case Type::Auto: + case Type::DeducedTemplateSpecialization: + // Stop walking: nothing to do. + return; + + case Type::TypeOfExpr: + // Stop walking: emit typeof expression. + buildIgnoredExpr(cast(ty)->getUnderlyingExpr()); + return; + + case Type::Atomic: + type = cast(ty)->getValueType(); + break; + + case Type::Pipe: + type = cast(ty)->getElementType(); + break; + } + } while (type->isVariablyModifiedType()); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 457cae34f42d..0a4149164687 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -93,6 +93,14 @@ class CIRGenFunction : public CIRGenTypeCache { llvm::DenseMap OpaqueLValues; llvm::DenseMap OpaqueRValues; + // This keeps track of the associated size for each VLA type. + // We track this by the size expression rather than the type itself because + // in certain situations, like a const qualifier applied to an VLA typedef, + // multiple VLA types can share the same size expression. + // FIXME: Maybe this could be a stack of maps that is pushed/popped as we + // enter/leave scopes. + llvm::DenseMap VLASizeMap; + public: /// A non-RAII class containing all the information about a bound /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for @@ -707,6 +715,22 @@ class CIRGenFunction : public CIRGenTypeCache { /// \returns SSA value with the argument. mlir::Value buildVAArg(VAArgExpr *VE, Address &VAListAddr); + void buildVariablyModifiedType(QualType Ty); + + struct VlaSizePair { + mlir::Value NumElts; + QualType Type; + + VlaSizePair(mlir::Value NE, QualType T) : NumElts(NE), Type(T) {} + }; + + /// Returns an MLIR value that corresponds to the size, + /// in non-variably-sized elements, of a variable length array type, + /// plus that largest non-variably-sized element type. Assumes that + /// the type has already been emitted with buildVariablyModifiedType. + VlaSizePair getVLASize(const VariableArrayType *vla); + VlaSizePair getVLASize(QualType vla); + mlir::Value emitBuiltinObjectSize(const Expr *E, unsigned Type, mlir::cir::IntType ResType, mlir::Value EmittedE, bool IsDynamic); @@ -1242,6 +1266,8 @@ class CIRGenFunction : public CIRGenTypeCache { void pushEHDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type); + void pushStackRestore(CleanupKind kind, Address SPMem); + static bool IsConstructorDelegationValid(const clang::CXXConstructorDecl *Ctor); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 69fb94aa5c44..936adfa58593 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -158,7 +158,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context, /*isSigned=*/false); UInt8PtrTy = builder.getPointerTo(UInt8Ty); UInt8PtrPtrTy = builder.getPointerTo(UInt8PtrTy); - // TODO: AllocaInt8PtrTy + AllocaInt8PtrTy = UInt8PtrTy; // TODO: GlobalsInt8PtrTy // TODO: ConstGlobalsPtrTy // TODO: ASTAllocaAddressSpace diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index ac3442626ca8..91290001d683 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -64,10 +64,10 @@ struct CIRGenTypeCache { }; /// void* in alloca address space - // union { - // mlir::cir::PointerType AllocaVoidPtrTy; - // mlir::cir::PointerType AllocaInt8PtrTy; - // }; + union { + mlir::cir::PointerType AllocaVoidPtrTy; + mlir::cir::PointerType AllocaInt8PtrTy; + }; /// void* in default globals address space // union { diff --git a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h index 6c699c709ab3..89a336146f68 100644 --- a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h +++ b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h @@ -58,6 +58,7 @@ struct UnimplementedFeature { static bool emitCheckedInBoundsGEP() { return false; } static bool pointerOverflowSanitizer() { return false; } static bool sanitizeDtor() { return false; } + static bool sanitizeVLABound() { return false; } // ObjC static bool setObjCGCLValueClass() { return false; }