summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroFrame.cpp95
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroInternal.h1
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;
OpenPOWER on IntegriCloud