Skip to content

Use typed boxes to simplify capture representation in SILGen #13

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 8 commits 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
20 changes: 18 additions & 2 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,24 @@ number of ways:
the value held there.

- An ``@inout`` parameter is indirect. The address must be of an
initialized object, and the function must leave an initialized
object there upon exit.
initialized object. The memory must remain initialized for the duration
of the call until the function returns. The function may mutate the
pointee, and furthermore may weakly assume that there are no aliasing
reads from or writes to the argument, though must preserve a valid
value at the argument so that well-ordered aliasing violations do not
compromise memory safety. This allows for optimizations such as local
load and store propagation, introduction or elimination of temporary
copies, and promotion of the ``@inout`` parameter to an ``@owned`` direct
parameter and result pair, but does not admit "take" optimization out
of the parameter or other optimization that would leave memory in an
uninitialized state.

- An ``@inout_aliasable`` parameter is indirect. The address must be of an
initialized object. The memory must remain initialized for the duration
of the call until the function returns. The function may mutate the
pointee, and must assume that other aliases may mutate it as well. These
aliases however can be assumed to be well-typed and well-ordered; ill-typed
accesses and data races to the parameter are still undefined.

- An ``@out`` parameter is indirect. The address must be of an
uninitialized object; the function is responsible for initializing
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ TYPE_ATTR(error)
TYPE_ATTR(out)
TYPE_ATTR(in)
TYPE_ATTR(inout)
TYPE_ATTR(inout_aliasable)
TYPE_ATTR(in_guaranteed)
TYPE_ATTR(noescape) // Only valid in sil mode.
TYPE_ATTR(owned)
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ ERROR(variable_used_before_initialized,sil_analysis,none,
ERROR(variable_inout_before_initialized,sil_analysis,none,
"%select{variable|constant}1 '%0' passed by reference before being"
" initialized", (StringRef, bool))
ERROR(variable_escape_before_initialized,sil_analysis,none,
ERROR(variable_closure_use_uninit,sil_analysis,none,
"%select{variable|constant}1 '%0' captured by a closure before being"
" initialized", (StringRef, bool))

Expand Down Expand Up @@ -145,7 +145,7 @@ ERROR(return_from_init_without_initing_stored_properties,sil_analysis,none,
"return from initializer without initializing all"
" stored properties", ())

ERROR(global_variable_function_use_uninit,sil_analysis,none,
ERROR(variable_function_use_uninit,sil_analysis,none,
"%select{variable|constant}1 '%0' used by function definition before"
" being initialized",
(StringRef, bool))
Expand Down
38 changes: 28 additions & 10 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2498,10 +2498,18 @@ enum class ParameterConvention {
Indirect_In_Guaranteed,

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The object is instantaneously valid on entry, and
/// it must be instantaneously valid on exit. The callee may assume that the
/// address does not alias any valid object.
/// of an object in memory. The object is always valid, but the callee may
/// assume that the address does not alias any valid object and reorder loads
/// stores to the parameter as long as the whole object remains valid. Invalid
/// single-threaded aliasing may produce inconsistent results, but should
/// remain memory safe.
Indirect_Inout,

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an object in memory. The object is allowed to be aliased by other
/// well-typed references, but is not allowed to be escaped. This is the
/// convention used by mutable captures in @noescape closures.
Indirect_InoutAliasable,

/// This argument is passed indirectly, i.e. by directly passing the address
/// of an uninitialized object in memory. The callee is responsible for
Expand Down Expand Up @@ -2531,6 +2539,7 @@ inline bool isIndirectParameter(ParameterConvention conv) {
switch (conv) {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Indirect_In_Guaranteed:
return true;
Expand All @@ -2550,6 +2559,7 @@ inline bool isConsumedParameter(ParameterConvention conv) {
return true;

case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Direct_Unowned:
case ParameterConvention::Direct_Guaranteed:
Expand All @@ -2570,6 +2580,7 @@ inline bool isGuaranteedParameter(ParameterConvention conv) {
return true;

case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Indirect_In:
case ParameterConvention::Direct_Unowned:
Expand All @@ -2587,6 +2598,7 @@ inline bool isDeallocatingParameter(ParameterConvention conv) {

case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Indirect_In_Guaranteed:
case ParameterConvention::Direct_Unowned:
Expand All @@ -2599,19 +2611,20 @@ inline bool isDeallocatingParameter(ParameterConvention conv) {

/// A parameter type and the rules for passing it.
class SILParameterInfo {
llvm::PointerIntPair<CanType, 3, ParameterConvention> TypeAndConvention;
CanType Ty;
ParameterConvention Convention;
public:
SILParameterInfo() = default;
SILParameterInfo() : Ty(), Convention((ParameterConvention)0) {}
SILParameterInfo(CanType type, ParameterConvention conv)
: TypeAndConvention(type, conv) {
: Ty(type), Convention(conv) {
assert(type->isLegalSILType() && "SILParameterInfo has illegal SIL type");
}

CanType getType() const {
return TypeAndConvention.getPointer();
return Ty;
}
ParameterConvention getConvention() const {
return TypeAndConvention.getInt();
return Convention;
}
bool isIndirect() const {
return isIndirectParameter(getConvention());
Expand All @@ -2624,6 +2637,10 @@ class SILParameterInfo {
bool isIndirectInOut() const {
return getConvention() == ParameterConvention::Indirect_Inout;
}
bool isIndirectMutating() const {
return getConvention() == ParameterConvention::Indirect_Inout
|| getConvention() == ParameterConvention::Indirect_InoutAliasable;
}
bool isIndirectResult() const {
return getConvention() == ParameterConvention::Indirect_Out;
}
Expand Down Expand Up @@ -2675,7 +2692,8 @@ class SILParameterInfo {
}

void profile(llvm::FoldingSetNodeID &id) {
id.AddPointer(TypeAndConvention.getOpaqueValue());
id.AddPointer(Ty.getPointer());
id.AddInteger((unsigned)Convention);
}

void dump() const;
Expand All @@ -2689,7 +2707,7 @@ class SILParameterInfo {
}

bool operator==(SILParameterInfo rhs) const {
return TypeAndConvention == rhs.TypeAndConvention;
return Ty == rhs.Ty && Convention == rhs.Convention;
}
bool operator!=(SILParameterInfo rhs) const {
return !(*this == rhs);
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/Demangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ enum class FunctionSigSpecializationParamKind : unsigned {
ConstantPropFloat = 3,
ConstantPropString = 4,
ClosureProp = 5,
InOutToValue = 6,
BoxToValue = 6,

// Option Set Flags use bits 6-31. This gives us 26 bits to use for option
// flags.
Expand Down
4 changes: 2 additions & 2 deletions include/swift/SIL/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class FunctionSignatureSpecializationMangler
Unmodified=0,
ConstantProp=1,
ClosureProp=2,
InOutToValue=3,
BoxToValue=3,
First_Option=0, Last_Option=31,

// Option Set Space. 12 bits (i.e. 12 option).
Expand All @@ -171,7 +171,7 @@ class FunctionSignatureSpecializationMangler
void setArgumentDead(unsigned ArgNo);
void setArgumentOwnedToGuaranteed(unsigned ArgNo);
void setArgumentSROA(unsigned ArgNo);
void setArgumentInOutToValue(unsigned ArgNo);
void setArgumentBoxToValue(unsigned ArgNo);

private:
void mangleSpecialization();
Expand Down
5 changes: 3 additions & 2 deletions include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const uint16_t VERSION_MAJOR = 0;
/// To ensure that two separate changes don't silently get merged into one
/// in source control, you should also update the comment to briefly
/// describe what change you made.
const uint16_t VERSION_MINOR = 222; // Last change: @_fixed_layout
const uint16_t VERSION_MINOR = 223; // Last change: SIL @inout_aliasable

using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;
Expand Down Expand Up @@ -179,13 +179,14 @@ enum class ParameterConvention : uint8_t {
Indirect_In,
Indirect_Out,
Indirect_Inout,
Indirect_InoutAliasable,
Direct_Owned,
Direct_Unowned,
Direct_Guaranteed,
Indirect_In_Guaranteed,
Direct_Deallocating,
};
using ParameterConventionField = BCFixed<3>;
using ParameterConventionField = BCFixed<4>;

// These IDs must \em not be renumbered or reordered without incrementing
// VERSION_MAJOR.
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2968,6 +2968,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_In_Guaranteed:
llvm_unreachable("callee convention cannot be indirect");
}
Expand Down Expand Up @@ -3218,6 +3219,7 @@ static StringRef getStringForParameterConvention(ParameterConvention conv) {
case ParameterConvention::Indirect_Out: return "@out ";
case ParameterConvention::Indirect_In_Guaranteed: return "@in_guaranteed ";
case ParameterConvention::Indirect_Inout: return "@inout ";
case ParameterConvention::Indirect_InoutAliasable: return "@inout_aliasable ";
case ParameterConvention::Direct_Owned: return "@owned ";
case ParameterConvention::Direct_Unowned: return "";
case ParameterConvention::Direct_Guaranteed: return "@guaranteed ";
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion,
// <impl-convention> ::= 'e' // direct, deallocating
// <impl-convention> ::= 'i' // indirect, ownership transfer
// <impl-convention> ::= 'l' // indirect, inout
// <impl-convention> ::= 'L' // indirect, inout, aliasable
// <impl-convention> ::= 'g' // direct, guaranteed
// <impl-convention> ::= 'G' // indirect, guaranteed
// <impl-convention> ::= 'z' <impl-convention> // error result
Expand All @@ -1129,6 +1130,7 @@ void Mangler::mangleType(Type type, ResilienceExpansion explosion,
case ParameterConvention::Indirect_In: return 'i';
case ParameterConvention::Indirect_Out: return 'i';
case ParameterConvention::Indirect_Inout: return 'l';
case ParameterConvention::Indirect_InoutAliasable: return 'L';
case ParameterConvention::Indirect_In_Guaranteed: return 'G';
case ParameterConvention::Direct_Owned: return 'o';
case ParameterConvention::Direct_Unowned: return 'd';
Expand Down
8 changes: 4 additions & 4 deletions lib/Basic/Demangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ class Demangler {
if (!demangleFuncSigSpecializationClosureProp(param))
return nullptr;
} else if (Mangled.nextIf("i_")) {
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(InOutToValue);
auto result = FUNCSIGSPEC_CREATE_PARAM_KIND(BoxToValue);
if (!result)
return nullptr;
param->addChild(result);
Expand Down Expand Up @@ -2634,7 +2634,7 @@ unsigned NodePrinter::printFunctionSigSpecializationParam(NodePointer pointer,
unsigned V = firstChild->getIndex();
auto K = FunctionSigSpecializationParamKind(V);
switch (K) {
case FunctionSigSpecializationParamKind::InOutToValue:
case FunctionSigSpecializationParamKind::BoxToValue:
print(pointer->getChild(Idx++));
return Idx;
case FunctionSigSpecializationParamKind::ConstantPropFunction:
Expand Down Expand Up @@ -3099,8 +3099,8 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
return;

switch (FunctionSigSpecializationParamKind(raw)) {
case FunctionSigSpecializationParamKind::InOutToValue:
Printer << "Value Promoted from InOut";
case FunctionSigSpecializationParamKind::BoxToValue:
Printer << "Value Promoted from Box";
break;
case FunctionSigSpecializationParamKind::ConstantPropFunction:
Printer << "Constant Propagated Function";
Expand Down
2 changes: 1 addition & 1 deletion lib/Basic/Remangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ void Remangler::mangleFunctionSignatureSpecializationParam(Node *node) {
}
Out << '_';
return;
case FunctionSigSpecializationParamKind::InOutToValue:
case FunctionSigSpecializationParamKind::BoxToValue:
Out << "i_";
return;
default:
Expand Down
7 changes: 4 additions & 3 deletions lib/IRGen/GenClangType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) {
llvm_unreachable("block takes owned parameter");
case ParameterConvention::Indirect_In:
case ParameterConvention::Indirect_Inout:
case ParameterConvention::Indirect_InoutAliasable:
case ParameterConvention::Indirect_Out:
case ParameterConvention::Indirect_In_Guaranteed:
llvm_unreachable("block takes indirect parameter");
Expand Down Expand Up @@ -720,9 +721,9 @@ clang::CanQualType IRGenModule::getClangType(SILType type) {

clang::CanQualType IRGenModule::getClangType(SILParameterInfo params) {
auto clangType = getClangType(params.getSILType());
// @block_storage types must be wrapped in an @inout and have special
// lowering
if (params.isIndirectInOut() &&
// @block_storage types must be @inout_aliasable and have
// special lowering
if (params.isIndirectMutating() &&
!params.getSILType().is<SILBlockStorageType>()) {
return getClangASTContext().getPointerType(clangType);
}
Expand Down
Loading