Skip to content

[WIP] SILGen: Capture address-only lets with the in_guaranteed convention. #17047

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

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 6 additions & 2 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1925,8 +1925,12 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(

// There are variables without storage, such as "struct { func foo() {}
// }". Emit them as constant 0.
if (isa<llvm::UndefValue>(Piece))
Piece = llvm::ConstantInt::get(IGM.Int64Ty, 0);
if (isa<llvm::UndefValue>(Piece)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What was this change about?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The existing behavior is broken for an undef of any type that isn't 64 bits in size. I should break it out into its own commit.

auto undefSize = IGM.DataLayout.getTypeSizeInBits(Piece->getType());

Piece = llvm::ConstantInt::get(
llvm::IntegerType::get(IGM.getLLVMContext(), undefSize), 0);
}

if (IsPiece) {
// Advance the offset and align it for the next piece.
Expand Down
11 changes: 9 additions & 2 deletions lib/SIL/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,9 +881,16 @@ lowerCaptureContextParameters(SILModule &M, AnyFunctionRef function,
case CaptureKind::StorageAddress: {
// Non-escaping lvalues are captured as the address of the value.
SILType ty = loweredTy.getAddressType();

ParameterConvention convention
= ParameterConvention::Indirect_InoutAliasable;

if (auto var = dyn_cast<VarDecl>(VD))
if (var->isLet())
convention = ParameterConvention::Indirect_In_Guaranteed;

auto param =
SILParameterInfo(ty.getASTType(),
ParameterConvention::Indirect_InoutAliasable);
SILParameterInfo(ty.getASTType(), convention);
inputs.push_back(param);
break;
}
Expand Down
26 changes: 16 additions & 10 deletions lib/SILOptimizer/IPO/ClosureSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,17 @@ SingleValueInstruction *CallSiteDescriptor::getClosure() const {
return CInfo->Closure;
}

static bool isNonInoutIndirectSILArgument(SILValue Arg,
static bool isConsumingIndirectSILArgumentConvention(SILArgumentConvention ArgConvention) {
return ArgConvention.isIndirectConvention() &&
ArgConvention != SILArgumentConvention::Indirect_In_Guaranteed &&
ArgConvention != SILArgumentConvention::Indirect_Inout &&
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable;
}

static bool isConsumingIndirectSILArgument(SILValue Arg,
SILArgumentConvention ArgConvention) {
return !Arg->getType().isObject() && ArgConvention.isIndirectConvention() &&
ArgConvention != SILArgumentConvention::Indirect_Inout &&
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable;
return !Arg->getType().isObject()
&& isConsumingIndirectSILArgumentConvention(ArgConvention);
}

/// Update the callsite to pass in the correct arguments.
Expand Down Expand Up @@ -332,12 +338,12 @@ static void rewriteApplyInst(const CallSiteDescriptor &CSDesc,

// Non-inout indirect arguments are not supported yet.
assert(ArgTy.isObject() ||
!isNonInoutIndirectSILArgument(Arg, ArgConvention));
!isConsumingIndirectSILArgument(Arg, ArgConvention));

// If argument is not an object and it is an inout parameter,
// continue...
if (!ArgTy.isObject() &&
!isNonInoutIndirectSILArgument(Arg, ArgConvention)) {
!isConsumingIndirectSILArgument(Arg, ArgConvention)) {
NewArgs.push_back(Arg);
++ClosureArgIdx;
continue;
Expand Down Expand Up @@ -472,7 +478,7 @@ void CallSiteDescriptor::extendArgumentLifetime(
SILBuilderWithScope Builder(getClosure());

// Indirect non-inout arguments are not supported yet.
assert(!isNonInoutIndirectSILArgument(Arg, ArgConvention));
assert(!isConsumingIndirectSILArgument(Arg, ArgConvention));

if (ArgTy.isObject()) {
Builder.createRetainValue(getClosure()->getLoc(), Arg,
Expand Down Expand Up @@ -534,8 +540,7 @@ static bool isSupportedClosure(const SILInstruction *Closure) {
}
auto ArgConvention =
ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx);
if (ArgConvention != SILArgumentConvention::Indirect_Inout &&
ArgConvention != SILArgumentConvention::Indirect_InoutAliasable)
if (isConsumingIndirectSILArgumentConvention(ArgConvention))
return false;
++ClosureArgIdx;
}
Expand Down Expand Up @@ -601,7 +606,8 @@ ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc,
ParamConv = PInfo.getConvention();
assert(!SILModuleConventions(M).useLoweredAddresses()
|| ParamConv == ParameterConvention::Indirect_Inout
|| ParamConv == ParameterConvention::Indirect_InoutAliasable);
|| ParamConv == ParameterConvention::Indirect_InoutAliasable
|| ParamConv == ParameterConvention::Indirect_In_Guaranteed);
} else {
ParamConv = ClosedOverFunConv.getSILType(PInfo).isTrivial(M)
? ParameterConvention::Direct_Unowned
Expand Down
4 changes: 2 additions & 2 deletions test/SILGen/generic_closures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ class NestedGeneric<U> {

// CHECK: sil hidden @$S16generic_closures018nested_closure_in_A0yxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T
// CHECK: function_ref [[OUTER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_]]
// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T
// CHECK: sil private [[OUTER_CLOSURE]] : $@convention(thin) <T> (@in_guaranteed T) -> @out T
// CHECK: function_ref [[INNER_CLOSURE:@\$S16generic_closures018nested_closure_in_A0yxxlFxyXEfU_xyXEfU_]]
// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@inout_aliasable T) -> @out T {
// CHECK: sil private [[INNER_CLOSURE]] : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
func nested_closure_in_generic<T>(_ x:T) -> T {
return { { x }() }()
}
Expand Down
32 changes: 32 additions & 0 deletions test/SILOptimizer/definite_init_address_only_let.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// RUN: %target-swift-frontend -emit-sil -verify %s

func foo<T>(a: Bool, t: T) {
let x: T
defer { print(x) }

x = t
return
}

func bar<T>(a: Bool, t: T) {
let x: T // expected-note {{defined here}}
defer { print(x) } //expected-error{{constant 'x' used before being initialized}}

if a {
x = t
return
}
}

func bas<T>(a: Bool, t: T) {
let x: T
defer { print(x) }

if a {
x = t
return
}

x = t
}