Skip to content

Commit 24c69c6

Browse files
authored
Merge pull request #85604 from gottesmm/alloc_stack_non_nested
[irgen] Implement support for alloc_stack non_nested.
2 parents 80c8bf0 + 94e9166 commit 24c69c6

32 files changed

+621
-136
lines changed

SwiftCompilerSources/Sources/SIL/Utilities/Verifier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ private func require(_ condition: Bool, _ message: @autoclosure () -> String, at
2222
if !condition {
2323
let msg = message()
2424
msg._withBridgedStringRef { stringRef in
25-
BridgedVerifier.verifierError(stringRef, atInstruction.bridged, Optional<Argument>.none.bridged)
25+
BridgedVerifier.verifierError(stringRef, atInstruction.bridged)
2626
}
2727
}
2828
}

include/swift/SIL/SILBridging.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1627,8 +1627,12 @@ struct BridgedVerifier {
16271627
static void runSwiftFunctionVerification(swift::SILFunction * _Nonnull f, swift::SILContext * _Nonnull context);
16281628

16291629
static void registerVerifier(VerifyFunctionFn verifyFunctionFn);
1630-
static void verifierError(BridgedStringRef message, OptionalBridgedInstruction atInstruction,
1630+
static void verifierError(BridgedStringRef message,
1631+
OptionalBridgedInstruction atInstruction);
1632+
static void verifierError(BridgedStringRef message,
16311633
OptionalBridgedArgument atArgument);
1634+
static void verifierError(BridgedStringRef message,
1635+
OptionalBridgedValue atValue);
16321636
};
16331637

16341638
struct BridgedUtilities {

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ SILCloner<ImplClass>::visitAllocStackInst(AllocStackInst *Inst) {
10621062
true
10631063
#endif
10641064
);
1065+
NewInst->setStackAllocationIsNested(Inst->isStackAllocationNested());
10651066
recordClonedInstruction(Inst, NewInst);
10661067
}
10671068

include/swift/SIL/SILInstruction.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ class SILPrintContext;
141141

142142
template <typename ImplClass> class SILClonerWithScopes;
143143

144+
/// An enum that describes whether or not a stack allocation may violate the
145+
/// stack discipline of swift.
146+
///
147+
/// DISCUSSION: In swift, we require that all allocations on the stack be
148+
/// strictly allocated in a LIFO order... that is the last stack allocation
149+
/// created must be the first stack allocation destroyed. In some cases, we
150+
/// cannot guarantee that behavior. In such cases we may need to use other
151+
/// strategies that do not involve stack memory (e.x.: using heap memory
152+
/// although we do not require heap memory to be used).
153+
enum StackAllocationIsNested_t : bool {
154+
/// The instruction may not obey the LIFO rule of stack allocation.
155+
StackAllocationIsNotNested = false,
156+
157+
/// The instruction obeys the LIFO rule of stack allocation and can allocate
158+
/// memory on the stack normally.
159+
StackAllocationIsNested = true,
160+
};
161+
144162
enum class MemoryBehavior {
145163
None,
146164
/// The instruction may read memory.
@@ -858,6 +876,15 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
858876
/// The stack allocation produced by the instruction, if any.
859877
SILValue getStackAllocation() const;
860878

879+
/// Returns the kind of stack memory that should be allocated. There are
880+
/// certain (unfortunate) situations in which "stack" allocations may become
881+
/// unnested and must use alternative allocation strategies. Rather than
882+
/// requiring all of these to explicitly use heap allocation, which may be
883+
/// to be significantly less efficient (e.g. )
884+
StackAllocationIsNested_t isStackAllocationNested() const;
885+
886+
void setStackAllocationIsNested(StackAllocationIsNested_t isNested);
887+
861888
/// Returns true if this is the deallocation of a stack allocating instruction.
862889
/// The first operand must be the allocating instruction.
863890
bool isDeallocatingStack() const;
@@ -2055,6 +2082,24 @@ class AllocStackInst final
20552082
}
20562083
}
20572084

2085+
StackAllocationIsNested_t isStackAllocationNested() const {
2086+
if (sharedUInt8().AllocStackInst.isNested) {
2087+
return StackAllocationIsNested;
2088+
}
2089+
return StackAllocationIsNotNested;
2090+
}
2091+
2092+
void setStackAllocationIsNested(StackAllocationIsNested_t isNested) {
2093+
switch (isNested) {
2094+
case StackAllocationIsNotNested:
2095+
sharedUInt8().AllocStackInst.isNested = false;
2096+
break;
2097+
case StackAllocationIsNested:
2098+
sharedUInt8().AllocStackInst.isNested = true;
2099+
break;
2100+
}
2101+
}
2102+
20582103
void markUsesMoveableValueDebugInfo() {
20592104
sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo =
20602105
(bool)UsesMoveableValueDebugInfo;

include/swift/SIL/SILModule.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,10 +1161,18 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILModule &M){
11611161
return OS;
11621162
}
11631163

1164-
void verificationFailure(const Twine &complaint,
1165-
const SILInstruction *atInstruction,
1166-
const SILArgument *atArgument,
1167-
llvm::function_ref<void(SILPrintContext &ctx)> extraContext);
1164+
void verificationFailure(
1165+
const Twine &complaint, const SILFunction *fn,
1166+
llvm::function_ref<void(SILPrintContext &ctx)> extraContext);
1167+
void verificationFailure(
1168+
const Twine &complaint, const SILInstruction *atInstruction,
1169+
llvm::function_ref<void(SILPrintContext &ctx)> extraContext);
1170+
void verificationFailure(
1171+
const Twine &complaint, const SILArgument *atArgument,
1172+
llvm::function_ref<void(SILPrintContext &ctx)> extraContext);
1173+
void verificationFailure(
1174+
const Twine &complaint, SILValue atValue,
1175+
llvm::function_ref<void(SILPrintContext &ctx)> extraContext);
11681176

11691177
inline bool SILOptions::supportsLexicalLifetimes(const SILModule &mod) const {
11701178
switch (mod.getStage()) {

include/swift/SIL/SILNode.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ class alignas(8) SILNode :
229229
lexical : 1,
230230
fromVarDecl : 1,
231231
usesMoveableValueDebugInfo : 1,
232-
hasInvalidatedVarInfo : 1);
232+
hasInvalidatedVarInfo : 1,
233+
isNested : 1);
233234

234235
SHARED_FIELD(AllocBoxInst, uint8_t
235236
dynamicLifetime : 1,

lib/IRGen/FixedTypeInfo.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,12 @@ class FixedTypeInfo : public TypeInfo {
8282
}
8383

8484
StackAddress allocateStack(IRGenFunction &IGF, SILType T,
85-
const llvm::Twine &name) const override;
86-
void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T) const override;
85+
const llvm::Twine &name,
86+
StackAllocationIsNested_t isNested =
87+
StackAllocationIsNested) const override;
88+
void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T,
89+
StackAllocationIsNested_t isNested =
90+
StackAllocationIsNested) const override;
8791
void destroyStack(IRGenFunction &IGF, StackAddress addr, SILType T,
8892
bool isOutlined) const override;
8993

lib/IRGen/GenArray.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -638,24 +638,26 @@ class NonFixedArrayTypeInfo final
638638
return nullptr;
639639
}
640640

641-
StackAddress allocateStack(IRGenFunction &IGF, SILType T,
642-
const llvm::Twine &name) const override {
641+
StackAddress
642+
allocateStack(IRGenFunction &IGF, SILType T, const llvm::Twine &name,
643+
StackAllocationIsNested_t isNested) const override {
643644
// Allocate memory on the stack.
644-
auto alloca = IGF.emitDynamicAlloca(T, name);
645+
auto alloca = IGF.emitDynamicStackAllocation(T, isNested, name);
645646
IGF.Builder.CreateLifetimeStart(alloca.getAddressPointer());
646647
return alloca.withAddress(getAddressForPointer(alloca.getAddressPointer()));
647648
}
648649

649-
void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress,
650-
SILType T) const override {
650+
void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T,
651+
StackAllocationIsNested_t isNested) const override {
651652
IGF.Builder.CreateLifetimeEnd(stackAddress.getAddress().getAddress());
652-
IGF.emitDeallocateDynamicAlloca(stackAddress);
653+
IGF.emitDynamicStackDeallocation(stackAddress, isNested);
653654
}
654655

655656
void destroyStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T,
656657
bool isOutlined) const override {
657658
emitDestroyCall(IGF, T, stackAddress.getAddress());
658-
deallocateStack(IGF, stackAddress, T);
659+
// For now, just always do nested.
660+
deallocateStack(IGF, stackAddress, T, StackAllocationIsNested);
659661
}
660662

661663
TypeLayoutEntry *

lib/IRGen/GenInit.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ void IRGenModule::emitSILGlobalVariable(SILGlobalVariable *var) {
5959
var->isDefinition() ? ForDefinition : NotForDefinition);
6060
}
6161

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

8384
void FixedTypeInfo::deallocateStack(IRGenFunction &IGF, StackAddress addr,
84-
SILType T) const {
85+
SILType T,
86+
StackAllocationIsNested_t isNested) const {
8587
if (isKnownEmpty(ResilienceExpansion::Maximal))
8688
return;
8789
IGF.Builder.CreateLifetimeEnd(addr.getAddress(), getFixedSize());

lib/IRGen/GenOpaque.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,38 @@ irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF,
553553
return call;
554554
}
555555

556+
StackAddress IRGenFunction::emitDynamicStackAllocation(
557+
SILType T, StackAllocationIsNested_t isNested, const llvm::Twine &name) {
558+
if (isNested) {
559+
return emitDynamicAlloca(T, name);
560+
}
561+
562+
// First malloc the memory.
563+
auto mallocFn = IGM.getMallocFunctionPointer();
564+
auto *size = emitLoadOfSize(*this, T);
565+
auto *call = Builder.CreateCall(mallocFn, {size});
566+
call->setDoesNotThrow();
567+
call->setCallingConv(IGM.C_CC);
568+
569+
// Then create the dynamic alloca to store the malloc pointer into.
570+
571+
// TODO: Alignment should be platform specific.
572+
auto address = Address(call, IGM.Int8Ty, Alignment(16));
573+
return StackAddress{address};
574+
}
575+
576+
void IRGenFunction::emitDynamicStackDeallocation(
577+
StackAddress address, StackAllocationIsNested_t isNested) {
578+
if (isNested) {
579+
return emitDeallocateDynamicAlloca(address);
580+
}
581+
582+
auto *call = Builder.CreateCall(IGM.getFreeFunctionPointer(),
583+
{address.getAddressPointer()});
584+
call->setDoesNotThrow();
585+
call->setCallingConv(IGM.C_CC);
586+
}
587+
556588
/// Emit a dynamic alloca call to allocate enough memory to hold an object of
557589
/// type 'T' and an optional llvm.stackrestore point if 'isInEntryBlock' is
558590
/// false.

0 commit comments

Comments
 (0)