Skip to content

Commit 406fe3e

Browse files
authored
[SILOpt] Allow pre-specializations for _Trivial of known size (#70256)
* [SILOpt] Allow pre-specializations for _Trivial of known size rdar://119224542 This allows pre-specializations to be generated and applied for trivial types of a shared size.
1 parent 1a60dae commit 406fe3e

File tree

7 files changed

+80
-41
lines changed

7 files changed

+80
-41
lines changed

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,6 @@ class SwiftPassInvocation {
7373

7474
SILSSAUpdater *ssaUpdater = nullptr;
7575

76-
/// IRGen module for passes that request it (e.g. simplification pass)
77-
irgen::IRGenModule *irgenModule = nullptr;
78-
79-
/// IRGenerator used by IRGenModule above
80-
irgen::IRGenerator *irgen = nullptr;
81-
8276
static constexpr int BlockSetCapacity = 8;
8377
char blockSetStorage[sizeof(BasicBlockSet) * BlockSetCapacity];
8478
bool aliveBlockSets[BlockSetCapacity];
@@ -184,6 +178,7 @@ class SILPassManager {
184178

185179
/// An optional IRGenModule associated with this PassManager.
186180
irgen::IRGenModule *IRMod;
181+
irgen::IRGenerator *irgen;
187182

188183
/// The list of transformations to run.
189184
llvm::SmallVector<SILTransform *, 16> Transformations;
@@ -290,7 +285,7 @@ class SILPassManager {
290285

291286
/// \returns the associated IGenModule or null if this is not an IRGen
292287
/// pass manager.
293-
irgen::IRGenModule *getIRGenModule() { return IRMod; }
288+
irgen::IRGenModule *getIRGenModule();
294289

295290
SwiftPassInvocation *getSwiftPassInvocation() {
296291
return &swiftPassInvocation;

include/swift/SILOptimizer/Utils/SILOptFunctionBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class SILOptFunctionBuilder {
5656
}
5757

5858
SILModule &getModule() const { return *getPassManager().getModule(); }
59+
irgen::IRGenModule *getIRGenModule() const {
60+
return transform.getIRGenModule();
61+
}
5962

6063
private:
6164
SILPassManager &getPassManager() const {

lib/AST/GenericSignature.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ CanType GenericSignature::getReducedType(Type type) const {
503503
GenericSignature GenericSignature::typeErased(ArrayRef<Type> typeErasedParams) const {
504504
bool changedSignature = false;
505505
llvm::SmallVector<Requirement, 2> requirementsErased;
506+
auto &C = Ptr->getASTContext();
506507

507508
for (auto req : getRequirements()) {
508509
bool found = std::any_of(typeErasedParams.begin(),
@@ -512,14 +513,20 @@ GenericSignature GenericSignature::typeErased(ArrayRef<Type> typeErasedParams) c
512513
return t->isEqual(other);
513514
});
514515
if (found && req.getKind() == RequirementKind::Layout) {
515-
if (req.getLayoutConstraint()->isClass()) {
516+
auto layout = req.getLayoutConstraint();
517+
if (layout->isClass()) {
518+
requirementsErased.push_back(Requirement(RequirementKind::SameType,
519+
req.getFirstType(),
520+
C.getAnyObjectType()));
521+
} else if (layout->isBridgeObject()) {
522+
requirementsErased.push_back(Requirement(RequirementKind::SameType,
523+
req.getFirstType(),
524+
C.TheBridgeObjectType));
525+
} else if (layout->isFixedSizeTrivial()) {
526+
unsigned bitWidth = layout->getTrivialSizeInBits();
516527
requirementsErased.push_back(
517528
Requirement(RequirementKind::SameType, req.getFirstType(),
518-
Ptr->getASTContext().getAnyObjectType()));
519-
} else if (req.getLayoutConstraint()->isBridgeObject()) {
520-
requirementsErased.push_back(
521-
Requirement(RequirementKind::SameType, req.getFirstType(),
522-
Ptr->getASTContext().TheBridgeObjectType));
529+
CanType(BuiltinIntegerType::get(bitWidth, C))));
523530
} else {
524531
requirementsErased.push_back(req);
525532
}

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ void swift::executePassPipelinePlan(SILModule *SM,
374374

375375
SILPassManager::SILPassManager(SILModule *M, bool isMandatory,
376376
irgen::IRGenModule *IRMod)
377-
: Mod(M), IRMod(IRMod),
377+
: Mod(M), IRMod(IRMod), irgen(nullptr),
378378
swiftPassInvocation(this),
379379
isMandatory(isMandatory), deserializationNotificationHandler(nullptr) {
380380
#define SIL_ANALYSIS(NAME) \
@@ -901,6 +901,27 @@ void SILPassManager::execute() {
901901
}
902902
}
903903

904+
irgen::IRGenModule *SILPassManager::getIRGenModule() {
905+
// We need an IRGenModule to get the actual sizes from type lowering.
906+
// Creating an IRGenModule involves some effort, let's cache it for the
907+
// whole pass.
908+
if (IRMod == nullptr) {
909+
SILModule *module = getModule();
910+
911+
auto *irgenOpts = module->getIRGenOptionsOrNull();
912+
if (!irgenOpts)
913+
return nullptr;
914+
915+
if (irgen == nullptr)
916+
irgen = new irgen::IRGenerator(*irgenOpts, *module);
917+
auto targetMachine = irgen->createTargetMachine();
918+
assert(targetMachine && "failed to create target");
919+
IRMod = new irgen::IRGenModule(*irgen, std::move(targetMachine));
920+
}
921+
922+
return IRMod;
923+
}
924+
904925
/// D'tor.
905926
SILPassManager::~SILPassManager() {
906927

@@ -940,6 +961,16 @@ SILPassManager::~SILPassManager() {
940961
"Deleting a locked analysis. Did we forget to unlock ?");
941962
delete A;
942963
}
964+
965+
if (irgen) {
966+
// If irgen is set, we also own the IRGenModule
967+
if (IRMod) {
968+
delete IRMod;
969+
IRMod = nullptr;
970+
}
971+
delete irgen;
972+
irgen = nullptr;
973+
}
943974
}
944975

945976
void SILPassManager::notifyOfNewFunction(SILFunction *F, SILTransform *T) {
@@ -1382,22 +1413,7 @@ void SwiftPassInvocation::finishedInstructionPassRun() {
13821413
}
13831414

13841415
irgen::IRGenModule *SwiftPassInvocation::getIRGenModule() {
1385-
// We need an IRGenModule to get the actual sizes from type lowering.
1386-
// Creating an IRGenModule involves some effort, let's cache it for the
1387-
// whole pass.
1388-
if (irgenModule == nullptr && irgen == nullptr) {
1389-
SILModule *module = getPassManager()->getModule();
1390-
1391-
auto *irgenOpts = module->getIRGenOptionsOrNull();
1392-
if (!irgenOpts)
1393-
return nullptr;
1394-
1395-
irgen = new irgen::IRGenerator(*irgenOpts, *module);
1396-
auto targetMachine = irgen->createTargetMachine();
1397-
assert(targetMachine && "failed to create target");
1398-
irgenModule = new irgen::IRGenModule(*irgen, std::move(targetMachine));
1399-
}
1400-
return irgenModule;
1416+
return passManager->getIRGenModule();
14011417
}
14021418

14031419
void SwiftPassInvocation::endPass() {
@@ -1430,16 +1446,7 @@ void SwiftPassInvocation::endTransformFunction() {
14301446
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
14311447
}
14321448

1433-
SwiftPassInvocation::~SwiftPassInvocation() {
1434-
if (irgenModule) {
1435-
delete irgenModule;
1436-
irgenModule = nullptr;
1437-
}
1438-
if (irgen) {
1439-
delete irgen;
1440-
irgen = nullptr;
1441-
}
1442-
}
1449+
SwiftPassInvocation::~SwiftPassInvocation() {}
14431450

14441451
//===----------------------------------------------------------------------===//
14451452
// OptimizerBridging

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define DEBUG_TYPE "generic-specializer"
1414

1515
#include "swift/SILOptimizer/Utils/Generics.h"
16+
#include "../../IRGen/IRGenModule.h"
1617
#include "swift/AST/Decl.h"
1718
#include "swift/AST/DiagnosticEngine.h"
1819
#include "swift/AST/DiagnosticsSIL.h"
@@ -3001,7 +3002,8 @@ bool usePrespecialized(
30013002
}
30023003

30033004
if (!erased || !layout ||
3004-
(!layout->isClass() && !layout->isBridgeObject())) {
3005+
(!layout->isClass() && !layout->isBridgeObject() &&
3006+
!layout->isFixedSizeTrivial())) {
30053007
newSubs.push_back(entry.value());
30063008
continue;
30073009
}
@@ -3022,6 +3024,18 @@ bool usePrespecialized(
30223024
} else {
30233025
newSubs.push_back(genericParam->getASTContext().getAnyObjectType());
30243026
}
3027+
} else if (layout->isFixedSizeTrivial() && lowered.isTrivial(refF)) {
3028+
auto *IGM = funcBuilder.getIRGenModule();
3029+
auto &ti = IGM->getTypeInfo(lowered);
3030+
auto fixedSize =
3031+
ti.buildTypeLayoutEntry(*IGM, lowered, false)->fixedSize(*IGM);
3032+
3033+
if (fixedSize &&
3034+
fixedSize->getValueInBits() == layout->getTrivialSizeInBits()) {
3035+
newSubs.push_back(CanType(
3036+
BuiltinIntegerType::get(layout->getTrivialSizeInBits(),
3037+
genericParam->getASTContext())));
3038+
}
30253039
} else {
30263040
// no match
30273041
break;

test/SILOptimizer/Inputs/pre_specialized_module_layouts.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class SomeClass {
1111
@_specialize(exported: true, where T == Double)
1212
@_specialize(exported: true, where @_noMetadata T : _Class)
1313
@_specialize(exported: true, where @_noMetadata T : _BridgeObject)
14+
@_specialize(exported: true, where @_noMetadata T : _Trivial(64))
1415
@_specialize(exported: true, availability: macOS 10.50, *; where T == SomeData)
1516
public func publicPrespecialized<T>(_ t: T) {
1617
}

test/SILOptimizer/pre_specialize_layouts.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public struct OveralignedReferenceWrapperStruct {
3131
let x: AnyObject
3232
}
3333

34+
public struct TwoInt32 {
35+
let x: Int32 = 0
36+
let y: Int32 = 0
37+
}
38+
3439
// Make sure we generate the public pre-specialized entry points.
3540

3641
// OPT-DAG: sil @$s22pre_specialize_layouts10testPublic1tyx_tlFSf_Ts5 : $@convention(thin) (Float) -> () {
@@ -79,6 +84,11 @@ internal func testEmitIntoClient<T>(t: T) {
7984
// OPT: apply [[F1]]
8085
// OPT: [[F2:%.*]] = function_ref @$s30pre_specialized_module_layouts20publicPrespecializedyyxlFSd_Ts5 : $@convention(thin) (Double) -> ()
8186
// OPT: apply [[F2]]
87+
// OPT: [[F9:%.*]] = function_ref @$s30pre_specialized_module_layouts20publicPrespecializedyyxlFBi64__Ts5 : $@convention(thin) (Builtin.Int64) -> ()
88+
// OPT: [[A5:%.*]] = unchecked_trivial_bit_cast {{%.*}} : $UInt64 to $Builtin.Int64
89+
// OPT: apply [[F9]]([[A5]]) : $@convention(thin) (Builtin.Int64) -> ()
90+
// OPT: [[A6:%.*]] = unchecked_trivial_bit_cast {{%.*}} : $TwoInt32 to $Builtin.Int64
91+
// OPT: apply [[F9]]([[A6]]) : $@convention(thin) (Builtin.Int64) -> ()
8292
// OPT-macosx: [[F6:%.*]] = function_ref @$s30pre_specialized_module_layouts20publicPrespecializedyyxlF : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
8393
// OPT-macosx: apply [[F6]]<SomeData>
8494
// OPT: [[F7:%.*]] = function_ref @$s30pre_specialized_module_layouts20publicPrespecializedyyxlFyXl_Ts5 : $@convention(thin) (@guaranteed AnyObject) -> ()
@@ -145,6 +155,8 @@ internal func testEmitIntoClient<T>(t: T) {
145155
public func usePrespecializedEntryPoints(wrapperStruct: ReferenceWrapperStruct, overaligned: OveralignedReferenceWrapperStruct, array: [Int]) {
146156
publicPrespecialized(1)
147157
publicPrespecialized(1.0)
158+
publicPrespecialized(UInt64(1))
159+
publicPrespecialized(TwoInt32())
148160
publicPrespecialized(SomeData())
149161
publicPrespecialized(SomeClass())
150162
publicPrespecialized(wrapperStruct)

0 commit comments

Comments
 (0)