Skip to content

5.9: [IRGen] Add metadata pack markers for more instructions. #67497

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
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
35 changes: 25 additions & 10 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,13 @@ class RecursiveTypeProperties {
/// they have a type variable originator.
SolverAllocated = 0x8000,

/// This type contains a concrete pack.
HasConcretePack = 0x10000,
/// Contains a PackType.
HasPack = 0x10000,

Last_Property = HasConcretePack
/// Contains a PackArchetypeType.
HasPackArchetype = 0x20000,

Last_Property = HasPackArchetype
};
enum { BitWidth = countBitsUsed(Property::Last_Property) };

Expand Down Expand Up @@ -259,7 +262,9 @@ class RecursiveTypeProperties {

bool hasParameterPack() const { return Bits & HasParameterPack; }

bool hasConcretePack() const { return Bits & HasConcretePack; }
bool hasPack() const { return Bits & HasPack; }

bool hasPackArchetype() const { return Bits & HasPackArchetype; }

/// Does a type with these properties structurally contain a
/// parameterized existential type?
Expand Down Expand Up @@ -419,12 +424,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
NumProtocols : 16
);

SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+30,
SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+29,
/// Type variable options.
Options : 7,
: NumPadBits,
/// The unique number assigned to this type variable.
ID : 30
ID : 29
);

SWIFT_INLINE_BITFIELD(SILFunctionType, TypeBase, NumSILExtInfoBits+1+4+1+2+1+1,
Expand Down Expand Up @@ -687,16 +692,26 @@ class alignas(1 << TypeAlignInBits) TypeBase
return getRecursiveProperties().hasLocalArchetype();
}

/// Whether the type contains a generic parameter declared as a parameter
/// pack.
bool hasParameterPack() const {
return getRecursiveProperties().hasParameterPack();
}

bool hasConcretePack() const {
return getRecursiveProperties().hasConcretePack();
/// Whether the type contains a PackType.
bool hasPack() const {
return getRecursiveProperties().hasPack();
}

/// Whether the type has some flavor of pack.
bool hasPack() const { return hasParameterPack() || hasConcretePack(); }
/// Whether the type contains a PackArchetypeType.
bool hasPackArchetype() const {
return getRecursiveProperties().hasPackArchetype();
}

/// Whether the type has any flavor of pack.
bool hasAnyPack() const {
return hasParameterPack() || hasPack() || hasPackArchetype();
}

/// Determine whether the type involves a parameterized existential type.
bool hasParameterizedExistential() const {
Expand Down
11 changes: 7 additions & 4 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,15 @@ class SILType {
/// pack.
bool hasParameterPack() const { return getASTType()->hasParameterPack(); }

/// Whether the type contains a concrete pack.
bool hasConcretePack() const { return getASTType()->hasConcretePack(); }

/// Whether the type contains some flavor of pack.
/// Whether the type contains a PackType.
bool hasPack() const { return getASTType()->hasPack(); }

/// Whether the type contains a PackArchetypeType.
bool hasPackArchetype() const { return getASTType()->hasPackArchetype(); }

/// Whether the type contains any flavor of pack.
bool hasAnyPack() const { return getASTType()->hasAnyPack(); }

/// True if the type is an empty tuple or an empty struct or a tuple or
/// struct containing only empty types.
bool isEmpty(const SILFunction &F) const;
Expand Down
8 changes: 4 additions & 4 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3404,7 +3404,7 @@ CanPackType CanPackType::get(const ASTContext &C,
}

PackType *PackType::get(const ASTContext &C, ArrayRef<Type> elements) {
RecursiveTypeProperties properties = RecursiveTypeProperties::HasConcretePack;
RecursiveTypeProperties properties = RecursiveTypeProperties::HasPack;
bool isCanonical = true;
for (Type eltTy : elements) {
assert(!eltTy->is<PackType>() &&
Expand Down Expand Up @@ -3444,7 +3444,7 @@ void PackType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef<Type> Elements) {

CanSILPackType SILPackType::get(const ASTContext &C, ExtInfo info,
ArrayRef<CanType> elements) {
RecursiveTypeProperties properties = RecursiveTypeProperties::HasConcretePack;
RecursiveTypeProperties properties;
for (CanType eltTy : elements) {
assert(!isa<SILPackType>(eltTy) &&
"Cannot have pack directly inside another pack");
Expand Down Expand Up @@ -4036,7 +4036,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
static RecursiveTypeProperties
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
Type result) {
static_assert(RecursiveTypeProperties::BitWidth == 17,
static_assert(RecursiveTypeProperties::BitWidth == 18,
"revisit this if you add new recursive type properties");
RecursiveTypeProperties properties;

Expand Down Expand Up @@ -4677,7 +4677,7 @@ CanSILFunctionType SILFunctionType::get(
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));

RecursiveTypeProperties properties;
static_assert(RecursiveTypeProperties::BitWidth == 17,
static_assert(RecursiveTypeProperties::BitWidth == 18,
"revisit this if you add new recursive type properties");
for (auto &param : params)
properties |= param.getInterfaceType()->getRecursiveProperties();
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3703,8 +3703,9 @@ PackArchetypeType::PackArchetypeType(
ArrayRef<ProtocolDecl *> ConformsTo, Type Superclass,
LayoutConstraint Layout, PackShape Shape)
: ArchetypeType(TypeKind::PackArchetype, Ctx,
RecursiveTypeProperties::HasArchetype, InterfaceType,
ConformsTo, Superclass, Layout, GenericEnv) {
RecursiveTypeProperties::HasArchetype |
RecursiveTypeProperties::HasPackArchetype,
InterfaceType, ConformsTo, Superclass, Layout, GenericEnv) {
assert(InterfaceType->isParameterPack());
*getTrailingObjects<PackShape>() = Shape;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,10 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
llvm::report_fatal_error(
"Instruction resulted in on-stack pack metadata emission but no "
"cleanup instructions were added");
// The markers which indicate where on-stack pack metadata should be
// deallocated were not inserted for I. To fix this, add I's opcode to
// SILInstruction::mayRequirePackMetadata subject to the appropriate
// checks.
}
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/PackMetadataMarkerInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Inserter::shouldInsertMarkersForInstruction(SILInstruction *inst) {
BuiltinValueKind::StartAsyncLetWithLocalBuffer ||
bi->getBuiltinKind() == BuiltinValueKind::StartAsyncLet)
return Inserter::FindResult::Unhandleable;
return Inserter::FindResult::None;
LLVM_FALLTHROUGH;
}
default:
return inst->mayRequirePackMetadata() ? FindResult::Some : FindResult::None;
Expand Down
53 changes: 42 additions & 11 deletions lib/SIL/IR/SILInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,33 +1305,64 @@ bool SILInstruction::mayRequirePackMetadata() const {
case SILInstructionKind::TryApplyInst: {
// Check the function type for packs.
auto apply = ApplySite::isa(const_cast<SILInstruction *>(this));
if (apply.getCallee()->getType().hasPack())
if (apply.getCallee()->getType().hasAnyPack())
return true;
// Check the substituted types for packs.
for (auto ty : apply.getSubstitutionMap().getReplacementTypes()) {
if (ty->hasPack())
if (ty->hasAnyPack())
return true;
}
return false;
}
case SILInstructionKind::DebugValueInst: {
auto *dvi = cast<DebugValueInst>(this);
return dvi->getOperand()->getType().hasPack();
case SILInstructionKind::ClassMethodInst:
case SILInstructionKind::DebugValueInst:
case SILInstructionKind::DestroyAddrInst:
case SILInstructionKind::DestroyValueInst:
// Unary instructions.
{
return getOperand(0)->getType().hasAnyPack();
}
case SILInstructionKind::AllocStackInst: {
auto *asi = cast<AllocStackInst>(this);
return asi->getType().hasAnyPack();
}
case SILInstructionKind::MetatypeInst: {
auto *mi = cast<MetatypeInst>(this);
return mi->getType().hasPack();
}
case SILInstructionKind::ClassMethodInst: {
auto *cmi = cast<ClassMethodInst>(this);
return cmi->getOperand()->getType().hasPack();
return mi->getType().hasAnyPack();
}
case SILInstructionKind::WitnessMethodInst: {
auto *wmi = cast<WitnessMethodInst>(this);
auto ty = wmi->getLookupType();
return ty->hasPack();
return ty->hasAnyPack();
}
default:
// Instructions that deallocate stack must not result in pack metadata
// materialization. If they did there would be no way to create the pack
// metadata on stack.
if (isDeallocatingStack())
return false;

// Terminators that exit the function must not result in pack metadata
// materialization.
auto *ti = dyn_cast<TermInst>(this);
if (ti && ti->isFunctionExiting())
return false;

// Check results and operands for packs. If a pack appears, lowering the
// instruction might result in pack metadata emission.
for (auto result : getResults()) {
if (result->getType().hasAnyPack())
return true;
}
for (auto operandTy : getOperandTypes()) {
if (operandTy.hasAnyPack())
return true;
}
for (auto &tdo : getTypeDependentOperands()) {
if (tdo.get()->getType().hasAnyPack())
return true;
}

return false;
}
}
Expand Down
6 changes: 6 additions & 0 deletions test/IRGen/pack_marker_insertion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %target-swift-frontend -emit-ir %s

// Verify that we don't hit the `Instruction missing on-stack pack metadata cleanups!` assertion.

// For alloc_stacks of tuples featuring a pack.
public func tupleExpansionWithMemberType<each T: Sequence>(seqs: (repeat each T), elts: (repeat (each T).Element)) {}
13 changes: 13 additions & 0 deletions test/IRGen/pack_metadata_marker_inserter.sil
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct S1 {}
struct S2 {}
struct S3 {}

struct GVT<each T> : Error {
}

struct GV<each T> {
var tu: (repeat each T)
}
Expand Down Expand Up @@ -145,6 +148,16 @@ entry:
return %retval : $()
}

// CHECK-SIL-LABEL: sil @return_variadic : {{.*}} {
// CHECK-SIL: [[RETVAL:%[^,]+]] = struct
// CHECK-SIL: return [[RETVAL]]
// CHECK-SIL-LABEL: } // end sil function 'return_variadic'
sil @return_variadic : $<each T>() -> GVT<repeat each T> {
entry:
%retval = struct $GVT<repeat each T> ()
return %retval : $GVT<repeat each T>
}

// =============================================================================
// FINISH: Instructions: Apply }}
// =============================================================================
Expand Down
23 changes: 23 additions & 0 deletions test/IRGen/pack_metadata_marker_inserter_no_ir.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -pack-metadata-marker-inserter -enable-pack-metadata-stack-promotion=true | %FileCheck %s --check-prefixes CHECK-SIL

// REQUIRES: asserts

sil_stage lowered

import Builtin

protocol Error {}

struct GVT<each T> {
}

// CHECK-SIL-LABEL: sil @throw_variadic : {{.*}} {
// CHECK-SIL: [[ERROR:%[^,]+]] = struct
// CHECK-SIL: throw [[ERROR]]
// CHECK-SIL-LABEL: } // end sil function 'throw_variadic'
sil @throw_variadic : $<each T>() -> ((), @error GVT<repeat each T>) {
entry:
%retval = struct $GVT<repeat each T> ()
throw %retval : $GVT<repeat each T>
}

41 changes: 41 additions & 0 deletions test/IRGen/rdar112792831.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %target-swift-frontend -emit-ir -O %s

@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
public struct Predicate<each Input> {
var x: Any? = nil
public func evaluate(_: repeat each Input) -> Bool { return false }
}

public struct PredicateBindings {
}

@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
public protocol PredicateExpression<Output> {
associatedtype Output

func evaluate(_ bindings: PredicateBindings) throws -> Output
}

@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
public struct PredicateEvaluate<
Condition : PredicateExpression,
each Input : PredicateExpression
>
where
Condition.Output == Predicate<repeat (each Input).Output>
{

public typealias Output = Bool

public let predicate: Condition
public let input: (repeat each Input)

public init(predicate: Condition, input: repeat each Input) {
self.predicate = predicate
self.input = (repeat each input)
}

public func evaluate(_ bindings: PredicateBindings) throws -> Output {
try predicate.evaluate(bindings).evaluate(repeat (each input).evaluate(bindings))
}
}