Skip to content

Commit ba42be5

Browse files
authored
Merge pull request #59665 from eeckstein/target-constprop
SILOptimizer: add a pass to perform target specific constant folding.
2 parents 672c106 + f420468 commit ba42be5

File tree

13 files changed

+275
-23
lines changed

13 files changed

+275
-23
lines changed

include/swift/AST/SILGenRequests.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class LangOptions;
2929
class ModuleDecl;
3030
class SILModule;
3131
class SILOptions;
32+
class IRGenOptions;
3233

3334
namespace Lowering {
3435
class TypeConverter;
@@ -47,6 +48,7 @@ struct ASTLoweringDescriptor {
4748
llvm::PointerUnion<FileUnit *, ModuleDecl *> context;
4849
Lowering::TypeConverter &conv;
4950
const SILOptions &opts;
51+
const IRGenOptions *irgenOptions;
5052

5153
/// A specific set of SILDeclRefs to emit. If set, only these refs will be
5254
/// emitted. Otherwise the entire \c context will be emitted.
@@ -74,15 +76,17 @@ struct ASTLoweringDescriptor {
7476
public:
7577
static ASTLoweringDescriptor
7678
forFile(FileUnit &sf, Lowering::TypeConverter &conv, const SILOptions &opts,
77-
Optional<SILRefsToEmit> refsToEmit = None) {
78-
return ASTLoweringDescriptor{&sf, conv, opts, refsToEmit};
79+
Optional<SILRefsToEmit> refsToEmit = None,
80+
const IRGenOptions *irgenOptions = nullptr) {
81+
return ASTLoweringDescriptor{&sf, conv, opts, irgenOptions, refsToEmit};
7982
}
8083

8184
static ASTLoweringDescriptor
8285
forWholeModule(ModuleDecl *mod, Lowering::TypeConverter &conv,
8386
const SILOptions &opts,
84-
Optional<SILRefsToEmit> refsToEmit = None) {
85-
return ASTLoweringDescriptor{mod, conv, opts, refsToEmit};
87+
Optional<SILRefsToEmit> refsToEmit = None,
88+
const IRGenOptions *irgenOptions = nullptr) {
89+
return ASTLoweringDescriptor{mod, conv, opts, irgenOptions, refsToEmit};
8690
}
8791

8892
/// Retrieves the files to generate SIL for. If the descriptor is configured

include/swift/SIL/SILModule.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class AnyFunctionType;
103103
class ASTContext;
104104
class FileUnit;
105105
class FuncDecl;
106+
class IRGenOptions;
106107
class KeyPathPattern;
107108
class ModuleDecl;
108109
class SILUndef;
@@ -353,6 +354,12 @@ class SILModule {
353354
/// The options passed into this SILModule.
354355
const SILOptions &Options;
355356

357+
/// IRGen options to be used by target specific SIL optimization passes.
358+
///
359+
/// Not null, if the module is created by the compiler itself (and not
360+
/// e.g. by lldb).
361+
const IRGenOptions *irgenOptions;
362+
356363
/// The number of functions created in this module, which will be the index of
357364
/// the next function.
358365
unsigned nextFunctionIndex = 0;
@@ -382,7 +389,8 @@ class SILModule {
382389
#endif
383390

384391
SILModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
385-
Lowering::TypeConverter &TC, const SILOptions &Options);
392+
Lowering::TypeConverter &TC, const SILOptions &Options,
393+
const IRGenOptions *irgenOptions = nullptr);
386394

387395
SILModule(const SILModule&) = delete;
388396
void operator=(const SILModule&) = delete;
@@ -537,7 +545,8 @@ class SILModule {
537545
/// single-file mode, and a ModuleDecl in whole-module mode.
538546
static std::unique_ptr<SILModule>
539547
createEmptyModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
540-
Lowering::TypeConverter &TC, const SILOptions &Options);
548+
Lowering::TypeConverter &TC, const SILOptions &Options,
549+
const IRGenOptions *irgenOptions = nullptr);
541550

542551
/// Get the Swift module associated with this SIL module.
543552
ModuleDecl *getSwiftModule() const { return TheSwiftModule; }
@@ -570,6 +579,7 @@ class SILModule {
570579
bool isOptimizedOnoneSupportModule() const;
571580

572581
const SILOptions &getOptions() const { return Options; }
582+
const IRGenOptions *getIRGenOptionsOrNull() const { return irgenOptions; }
573583

574584
using iterator = FunctionListType::iterator;
575585
using const_iterator = FunctionListType::const_iterator;

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ PASS(ReleaseHoisting, "release-hoisting",
356356
"SIL release Hoisting")
357357
PASS(LateReleaseHoisting, "late-release-hoisting",
358358
"Late SIL release Hoisting Preserving Epilogues")
359+
PASS(TargetConstantFolding, "target-constant-folding",
360+
"Target specific constant folding")
359361
IRGEN_PASS(LoadableByAddress, "loadable-address",
360362
"SIL Large Loadable type by-address lowering.")
361363
PASS(MandatorySILLinker, "mandatory-linker",

include/swift/Subsystems.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,14 @@ namespace swift {
179179
/// SIL of all files in the module is present in the SILModule.
180180
std::unique_ptr<SILModule>
181181
performASTLowering(ModuleDecl *M, Lowering::TypeConverter &TC,
182-
const SILOptions &options);
182+
const SILOptions &options,
183+
const IRGenOptions *irgenOptions = nullptr);
183184

184185
/// Turn a source file into SIL IR.
185186
std::unique_ptr<SILModule>
186187
performASTLowering(FileUnit &SF, Lowering::TypeConverter &TC,
187-
const SILOptions &options);
188+
const SILOptions &options,
189+
const IRGenOptions *irgenOptions = nullptr);
188190

189191
using ModuleOrSourceFile = PointerUnion<ModuleDecl *, SourceFile *>;
190192

lib/FrontendTool/FrontendTool.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,9 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
766766
const PrimarySpecificPaths PSPs =
767767
Instance.getPrimarySpecificPathsForWholeModuleOptimizationMode();
768768
SILOptions SILOpts = getSILOptions(PSPs);
769-
auto SM = performASTLowering(mod, Instance.getSILTypes(), SILOpts);
769+
IRGenOptions irgenOpts = Invocation.getIRGenOptions();
770+
auto SM = performASTLowering(mod, Instance.getSILTypes(), SILOpts,
771+
&irgenOpts);
770772
return performCompileStepsPostSILGen(Instance, std::move(SM), mod, PSPs,
771773
ReturnValue, observer);
772774
}
@@ -779,8 +781,9 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
779781
const PrimarySpecificPaths PSPs =
780782
Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
781783
SILOptions SILOpts = getSILOptions(PSPs);
784+
IRGenOptions irgenOpts = Invocation.getIRGenOptions();
782785
auto SM = performASTLowering(*PrimaryFile, Instance.getSILTypes(),
783-
SILOpts);
786+
SILOpts, &irgenOpts);
784787
result |= performCompileStepsPostSILGen(Instance, std::move(SM),
785788
PrimaryFile, PSPs, ReturnValue,
786789
observer);

lib/IRGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ add_swift_host_library(swiftIRGen STATIC
5757
Outlining.cpp
5858
StructLayout.cpp
5959
SwiftTargetInfo.cpp
60+
TargetConstantFolding.cpp
6061
TypeLayout.cpp
6162
TypeLayoutDumper.cpp
6263
TypeLayoutVerifier.cpp

lib/IRGen/IRGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
10591059
auto SILMod = std::unique_ptr<SILModule>(desc.SILMod);
10601060
if (!SILMod) {
10611061
auto loweringDesc = ASTLoweringDescriptor{
1062-
desc.Ctx, desc.Conv, desc.SILOpts,
1062+
desc.Ctx, desc.Conv, desc.SILOpts, nullptr,
10631063
symsToEmit.map([](const auto &x) { return x.silRefsToEmit; })};
10641064
SILMod = llvm::cantFail(Ctx.evaluator(LoweredSILRequest{loweringDesc}));
10651065

lib/IRGen/TargetConstantFolding.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===--- TargetConstantFolding.cpp ----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// This pass lowers loadable SILTypes. On completion, the SILType of every
12+
// function argument is an address instead of the type itself.
13+
// This reduces the code size.
14+
// Consequently, this pass is required for IRGen.
15+
// It is a mandatory IRGen preparation pass (not a diagnostic pass).
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#define DEBUG_TYPE "target-constant-folding"
20+
#include "IRGenModule.h"
21+
#include "swift/SIL/SILBuilder.h"
22+
#include "swift/SILOptimizer/PassManager/Transforms.h"
23+
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
24+
#include "llvm/Support/Debug.h"
25+
26+
using namespace swift;
27+
using namespace swift::irgen;
28+
29+
namespace {
30+
31+
/// Performs constant folding for target-specific values.
32+
///
33+
/// Specifically, this optimization constant folds
34+
/// ```
35+
/// MemoryLayout<S>.size
36+
/// MemoryLayout<S>.alignment
37+
/// MemoryLayout<S>.stride
38+
/// ```
39+
/// Constant folding those expressions in the middle of the SIL pipeline
40+
/// enables other optimizations to e.g. allow such expressions in statically
41+
/// allocated global variables (done by the GlobalOpt pass).
42+
class TargetConstantFolding : public SILModuleTransform {
43+
private:
44+
/// The entry point to the transformation.
45+
void run() override {
46+
auto *irgenOpts = getModule()->getIRGenOptionsOrNull();
47+
if (!irgenOpts)
48+
return;
49+
50+
// We need an IRGenModule to get the actual sizes from type lowering.
51+
// Creating an IRGenModule involves some effort. Therefore this is a
52+
// module pass rather than a function pass so that this one-time setup
53+
// only needs to be done once and not for all functions in a module.
54+
IRGenerator irgen(*irgenOpts, *getModule());
55+
auto targetMachine = irgen.createTargetMachine();
56+
if (!targetMachine)
57+
return;
58+
IRGenModule IGM(irgen, std::move(targetMachine));
59+
60+
// Scan all instructions in the module for constant foldable instructions.
61+
for (SILFunction &function : *getModule()) {
62+
63+
if (!function.shouldOptimize())
64+
continue;
65+
66+
bool changed = false;
67+
for (SILBasicBlock &block : function) {
68+
InstructionDeleter deleter;
69+
70+
for (SILInstruction *inst : deleter.updatingRange(&block)) {
71+
if (constFold(inst, IGM)) {
72+
deleter.forceDelete(inst);
73+
changed = true;
74+
}
75+
}
76+
deleter.cleanupDeadInstructions();
77+
}
78+
if (changed) {
79+
invalidateAnalysis(&function, SILAnalysis::InvalidationKind::Instructions);
80+
}
81+
}
82+
}
83+
84+
/// Constant fold a single instruction.
85+
///
86+
/// Returns true if `inst` was replaced and can be deleted.
87+
bool constFold(SILInstruction *inst, IRGenModule &IGM) {
88+
auto *bi = dyn_cast<BuiltinInst>(inst);
89+
if (!bi)
90+
return false;
91+
92+
llvm::Constant *c = nullptr;
93+
uint64_t offset = 0;
94+
95+
switch (bi->getBuiltinInfo().ID) {
96+
case BuiltinValueKind::Sizeof:
97+
c = getTypeInfoOfBuiltin(bi, IGM).getStaticSize(IGM);
98+
break;
99+
case BuiltinValueKind::Alignof:
100+
c = getTypeInfoOfBuiltin(bi, IGM).getStaticAlignmentMask(IGM);
101+
// The constant is the alignment _mask_. We get the actual alignment by
102+
// adding 1.
103+
offset = 1;
104+
break;
105+
case BuiltinValueKind::Strideof:
106+
c = getTypeInfoOfBuiltin(bi, IGM).getStaticStride(IGM);
107+
break;
108+
default:
109+
return false;
110+
}
111+
auto *intConst = dyn_cast_or_null<llvm::ConstantInt>(c);
112+
if (!intConst)
113+
return false;
114+
115+
APInt value = intConst->getValue();
116+
value += APInt(value.getBitWidth(), offset);
117+
auto intTy = bi->getType().getAs<BuiltinIntegerType>();
118+
if (!intTy)
119+
return false;
120+
121+
value = value.sextOrTrunc(intTy->getGreatestWidth());
122+
123+
// Replace the builtin by an integer literal.
124+
SILBuilderWithScope builder(bi);
125+
auto *intLit = builder.createIntegerLiteral(bi->getLoc(), bi->getType(),
126+
value);
127+
bi->replaceAllUsesWith(intLit);
128+
return true;
129+
}
130+
131+
const TypeInfo &getTypeInfoOfBuiltin(BuiltinInst *bi, IRGenModule &IGM) {
132+
SubstitutionMap subs = bi->getSubstitutions();
133+
SILType lowered = IGM.getLoweredType(subs.getReplacementTypes()[0]);
134+
return IGM.getTypeInfo(lowered);
135+
}
136+
};
137+
138+
} // end anonymous namespace
139+
140+
SILTransform *swift::createTargetConstantFolding() {
141+
return new TargetConstantFolding();
142+
}

lib/SIL/IR/SILModule.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,11 @@ class SILModule::SerializationCallback final
9090
};
9191

9292
SILModule::SILModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
93-
Lowering::TypeConverter &TC, const SILOptions &Options)
93+
Lowering::TypeConverter &TC, const SILOptions &Options,
94+
const IRGenOptions *irgenOptions)
9495
: Stage(SILStage::Raw), loweredAddresses(!Options.EnableSILOpaqueValues),
95-
indexTrieRoot(new IndexTrieNode()), Options(Options), serialized(false),
96+
indexTrieRoot(new IndexTrieNode()), Options(Options),
97+
irgenOptions(irgenOptions), serialized(false),
9698
regDeserializationNotificationHandlerForNonTransparentFuncOME(false),
9799
regDeserializationNotificationHandlerForAllFuncOME(false),
98100
prespecializedFunctionDeclsImported(false), SerializeSILAction(),
@@ -203,8 +205,10 @@ void SILModule::checkForLeaksAfterDestruction() {
203205

204206
std::unique_ptr<SILModule> SILModule::createEmptyModule(
205207
llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
206-
Lowering::TypeConverter &TC, const SILOptions &Options) {
207-
return std::unique_ptr<SILModule>(new SILModule(context, TC, Options));
208+
Lowering::TypeConverter &TC, const SILOptions &Options,
209+
const IRGenOptions *irgenOptions) {
210+
return std::unique_ptr<SILModule>(new SILModule(context, TC, Options,
211+
irgenOptions));
208212
}
209213

210214
ASTContext &SILModule::getASTContext() const {

lib/SILGen/SILGen.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,7 +2243,7 @@ ASTLoweringRequest::evaluate(Evaluator &evaluator,
22432243
SILInstruction::resetInstructionCounts();
22442244

22452245
auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
2246-
desc.opts);
2246+
desc.opts, desc.irgenOptions);
22472247

22482248
// If all function bodies are being skipped there's no reason to do any
22492249
// SIL generation.
@@ -2285,15 +2285,18 @@ ASTLoweringRequest::evaluate(Evaluator &evaluator,
22852285

22862286
std::unique_ptr<SILModule>
22872287
swift::performASTLowering(ModuleDecl *mod, Lowering::TypeConverter &tc,
2288-
const SILOptions &options) {
2289-
auto desc = ASTLoweringDescriptor::forWholeModule(mod, tc, options);
2288+
const SILOptions &options,
2289+
const IRGenOptions *irgenOptions) {
2290+
auto desc = ASTLoweringDescriptor::forWholeModule(mod, tc, options,
2291+
None, irgenOptions);
22902292
return llvm::cantFail(
22912293
mod->getASTContext().evaluator(ASTLoweringRequest{desc}));
22922294
}
22932295

22942296
std::unique_ptr<SILModule>
22952297
swift::performASTLowering(FileUnit &sf, Lowering::TypeConverter &tc,
2296-
const SILOptions &options) {
2297-
auto desc = ASTLoweringDescriptor::forFile(sf, tc, options);
2298+
const SILOptions &options,
2299+
const IRGenOptions *irgenOptions) {
2300+
auto desc = ASTLoweringDescriptor::forFile(sf, tc, options, None, irgenOptions);
22982301
return llvm::cantFail(sf.getASTContext().evaluator(ASTLoweringRequest{desc}));
22992302
}

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ static void addMidLevelFunctionPipeline(SILPassPipelinePlan &P) {
666666
static void addClosureSpecializePassPipeline(SILPassPipelinePlan &P) {
667667
P.startPipeline("ClosureSpecialize");
668668
P.addDeadFunctionAndGlobalElimination();
669+
P.addTargetConstantFolding();
669670
P.addDeadStoreElimination();
670671
P.addDeadObjectElimination();
671672

test/SILOptimizer/devirt_protocol_method_invocations.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,8 @@ public func test_devirt_protocol_extension_method_invocation_with_self_return_ty
138138
// CHECK: return [[T1]]
139139

140140
// CHECK: sil @$s34devirt_protocol_method_invocations14testExMetatypeSiyF
141-
// CHECK: [[T0:%.*]] = builtin "sizeof"<Int>
142-
// CHECK: [[T1:%.*]] = builtin {{.*}}([[T0]]
143-
// CHECK: [[T2:%.*]] = struct $Int ([[T1]] : {{.*}})
141+
// CHECK: [[T0:%.*]] = integer_literal
142+
// CHECK: [[T2:%.*]] = struct $Int ([[T0]] : {{.*}})
144143
// CHECK: return [[T2]] : $Int
145144

146145
@inline(never)

0 commit comments

Comments
 (0)