Skip to content

Commit 2b117fd

Browse files
committed
Swift Optimizer: add APIs to copy from or to a global static initializer
* `Context.copyStaticInitializer(fromInitValue:, to:)` * `FunctionPassContext.createStaticInitializer(for:,initValue:)`
1 parent 78ce13d commit 2b117fd

File tree

8 files changed

+102
-25
lines changed

8 files changed

+102
-25
lines changed

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,33 @@ extension MutatingContext {
7171
erase(instruction: inst)
7272
}
7373

74+
/// Copies all instructions of a static init value of a global to the insertion point of `builder`.
75+
func copyStaticInitializer(fromInitValue: Value, to builder: Builder) -> Value? {
76+
let range = _bridged.copyStaticInitializer(fromInitValue.bridged, builder.bridged)
77+
guard let result = range.clonedInitValue.value,
78+
let firstClonedInst = range.firstClonedInst.instruction else {
79+
return nil
80+
}
81+
let resultInst = result.definingInstruction!
82+
notifyNewInstructions(from: firstClonedInst, to: resultInst)
83+
notifyInstructionChanged(resultInst)
84+
return result
85+
}
86+
87+
private func notifyNewInstructions(from: Instruction, to: Instruction) {
88+
var inst = from
89+
while inst != to {
90+
if !inst.isDeleted {
91+
notifyInstructionChanged(inst)
92+
}
93+
if let next = inst.next {
94+
inst = next
95+
} else {
96+
inst = inst.parentBlock.next!.instructions.first!
97+
}
98+
}
99+
}
100+
74101
func tryDeleteDeadClosure(closure: SingleValueInstruction) -> Bool {
75102
_bridged.tryDeleteDeadClosure(closure.bridged)
76103
}
@@ -148,6 +175,12 @@ struct FunctionPassContext : MutatingContext {
148175
fileprivate func notifyEffectsChanged() {
149176
_bridged.asNotificationHandler().notifyChanges(.effectsChanged)
150177
}
178+
179+
/// Copies `initValue` (including all operand instructions, transitively) to the
180+
/// static init value of `global`.
181+
func createStaticInitializer(for global: GlobalVariable, initValue: SingleValueInstruction) {
182+
_bridged.createStaticInitializer(global.bridged, initValue.bridged)
183+
}
151184
}
152185

153186
struct SimplifyContext : MutatingContext {

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public struct Builder {
2626
private let notificationHandler: BridgedChangeNotificationHandler
2727
private let notifyNewInstruction: (Instruction) -> ()
2828

29-
private var bridged: BridgedBuilder {
29+
public var bridged: BridgedBuilder {
3030
switch insertAt {
3131
case .before(let inst):
3232
return BridgedBuilder(insertBefore: inst.bridged.optional,

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ struct BridgedPassContext {
207207
SWIFT_IMPORT_UNSAFE
208208
OptionalBridgedValue constantFoldBuiltin(BridgedInstruction builtin) const;
209209

210+
void createStaticInitializer(BridgedGlobalVar global, BridgedInstruction initValue) const;
211+
212+
struct StaticInitCloneResult {
213+
OptionalBridgedInstruction firstClonedInst;
214+
OptionalBridgedValue clonedInitValue;
215+
};
216+
217+
SWIFT_IMPORT_UNSAFE
218+
StaticInitCloneResult copyStaticInitializer(BridgedValue initValue, BridgedBuilder b) const;
219+
210220
SWIFT_IMPORT_UNSAFE
211221
BridgedValue getSILUndef(swift::SILType type) const {
212222
return {swift::SILUndef::get(type, *invocation->getFunction())};

include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -357,30 +357,43 @@ class StaticInitCloner : public SILCloner<StaticInitCloner> {
357357
/// don't have any operands).
358358
llvm::SmallVector<SILInstruction *, 8> readyToClone;
359359

360-
SILInstruction *insertionPoint = nullptr;
360+
SILDebugLocation insertLoc;
361+
362+
SILInstruction *firstClonedInst = nullptr;
361363

362364
public:
363365
StaticInitCloner(SILGlobalVariable *gVar)
364-
: SILCloner<StaticInitCloner>(gVar) {}
366+
: SILCloner<StaticInitCloner>(gVar),
367+
insertLoc(ArtificialUnreachableLocation(), nullptr) {}
365368

366369
StaticInitCloner(SILInstruction *insertionPoint)
367370
: SILCloner<StaticInitCloner>(*insertionPoint->getFunction()),
368-
insertionPoint(insertionPoint) {
371+
insertLoc(insertionPoint->getDebugLocation()) {
369372
Builder.setInsertionPoint(insertionPoint);
370373
}
371374

375+
StaticInitCloner(const SILBuilder &builder)
376+
: SILCloner<StaticInitCloner>(builder.getFunction()),
377+
insertLoc(ArtificialUnreachableLocation(), nullptr) {
378+
Builder.setInsertionPoint(builder.getInsertionBB(), builder.getInsertionPoint());
379+
if (builder.getInsertionPoint() != builder.getInsertionBB()->end())
380+
insertLoc = builder.getInsertionPoint()->getDebugLocation();
381+
}
382+
372383
/// Add \p InitVal and all its operands (transitively) for cloning.
373384
///
374385
/// Note: all init values must are added, before calling clone().
375386
/// Returns false if cloning is not possible, e.g. if we would end up cloning
376387
/// a reference to a private function into a function which is serialized.
377-
bool add(SILInstruction *initVal);
388+
bool add(SILValue initVal);
378389

379390
/// Clone \p InitVal and all its operands into the initializer of the
380391
/// SILGlobalVariable.
381392
///
382393
/// \return Returns the cloned instruction in the SILGlobalVariable.
383-
SingleValueInstruction *clone(SingleValueInstruction *initVal);
394+
SILValue clone(SILValue initVal);
395+
396+
SILInstruction *getFirstClonedInst() const { return firstClonedInst; }
384397

385398
/// Convenience function to clone a single \p InitVal.
386399
static void appendToInitializer(SILGlobalVariable *gVar,
@@ -393,16 +406,19 @@ class StaticInitCloner : public SILCloner<StaticInitCloner> {
393406
}
394407

395408
protected:
409+
410+
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
411+
if (!firstClonedInst)
412+
firstClonedInst = Cloned;
413+
SILCloner<StaticInitCloner>::postProcess(Orig, Cloned);
414+
}
415+
396416
SILLocation remapLocation(SILLocation loc) {
397-
if (insertionPoint)
398-
return insertionPoint->getLoc();
399-
return ArtificialUnreachableLocation();
417+
return insertLoc.getLocation();
400418
}
401419

402420
const SILDebugScope *remapScope(const SILDebugScope *DS) {
403-
if (insertionPoint)
404-
return insertionPoint->getDebugScope();
405-
return nullptr;
421+
return insertLoc.getScope();
406422
}
407423
};
408424

lib/SILOptimizer/IPO/GlobalOpt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ static void replaceLoadsFromGlobal(SILValue addr,
348348
for (Operand *use : addr->getUses()) {
349349
SILInstruction *user = use->getUser();
350350
if (auto *load = dyn_cast<LoadInst>(user)) {
351-
SingleValueInstruction *clonedInitVal = cloner.clone(initVal);
351+
SingleValueInstruction *clonedInitVal = cast<SingleValueInstruction>(cloner.clone(initVal));
352352
load->replaceAllUsesWith(clonedInitVal);
353353
continue;
354354
}

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/SILOptimizer/OptimizerBridging.h"
2828
#include "swift/SILOptimizer/PassManager/PrettyStackTrace.h"
2929
#include "swift/SILOptimizer/PassManager/Transforms.h"
30+
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
3031
#include "swift/SILOptimizer/Utils/ConstantFolding.h"
3132
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
3233
#include "swift/SILOptimizer/Utils/OptimizerStatsUtils.h"
@@ -1436,6 +1437,21 @@ OptionalBridgedValue BridgedPassContext::constantFoldBuiltin(BridgedInstruction
14361437
return {::constantFoldBuiltin(bi, resultsInError)};
14371438
}
14381439

1440+
void BridgedPassContext::createStaticInitializer(BridgedGlobalVar global, BridgedInstruction initValue) const {
1441+
StaticInitCloner::appendToInitializer(global.getGlobal(), initValue.getAs<SingleValueInstruction>());
1442+
}
1443+
1444+
BridgedPassContext::StaticInitCloneResult BridgedPassContext::
1445+
copyStaticInitializer(BridgedValue initValue, BridgedBuilder b) const {
1446+
swift::SILBuilder builder(b.insertBefore.getInst(), b.insertAtEnd.getBlock(), b.loc.getScope());
1447+
StaticInitCloner cloner(builder);
1448+
if (!cloner.add(initValue.getSILValue())) {
1449+
return {{nullptr}, {nullptr}};
1450+
}
1451+
SILValue result = cloner.clone(initValue.getSILValue());
1452+
return {{cloner.getFirstClonedInst()->asSILNode()}, {result}};
1453+
}
1454+
14391455
void BridgedPassContext::fixStackNesting(BridgedFunction function) const {
14401456
switch (StackNesting::fixNesting(function.getFunction())) {
14411457
case StackNesting::Changes::None:

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) {
996996
if (SingleValueInstruction *initVal = getValueFromStaticLet(LI->getOperand())) {
997997
StaticInitCloner cloner(LI);
998998
if (cloner.add(initVal)) {
999-
return cloner.clone(initVal);
999+
return cloner.clone(initVal).getDefiningInstruction();
10001000
}
10011001
}
10021002

lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,11 @@ bool SinkAddressProjections::cloneProjections() {
310310
return true;
311311
}
312312

313-
bool StaticInitCloner::add(SILInstruction *initVal) {
313+
bool StaticInitCloner::add(SILValue initVal) {
314+
SILInstruction *initInst = initVal->getDefiningInstruction();
315+
314316
// Don't schedule an instruction twice for cloning.
315-
if (numOpsToClone.count(initVal) != 0)
317+
if (numOpsToClone.count(initInst) != 0)
316318
return true;
317319

318320
if (auto *funcRef = dyn_cast<FunctionRefInst>(initVal)) {
@@ -324,25 +326,25 @@ bool StaticInitCloner::add(SILInstruction *initVal) {
324326
}
325327
}
326328

327-
ArrayRef<Operand> operands = initVal->getAllOperands();
328-
numOpsToClone[initVal] = operands.size();
329+
ArrayRef<Operand> operands = initInst->getAllOperands();
330+
numOpsToClone[initInst] = operands.size();
329331
if (operands.empty()) {
330332
// It's an instruction without operands, e.g. a literal. It's ready to be
331333
// cloned first.
332-
readyToClone.push_back(initVal);
334+
readyToClone.push_back(initInst);
333335
} else {
334336
// Recursively add all operands.
335337
for (const Operand &operand : operands) {
336-
if (!add(cast<SingleValueInstruction>(operand.get())))
338+
if (!add(operand.get()))
337339
return false;
338340
}
339341
}
340342
return true;
341343
}
342344

343-
SingleValueInstruction *
344-
StaticInitCloner::clone(SingleValueInstruction *initVal) {
345-
assert(numOpsToClone.count(initVal) != 0 && "initVal was not added");
345+
SILValue StaticInitCloner::clone(SILValue initVal) {
346+
SILInstruction *initInst = initVal->getDefiningInstruction();
347+
assert(numOpsToClone.count(initInst) != 0 && "initVal was not added");
346348

347349
if (!isValueCloned(initVal)) {
348350
// Find the right order to clone: all operands of an instruction must be
@@ -361,9 +363,9 @@ StaticInitCloner::clone(SingleValueInstruction *initVal) {
361363
readyToClone.push_back(user);
362364
}
363365
}
364-
if (inst == initVal)
366+
if (inst == initInst)
365367
break;
366368
}
367369
}
368-
return cast<SingleValueInstruction>(getMappedValue(initVal));
370+
return getMappedValue(initVal);
369371
}

0 commit comments

Comments
 (0)