Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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 include/swift/AST/SILLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ class SILField final {
/// destroying the old value and emplacing a new value with the modified
/// field in the same place.
bool isMutable() const { return LoweredTypeAndFlags.getInt() & IsMutable; }

/// Change the current SILField's mutability field.
void setIsMutable(bool newValue) {
LoweredTypeAndFlags = {getLoweredType(), getFlagsValue(newValue)};
}
};

/// A layout.
Expand Down Expand Up @@ -133,14 +138,25 @@ class SILLayout final : public llvm::FoldingSetNode,
bool isMutable() const {
return GenericSigAndFlags.getInt() & IsMutable;
}


/// Returns a SILLayout that is the same as the current layout but with the
/// mutability of each field specified via index in \p
/// fieldIndexMutabilityUpdatePairs to have its mutability be the index's
/// associated bool pair.
SILLayout *withMutable(ASTContext &ctx,
std::initializer_list<std::pair<unsigned, bool>>
fieldIndexMutabilityUpdatePairs) const;

/// True if the layout captures the generic arguments it is substituted with
/// and can provide generic bindings when passed as a closure argument.
bool capturesGenericEnvironment() const {
return GenericSigAndFlags.getInt() & CapturesGenericEnvironment;
}

/// Get the fields inside the layout.
///
/// NOTE: The types inside the fields have not been specialized for the given
/// environment.
ArrayRef<SILField> getFields() const { return getTrailingObjects(NumFields); }

/// Produce a profile of this layout, for use in a folding set.
Expand Down
47 changes: 47 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6152,6 +6152,7 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(SILFunctionType, Type)
class SILBoxType;
class SILLayout; // From SIL
class SILModule; // From SIL
class SILField; // From SIL
typedef CanTypeWrapper<SILBoxType> CanSILBoxType;

/// The SIL-only type for boxes, which represent a reference to a (non-class)
Expand All @@ -6172,6 +6173,52 @@ class SILBoxType final : public TypeBase, public llvm::FoldingSetNode
SILLayout *getLayout() const { return Layout; }
SubstitutionMap getSubstitutions() const { return Substitutions; }

/// Return the fields of this type from its layout.
///
/// NOTE: These types have not been appropriately specialized either for a
/// SILFunction where it occurs or any substitutions that are stored within
/// the substitution map of the function. In order to get appropriate SILTypes
/// for fields to work with directly in SIL, please call getFieldType below
/// which handles the relevant specializations correctly for you.
ArrayRef<SILField> getFields() const;

/// Return the SILType of the field of the layout of the SILBoxType.
///
/// NOTE: This ensures that the type is probably specialized both for the
/// substitutions of this type and the relevant SILFunction.
///
/// Defined in SILType.cpp.
SILType getFieldType(SILFunction &fn, unsigned index);

/// Returns the number of fields in the box type's layout.
unsigned getNumFields() const { return getFields().size(); }

/// Returns true if the given field in the box is mutable. Returns false
/// otherwise.
bool isFieldMutable(unsigned index) const;

/// Returns a SILBoxType that is the same as the current box type but with the
/// mutability of each field specified via index in \p
/// fieldIndexMutabilityUpdatePairs to have its mutability be the index's
/// associated bool pair.
CanSILBoxType withMutable(ASTContext &ctx,
std::initializer_list<std::pair<unsigned, bool>>
fieldIndexMutabilityUpdatePairs) const;

using SILFieldIndexToSILTypeTransform = std::function<SILType(unsigned)>;
using SILFieldToSILTypeRange =
iterator_range<llvm::mapped_iterator<IntRange<unsigned>::iterator,
SILFieldIndexToSILTypeTransform>>;

/// Returns a range of SILTypes that have been specialized correctly for use
/// in the passed in SILFunction.
///
/// DISCUSSION: The inner range is an IntRange since the inner API that we use
/// to transform fields is defined in terms of indices.
///
/// Defined in SILType.cpp.
SILFieldToSILTypeRange getSILFieldTypes(SILFunction &fn);

// TODO: SILBoxTypes should be explicitly constructed in terms of specific
// layouts. As a staging mechanism, we expose the old single-boxed-type
// interface.
Expand Down
17 changes: 14 additions & 3 deletions include/swift/SIL/OperandDatastructures.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ class OperandWorklist {
return false;
}

/// Pushes the operands of all uses of \p value onto the worklist if the
/// operands have never been pushed before. Returns \p true if we inserted
/// /any/ values.
///
/// This is a bulk convenience API.
bool pushResultOperandsIfNotVisited(SILValue value) {
bool insertedOperand = false;
for (auto *use : value->getUses()) {
insertedOperand |= pushIfNotVisited(use);
}
return insertedOperand;
}

/// Pushes the operands of all uses of \p instruction onto the worklist if the
/// operands have never been pushed before. Returns \p true if we inserted
/// /any/ values.
Expand All @@ -110,9 +123,7 @@ class OperandWorklist {
bool pushResultOperandsIfNotVisited(SILInstruction *inst) {
bool insertedOperand = false;
for (auto result : inst->getResults()) {
for (auto *use : result->getUses()) {
insertedOperand |= pushIfNotVisited(use);
}
insertedOperand |= pushResultOperandsIfNotVisited(result);
}
return insertedOperand;
}
Expand Down
15 changes: 14 additions & 1 deletion include/swift/SIL/SILArgument.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,15 @@ class SILFunctionArgument : public SILArgument {
ValueOwnershipKind ownershipKind, ValueDecl *decl = nullptr,
bool isNoImplicitCopy = false,
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None,
bool isCapture = false, bool isParameterPack = false)
bool isCapture = false, bool isParameterPack = false,
bool isInferredImmutable = false)
: SILArgument(ValueKind::SILFunctionArgument, parentBlock, type,
ownershipKind, decl) {
sharedUInt32().SILFunctionArgument.noImplicitCopy = isNoImplicitCopy;
sharedUInt32().SILFunctionArgument.lifetimeAnnotation = lifetimeAnnotation;
sharedUInt32().SILFunctionArgument.closureCapture = isCapture;
sharedUInt32().SILFunctionArgument.parameterPack = isParameterPack;
sharedUInt32().SILFunctionArgument.inferredImmutable = isInferredImmutable;
}

// A special constructor, only intended for use in
Expand Down Expand Up @@ -415,6 +417,16 @@ class SILFunctionArgument : public SILArgument {
sharedUInt32().SILFunctionArgument.parameterPack = isPack;
}

/// Returns true if this argument is inferred to be immutable.
bool isInferredImmutable() const {
return sharedUInt32().SILFunctionArgument.inferredImmutable;
}

/// Set whether this argument is inferred to be immutable.
void setInferredImmutable(bool newValue) {
sharedUInt32().SILFunctionArgument.inferredImmutable = newValue;
}

LifetimeAnnotation getLifetimeAnnotation() const {
return LifetimeAnnotation::Case(
sharedUInt32().SILFunctionArgument.lifetimeAnnotation);
Expand Down Expand Up @@ -472,6 +484,7 @@ class SILFunctionArgument : public SILArgument {
setLifetimeAnnotation(arg->getLifetimeAnnotation());
setClosureCapture(arg->isClosureCapture());
setFormalParameterPack(arg->isFormalParameterPack());
setInferredImmutable(arg->isInferredImmutable());
}

static bool classof(const SILInstruction *) = delete;
Expand Down
17 changes: 9 additions & 8 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,12 +490,12 @@ class SILBuilder {
bool reflection = false,
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
DoesNotUseMoveableValueDebugInfo,
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape) {
return createAllocBox(loc, SILBoxType::get(fieldType.getASTType()), Var,
hasDynamicLifetime, reflection,
usesMoveableValueDebugInfo,
/*skipVarDeclAssert*/ false,
hasPointerEscape);
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape,
bool inferredImmutable = false) {
return createAllocBox(
loc, SILBoxType::get(fieldType.getASTType()), Var, hasDynamicLifetime,
reflection, usesMoveableValueDebugInfo,
/*skipVarDeclAssert*/ false, hasPointerEscape, inferredImmutable);
}

AllocBoxInst *createAllocBox(
Expand All @@ -506,7 +506,8 @@ class SILBuilder {
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
DoesNotUseMoveableValueDebugInfo,
bool skipVarDeclAssert = false,
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape) {
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape,
bool inferredImmutable = false) {
#if NDEBUG
(void)skipVarDeclAssert;
#endif
Expand All @@ -521,7 +522,7 @@ class SILBuilder {
return insert(AllocBoxInst::create(
getSILDebugLocation(Loc, true), BoxType, *F,
substituteAnonymousArgs(Name, Var, Loc), hasDynamicLifetime, reflection,
usesMoveableValueDebugInfo, hasPointerEscape));
usesMoveableValueDebugInfo, hasPointerEscape, inferredImmutable));
}

AllocExistentialBoxInst *
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,8 @@ SILCloner<ImplClass>::visitAllocBoxInst(AllocBoxInst *Inst) {
Loc, this->getOpType(Inst->getType()).template castTo<SILBoxType>(),
VarInfo, Inst->hasDynamicLifetime(), Inst->emitReflectionMetadata(),
Inst->usesMoveableValueDebugInfo(),
/*skipVarDeclAssert*/ true, Inst->hasPointerEscape()));
/*skipVarDeclAssert*/ true, Inst->hasPointerEscape(),
Inst->isInferredImmutable()));
}

template<typename ImplClass>
Expand Down
14 changes: 12 additions & 2 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2482,14 +2482,16 @@ class AllocBoxInst final
HasDynamicLifetime_t hasDynamicLifetime, bool reflection = false,
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
DoesNotUseMoveableValueDebugInfo,
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape);
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape,
bool inferredImmutable = false);

static AllocBoxInst *create(
SILDebugLocation Loc, CanSILBoxType boxType, SILFunction &F,
std::optional<SILDebugVariable> Var,
HasDynamicLifetime_t hasDynamicLifetime, bool reflection = false,
UsesMoveableValueDebugInfo_t wasMoved = DoesNotUseMoveableValueDebugInfo,
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape);
HasPointerEscape_t hasPointerEscape = DoesNotHavePointerEscape,
bool inferredImmutable = false);

public:
CanSILBoxType getBoxType() const {
Expand All @@ -2512,6 +2514,14 @@ class AllocBoxInst final
return HasPointerEscape_t(sharedUInt8().AllocBoxInst.pointerEscape);
}

void setInferredImmutable(bool value) {
sharedUInt8().AllocBoxInst.inferredImmutable = value;
}

bool isInferredImmutable() const {
return sharedUInt8().AllocBoxInst.inferredImmutable;
}

/// True if the box should be emitted with reflection metadata for its
/// contents.
bool emitReflectionMetadata() const {
Expand Down
5 changes: 3 additions & 2 deletions include/swift/SIL/SILNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ class alignas(8) SILNode :
dynamicLifetime : 1,
reflection : 1,
usesMoveableValueDebugInfo : 1,
pointerEscape : 1);
pointerEscape : 1,
inferredImmutable : 1);

SHARED_FIELD(AllocRefInstBase, uint8_t
objC : 1,
Expand Down Expand Up @@ -317,7 +318,7 @@ class alignas(8) SILNode :
SHARED_FIELD(PointerToAddressInst, uint32_t alignment);
SHARED_FIELD(SILFunctionArgument, uint32_t noImplicitCopy : 1,
lifetimeAnnotation : 2, closureCapture : 1,
parameterPack : 1);
parameterPack : 1, inferredImmutable : 1);
SHARED_FIELD(MergeRegionIsolationInst, uint32_t numOperands);

// Do not use `_sharedUInt32_private` outside of SILNode.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ LEGACY_PASS(DiagnoseUnnecessaryPreconcurrencyImports, "sil-diagnose-unnecessary-
"Diagnose any preconcurrency imports that Sema and TransferNonSendable did not use")
LEGACY_PASS(ThunkLowering, "sil-thunk-lowering",
"Lower thunk instructions to actual thunks")
LEGACY_PASS(MarkNeverWrittenMutableClosureBoxesAsImmutable, "mark-never-written-mutable-closure-boxes-as-immutable",
"Mark never written mutable closure boxes as immutable")
LEGACY_PASS(PruneVTables, "prune-vtables",
"Mark class methods that do not require vtable dispatch")

Expand Down
17 changes: 13 additions & 4 deletions include/swift/SILOptimizer/Utils/SILIsolationInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ class SILIsolationInfo {
/// SILIsolationInfo.
static SILIsolationInfo getFunctionIsolation(SILFunction *fn);

private:
/// A helper that is used to ensure that we treat certain builtin values as
/// non-Sendable that the AST level otherwise thinks are non-Sendable.
///
Expand All @@ -580,12 +581,20 @@ class SILIsolationInfo {
return !isNonSendableType(type, fn);
}

static bool isNonSendableType(SILValue value) {
return isNonSendableType(value->getType(), value->getFunction());
public:
static bool isSendable(SILValue value);

static bool isNonSendable(SILValue value) { return !isSendable(value); }

static bool boxContainsOnlySendableFields(AllocBoxInst *abi) {
return boxTypeContainsOnlySendableFields(abi->getBoxType(),
abi->getFunction());
}

static bool isSendableType(SILValue value) {
return !isNonSendableType(value);
static bool boxTypeContainsOnlySendableFields(CanSILBoxType boxType,
SILFunction *fn) {
return llvm::all_of(boxType->getSILFieldTypes(*fn),
[&](SILType type) { return isSendableType(type, fn); });
}

bool hasSameIsolation(ActorIsolation actorIsolation) const;
Expand Down
32 changes: 32 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6976,6 +6976,21 @@ SILLayout *SILLayout::get(ASTContext &C,
return newLayout;
}

SILLayout *
SILLayout::withMutable(ASTContext &ctx,
std::initializer_list<std::pair<unsigned, bool>>
fieldIndexMutabilityUpdatePairs) const {
// Copy the fields, setting the mutable field to newMutable.
SmallVector<SILField, 8> newFields;
llvm::copy(getFields(), std::back_inserter(newFields));
for (auto p : fieldIndexMutabilityUpdatePairs) {
newFields[p.first].setIsMutable(p.second);
}

return SILLayout::get(ctx, getGenericSignature(), newFields,
capturesGenericEnvironment());
}

CanSILBoxType SILBoxType::get(ASTContext &C,
SILLayout *Layout,
SubstitutionMap Substitutions) {
Expand Down Expand Up @@ -7012,6 +7027,23 @@ CanSILBoxType SILBoxType::get(CanType boxedType) {
return get(boxedType->getASTContext(), layout, subMap);
}

CanSILBoxType
SILBoxType::withMutable(ASTContext &ctx,
std::initializer_list<std::pair<unsigned, bool>>
fieldIndexMutabilityUpdatePairs) const {
return SILBoxType::get(
ctx, getLayout()->withMutable(ctx, fieldIndexMutabilityUpdatePairs),
getSubstitutions());
}

ArrayRef<SILField> SILBoxType::getFields() const {
return getLayout()->getFields();
}

bool SILBoxType::isFieldMutable(unsigned index) const {
return getFields()[index].isMutable();
}

LayoutConstraint
LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind,
ASTContext &C) {
Expand Down
Loading