Skip to content

Commit

Permalink
Add a new parameter convention @in_cxx for non-trivial C++ classes …
Browse files Browse the repository at this point in the history
…that are passed indirectly and destructed by the caller (swiftlang#73019)

This corresponds to the parameter-passing convention of the Itanium C++
ABI, in which the argument is passed indirectly and possibly modified,
but not destroyed, by the callee.

@in_cxx is handled the same way as @in in callers and @in_guaranteed in
callees. OwnershipModelEliminator emits the call to destroy_addr that is
needed to destroy the argument in the caller.

rdar://122707697
  • Loading branch information
ahatanaka committed Jun 27, 2024
1 parent 9d6e36b commit 42bc49d
Show file tree
Hide file tree
Showing 64 changed files with 736 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ private struct CollectedEffects {
private mutating func addEffects<Arguments: Sequence>(ofFunctions callees: FunctionArray?,
withArguments arguments: Arguments)
where Arguments.Element == (calleeArgumentIndex: Int, callerArgument: Value) {
// The argument summary for @in_cxx is insufficient in OSSA because the function body does not contain the
// destroy. But the call is still effectively a release from the caller's perspective.
guard let callees = callees else {
// We don't know which function(s) are called.
globalEffects = .worstEffects
Expand Down
30 changes: 22 additions & 8 deletions SwiftCompilerSources/Sources/SIL/Argument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ public enum ArgumentConvention : CustomStringConvertible {
/// convention used by mutable captures in @noescape closures.
case indirectInoutAliasable

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The callee may modify, but does not destroy the
/// object. This corresponds to the parameter-passing convention of the
/// Itanium C++ ABI, which is used ubiquitously on non-Windows targets.
case indirectInCXX

/// This argument represents an indirect return value address. The callee stores
/// the returned value to this argument. At the time when the function is called,
/// the memory location referenced by the argument is uninitialized.
Expand Down Expand Up @@ -407,8 +413,9 @@ public enum ArgumentConvention : CustomStringConvertible {
public var isIndirect: Bool {
switch self {
case .indirectIn, .indirectInGuaranteed,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.packOut, .packInout, .packOwned, .packGuaranteed:
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.indirectOut, .packOut, .packInout, .packOwned,
.packGuaranteed:
return true
case .directOwned, .directUnowned, .directGuaranteed:
return false
Expand All @@ -417,11 +424,12 @@ public enum ArgumentConvention : CustomStringConvertible {

public var isIndirectIn: Bool {
switch self {
case .indirectIn, .indirectInGuaranteed,
case .indirectIn, .indirectInGuaranteed, .indirectInCXX,
.packOwned, .packGuaranteed:
return true
case .directOwned, .directUnowned, .directGuaranteed,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.indirectInout, .indirectInoutAliasable,
.indirectOut,
.packOut, .packInout:
return false
}
Expand All @@ -433,7 +441,7 @@ public enum ArgumentConvention : CustomStringConvertible {
return true
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed,
.indirectIn, .directOwned, .directUnowned,
.indirectInout, .indirectInoutAliasable,
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.packInout, .packOwned:
return false
}
Expand All @@ -444,15 +452,15 @@ public enum ArgumentConvention : CustomStringConvertible {
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed:
return true
case .indirectIn, .directOwned, .directUnowned,
.indirectInout, .indirectInoutAliasable, .indirectOut,
.packOut, .packInout, .packOwned:
.indirectInout, .indirectInoutAliasable, .indirectInCXX,
.indirectOut, .packOut, .packInout, .packOwned:
return false
}
}

public var isConsumed: Bool {
switch self {
case .indirectIn, .directOwned, .packOwned:
case .indirectIn, .indirectInCXX, .directOwned, .packOwned:
return true
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed,
.indirectInout, .indirectInoutAliasable, .indirectOut,
Expand All @@ -467,6 +475,7 @@ public enum ArgumentConvention : CustomStringConvertible {
.indirectOut,
.indirectInGuaranteed,
.indirectInout,
.indirectInCXX,
.packOut,
.packInout,
.packOwned,
Expand All @@ -491,6 +500,7 @@ public enum ArgumentConvention : CustomStringConvertible {
case .indirectIn,
.indirectOut,
.indirectInGuaranteed,
.indirectInCXX,
.directUnowned,
.directGuaranteed,
.directOwned,
Expand All @@ -511,6 +521,8 @@ public enum ArgumentConvention : CustomStringConvertible {
return "indirectInout"
case .indirectInoutAliasable:
return "indirectInoutAliasable"
case .indirectInCXX:
return "indirectInCXX"
case .indirectOut:
return "indirectOut"
case .directOwned:
Expand Down Expand Up @@ -545,6 +557,7 @@ extension BridgedArgumentConvention {
case .Indirect_In_Guaranteed: return .indirectInGuaranteed
case .Indirect_Inout: return .indirectInout
case .Indirect_InoutAliasable: return .indirectInoutAliasable
case .Indirect_In_CXX: return .indirectInCXX
case .Indirect_Out: return .indirectOut
case .Direct_Owned: return .directOwned
case .Direct_Unowned: return .directUnowned
Expand All @@ -566,6 +579,7 @@ extension ArgumentConvention {
case .indirectInGuaranteed: return .Indirect_In_Guaranteed
case .indirectInout: return .Indirect_Inout
case .indirectInoutAliasable: return .Indirect_InoutAliasable
case .indirectInCXX: return .Indirect_In_CXX
case .indirectOut: return .Indirect_Out
case .directOwned: return .Direct_Owned
case .directUnowned: return .Direct_Unowned
Expand Down
2 changes: 1 addition & 1 deletion SwiftCompilerSources/Sources/SIL/Effects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
result.memory = SideEffects.Memory()
}

case .indirectInout, .indirectInoutAliasable:
case .indirectInout, .indirectInoutAliasable, .indirectInCXX:
break
}
return result
Expand Down
2 changes: 1 addition & 1 deletion SwiftCompilerSources/Sources/SIL/FunctionConvention.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public struct ParameterInfo : CustomStringConvertible {
switch convention {
case .indirectIn, .indirectInGuaranteed:
return hasLoweredAddresses || type.isOpenedExistentialWithError()
case .indirectInout, .indirectInoutAliasable:
case .indirectInout, .indirectInoutAliasable, .indirectInCXX:
return true
case .directOwned, .directUnowned, .directGuaranteed:
return false
Expand Down
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,7 @@ mangled in to disambiguate.
PARAM-CONVENTION ::= 'l' // indirect inout
PARAM-CONVENTION ::= 'b' // indirect inout aliasable
PARAM-CONVENTION ::= 'n' // indirect in guaranteed
PARAM-CONVENTION ::= 'X' // indirect in C++
PARAM-CONVENTION ::= 'x' // direct owned
PARAM-CONVENTION ::= 'y' // direct unowned
PARAM-CONVENTION ::= 'g' // direct guaranteed
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ SIMPLE_SIL_TYPE_ATTR(in, In)
SIMPLE_SIL_TYPE_ATTR(inout, Inout)
SIMPLE_SIL_TYPE_ATTR(inout_aliasable, InoutAliasable)
SIMPLE_SIL_TYPE_ATTR(in_guaranteed, InGuaranteed)
SIMPLE_SIL_TYPE_ATTR(in_cxx, InCXX)
SIMPLE_SIL_TYPE_ATTR(in_constant, InConstant)
SIMPLE_SIL_TYPE_ATTR(pack_owned, PackOwned)
SIMPLE_SIL_TYPE_ATTR(pack_guaranteed, PackGuaranteed)
Expand Down
19 changes: 17 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4068,6 +4068,12 @@ enum class ParameterConvention : uint8_t {
/// convention used by mutable captures in @noescape closures.
Indirect_InoutAliasable,

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The callee may modify, but does not destroy the
/// object. This corresponds to the parameter-passing convention of the
/// Itanium C++ ABI, which is used ubiquitously on non-Windows targets.
Indirect_In_CXX,

/// This argument is passed directly. Its type is non-trivial, and the callee
/// is responsible for destroying it.
Direct_Owned,
Expand Down Expand Up @@ -4108,6 +4114,7 @@ inline bool isIndirectFormalParameter(ParameterConvention conv) {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed:
return true;

Expand All @@ -4129,7 +4136,8 @@ bool isConsumedParameter(ParameterConvention conv) {
case ParameterConvention::Direct_Owned:
case ParameterConvention::Pack_Owned:
return true;

case ParameterConvention::Indirect_In_CXX:
return !InCallee;
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Direct_Unowned:
Expand Down Expand Up @@ -4160,7 +4168,8 @@ bool isGuaranteedParameter(ParameterConvention conv) {
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Pack_Guaranteed:
return true;

case ParameterConvention::Indirect_In_CXX:
return InCallee;
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In:
Expand All @@ -4185,6 +4194,7 @@ inline bool isMutatingParameter(ParameterConvention conv) {
switch (conv) {
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Pack_Inout:
return true;

Expand All @@ -4211,6 +4221,7 @@ inline bool isPackParameter(ParameterConvention conv) {
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In:
case ParameterConvention::Direct_Guaranteed:
case ParameterConvention::Direct_Unowned:
Expand Down Expand Up @@ -4291,6 +4302,10 @@ class SILParameterInfo {
return getConvention() == ParameterConvention::Indirect_In;
}

bool isIndirectInCXX() const {
return getConvention() == ParameterConvention::Indirect_In_CXX;
}

bool isIndirectInOut() const {
return getConvention() == ParameterConvention::Indirect_Inout;
}
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/ApplySite.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ class ApplySite {
: SILArgumentConvention::Direct_Owned;
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_In_CXX:
return pai->isOnStack() ? SILArgumentConvention::Indirect_In_Guaranteed
: SILArgumentConvention::Indirect_In;
case SILArgumentConvention::Pack_Guaranteed:
Expand Down
11 changes: 11 additions & 0 deletions include/swift/SIL/SILArgumentConvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct SILArgumentConvention {
Indirect_In_Guaranteed,
Indirect_Inout,
Indirect_InoutAliasable,
Indirect_In_CXX,
Indirect_Out,
Direct_Owned,
Direct_Unowned,
Expand Down Expand Up @@ -55,6 +56,9 @@ struct SILArgumentConvention {
case ParameterConvention::Indirect_In_Guaranteed:
Value = SILArgumentConvention::Indirect_In_Guaranteed;
return;
case ParameterConvention::Indirect_In_CXX:
Value = SILArgumentConvention::Indirect_In_CXX;
return;
case ParameterConvention::Direct_Unowned:
Value = SILArgumentConvention::Direct_Unowned;
return;
Expand Down Expand Up @@ -92,6 +96,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Direct_Owned:
case SILArgumentConvention::Direct_Guaranteed:
Expand All @@ -110,6 +115,8 @@ struct SILArgumentConvention {
case SILArgumentConvention::Direct_Owned:
case SILArgumentConvention::Pack_Owned:
return true;
case SILArgumentConvention::Indirect_In_CXX:
return !InCallee;
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Direct_Guaranteed:
case SILArgumentConvention::Indirect_Inout:
Expand All @@ -135,6 +142,8 @@ struct SILArgumentConvention {
case SILArgumentConvention::Direct_Guaranteed:
case SILArgumentConvention::Pack_Guaranteed:
return true;
case SILArgumentConvention::Indirect_In_CXX:
return InCallee;
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_In:
case SILArgumentConvention::Indirect_Out:
Expand Down Expand Up @@ -164,6 +173,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_Out:
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_In_CXX:
return true;

case SILArgumentConvention::Indirect_InoutAliasable:
Expand All @@ -190,6 +200,7 @@ struct SILArgumentConvention {
case SILArgumentConvention::Indirect_In_Guaranteed:
case SILArgumentConvention::Indirect_Inout:
case SILArgumentConvention::Indirect_InoutAliasable:
case SILArgumentConvention::Indirect_In_CXX:
case SILArgumentConvention::Direct_Unowned:
case SILArgumentConvention::Direct_Guaranteed:
case SILArgumentConvention::Direct_Owned:
Expand Down
3 changes: 3 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ enum class BridgedArgumentConvention {
Indirect_In_Guaranteed,
Indirect_Inout,
Indirect_InoutAliasable,
Indirect_In_CXX,
Indirect_Out,
Direct_Owned,
Direct_Unowned,
Expand All @@ -153,6 +154,7 @@ inline swift::ParameterConvention getParameterConvention(BridgedArgumentConventi
case BridgedArgumentConvention::Indirect_In_Guaranteed: return swift::ParameterConvention::Indirect_In_Guaranteed;
case BridgedArgumentConvention::Indirect_Inout: return swift::ParameterConvention::Indirect_Inout;
case BridgedArgumentConvention::Indirect_InoutAliasable: return swift::ParameterConvention::Indirect_InoutAliasable;
case BridgedArgumentConvention::Indirect_In_CXX: return swift::ParameterConvention::Indirect_In_CXX;
case BridgedArgumentConvention::Indirect_Out: break;
case BridgedArgumentConvention::Direct_Owned: return swift::ParameterConvention::Direct_Owned;
case BridgedArgumentConvention::Direct_Unowned: return swift::ParameterConvention::Direct_Unowned;
Expand All @@ -171,6 +173,7 @@ inline BridgedArgumentConvention getArgumentConvention(swift::ParameterConventio
case swift::ParameterConvention::Indirect_In_Guaranteed: return BridgedArgumentConvention::Indirect_In_Guaranteed;
case swift::ParameterConvention::Indirect_Inout: return BridgedArgumentConvention::Indirect_Inout;
case swift::ParameterConvention::Indirect_InoutAliasable: return BridgedArgumentConvention::Indirect_InoutAliasable;
case swift::ParameterConvention::Indirect_In_CXX: return BridgedArgumentConvention::Indirect_In_CXX;
case swift::ParameterConvention::Direct_Owned: return BridgedArgumentConvention::Direct_Owned;
case swift::ParameterConvention::Direct_Unowned: return BridgedArgumentConvention::Direct_Unowned;
case swift::ParameterConvention::Direct_Guaranteed: return BridgedArgumentConvention::Direct_Guaranteed;
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILFunctionConventions.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ inline bool SILModuleConventions::isIndirectSILParam(SILParameterInfo param,

case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
return isTypeIndirectForIndirectParamConvention(param.getInterfaceType(),
loweredAddresses);
case ParameterConvention::Indirect_Inout:
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ static char getParamConvention(ParameterConvention conv) {
case ParameterConvention::Indirect_Inout: return 'l';
case ParameterConvention::Indirect_InoutAliasable: return 'b';
case ParameterConvention::Indirect_In_Guaranteed: return 'n';
case ParameterConvention::Indirect_In_CXX: return 'X';
case ParameterConvention::Direct_Owned: return 'x';
case ParameterConvention::Direct_Unowned: return 'y';
case ParameterConvention::Direct_Guaranteed: return 'g';
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6757,6 +6757,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In_Guaranteed:
llvm_unreachable("callee convention cannot be indirect");
case ParameterConvention::Pack_Guaranteed:
Expand Down Expand Up @@ -7526,6 +7527,7 @@ StringRef swift::getStringForParameterConvention(ParameterConvention conv) {
case ParameterConvention::Indirect_In_Guaranteed: return "@in_guaranteed ";
case ParameterConvention::Indirect_Inout: return "@inout ";
case ParameterConvention::Indirect_InoutAliasable: return "@inout_aliasable ";
case ParameterConvention::Indirect_In_CXX: return "@in_cxx ";
case ParameterConvention::Direct_Owned: return "@owned ";
case ParameterConvention::Direct_Unowned: return "";
case ParameterConvention::Direct_Guaranteed: return "@guaranteed ";
Expand Down
1 change: 1 addition & 0 deletions lib/ASTGen/Sources/ASTGen/TypeAttrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ extension ASTGenVisitor {
.in,
.inConstant,
.inGuaranteed,
.inCXX,
.inout,
.inoutAliasable,
.moveOnly,
Expand Down
1 change: 1 addition & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2161,6 +2161,7 @@ NodePointer Demangler::demangleImplParamConvention(Node::Kind ConvKind) {
case 'l': attr = "@inout"; break;
case 'b': attr = "@inout_aliasable"; break;
case 'n': attr = "@in_guaranteed"; break;
case 'X': attr = "@in_cxx"; break;
case 'x': attr = "@owned"; break;
case 'g': attr = "@guaranteed"; break;
case 'e': attr = "@deallocating"; break;
Expand Down
1 change: 1 addition & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,7 @@ ManglingError Remangler::mangleImplFunctionType(Node *node, unsigned depth) {
.Case("@inout", 'l')
.Case("@inout_aliasable", 'b')
.Case("@in_guaranteed", 'n')
.Case("@in_cxx", 'X')
.Case("@in_constant", 'c')
.Case("@owned", 'x')
.Case("@guaranteed", 'g')
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,7 @@ const TypeInfo &SignatureExpansion::expand(SILParameterInfo param) {
switch (auto conv = param.getConvention()) {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Indirect_In_CXX:
addIndirectValueParameterAttributes(IGM, Attrs, ti, ParamIRTypes.size());
addPointerParameter(IGM.getStorageType(getSILFuncConventions().getSILType(
param, IGM.getMaximalTypeExpansionContext())));
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenDistributed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx,
}

switch (param.getConvention()) {
case ParameterConvention::Indirect_In_CXX:
case ParameterConvention::Indirect_In: {
// The only way to load opaque type is to allocate a temporary
// variable on the stack for it and initialize from the given address
Expand Down
Loading

0 comments on commit 42bc49d

Please sign in to comment.