diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Transforms/Coroutines/CoroFrame.cpp | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'llvm/lib/Transforms/Coroutines/CoroFrame.cpp')
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 177 |
1 files changed, 106 insertions, 71 deletions
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 9c16d3750998..d09607bb1c4c 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -27,7 +27,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/OptimizedStructLayout.h" @@ -44,13 +44,6 @@ using namespace llvm; // "coro-frame", which results in leaner debug spew. #define DEBUG_TYPE "coro-suspend-crossing" -static cl::opt<bool> EnableReuseStorageInFrame( - "reuse-storage-in-coroutine-frame", cl::Hidden, - cl::desc( - "Enable the optimization which would reuse the storage in the coroutine \ - frame for allocas whose liferanges are not overlapped, for testing purposes"), - llvm::cl::init(false)); - enum { SmallVectorThreshold = 32 }; // Provides two way mapping between the blocks and numbers. @@ -347,15 +340,26 @@ struct FrameDataInfo { FieldIndexMap[V] = Index; } - uint64_t getAlign(Value *V) const { + Align getAlign(Value *V) const { auto Iter = FieldAlignMap.find(V); assert(Iter != FieldAlignMap.end()); return Iter->second; } - void setAlign(Value *V, uint64_t Align) { + void setAlign(Value *V, Align AL) { assert(FieldAlignMap.count(V) == 0); - FieldAlignMap.insert({V, Align}); + FieldAlignMap.insert({V, AL}); + } + + uint64_t getDynamicAlign(Value *V) const { + auto Iter = FieldDynamicAlignMap.find(V); + assert(Iter != FieldDynamicAlignMap.end()); + return Iter->second; + } + + void setDynamicAlign(Value *V, uint64_t Align) { + assert(FieldDynamicAlignMap.count(V) == 0); + FieldDynamicAlignMap.insert({V, Align}); } uint64_t getOffset(Value *V) const { @@ -382,7 +386,8 @@ private: DenseMap<Value *, uint32_t> FieldIndexMap; // Map from values to their alignment on the frame. They would be set after // the frame is built. - DenseMap<Value *, uint64_t> FieldAlignMap; + DenseMap<Value *, Align> FieldAlignMap; + DenseMap<Value *, uint64_t> FieldDynamicAlignMap; // Map from values to their offset on the frame. They would be set after // the frame is built. DenseMap<Value *, uint64_t> FieldOffsetMap; @@ -423,6 +428,7 @@ private: FieldIDType LayoutFieldIndex; Align Alignment; Align TyAlignment; + uint64_t DynamicAlignBuffer; }; const DataLayout &DL; @@ -489,7 +495,7 @@ public: coro::Shape &Shape); /// Add a field to this structure. - LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign FieldAlignment, + LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign MaybeFieldAlignment, bool IsHeader = false, bool IsSpillOfValue = false) { assert(!IsFinished && "adding fields to a finished builder"); @@ -508,13 +514,21 @@ public: // to remember the type alignment anyway to build the type. // If we are spilling values we don't need to worry about ABI alignment // concerns. - auto ABIAlign = DL.getABITypeAlign(Ty); - Align TyAlignment = - (IsSpillOfValue && MaxFrameAlignment) - ? (*MaxFrameAlignment < ABIAlign ? *MaxFrameAlignment : ABIAlign) - : ABIAlign; - if (!FieldAlignment) { - FieldAlignment = TyAlignment; + Align ABIAlign = DL.getABITypeAlign(Ty); + Align TyAlignment = ABIAlign; + if (IsSpillOfValue && MaxFrameAlignment && *MaxFrameAlignment < ABIAlign) + TyAlignment = *MaxFrameAlignment; + Align FieldAlignment = MaybeFieldAlignment.value_or(TyAlignment); + + // The field alignment could be bigger than the max frame case, in that case + // we request additional storage to be able to dynamically align the + // pointer. + uint64_t DynamicAlignBuffer = 0; + if (MaxFrameAlignment && (FieldAlignment > *MaxFrameAlignment)) { + DynamicAlignBuffer = + offsetToAlignment(MaxFrameAlignment->value(), FieldAlignment); + FieldAlignment = *MaxFrameAlignment; + FieldSize = FieldSize + DynamicAlignBuffer; } // Lay out header fields immediately. @@ -523,12 +537,13 @@ public: Offset = alignTo(StructSize, FieldAlignment); StructSize = Offset + FieldSize; - // Everything else has a flexible offset. + // Everything else has a flexible offset. } else { Offset = OptimizedStructLayoutField::FlexibleOffset; } - Fields.push_back({FieldSize, Offset, Ty, 0, *FieldAlignment, TyAlignment}); + Fields.push_back({FieldSize, Offset, Ty, 0, FieldAlignment, TyAlignment, + DynamicAlignBuffer}); return Fields.size() - 1; } @@ -561,7 +576,12 @@ void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder &B) { auto Updater = [&](Value *I) { auto Field = B.getLayoutField(getFieldIndex(I)); setFieldIndex(I, Field.LayoutFieldIndex); - setAlign(I, Field.Alignment.value()); + setAlign(I, Field.Alignment); + uint64_t dynamicAlign = + Field.DynamicAlignBuffer + ? Field.DynamicAlignBuffer + Field.Alignment.value() + : 0; + setDynamicAlign(I, dynamicAlign); setOffset(I, Field.Offset); }; LayoutIndexUpdateStarted = true; @@ -588,7 +608,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F, } }); - if (!Shape.OptimizeFrame && !EnableReuseStorageInFrame) { + if (!Shape.OptimizeFrame) { for (const auto &A : FrameData.Allocas) { AllocaInst *Alloca = A.Alloca; NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca)); @@ -755,6 +775,10 @@ void FrameTypeBuilder::finish(StructType *Ty) { F.LayoutFieldIndex = FieldTypes.size(); FieldTypes.push_back(F.Ty); + if (F.DynamicAlignBuffer) { + FieldTypes.push_back( + ArrayType::get(Type::getInt8Ty(Context), F.DynamicAlignBuffer)); + } LastOffset = Offset + F.Size; } @@ -807,9 +831,10 @@ static StringRef solveTypeName(Type *Ty) { return "__floating_type_"; } - if (Ty->isPointerTy()) { - auto *PtrTy = cast<PointerType>(Ty); - Type *PointeeTy = PtrTy->getPointerElementType(); + if (auto *PtrTy = dyn_cast<PointerType>(Ty)) { + if (PtrTy->isOpaque()) + return "PointerType"; + Type *PointeeTy = PtrTy->getNonOpaquePointerElementType(); auto Name = solveTypeName(PointeeTy); if (Name == "UnknownType") return "PointerType"; @@ -826,10 +851,9 @@ static StringRef solveTypeName(Type *Ty) { auto Name = Ty->getStructName(); SmallString<16> Buffer(Name); - for_each(Buffer, [](auto &Iter) { + for (auto &Iter : Buffer) if (Iter == '.' || Iter == ':') Iter = '_'; - }); auto *MDName = MDString::get(Ty->getContext(), Buffer.str()); return MDName->getString(); } @@ -1012,7 +1036,7 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape, auto Index = FrameData.getFieldIndex(V); OffsetCache.insert( - {Index, {FrameData.getAlign(V), FrameData.getOffset(V)}}); + {Index, {FrameData.getAlign(V).value(), FrameData.getOffset(V)}}); } DenseMap<Type *, DIType *> DITypeCache; @@ -1078,7 +1102,7 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape, DBuilder.insertDeclare(Shape.FramePtr, FrameDIVar, DBuilder.createExpression(), DILoc, - Shape.FramePtr->getNextNode()); + Shape.getInsertPtAfterFramePtr()); } // Build a struct that will keep state for an active coroutine. @@ -1367,7 +1391,7 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> { bool getShouldLiveOnFrame() const { if (!ShouldLiveOnFrame) ShouldLiveOnFrame = computeShouldLiveOnFrame(); - return ShouldLiveOnFrame.getValue(); + return *ShouldLiveOnFrame; } bool getMayWriteBeforeCoroBegin() const { return MayWriteBeforeCoroBegin; } @@ -1455,7 +1479,7 @@ private: auto Itr = AliasOffetMap.find(&I); if (Itr == AliasOffetMap.end()) { AliasOffetMap[&I] = Offset; - } else if (Itr->second.hasValue() && Itr->second.getValue() != Offset) { + } else if (Itr->second && *Itr->second != Offset) { // If we have seen two different possible values for this alias, we set // it to empty. AliasOffetMap[&I].reset(); @@ -1517,13 +1541,12 @@ static void createFramePtr(coro::Shape &Shape) { // whatever // // -static Instruction *insertSpills(const FrameDataInfo &FrameData, - coro::Shape &Shape) { +static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) { auto *CB = Shape.CoroBegin; LLVMContext &C = CB->getContext(); IRBuilder<> Builder(C); StructType *FrameTy = Shape.FrameTy; - Instruction *FramePtr = Shape.FramePtr; + Value *FramePtr = Shape.FramePtr; DominatorTree DT(*CB->getFunction()); SmallDenseMap<llvm::Value *, llvm::AllocaInst *, 4> DbgPtrAllocaCache; @@ -1550,7 +1573,18 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, auto GEP = cast<GetElementPtrInst>( Builder.CreateInBoundsGEP(FrameTy, FramePtr, Indices)); - if (isa<AllocaInst>(Orig)) { + if (auto *AI = dyn_cast<AllocaInst>(Orig)) { + if (FrameData.getDynamicAlign(Orig) != 0) { + assert(FrameData.getDynamicAlign(Orig) == AI->getAlign().value()); + auto *M = AI->getModule(); + auto *IntPtrTy = M->getDataLayout().getIntPtrType(AI->getType()); + auto *PtrValue = Builder.CreatePtrToInt(GEP, IntPtrTy); + auto *AlignMask = + ConstantInt::get(IntPtrTy, AI->getAlign().value() - 1); + PtrValue = Builder.CreateAdd(PtrValue, AlignMask); + PtrValue = Builder.CreateAnd(PtrValue, Builder.CreateNot(AlignMask)); + return Builder.CreateIntToPtr(PtrValue, AI->getType()); + } // If the type of GEP is not equal to the type of AllocaInst, it implies // that the AllocaInst may be reused in the Frame slot of other // AllocaInst. So We cast GEP to the AllocaInst here to re-use @@ -1571,20 +1605,19 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, // Create a store instruction storing the value into the // coroutine frame. Instruction *InsertPt = nullptr; - bool NeedToCopyArgPtrValue = false; + Type *ByValTy = nullptr; if (auto *Arg = dyn_cast<Argument>(Def)) { // For arguments, we will place the store instruction right after // the coroutine frame pointer instruction, i.e. bitcast of // coro.begin from i8* to %f.frame*. - InsertPt = FramePtr->getNextNode(); + InsertPt = Shape.getInsertPtAfterFramePtr(); // If we're spilling an Argument, make sure we clear 'nocapture' // from the coroutine function. Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture); if (Arg->hasByValAttr()) - NeedToCopyArgPtrValue = true; - + ByValTy = Arg->getParamByValType(); } else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) { // Don't spill immediately after a suspend; splitting assumes // that the suspend will be followed by a branch. @@ -1594,7 +1627,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, if (!DT.dominates(CB, I)) { // If it is not dominated by CoroBegin, then spill should be // inserted immediately after CoroFrame is computed. - InsertPt = FramePtr->getNextNode(); + InsertPt = Shape.getInsertPtAfterFramePtr(); } else if (auto *II = dyn_cast<InvokeInst>(I)) { // If we are spilling the result of the invoke instruction, split // the normal edge and insert the spill in the new block. @@ -1619,11 +1652,10 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, Builder.SetInsertPoint(InsertPt); auto *G = Builder.CreateConstInBoundsGEP2_32( FrameTy, FramePtr, 0, Index, Def->getName() + Twine(".spill.addr")); - if (NeedToCopyArgPtrValue) { + if (ByValTy) { // For byval arguments, we need to store the pointed value in the frame, // instead of the pointer itself. - auto *Value = - Builder.CreateLoad(Def->getType()->getPointerElementType(), Def); + auto *Value = Builder.CreateLoad(ByValTy, Def); Builder.CreateAlignedStore(Value, G, SpillAlignment); } else { Builder.CreateAlignedStore(Def, G, SpillAlignment); @@ -1641,7 +1673,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, auto *GEP = GetFramePointer(E.first); GEP->setName(E.first->getName() + Twine(".reload.addr")); - if (NeedToCopyArgPtrValue) + if (ByValTy) CurrentReload = GEP; else CurrentReload = Builder.CreateAlignedLoad( @@ -1664,6 +1696,12 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, } } + // Salvage debug info on any dbg.addr that we see. We do not insert them + // into each block where we have a use though. + if (auto *DI = dyn_cast<DbgAddrIntrinsic>(U)) { + coro::salvageDebugInfo(DbgPtrAllocaCache, DI, Shape.OptimizeFrame); + } + // If we have a single edge PHINode, remove it and replace it with a // reload from the coroutine frame. (We already took care of multi edge // PHINodes by rewriting them in the rewritePHIs function). @@ -1682,10 +1720,10 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, } } - BasicBlock *FramePtrBB = FramePtr->getParent(); + BasicBlock *FramePtrBB = Shape.getInsertPtAfterFramePtr()->getParent(); - auto SpillBlock = - FramePtrBB->splitBasicBlock(FramePtr->getNextNode(), "AllocaSpillBB"); + auto SpillBlock = FramePtrBB->splitBasicBlock( + Shape.getInsertPtAfterFramePtr(), "AllocaSpillBB"); SpillBlock->splitBasicBlock(&SpillBlock->front(), "PostSpill"); Shape.AllocaSpillBlock = SpillBlock; @@ -1704,7 +1742,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, Alloca->replaceAllUsesWith(G); Alloca->eraseFromParent(); } - return FramePtr; + return; } // If we found any alloca, replace all of their remaining uses with GEP @@ -1735,7 +1773,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, for (Instruction *I : UsersToUpdate) I->replaceUsesOfWith(Alloca, G); } - Builder.SetInsertPoint(FramePtr->getNextNode()); + Builder.SetInsertPoint(Shape.getInsertPtAfterFramePtr()); for (const auto &A : FrameData.Allocas) { AllocaInst *Alloca = A.Alloca; if (A.MayWriteBeforeCoroBegin) { @@ -1755,16 +1793,16 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData, auto *FramePtr = GetFramePointer(Alloca); auto *FramePtrRaw = Builder.CreateBitCast(FramePtr, Type::getInt8PtrTy(C)); - auto *AliasPtr = Builder.CreateGEP( - Type::getInt8Ty(C), FramePtrRaw, - ConstantInt::get(Type::getInt64Ty(C), Alias.second.getValue())); + auto &Value = *Alias.second; + auto ITy = IntegerType::get(C, Value.getBitWidth()); + auto *AliasPtr = Builder.CreateGEP(Type::getInt8Ty(C), FramePtrRaw, + ConstantInt::get(ITy, Value)); auto *AliasPtrTyped = Builder.CreateBitCast(AliasPtr, Alias.first->getType()); Alias.first->replaceUsesWithIf( AliasPtrTyped, [&](Use &U) { return DT.dominates(CB, U); }); } } - return FramePtr; } // Moves the values in the PHIs in SuccBB that correspong to PredBB into a new @@ -2130,7 +2168,7 @@ static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas, // Allocate memory. auto Alloca = Builder.CreateAlloca(Builder.getInt8Ty(), AI->getSize()); - Alloca->setAlignment(Align(AI->getAlignment())); + Alloca->setAlignment(AI->getAlignment()); for (auto U : AI->users()) { // Replace gets with the allocation. @@ -2279,7 +2317,10 @@ static void eliminateSwiftErrorArgument(Function &F, Argument &Arg, IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg()); auto ArgTy = cast<PointerType>(Arg.getType()); - auto ValueTy = ArgTy->getPointerElementType(); + // swifterror arguments are required to have pointer-to-pointer type, + // so create a pointer-typed alloca with opaque pointers. + auto ValueTy = ArgTy->isOpaque() ? PointerType::getUnqual(F.getContext()) + : ArgTy->getNonOpaquePointerElementType(); // Reduce to the alloca case: @@ -2520,6 +2561,7 @@ void coro::salvageDebugInfo( bool SkipOutermostLoad = !isa<DbgValueInst>(DVI); Value *Storage = DVI->getVariableLocationOp(0); Value *OriginalStorage = Storage; + while (auto *Inst = dyn_cast_or_null<Instruction>(Storage)) { if (auto *LdInst = dyn_cast<LoadInst>(Inst)) { Storage = LdInst->getOperand(0); @@ -2559,7 +2601,7 @@ void coro::salvageDebugInfo( // // Avoid to create the alloca would be eliminated by optimization // passes and the corresponding dbg.declares would be invalid. - if (!OptimizeFrame && !EnableReuseStorageInFrame) + if (!OptimizeFrame) if (auto *Arg = dyn_cast<llvm::Argument>(Storage)) { auto &Cached = DbgPtrAllocaCache[Storage]; if (!Cached) { @@ -2575,14 +2617,15 @@ void coro::salvageDebugInfo( // expression, we need to add a DW_OP_deref at the *start* of the // expression to first load the contents of the alloca before // adjusting it with the expression. - if (Expr && Expr->isComplex()) - Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); } DVI->replaceVariableLocationOp(OriginalStorage, Storage); DVI->setExpression(Expr); - /// It makes no sense to move the dbg.value intrinsic. - if (!isa<DbgValueInst>(DVI)) { + // We only hoist dbg.declare today since it doesn't make sense to hoist + // dbg.value or dbg.addr since they do not have the same function wide + // guarantees that dbg.declare does. + if (!isa<DbgValueInst>(DVI) && !isa<DbgAddrIntrinsic>(DVI)) { if (auto *II = dyn_cast<InvokeInst>(Storage)) DVI->moveBefore(II->getNormalDest()->getFirstNonPHI()); else if (auto *CBI = dyn_cast<CallBrInst>(Storage)) @@ -2661,13 +2704,6 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { for (User *U : I.users()) if (Checker.isDefinitionAcrossSuspend(I, U)) Spills[&I].push_back(cast<Instruction>(U)); - - // Manually add dbg.value metadata uses of I. - SmallVector<DbgValueInst *, 16> DVIs; - findDbgValues(DVIs, &I); - for (auto *DVI : DVIs) - if (Checker.isDefinitionAcrossSuspend(I, DVI)) - Spills[&I].push_back(DVI); } if (Spills.empty()) @@ -2754,10 +2790,9 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { auto *V = Iter.first; SmallVector<DbgValueInst *, 16> DVIs; findDbgValues(DVIs, V); - llvm::for_each(DVIs, [&](DbgValueInst *DVI) { + for (DbgValueInst *DVI : DVIs) if (Checker.isDefinitionAcrossSuspend(*V, DVI)) FrameData.Spills[V].push_back(DVI); - }); } LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills)); |
