Skip to content

SILGen: Complete initialization of FinalContext in ConversionInitialization::tryPeephole #59122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 27, 2022
Merged
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
2 changes: 1 addition & 1 deletion lib/SIL/Parser/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2795,7 +2795,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createAllocBox(InstLoc, Ty.castTo<SILBoxType>(), VarInfo,
hasDynamicLifetime);
hasDynamicLifetime, hasReflection);
break;
}
case SILInstructionKind::ApplyInst:
Expand Down
9 changes: 0 additions & 9 deletions lib/SILGen/Conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,6 @@ canPeepholeConversions(SILGenFunction &SGF,
const Conversion &outerConversion,
const Conversion &innerConversion);

ManagedValue emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
const Conversion &outerConversion,
const Conversion &innerConversion,
ConversionPeepholeHint hint,
SGFContext C,
ValueProducerRef produceValue);

/// An initialization where we ultimately want to apply a conversion to
/// the value before completing the initialization.
///
Expand Down Expand Up @@ -354,8 +347,6 @@ class ConvertingInitialization final : public Initialization {
void finishInitialization(SILGenFunction &SGF) override {
assert(getState() == Initialized);
State = Finished;
if (OwnedSubInitialization)
OwnedSubInitialization->finishInitialization(SGF);
}
};

Expand Down
144 changes: 75 additions & 69 deletions lib/SILGen/SILGenConvert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,69 @@ ConvertingInitialization::finishEmission(SILGenFunction &SGF,
llvm_unreachable("bad state");
}

static ManagedValue
emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
const Conversion &outerConversion,
const Conversion &innerConversion,
ConversionPeepholeHint hint,
SGFContext C,
ValueProducerRef produceOrigValue) {
auto produceValue = [&](SGFContext C) {
if (!hint.isForced()) {
return produceOrigValue(SGF, loc, C);
}

auto value = produceOrigValue(SGF, loc, SGFContext());
auto &optTL = SGF.getTypeLowering(value.getType());
// isForceUnwrap is hardcoded true because hint.isForced() is only
// set by implicit force unwraps.
return SGF.emitCheckedGetOptionalValueFrom(loc, value,
/*isForceUnwrap*/ true,
optTL, C);
};

auto getBridgingSourceType = [&] {
CanType sourceType = innerConversion.getBridgingSourceType();
if (hint.isForced())
sourceType = sourceType.getOptionalObjectType();
return sourceType;
};
auto getBridgingResultType = [&] {
return outerConversion.getBridgingResultType();
};
auto getBridgingLoweredResultType = [&] {
return outerConversion.getBridgingLoweredResultType();
};

switch (hint.getKind()) {
case ConversionPeepholeHint::Identity:
return produceValue(C);

case ConversionPeepholeHint::BridgeToAnyObject: {
auto value = produceValue(SGFContext());
return SGF.emitNativeToBridgedValue(loc, value, getBridgingSourceType(),
getBridgingResultType(),
getBridgingLoweredResultType(), C);
}

case ConversionPeepholeHint::Subtype: {
// Otherwise, emit and convert.
// TODO: if the context allows +0, use it in more situations.
auto value = produceValue(SGFContext());
SILType loweredResultTy = getBridgingLoweredResultType();

// Nothing to do if the value already has the right representation.
if (value.getType().getObjectType() == loweredResultTy.getObjectType())
return value;

CanType sourceType = getBridgingSourceType();
CanType resultType = getBridgingResultType();
return SGF.emitTransformedValue(loc, value, sourceType, resultType, C);
}
}
llvm_unreachable("bad kind");
}

bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF,
SILLocation loc,
ManagedValue origValue,
Expand Down Expand Up @@ -1104,6 +1167,15 @@ bool ConvertingInitialization::tryPeephole(SILGenFunction &SGF, SILLocation loc,
ManagedValue value = emitPeepholedConversions(SGF, loc, outerConversion,
innerConversion, *hint,
FinalContext, produceValue);

// The callers to tryPeephole assume that the initialization is ready to be
// finalized after returning. If this conversion sits on top of another
// initialization, forward the value into the underlying initialization and
// report the value as emitted in context.
if (FinalContext.getEmitInto() && !value.isInContext()) {
value.ensurePlusOne(SGF, loc).forwardInto(SGF, loc, FinalContext.getEmitInto());
value = ManagedValue::forInContext();
}
setConvertedValue(value);
return true;
}
Expand All @@ -1117,15 +1189,11 @@ void ConvertingInitialization::copyOrInitValueInto(SILGenFunction &SGF,
// TODO: take advantage of borrowed inputs?
if (!isInit) formalValue = formalValue.copy(SGF, loc);
State = Initialized;
SGFContext emissionContext = OwnedSubInitialization
? SGFContext() : FinalContext;

Value = TheConversion.emit(SGF, loc, formalValue, emissionContext);
Value = TheConversion.emit(SGF, loc, formalValue, FinalContext);

if (OwnedSubInitialization) {
OwnedSubInitialization->copyOrInitValueInto(SGF, loc,
Value,
isInit);
if (FinalContext.getEmitInto() && !Value.isInContext()) {
Value.forwardInto(SGF, loc, FinalContext.getEmitInto());
Value = ManagedValue::forInContext();
}
}
Expand Down Expand Up @@ -1512,65 +1580,3 @@ Lowering::canPeepholeConversions(SILGenFunction &SGF,
llvm_unreachable("bad kind");
}

ManagedValue
Lowering::emitPeepholedConversions(SILGenFunction &SGF, SILLocation loc,
const Conversion &outerConversion,
const Conversion &innerConversion,
ConversionPeepholeHint hint,
SGFContext C,
ValueProducerRef produceOrigValue) {
auto produceValue = [&](SGFContext C) {
if (!hint.isForced()) {
return produceOrigValue(SGF, loc, C);
}

auto value = produceOrigValue(SGF, loc, SGFContext());
auto &optTL = SGF.getTypeLowering(value.getType());
// isForceUnwrap is hardcoded true because hint.isForced() is only
// set by implicit force unwraps.
return SGF.emitCheckedGetOptionalValueFrom(loc, value,
/*isForceUnwrap*/ true,
optTL, C);
};

auto getBridgingSourceType = [&] {
CanType sourceType = innerConversion.getBridgingSourceType();
if (hint.isForced())
sourceType = sourceType.getOptionalObjectType();
return sourceType;
};
auto getBridgingResultType = [&] {
return outerConversion.getBridgingResultType();
};
auto getBridgingLoweredResultType = [&] {
return outerConversion.getBridgingLoweredResultType();
};

switch (hint.getKind()) {
case ConversionPeepholeHint::Identity:
return produceValue(C);

case ConversionPeepholeHint::BridgeToAnyObject: {
auto value = produceValue(SGFContext());
return SGF.emitNativeToBridgedValue(loc, value, getBridgingSourceType(),
getBridgingResultType(),
getBridgingLoweredResultType(), C);
}

case ConversionPeepholeHint::Subtype: {
// Otherwise, emit and convert.
// TODO: if the context allows +0, use it in more situations.
auto value = produceValue(SGFContext());
SILType loweredResultTy = getBridgingLoweredResultType();

// Nothing to do if the value already has the right representation.
if (value.getType().getObjectType() == loweredResultTy.getObjectType())
return value;

CanType sourceType = getBridgingSourceType();
CanType resultType = getBridgingResultType();
return SGF.emitTransformedValue(loc, value, sourceType, resultType, C);
}
}
llvm_unreachable("bad kind");
}
18 changes: 18 additions & 0 deletions test/SIL/Parser/boxes.sil
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,21 @@ sil [ossa] @address_of_box : $@convention(thin) (@in { var Int }, @in <T> { let
entry(%0 : $*{ var Int }, %1 : $*<T> { let T } <Int>):
unreachable
}

// CHECK-LABEL: sil [ossa] @alloc_box_attrs
sil [ossa] @alloc_box_attrs : $@convention(thin) () -> () {
entry:
// CHECK: %0 = alloc_box $
%0 = alloc_box ${ let Int }
// CHECK: %1 = alloc_box [dynamic_lifetime] $
%1 = alloc_box [dynamic_lifetime] ${ let Int }
// CHECK: %2 = alloc_box [reflection] $
%2 = alloc_box [reflection] ${ let Int }
// CHECK: %3 = alloc_box [dynamic_lifetime] [reflection] $
%3 = alloc_box [dynamic_lifetime] [reflection] ${ let Int }
dealloc_box %3: ${ let Int }
dealloc_box %2: ${ let Int }
dealloc_box %1: ${ let Int }
dealloc_box %0: ${ let Int }
return undef : $()
}
32 changes: 32 additions & 0 deletions test/SILGen/literal_closure_reabstraction_with_peephole.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// RUN: %target-swift-emit-silgen -verify %s

fileprivate typealias Closure = () -> Void

func crash1() {
let closure1: Closure? = nil
let closure2: Closure? = nil
let closure3: Closure? = nil
print("Closures: \(String(describing: closure1)), \(String(describing: closure2)), \(String(describing: closure3))")

let closure = closure1 ?? closure2 ?? closure3

print("\(#line): \(String(describing: closure))")
closure?() // <- EXC_BAD_ACCESS
assert(closure == nil)
}

func crash2() {
let closure1: Closure? = nil
let closure2: Closure? = nil
let closure3: Closure? = { }
print("Closures: \(String(describing: closure1)), \(String(describing: closure2)), \(String(describing: closure3))")

let closure = closure1 ?? closure2 ?? closure3

print("\(#line): \(String(describing: closure))")
closure?() // <- EXC_BAD_ACCESS
assert(closure != nil)
}

crash1()
crash2()