diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenBuilder.h | 8 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 98 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 58 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.h | 32 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenModule.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp | 4 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenTypeCache.h | 3 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 10 |
9 files changed, 189 insertions, 28 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index a6f10e6..84acc74 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -519,6 +519,14 @@ public: return createGlobal(module, loc, uniqueName, type, isConstant, linkage); } + cir::StackSaveOp createStackSave(mlir::Location loc, mlir::Type ty) { + return cir::StackSaveOp::create(*this, loc, ty); + } + + cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v) { + return cir::StackRestoreOp::create(*this, loc, v); + } + mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType, Address dstAddr, mlir::Type storageType, mlir::Value src, const CIRGenBitFieldInfo &info, diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 039d290..4a19d91 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -44,38 +44,70 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d, // If the type is variably-modified, emit all the VLA sizes for it. if (ty->isVariablyModifiedType()) - cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type"); + emitVariablyModifiedType(ty); assert(!cir::MissingFeatures::openMP()); Address address = Address::invalid(); - if (!ty->isConstantSizeType()) - cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type"); - - // A normal fixed sized variable becomes an alloca in the entry block, - // unless: - // - it's an NRVO variable. - // - we are compiling OpenMP and it's an OpenMP local variable. - if (nrvo) { - // The named return value optimization: allocate this variable in the - // return slot, so that we can elide the copy when returning this - // variable (C++0x [class.copy]p34). - address = returnValue; - - if (const RecordDecl *rd = ty->getAsRecordDecl()) { - if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd); - (cxxrd && !cxxrd->hasTrivialDestructor()) || - rd->isNonTrivialToPrimitiveDestroy()) - cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag"); + if (ty->isConstantSizeType()) { + // A normal fixed sized variable becomes an alloca in the entry block, + // unless: + // - it's an NRVO variable. + // - we are compiling OpenMP and it's an OpenMP local variable. + if (nrvo) { + // The named return value optimization: allocate this variable in the + // return slot, so that we can elide the copy when returning this + // variable (C++0x [class.copy]p34). + address = returnValue; + + if (const RecordDecl *rd = ty->getAsRecordDecl()) { + if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd); + (cxxrd && !cxxrd->hasTrivialDestructor()) || + rd->isNonTrivialToPrimitiveDestroy()) + cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag"); + } + } else { + // A normal fixed sized variable becomes an alloca in the entry block, + mlir::Type allocaTy = convertTypeForMem(ty); + // Create the temp alloca and declare variable using it. + address = createTempAlloca(allocaTy, alignment, loc, d.getName(), + /*arraySize=*/nullptr, /*alloca=*/nullptr, ip); + declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), + alignment); } } else { - // A normal fixed sized variable becomes an alloca in the entry block, - mlir::Type allocaTy = convertTypeForMem(ty); - // Create the temp alloca and declare variable using it. - address = createTempAlloca(allocaTy, alignment, loc, d.getName(), - /*arraySize=*/nullptr, /*alloca=*/nullptr, ip); - declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), - alignment); + // Non-constant size type + assert(!cir::MissingFeatures::openMP()); + if (!didCallStackSave) { + // Save the stack. + cir::PointerType defaultTy = AllocaInt8PtrTy; + CharUnits align = CharUnits::fromQuantity( + cgm.getDataLayout().getAlignment(defaultTy, false)); + Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack"); + + mlir::Value v = builder.createStackSave(loc, defaultTy); + assert(v.getType() == AllocaInt8PtrTy); + builder.createStore(loc, v, stack); + + didCallStackSave = true; + + // Push a cleanup block and restore the stack there. + // FIXME: in general circumstances, this should be an EH cleanup. + pushStackRestore(NormalCleanup, stack); + } + + VlaSizePair vlaSize = getVLASize(ty); + mlir::Type memTy = convertTypeForMem(vlaSize.type); + + // Allocate memory for the array. + address = + createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts, + /*alloca=*/nullptr, builder.saveInsertionPoint()); + + // If we have debug info enabled, properly describe the VLA dimensions for + // this type by registering the vla size expression for each of the + // dimensions. + assert(!cir::MissingFeatures::generateDebugInfo()); } emission.addr = address; @@ -696,6 +728,16 @@ struct DestroyObject final : EHScopeStack::Cleanup { cgf.emitDestroy(addr, type, destroyer); } }; + +struct CallStackRestore final : EHScopeStack::Cleanup { + Address stack; + CallStackRestore(Address stack) : stack(stack) {} + void emit(CIRGenFunction &cgf) override { + mlir::Location loc = stack.getPointer().getLoc(); + mlir::Value v = cgf.getBuilder().createLoad(loc, stack); + cgf.getBuilder().createStackRestore(loc, v); + } +}; } // namespace void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr, @@ -805,6 +847,10 @@ CIRGenFunction::getDestroyer(QualType::DestructionKind kind) { llvm_unreachable("Unknown DestructionKind"); } +void CIRGenFunction::pushStackRestore(CleanupKind kind, Address spMem) { + ehStack.pushCleanup<CallStackRestore>(kind, spMem); +} + /// Enter a destroy cleanup for the given local variable. void CIRGenFunction::emitAutoVarTypeCleanup( const CIRGenFunction::AutoVarEmission &emission, diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index f416571..4897c29 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2068,7 +2068,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty, mlir::OpBuilder::InsertionGuard guard(builder); builder.restoreInsertionPoint(ip); addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy, - /*var type*/ ty, name, alignIntAttr); + /*var type*/ ty, name, alignIntAttr, arraySize); assert(!cir::MissingFeatures::astVarDeclInterface()); } return addr; diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 01a43a99..ba36cbe 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -410,6 +410,8 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType, curFn = fn; const Decl *d = gd.getDecl(); + + didCallStackSave = false; curCodeDecl = d; const auto *fd = dyn_cast_or_null<FunctionDecl>(d); curFuncDecl = d->getNonClosureContext(); @@ -1006,6 +1008,41 @@ mlir::Value CIRGenFunction::emitAlignmentAssumption( offsetValue); } +CIRGenFunction::VlaSizePair CIRGenFunction::getVLASize(QualType type) { + const VariableArrayType *vla = + cgm.getASTContext().getAsVariableArrayType(type); + assert(vla && "type was not a variable array type!"); + return getVLASize(vla); +} + +CIRGenFunction::VlaSizePair +CIRGenFunction::getVLASize(const VariableArrayType *type) { + // The number of elements so far; always size_t. + mlir::Value numElements; + + QualType elementType; + do { + elementType = type->getElementType(); + mlir::Value vlaSize = vlaSizeMap[type->getSizeExpr()]; + assert(vlaSize && "no size for VLA!"); + assert(vlaSize.getType() == SizeTy); + + if (!numElements) { + numElements = vlaSize; + } else { + // It's undefined behavior if this wraps around, so mark it that way. + // FIXME: Teach -fsanitize=undefined to trap this. + + numElements = + builder.createMul(numElements.getLoc(), numElements, vlaSize, + cir::OverflowBehavior::NoUnsignedWrap); + } + } while ((type = getContext().getAsVariableArrayType(elementType))); + + assert(numElements && "Undefined elements number"); + return {numElements, elementType}; +} + // TODO(cir): Most of this function can be shared between CIRGen // and traditional LLVM codegen void CIRGenFunction::emitVariablyModifiedType(QualType type) { @@ -1086,7 +1123,26 @@ void CIRGenFunction::emitVariablyModifiedType(QualType type) { break; case Type::VariableArray: { - cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType VLA"); + // Losing element qualification here is fine. + const VariableArrayType *vat = cast<clang::VariableArrayType>(ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (const Expr *sizeExpr = vat->getSizeExpr()) { + // It's possible that we might have emitted this already, + // e.g. with a typedef and a pointer to it. + mlir::Value &entry = vlaSizeMap[sizeExpr]; + if (!entry) { + mlir::Value size = emitScalarExpr(sizeExpr); + assert(!cir::MissingFeatures::sanitizers()); + + // Always zexting here would be wrong if it weren't + // undefined behavior to have a negative bound. + // FIXME: What about when size's type is larger than size_t? + entry = builder.createIntCast(size, SizeTy); + } + } + type = vat->getElementType(); break; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index d71de2f..0d64c31 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -149,6 +149,10 @@ public: using SymTableTy = llvm::ScopedHashTable<const clang::Decl *, mlir::Value>; SymTableTy symbolTable; + /// Whether a cir.stacksave operation has been added. Used to avoid + /// inserting cir.stacksave for multiple VLAs in the same scope. + bool didCallStackSave = false; + /// Whether or not a Microsoft-style asm block has been processed within /// this fuction. These can potentially set the return value. bool sawAsmBlock = false; @@ -188,6 +192,14 @@ public: llvm::DenseMap<const OpaqueValueExpr *, LValue> opaqueLValues; llvm::DenseMap<const OpaqueValueExpr *, RValue> opaqueRValues; + // This keeps track of the associated size for each VLA type. + // We track this by the size expression rather than the type itself because + // in certain situations, like a const qualifier applied to an VLA typedef, + // multiple VLA types can share the same size expression. + // FIXME: Maybe this could be a stack of maps that is pushed/popped as we + // enter/leave scopes. + llvm::DenseMap<const Expr *, mlir::Value> vlaSizeMap; + public: /// A non-RAII class containing all the information about a bound /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for @@ -436,6 +448,20 @@ public: } }; + struct VlaSizePair { + mlir::Value numElts; + QualType type; + + VlaSizePair(mlir::Value num, QualType ty) : numElts(num), type(ty) {} + }; + + /// Returns an MLIR::Value+QualType pair that corresponds to the size, + /// in non-variably-sized elements, of a variable length array type, + /// plus that largest non-variably-sized element type. Assumes that + /// the type has already been emitted with emitVariablyModifiedType. + VlaSizePair getVLASize(const VariableArrayType *type); + VlaSizePair getVLASize(QualType type); + void finishFunction(SourceLocation endLoc); /// Determine whether the given initializer is trivial in the sense @@ -583,6 +609,8 @@ public: return needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup; } + void pushStackRestore(CleanupKind kind, Address spMem); + /// Set the address of a local variable. void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) { assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!"); @@ -854,6 +882,7 @@ public: protected: bool performCleanup; + bool oldDidCallStackSave; private: RunCleanupsScope(const RunCleanupsScope &) = delete; @@ -867,6 +896,8 @@ public: explicit RunCleanupsScope(CIRGenFunction &cgf) : performCleanup(true), cgf(cgf) { cleanupStackDepth = cgf.ehStack.stable_begin(); + oldDidCallStackSave = cgf.didCallStackSave; + cgf.didCallStackSave = false; oldCleanupStackDepth = cgf.currentCleanupStackDepth; cgf.currentCleanupStackDepth = cleanupStackDepth; } @@ -883,6 +914,7 @@ public: assert(performCleanup && "Already forced cleanup"); { mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder()); + cgf.didCallStackSave = oldDidCallStackSave; cgf.popCleanupBlocks(cleanupStackDepth); performCleanup = false; cgf.currentCleanupStackDepth = oldCleanupStackDepth; diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 82b1051..57c7a44 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -88,6 +88,8 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext, FP80Ty = cir::FP80Type::get(&getMLIRContext()); FP128Ty = cir::FP128Type::get(&getMLIRContext()); + AllocaInt8PtrTy = cir::PointerType::get(UInt8Ty, cirAllocaAddressSpace); + PointerAlignInBytes = astContext .toCharUnitsFromBits( diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp index ce14aa8..f638d39 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp @@ -398,6 +398,7 @@ void OpenACCRecipeBuilderBase::createRecipeDestroySection( emitDestroy(block->getArgument(1), elementTy); } + ls.forceCleanup(); mlir::acc::YieldOp::create(builder, locEnd); } void OpenACCRecipeBuilderBase::makeBoundsInit( @@ -480,6 +481,7 @@ void OpenACCRecipeBuilderBase::createInitRecipe( /*isInitSection=*/true); } + ls.forceCleanup(); mlir::acc::YieldOp::create(builder, locEnd); } @@ -518,6 +520,7 @@ void OpenACCRecipeBuilderBase::createFirstprivateRecipeCopy( cgf.emitAutoVarInit(tempDeclEmission); builder.setInsertionPointToEnd(©Region.back()); + ls.forceCleanup(); mlir::acc::YieldOp::create(builder, locEnd); } @@ -662,6 +665,7 @@ void OpenACCRecipeBuilderBase::createReductionRecipeCombiner( } builder.setInsertionPointToEnd(&recipe.getCombinerRegion().back()); + ls.forceCleanup(); mlir::acc::YieldOp::create(builder, locEnd, block->getArgument(0)); } diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index 273ec7f..b5612d9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -65,6 +65,9 @@ struct CIRGenTypeCache { cir::PointerType VoidPtrTy; cir::PointerType UInt8PtrTy; + /// void* in alloca address space + cir::PointerType AllocaInt8PtrTy; + /// The size and alignment of a pointer into the generic address space. union { unsigned char PointerAlignInBytes; diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index b6d3c95..d1b91d0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -420,6 +420,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) { break; } + case Type::VariableArray: { + const VariableArrayType *a = cast<VariableArrayType>(ty); + if (a->getIndexTypeCVRQualifiers() != 0) + cgm.errorNYI(SourceLocation(), "non trivial array types", type); + // VLAs resolve to the innermost element type; this matches + // the return of alloca, and there isn't any obviously better choice. + resultType = convertTypeForMem(a->getElementType()); + break; + } + case Type::IncompleteArray: { const IncompleteArrayType *arrTy = cast<IncompleteArrayType>(ty); if (arrTy->getIndexTypeCVRQualifiers() != 0) |