Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -2570,7 +2570,7 @@ FUNCTION(AsyncLetBegin,
),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::Concurrency),
MEMEFFECTS(ArgMemOnly))
UNKNOWN_MEMEFFECTS)

/// void swift_asyncLet_finish(
/// AsyncLet *alet,
Expand All @@ -2592,7 +2592,7 @@ FUNCTION(AsyncLetFinish,
),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::Concurrency),
MEMEFFECTS(ArgMemOnly))
UNKNOWN_MEMEFFECTS)

/// void swift_task_run_inline(
/// OpaqueValue *result,
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,7 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
true
#endif
);
NewInst->setStackAllocationIsNested(Inst->isStackAllocationNested());
recordClonedInstruction(Inst, NewInst);
}

Expand Down
26 changes: 26 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ class SILPrintContext;

template <typename ImplClass> class SILClonerWithScopes;

enum StackAllocationIsNested_t : bool {
/// The instruction may not obey the ABBA rule of stack allocation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is LIFO a better term of art here than ABBA?

StackAllocationIsNotNested = false,

/// The instruction obeys the ABBA rule of stack allocation and can
/// allocate memory on the stack normally.
StackAllocationIsNested = true,
};

enum class MemoryBehavior {
None,
/// The instruction may read memory.
Expand Down Expand Up @@ -858,6 +867,15 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
/// The stack allocation produced by the instruction, if any.
SILValue getStackAllocation() const;

/// Returns the kind of stack memory that should be allocated. There are
/// certain (unfortunate) situations in which "stack" allocations may become
/// unnested and must use alternative allocation strategies. Rather than
/// requiring all of these to explicitly use heap allocation, which may be
/// to be significantly less efficient (e.g. )
StackAllocationIsNested_t isStackAllocationNested() const;

void setStackAllocationIsNested(StackAllocationIsNested_t isNested);

/// Returns true if this is the deallocation of a stack allocating instruction.
/// The first operand must be the allocating instruction.
bool isDeallocatingStack() const;
Expand Down Expand Up @@ -2055,6 +2073,14 @@ class AllocStackInst final
}
}

StackAllocationIsNested_t isStackAllocationNested() const {
return StackAllocationIsNested_t(!sharedUInt8().AllocStackInst.isNested);
}

void setStackAllocationIsNested(StackAllocationIsNested_t isNested) {
sharedUInt8().AllocStackInst.isNested = bool(isNested);
}

void markUsesMoveableValueDebugInfo() {
sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo =
(bool)UsesMoveableValueDebugInfo;
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ class alignas(8) SILNode :
lexical : 1,
fromVarDecl : 1,
usesMoveableValueDebugInfo : 1,
hasInvalidatedVarInfo : 1);
hasInvalidatedVarInfo : 1,
isNested : 1);

SHARED_FIELD(AllocBoxInst, uint8_t
dynamicLifetime : 1,
Expand Down
8 changes: 6 additions & 2 deletions lib/IRGen/FixedTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ class FixedTypeInfo : public TypeInfo {
}

StackAddress allocateStack(IRGenFunction &IGF, SILType T,
const llvm::Twine &name) const override;
void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T) const override;
const llvm::Twine &name,
StackAllocationIsNested_t isNested =
StackAllocationIsNested) const override;
void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T,
StackAllocationIsNested_t isNested =
StackAllocationIsNested) const override;
void destroyStack(IRGenFunction &IGF, StackAddress addr, SILType T,
bool isOutlined) const override;

Expand Down
9 changes: 5 additions & 4 deletions lib/IRGen/GenArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,17 +639,18 @@ class NonFixedArrayTypeInfo final
}

StackAddress allocateStack(IRGenFunction &IGF, SILType T,
const llvm::Twine &name) const override {
const llvm::Twine &name,
StackAllocationIsNested_t isNested) const override {
// Allocate memory on the stack.
auto alloca = IGF.emitDynamicAlloca(T, name);
auto alloca = IGF.emitDeallocStackDynamic(T, name, isNested);
IGF.Builder.CreateLifetimeStart(alloca.getAddressPointer());
return alloca.withAddress(getAddressForPointer(alloca.getAddressPointer()));
}

void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress,
SILType T) const override {
SILType T, StackAllocationIsNested_t isNested) const override {
IGF.Builder.CreateLifetimeEnd(stackAddress.getAddress().getAddress());
IGF.emitDeallocateDynamicAlloca(stackAddress);
IGF.emitDeallocStackDynamic(stackAddress, isNested);
}

void destroyStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T,
Expand Down
6 changes: 4 additions & 2 deletions lib/IRGen/GenInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ void IRGenModule::emitSILGlobalVariable(SILGlobalVariable *var) {
}

StackAddress FixedTypeInfo::allocateStack(IRGenFunction &IGF, SILType T,
const Twine &name) const {
const Twine &name,
StackAllocationIsNested_t isNested) const {
// If the type is known to be empty, don't actually allocate anything.
if (isKnownEmpty(ResilienceExpansion::Maximal)) {
auto addr = getUndefAddress();
Expand All @@ -81,7 +82,8 @@ void FixedTypeInfo::destroyStack(IRGenFunction &IGF, StackAddress addr,
}

void FixedTypeInfo::deallocateStack(IRGenFunction &IGF, StackAddress addr,
SILType T) const {
SILType T,
StackAllocationIsNested_t isNested) const {
if (isKnownEmpty(ResilienceExpansion::Maximal))
return;
IGF.Builder.CreateLifetimeEnd(addr.getAddress(), getFixedSize());
Expand Down
21 changes: 21 additions & 0 deletions lib/IRGen/GenOpaque.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,27 @@ irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF,
return call;
}

StackAddress
IRGenFunction::emitDynamicStackAllocation(SILType T,
StackAllocationIsNested_t isNested,
const llvm::Twine &name) {
if (isNested) {
return emitDynamicAlloca(T, name);
}

FIXME: use malloc
}

void
IRGenFunction::emitDynamicStackDeallocation(StackAddress address,
StackAllocationIsNested_t isNested) {
if (isNested) {
return emitDeallocateDynamicAlloca(address);
}

FIXME: use malloc
}

/// Emit a dynamic alloca call to allocate enough memory to hold an object of
/// type 'T' and an optional llvm.stackrestore point if 'isInEntryBlock' is
/// false.
Expand Down
6 changes: 4 additions & 2 deletions lib/IRGen/GenType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1374,11 +1374,13 @@ namespace {
return nullptr;
}
StackAddress allocateStack(IRGenFunction &IGF, SILType T,
const llvm::Twine &name) const override {
const llvm::Twine &name,
StackAllocationIsNested_t isNested) const override {
llvm_unreachable("should not call on an immovable opaque type");
}
void deallocateStack(IRGenFunction &IGF, StackAddress addr,
SILType T) const override {
SILType T,
StackAllocationIsNested_t isNested) const override {
llvm_unreachable("should not call on an immovable opaque type");
}
void destroyStack(IRGenFunction &IGF, StackAddress addr, SILType T,
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/IRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ class IRGenFunction {
bool useTaskDeallocThrough = false,
bool forCalleeCoroutineFrame = false);

StackAddress emitAllocStackDynamic(SILType type,
StackAllocationIsNested_t isNested,
const llvm::Twine &name = "");
void emitDeallocStackDynamic(StackAddress address,
StackAllocationIsNested_t isNested);

llvm::BasicBlock *createBasicBlock(const llvm::Twine &Name);
const TypeInfo &getTypeInfoForUnlowered(Type subst);
const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig, Type subst);
Expand Down
16 changes: 11 additions & 5 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6575,7 +6575,9 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
DebugTypeInfo DbgTy;
emitDebugInfoBeforeAllocStack(i, type, DbgTy);

auto stackAddr = type.allocateStack(*this, i->getElementType(), dbgname);
auto stackAddr = type.allocateStack(*this, i->getElementType(),
i->isStackAllocationNested(),
dbgname);
setLoweredStackAddress(i, stackAddr);
Address addr = stackAddr.getAddress();

Expand Down Expand Up @@ -6668,23 +6670,27 @@ void IRGenSILFunction::visitDeallocStackInst(swift::DeallocStackInst *i) {
if (auto *closure = dyn_cast<PartialApplyInst>(i->getOperand())) {
assert(closure->isOnStack());
auto stackAddr = LoweredPartialApplyAllocations[i->getOperand()];
emitDeallocateDynamicAlloca(stackAddr);
emitDeallocStackDynamic(stackAddr, closure->isStackAllocationNested());
return;
}
if (isaResultOf<BeginApplyInst>(i->getOperand())) {
auto *mvi = getAsResultOf<BeginApplyInst>(i->getOperand());
auto *bai = cast<BeginApplyInst>(mvi->getParent());
// FIXME: [non_nested]
const auto &coroutine = getLoweredCoroutine(bai->getTokenResult());
emitDeallocYieldOnce2CoroutineFrame(*this,
coroutine.getCalleeAllocatedFrame());
return;
}

auto allocatedType = i->getOperand()->getType();
auto *asi = cast<AllocStackInst>(i->getOperand());

auto allocatedType = asi->getType();
const TypeInfo &allocatedTI = getTypeInfo(allocatedType);
StackAddress stackAddr = getLoweredStackAddress(i->getOperand());
StackAddress stackAddr = getLoweredStackAddress(asi);
auto isNested = asi->isStackAllocationNested();

allocatedTI.deallocateStack(*this, stackAddr, allocatedType);
allocatedTI.deallocateStack(*this, stackAddr, allocatedType, isNested);
}

void IRGenSILFunction::visitDeallocStackRefInst(DeallocStackRefInst *i) {
Expand Down
11 changes: 7 additions & 4 deletions lib/IRGen/NonFixedTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,21 @@ class WitnessSizedTypeInfo : public IndirectTypeInfo<Impl, TypeInfo> {
static bool isFixed() { return false; }

StackAddress allocateStack(IRGenFunction &IGF, SILType T,
const llvm::Twine &name) const override {
const llvm::Twine &name,
StackAllocationIsNested_t isNested =
StackAllocationIsNested) const override {
// Allocate memory on the stack.
auto alloca = IGF.emitDynamicAlloca(T, name);
auto alloca = IGF.emitDynamicStackAllocation(T, name, isNested);
IGF.Builder.CreateLifetimeStart(alloca.getAddressPointer());
return alloca.withAddress(
getAsBitCastAddress(IGF, alloca.getAddressPointer()));
}

void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress,
SILType T) const override {
SILType T, StackAllocationIsNested_t isNested =
StackAllocationIsNested) const override {
IGF.Builder.CreateLifetimeEnd(stackAddress.getAddress().getAddress());
IGF.emitDeallocateDynamicAlloca(stackAddress);
IGF.emitDynamicStackDeallocation(stackAddress, isNested);
}

void destroyStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T,
Expand Down
8 changes: 6 additions & 2 deletions lib/IRGen/TypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,15 @@ class TypeInfo {

/// Allocate a variable of this type on the stack.
virtual StackAddress allocateStack(IRGenFunction &IGF, SILType T,
const llvm::Twine &name) const = 0;
const llvm::Twine &name,
StackAllocationIsNested_t isNested =
StackAllocationIsNested) const = 0;

/// Deallocate a variable of this type.
virtual void deallocateStack(IRGenFunction &IGF, StackAddress addr,
SILType T) const = 0;
SILType T,
StackAllocationIsNested_t isNested =
StackAllocationIsNested) const = 0;

/// Destroy the value of a variable of this type, then deallocate its
/// memory.
Expand Down
19 changes: 19 additions & 0 deletions lib/SIL/IR/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,25 @@ SILValue SILInstruction::getStackAllocation() const {
return cast<SingleValueInstruction>(this);
}

StackAllocationIsNested_t SILInstruction::isStackAllocationNested() const {
assert(isAllocatingStack());
if (auto ASI = dyn_cast<AllocStackInst>(this)) {
return ASI->isStackAllocationNested();
} else {
// TODO: implement for all remaining allocations
return StackAllocationIsNested;
}
}

void SILInstruction::setStackAllocationIsNested(StackAllocationIsNested_t nested) {
assert(isAllocatingStack());
if (auto ASI = dyn_cast<AllocStackInst>(this)) {
ASI->setStackAllocationIsNested(nested);
} else if (!nested) {
llvm_unreachable("unimplemented");
}
}

bool SILInstruction::isDeallocatingStack() const {
// NOTE: If you're adding a new kind of deallocating instruction,
// there are several places scattered around the SIL optimizer which
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ AllocStackInst::AllocStackInst(
sharedUInt8().AllocStackInst.fromVarDecl = (bool)isFromVarDecl;
sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo =
(bool)usesMoveableValueDebugInfo || elementType.isMoveOnly();
sharedUInt8().AllocStackInst.isNested = true;
sharedUInt32().AllocStackInst.numOperands = TypeDependentOperands.size();

// VarInfo must be initialized after
Expand Down
10 changes: 10 additions & 0 deletions lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,17 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
printDebugInfoExpression(Var->DIExpr);
}

template <class T>
void printNonNested(T *inst) {
static_assert(&T::isStackAllocationNested !=
&SILInstruction::isStackAllocationNested,
"Type doesn't override isStackAllocationNested");
if (!inst->isStackAllocationNested())
*this << "[non_nested] ";
}

void visitAllocStackInst(AllocStackInst *AVI) {
printNonNested(AVI);
if (AVI->hasDynamicLifetime())
*this << "[dynamic_lifetime] ";
if (AVI->isLexical())
Expand Down
17 changes: 11 additions & 6 deletions lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4994,6 +4994,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
auto isFromVarDecl = IsNotFromVarDecl;
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
DoesNotUseMoveableValueDebugInfo;
auto isNested = StackAllocationIsNested;

StringRef attributeName;
SourceLoc attributeLoc;
Expand All @@ -5006,6 +5007,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
isFromVarDecl = IsFromVarDecl;
else if (attributeName == "moveable_value_debuginfo")
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
else if (attributeName == "non_nested")
isNested = StackAllocationIsNotNested;
else {
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
attributeName, "alloc_stack");
Expand All @@ -5025,14 +5028,16 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;

// It doesn't make sense to attach a debug var info if the name is empty
AllocStackInst *ASI;
if (VarInfo.Name.size())
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
isLexical, isFromVarDecl,
usesMoveableValueDebugInfo);
ASI = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
isLexical, isFromVarDecl,
usesMoveableValueDebugInfo);
else
ResultVal =
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical,
isFromVarDecl, usesMoveableValueDebugInfo);
ASI = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical,
isFromVarDecl, usesMoveableValueDebugInfo);
ASI->setStackAllocationIsNested(isNested);
ResultVal = ASI;
break;
}
case SILInstructionKind::MetatypeInst: {
Expand Down
Loading