diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 95 | ||||
-rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroInternal.h | 1 |
2 files changed, 87 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 2bf142a7be1..85423b3166c 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -263,8 +263,9 @@ SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape) namespace { class Spill { - Value *Def; - Instruction *User; + Value *Def = nullptr; + Instruction *User = nullptr; + unsigned FieldNo = 0; public: Spill(Value *Def, llvm::User *U) : Def(Def), User(cast<Instruction>(U)) {} @@ -272,6 +273,20 @@ public: Value *def() const { return Def; } Instruction *user() const { return User; } BasicBlock *userBlock() const { return User->getParent(); } + + // Note that field index is stored in the first SpillEntry for a particular + // definition. Subsequent mentions of a defintion do not have fieldNo + // assigned. This works out fine as the users of Spills capture the info about + // the definition the first time they encounter it. Consider refactoring + // SpillInfo into two arrays to normalize the spill representation. + unsigned fieldIndex() const { + assert(FieldNo && "Accessing unassigned field"); + return FieldNo; + } + void setFieldIndex(unsigned FieldNumber) { + assert(!FieldNo && "Reassigning field number"); + FieldNo = FieldNumber; + } }; } // namespace @@ -294,6 +309,55 @@ static void dump(StringRef Title, SpillInfo const &Spills) { } #endif +// We cannot rely solely on natural alignment of a type when building a +// coroutine frame and if the alignment specified on the Alloca instruction +// differs from the natural alignment of the alloca type we will need to insert +// padding. +struct PaddingCalculator { + const DataLayout &DL; + LLVMContext &Context; + unsigned StructSize = 0; + + PaddingCalculator(LLVMContext &Context, DataLayout const &DL) + : DL(DL), Context(Context) {} + + // Replicate the logic from IR/DataLayout.cpp to match field offset + // computation for LLVM structs. + void addType(Type *Ty) { + unsigned TyAlign = DL.getABITypeAlignment(Ty); + if ((StructSize & (TyAlign - 1)) != 0) + StructSize = alignTo(StructSize, TyAlign); + + StructSize += DL.getTypeAllocSize(Ty); // Consume space for this data item. + } + + void addTypes(SmallVectorImpl<Type *> const &Types) { + for (auto *Ty : Types) + addType(Ty); + } + + unsigned computePadding(Type *Ty, unsigned ForcedAlignment) { + unsigned TyAlign = DL.getABITypeAlignment(Ty); + auto Natural = alignTo(StructSize, TyAlign); + auto Forced = alignTo(StructSize, ForcedAlignment); + + // Return how many bytes of padding we need to insert. + if (Natural != Forced) + return std::max(Natural, Forced) - StructSize; + + // Rely on natural alignment. + return 0; + } + + // If padding required, return the padding field type to insert. + ArrayType *getPaddingType(Type *Ty, unsigned ForcedAlignment) { + if (auto Padding = computePadding(Ty, ForcedAlignment)) + return ArrayType::get(Type::getInt8Ty(Context), Padding); + + return nullptr; + } +}; + // Build a struct that will keep state for an active coroutine. // struct f.frame { // ResumeFnTy ResumeFnAddr; @@ -305,6 +369,8 @@ static void dump(StringRef Title, SpillInfo const &Spills) { static StructType *buildFrameType(Function &F, coro::Shape &Shape, SpillInfo &Spills) { LLVMContext &C = F.getContext(); + const DataLayout &DL = F.getParent()->getDataLayout(); + PaddingCalculator Padder(C, DL); SmallString<32> Name(F.getName()); Name.append(".Frame"); StructType *FrameTy = StructType::create(C, Name); @@ -322,8 +388,10 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, Type::getIntNTy(C, IndexBits)}; Value *CurrentDef = nullptr; + Padder.addTypes(Types); + // Create an entry for every spilled value. - for (auto const &S : Spills) { + for (auto &S : Spills) { if (CurrentDef == S.def()) continue; @@ -333,12 +401,22 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, continue; Type *Ty = nullptr; - if (auto *AI = dyn_cast<AllocaInst>(CurrentDef)) + if (auto *AI = dyn_cast<AllocaInst>(CurrentDef)) { Ty = AI->getAllocatedType(); - else + if (unsigned AllocaAlignment = AI->getAlignment()) { + // If alignment is specified in alloca, see if we need to insert extra + // padding. + if (auto PaddingTy = Padder.getPaddingType(Ty, AllocaAlignment)) { + Types.push_back(PaddingTy); + Padder.addType(PaddingTy); + } + } + } else { Ty = CurrentDef->getType(); - + } + S.setFieldIndex(Types.size()); Types.push_back(Ty); + Padder.addType(Ty); } FrameTy->setBody(Types); @@ -399,7 +477,7 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) { Value *CurrentValue = nullptr; BasicBlock *CurrentBlock = nullptr; Value *CurrentReload = nullptr; - unsigned Index = coro::Shape::LastKnownField; + unsigned Index = 0; // Proper field number will be read from field definition. // We need to keep track of any allocas that need "spilling" // since they will live in the coroutine frame now, all access to them @@ -414,6 +492,7 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) { // Create a load instruction to reload the spilled value from the coroutine // frame. auto CreateReload = [&](Instruction *InsertBefore) { + assert(Index && "accessing unassigned field number"); Builder.SetInsertPoint(InsertBefore); auto *G = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index, CurrentValue->getName() + @@ -431,7 +510,7 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) { CurrentBlock = nullptr; CurrentReload = nullptr; - ++Index; + Index = E.fieldIndex(); if (auto *AI = dyn_cast<AllocaInst>(CurrentValue)) { // Spilled AllocaInst will be replaced with GEP from the coroutine frame diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 1eac88dbac3..8e690d649cf 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -76,7 +76,6 @@ struct LLVM_LIBRARY_VISIBILITY Shape { DestroyField, PromiseField, IndexField, - LastKnownField = IndexField }; StructType *FrameTy; |