Skip to content

Swift SIL: some small fixes #60798

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
merged 4 commits into from
Aug 26, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,31 @@ extension Builder {
self.init(insertAt: .before(insPnt), location: insPnt.location, passContext: context._bridged)
}

/// Creates a builder which inserts _after_ `insPnt`, using the location of `insPnt`.
init(after insPnt: Instruction, _ context: PassContext) {
/// Creates a builder which inserts _after_ `insPnt`, using a custom `location`.
init(after insPnt: Instruction, location: Location, _ context: PassContext) {
if let nextInst = insPnt.next {
self.init(insertAt: .before(nextInst), location: insPnt.location, passContext: context._bridged)
self.init(insertAt: .before(nextInst), location: location, passContext: context._bridged)
} else {
self.init(insertAt: .atEndOf(insPnt.block), location: insPnt.location, passContext: context._bridged)
self.init(insertAt: .atEndOf(insPnt.block), location: location, passContext: context._bridged)
}
}

/// Creates a builder which inserts _after_ `insPnt`, using the location of `insPnt`.
init(after insPnt: Instruction, _ context: PassContext) {
self.init(after: insPnt, location: insPnt.location, context)
}

/// Creates a builder which inserts at the end of `block`, using a custom `location`.
init(atEndOf block: BasicBlock, location: Location, _ context: PassContext) {
self.init(insertAt: .atEndOf(block), location: location, passContext: context._bridged)
}

/// Creates a builder which inserts at the begin of `block`, using a custom `location`.
init(atBeginOf block: BasicBlock, location: Location, _ context: PassContext) {
let firstInst = block.instructions.first!
self.init(insertAt: .before(firstInst), location: location, passContext: context._bridged)
}

/// Creates a builder which inserts at the begin of `block`, using the location of the first
/// instruction of `block`.
init(atBeginOf block: BasicBlock, _ context: PassContext) {
Expand Down
7 changes: 3 additions & 4 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,8 @@ final public class RefTailAddrInst : SingleValueInstruction, UnaryInstruction {}
final public class KeyPathInst : SingleValueInstruction {
public override func visitReferencedFunctions(_ cl: (Function) -> ()) {
var results = KeyPathFunctionResults()
var componentIdx = 0
repeat {
componentIdx = KeyPathInst_getReferencedFunctions(bridged, componentIdx, &results)
for componentIdx in 0..<KeyPathInst_getNumComponents(bridged) {
KeyPathInst_getReferencedFunctions(bridged, componentIdx, &results)
let numFuncs = results.numFunctions
withUnsafePointer(to: &results) {
$0.withMemoryRebound(to: BridgedFunction.self, capacity: numFuncs) {
Expand All @@ -492,7 +491,7 @@ final public class KeyPathInst : SingleValueInstruction {
}
}
}
} while componentIdx >= 0
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Location.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ import SILBridging

public struct Location {
let bridged: BridgedLocation

public static var autoGeneratedLocation: Location {
Location(bridged: SILLocation_getAutogeneratedLocation())
}
}
2 changes: 2 additions & 0 deletions SwiftCompilerSources/Sources/SIL/WitnessTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public struct WitnessTable : CustomStringConvertible, CustomReflectable {
fileprivate let bridged: BridgedWitnessTableEntry

public enum Kind {
case invalid
case method
case associatedType
case associatedTypeProtocol
Expand All @@ -29,6 +30,7 @@ public struct WitnessTable : CustomStringConvertible, CustomReflectable {

public var kind: Kind {
switch SILWitnessTableEntry_getKind(bridged) {
case SILWitnessTableEntry_Invalid: return .invalid
case SILWitnessTableEntry_Method: return .method
case SILWitnessTableEntry_AssociatedType: return .associatedType
case SILWitnessTableEntry_AssociatedTypeProtocol: return .associatedTypeProtocol
Expand Down
6 changes: 5 additions & 1 deletion include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ typedef struct {
} BridgedWitnessTableEntry;

typedef enum {
SILWitnessTableEntry_Invalid,
SILWitnessTableEntry_Method,
SILWitnessTableEntry_AssociatedType,
SILWitnessTableEntry_AssociatedTypeProtocol,
Expand Down Expand Up @@ -333,6 +334,8 @@ SwiftInt SILType_getCaseIdxOfEnumType(BridgedType type,

BridgedSubstitutionMap SubstitutionMap_getEmpty();

BridgedLocation SILLocation_getAutogeneratedLocation();

BridgedBasicBlock SILArgument_getParent(BridgedArgument argument);
SwiftInt SILArgument_isExclusiveIndirectParameter(BridgedArgument argument);

Expand Down Expand Up @@ -396,7 +399,8 @@ struct KeyPathFunctionResults {
BridgedFunction functions[maxFunctions];
SwiftInt numFunctions;
};
SwiftInt KeyPathInst_getReferencedFunctions(BridgedInstruction kpi, SwiftInt componentIdx,
SwiftInt KeyPathInst_getNumComponents(BridgedInstruction kpi);
void KeyPathInst_getReferencedFunctions(BridgedInstruction kpi, SwiftInt componentIdx,
KeyPathFunctionResults * _Nonnull results);

BridgedSubstitutionMap ApplySite_getSubstitutionMap(BridgedInstruction inst);
Expand Down
28 changes: 8 additions & 20 deletions include/swift/SILOptimizer/PassManager/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class SwiftPassInvocation {
/// Non-null if this is an instruction pass, invoked from SILCombine.
SILCombiner *silCombiner = nullptr;

/// Change notifications, collected during a pass run.
SILAnalysis::InvalidationKind changeNotifications =
SILAnalysis::InvalidationKind::Nothing;

/// All slabs, allocated by the pass.
SILModule::SlabList allocatedSlabs;

Expand Down Expand Up @@ -126,17 +130,9 @@ class SwiftPassInvocation {
/// Called by the SILCombiner when the instruction pass has finished.
void finishedInstructionPassRun();

void beginTransformFunction(SILFunction *function) {
assert(!this->function && transform && "not running a module pass");
this->function = function;
}
void beginTransformFunction(SILFunction *function);

void endTransformFunction() {
assert(function && "beginTransformFunction not called");
function = nullptr;
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
}
void endTransformFunction();
};

/// The SIL pass manager.
Expand Down Expand Up @@ -184,10 +180,6 @@ class SILPassManager {
/// For invoking Swift passes.
SwiftPassInvocation swiftPassInvocation;

/// Change notifications, collected during a bridged pass run.
SILAnalysis::InvalidationKind changeNotifications =
SILAnalysis::InvalidationKind::Nothing;

/// A mask which has one bit for each pass. A one for a pass-bit means that
/// the pass doesn't need to run, because nothing has changed since the
/// previous run of that pass.
Expand Down Expand Up @@ -341,11 +333,6 @@ class SILPassManager {
CompletedPassesMap[F].reset();
}

void notifyPassChanges(SILAnalysis::InvalidationKind invalidationKind) {
changeNotifications = (SILAnalysis::InvalidationKind)
(changeNotifications | invalidationKind);
}

/// Reset the state of the pass manager and remove all transformation
/// owned by the pass manager. Analysis passes will be kept.
void resetAndRemoveTransformations();
Expand Down Expand Up @@ -440,7 +427,8 @@ class SILPassManager {

inline void SwiftPassInvocation::
notifyChanges(SILAnalysis::InvalidationKind invalidationKind) {
passManager->notifyPassChanges(invalidationKind);
changeNotifications = (SILAnalysis::InvalidationKind)
(changeNotifications | invalidationKind);
}

} // end namespace swift
Expand Down
25 changes: 19 additions & 6 deletions lib/SIL/Utils/SILBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,15 @@ BridgedSubstitutionMap SubstitutionMap_getEmpty() {
return {SubstitutionMap().getOpaqueValue()};
}

//===----------------------------------------------------------------------===//
// SILLocation
//===----------------------------------------------------------------------===//

BridgedLocation SILLocation_getAutogeneratedLocation() {
SILDebugLocation loc;
return *reinterpret_cast<BridgedLocation *>(&loc);
}

//===----------------------------------------------------------------------===//
// SILGlobalVariable
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -625,6 +634,8 @@ std::string SILWitnessTableEntry_debugDescription(BridgedWitnessTableEntry entry

SILWitnessTableEntryKind SILWitnessTableEntry_getKind(BridgedWitnessTableEntry entry) {
switch (castToWitnessTableEntry(entry)->getKind()) {
case SILWitnessTable::Invalid:
return SILWitnessTableEntry_Invalid;
case SILWitnessTable::Method:
return SILWitnessTableEntry_Method;
case SILWitnessTable::AssociatedType:
Expand All @@ -633,8 +644,6 @@ SILWitnessTableEntryKind SILWitnessTableEntry_getKind(BridgedWitnessTableEntry e
return SILWitnessTableEntry_AssociatedTypeProtocol;
case SILWitnessTable::BaseProtocol:
return SILWitnessTableEntry_BaseProtocol;
default:
llvm_unreachable("wrong witness table entry kind");
}
}

Expand Down Expand Up @@ -877,7 +886,14 @@ SwiftInt CondBranchInst_getNumTrueArgs(BridgedInstruction cbr) {
return castToInst<CondBranchInst>(cbr)->getNumTrueArgs();
}

SwiftInt KeyPathInst_getReferencedFunctions(BridgedInstruction kpi, SwiftInt componentIdx,
SwiftInt KeyPathInst_getNumComponents(BridgedInstruction kpi) {
if (KeyPathPattern *pattern = castToInst<KeyPathInst>(kpi)->getPattern()) {
return (SwiftInt)pattern->getComponents().size();
}
return 0;
}

void KeyPathInst_getReferencedFunctions(BridgedInstruction kpi, SwiftInt componentIdx,
KeyPathFunctionResults * _Nonnull results) {
KeyPathPattern *pattern = castToInst<KeyPathInst>(kpi)->getPattern();
const KeyPathPatternComponent &comp = pattern->getComponents()[componentIdx];
Expand All @@ -887,9 +903,6 @@ SwiftInt KeyPathInst_getReferencedFunctions(BridgedInstruction kpi, SwiftInt com
assert(results->numFunctions < KeyPathFunctionResults::maxFunctions);
results->functions[results->numFunctions++] = {func};
}, [](SILDeclRef) {});

++componentIdx;
return componentIdx < (int)pattern->getComponents().size() ? componentIdx : -1;
}

BridgedSubstitutionMap ApplySite_getSubstitutionMap(BridgedInstruction inst) {
Expand Down
40 changes: 27 additions & 13 deletions lib/SILOptimizer/PassManager/PassManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,6 @@ void SILPassManager::runPassOnFunction(unsigned TransIdx, SILFunction *F) {
forcePrecomputeAnalyses(F);
}

assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing
&& "change notifications not cleared");

llvm::sys::TimePoint<> startTime = std::chrono::system_clock::now();
std::chrono::nanoseconds duration(0);

Expand All @@ -553,24 +550,21 @@ void SILPassManager::runPassOnFunction(unsigned TransIdx, SILFunction *F) {
// Run it!
SFT->run();

if (CurrentPassHasInvalidated ||
changeNotifications != SILAnalysis::InvalidationKind::Nothing) {
swiftPassInvocation.finishedFunctionPassRun();

if (CurrentPassHasInvalidated) {
// Pause time measurement while invalidating analysis and restoring the snapshot.
duration += (std::chrono::system_clock::now() - startTime);

if (runIdx < numRepeats - 1) {
invalidateAnalysis(F, SILAnalysis::InvalidationKind::Everything);
F->restoreFromSnapshot(SnapshotID);
} else if (changeNotifications != SILAnalysis::InvalidationKind::Nothing) {
invalidateAnalysis(F, changeNotifications);
}
changeNotifications = SILAnalysis::InvalidationKind::Nothing;

// Continue time measurement (including flushing deleted instructions).
startTime = std::chrono::system_clock::now();
}
Mod->flushDeletedInsts();
swiftPassInvocation.finishedFunctionPassRun();
}

duration += (std::chrono::system_clock::now() - startTime);
Expand Down Expand Up @@ -1289,9 +1283,9 @@ void SwiftPassInvocation::startModulePassRun(SILModuleTransform *transform) {
}

void SwiftPassInvocation::startFunctionPassRun(SILFunctionTransform *transform) {
assert(!this->function && !this->transform && "a pass is already running");
this->function = transform->getFunction();
assert(!this->transform && "a pass is already running");
this->transform = transform;
beginTransformFunction(transform->getFunction());
}

void SwiftPassInvocation::startInstructionPassRun(SILInstruction *inst) {
Expand All @@ -1302,13 +1296,15 @@ void SwiftPassInvocation::startInstructionPassRun(SILInstruction *inst) {
void SwiftPassInvocation::finishedModulePassRun() {
endPassRunChecks();
assert(!function && transform && "not running a pass");
assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing
&& "unhandled change notifications at end of module pass");
transform = nullptr;
}

void SwiftPassInvocation::finishedFunctionPassRun() {
endPassRunChecks();
assert(function && transform && "not running a pass");
function = nullptr;
endTransformFunction();
assert(allocatedSlabs.empty() && "StackList is leaking slabs");
transform = nullptr;
}

Expand All @@ -1322,6 +1318,24 @@ void SwiftPassInvocation::endPassRunChecks() {
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
}

void SwiftPassInvocation::beginTransformFunction(SILFunction *function) {
assert(!this->function && transform && "not running a pass");
assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing
&& "change notifications not cleared");
this->function = function;
}

void SwiftPassInvocation::endTransformFunction() {
assert(function && transform && "not running a pass");
if (changeNotifications != SILAnalysis::InvalidationKind::Nothing) {
passManager->invalidateAnalysis(function, changeNotifications);
changeNotifications = SILAnalysis::InvalidationKind::Nothing;
}
function = nullptr;
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
}

//===----------------------------------------------------------------------===//
// Swift Bridging
//===----------------------------------------------------------------------===//
Expand Down
26 changes: 26 additions & 0 deletions test/SILOptimizer/function_uses.sil
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,26 @@ sil_default_witness_table RP {
method #RP.default_witness: @default_witness
}

public protocol RP2 {
}

sil_default_witness_table RP2 {
no_default
}

protocol P {
func witness()
func witness2()
}

struct SP : P {
func witness()
func witness2()
}

struct SP2 : P {
func witness()
func witness2()
}

// CHECK-LABEL: Uses of witness
Expand All @@ -172,8 +186,20 @@ bb0(%0 : $*SP):
return %7 : $()
}

sil @witness2 : $@convention(witness_method: P) (@inout SP) -> () {
bb0(%0 : $*SP):
%7 = tuple ()
return %7 : $()
}

sil_witness_table SP: P module witness_tables {
method #P.witness: @witness
method #P.witness2: @witness2
}

sil_witness_table SP2: P module witness_tables {
method #P.witness: @witness
method #P.witness2: @witness2
}

// CHECK-LABEL: Uses of hash_func
Expand Down