@@ -59,39 +59,53 @@ class InstModCallbacks {
59
59
// /
60
60
// / NOTE: It is assumed that this operation will never invalidate instruction
61
61
// / iterators.
62
+ // /
63
+ // / This can have compile-time implications and should be avoided
64
+ // / whenever possible in favor of more structured optimization passes.
62
65
std::function<void (Operand *use, SILValue newValue)> setUseValueFunc;
63
66
64
67
// / A function that takes in an instruction and deletes the inst.
65
68
// /
66
- // / Default implementation is instToDelete->eraseFromParent();
69
+ // / This is used to invalidate dangling instruction pointers. The SIL will be
70
+ // / invalid when it is invoked. The callback is only allowed to inspect the
71
+ // / inline fields of \p instToDelete and iterate over the results. It is not
72
+ // / allowed to dereference operands or iterate uses.
73
+ // /
74
+ // / See comments for notifyWillBeDeletedFunc.
75
+ // /
76
+ // / The default implementation is:
77
+ // /
78
+ // / instToDelete->eraseFromParent();
79
+ // /
80
+ // / The reason this callback is reponsible for deleting the instruction is to
81
+ // / interoperate more easily with
82
+ // / CanonicalizeInstruction::killInstruction(). This allows updates to choose
83
+ // / whether to happen before or after deleting the instruction and possibly
84
+ // / keep it around as a zombie object. All implementations must at least
85
+ // / immediately remove all references to the instruction, including the parent
86
+ // / block list.
67
87
// /
68
- // / NOTE: The reason why we have deleteInstFunc and notifyWillBeDeletedFunc is
69
- // / InstModCallback supports 2 stage deletion where a callee passed
70
- // / InstModCallback is allowed to drop all references to the instruction
71
- // / before calling deleteInstFunc. In contrast, notifyWillBeDeletedFunc
72
- // / assumes that the IR is in a good form before being called so that the
73
- // / caller can via the callback gather state about the instruction that will
74
- // / be deleted. As an example, see InstructionDeleter::deleteInstruction() in
75
- // / InstOptUtils.cpp.
88
+ // / TODO: When zombie instructions are implemented at the module level, we
89
+ // / should move the eraseFromParent() functionality out of the callback.
76
90
std::function<void (SILInstruction *instToDelete)> deleteInstFunc;
77
91
78
- // / If non-null, called before an instruction is deleted or has its references
79
- // / dropped. If null, no-op.
92
+ // / If non-null, called before a salient instruction is deleted or has its
93
+ // / references dropped. If null, no-op.
80
94
// /
81
- // / NOTE: The reason why we have deleteInstFunc and notifyWillBeDeletedFunc is
82
- // / InstModCallback supports 2 stage deletion where a callee passed
83
- // / InstModCallback is allowed to drop all references to the instruction
84
- // / before calling deleteInstFunc. In contrast, notifyWillBeDeletedFunc
85
- // / assumes that the IR is in a good form before being called so that the
86
- // / caller can via the callback gather state about the instruction that will
87
- // / be deleted. As an example, see InstructionDeleter::deleteInstruction() in
88
- // / InstOptUtils.cpp.
95
+ // / This can be used to respond to dead instructions that will be deleted in
96
+ // / the future. Unlike deleteInstFunc, the SIL will be in a valid
97
+ // / state. However, arbitrary SIL transformations may happen between this
98
+ // / invocation and actual instruction deletion.
89
99
// /
90
- // / NOTE: This is called in InstModCallback::deleteInst() if one does not use
91
- // / a default bool argument to disable the notification. In general that
92
- // / should only be done when one is writing custom handling and is performing
93
- // / the notification ones self. It is assumed that the notification will be
94
- // / called with a valid instruction.
100
+ // / This callback is not guaranteed to be called for every deleted
101
+ // / instruction. It cannot be used to invalidate dangling pointers. It is only
102
+ // / called for "salient" instructions that likely create additional
103
+ // / optimization opportunities when deleted. If a dead def-use chain is
104
+ // / deleted, notification only occurs for the initial def.
105
+ // /
106
+ // / This is used in rare circumstances to update an optimization worklist. It
107
+ // / should be avoided whenever possible in favor of more structured
108
+ // / optimization passes.
95
109
std::function<void (SILInstruction *instThatWillBeDeleted)>
96
110
notifyWillBeDeletedFunc;
97
111
@@ -265,6 +279,9 @@ void recursivelyDeleteTriviallyDeadInstructions(
265
279
SILInstruction *inst, bool force = false ,
266
280
InstModCallbacks callbacks = InstModCallbacks());
267
281
282
+ // / True if this instruction can be deleted if all its uses can also be deleted.
283
+ bool isInstructionTriviallyDeletable (SILInstruction *inst);
284
+
268
285
// / Perform a fast local check to see if the instruction is dead.
269
286
// /
270
287
// / This routine only examines the state of the instruction at hand.
@@ -279,11 +296,6 @@ bool isIntermediateRelease(SILInstruction *inst, EpilogueARCFunctionInfo *erfi);
279
296
void collectUsesOfValue (SILValue V,
280
297
llvm::SmallPtrSetImpl<SILInstruction *> &Insts);
281
298
282
- // / Recursively erase all of the uses of the instruction (but not the
283
- // / instruction itself)
284
- void eraseUsesOfInstruction (SILInstruction *inst,
285
- InstModCallbacks callbacks = InstModCallbacks());
286
-
287
299
// / Recursively erase all of the uses of the value (but not the
288
300
// / value itself)
289
301
void eraseUsesOfValue (SILValue value);
@@ -375,7 +387,42 @@ bool tryCheckedCastBrJumpThreading(
375
387
// / cleaning up any dead code resulting from deleting those instructions. Use
376
388
// / this utility instead of
377
389
// / \c recursivelyDeleteTriviallyDeadInstruction.
390
+ // /
391
+ // / This is designed to be used with a single 'onDelete' callback, which is
392
+ // / invoked consistently just before deleting each instruction. It's usually
393
+ // / used to avoid iterator invalidation (see the updatingIterator() factory
394
+ // / method). The other InstModCallbacks should generally be handled at a higher
395
+ // / level, and avoided altogether if possible. The following two are supported
396
+ // / for flexibility:
397
+ // /
398
+ // / callbacks.createdNewInst() is invoked incrementally when it fixes lifetimes
399
+ // / while deleting a set of instructions, but the SIL may still be invalid
400
+ // / relative to the new instruction.
401
+ // /
402
+ // / callbacks.notifyWillBeDeletedFunc() is invoked when a dead instruction is
403
+ // / first recognized and was not already passed in by the client. During the
404
+ // / callback, the to-be-deleted instruction has valid SIL. It's operands and
405
+ // / uses can be inspected and cached. It will be deleted later during
406
+ // / cleanupDeadInstructions().
407
+ // /
408
+ // / Note that the forceDelete* APIs only invoke notifyWillBeDeletedFunc() when
409
+ // / an operand's definition will become dead after force-deleting the specified
410
+ // / instruction. Some clients force-delete related instructions one at a
411
+ // / time. They may not force-deleted. It's the client's responsiblity to invoke
412
+ // / notifyWillBeDeletedFunc() on those explicitly deleted instructions if
413
+ // / needed.
414
+ // /
378
415
class InstructionDeleter {
416
+ public:
417
+ static InstructionDeleter updatingIterator (SILBasicBlock::iterator &iter) {
418
+ auto onDelete = InstModCallbacks ().onDelete ([&](SILInstruction *deadInst) {
419
+ if (deadInst->getIterator () == iter)
420
+ ++iter;
421
+ deadInst->eraseFromParent ();
422
+ });
423
+ return InstructionDeleter (onDelete);
424
+ }
425
+
379
426
private:
380
427
// / A set vector of instructions that are found to be dead. The ordering of
381
428
// / instructions in this set is important as when a dead instruction is
@@ -384,20 +431,33 @@ class InstructionDeleter {
384
431
SmallSetVector<SILInstruction *, 8 > deadInstructions;
385
432
386
433
// / Callbacks used when adding/deleting instructions.
387
- InstModCallbacks instModCallbacks ;
434
+ InstModCallbacks callbacks ;
388
435
389
436
public:
390
- InstructionDeleter () : deadInstructions(), instModCallbacks() {}
391
- InstructionDeleter (InstModCallbacks inputCallbacks)
392
- : deadInstructions(), instModCallbacks(inputCallbacks) {}
437
+ InstructionDeleter () : deadInstructions(), callbacks() {}
438
+ InstructionDeleter (InstModCallbacks callbacks)
439
+ : deadInstructions(), callbacks(callbacks) {}
440
+
441
+ InstModCallbacks &getCallbacks () { return callbacks; }
393
442
394
443
// / If the instruction \p inst is dead, record it so that it can be cleaned
395
444
// / up.
396
- void trackIfDead (SILInstruction *inst);
445
+ // /
446
+ // / Calls callbacks.notifyWillBeDeleted().
447
+ bool trackIfDead (SILInstruction *inst);
448
+
449
+ // / Force track this instruction as dead. Used to enable the deletion of a
450
+ // / bunch of instructions at the same time.
451
+ // /
452
+ // / Calls callbacks.notifyWillBeDeleted().
453
+ void forceTrackAsDead (SILInstruction *inst);
397
454
398
- // / If the instruction \p inst is dead, delete it immediately and record
399
- // / its operands so that they can be cleaned up later.
400
- void deleteIfDead (SILInstruction *inst);
455
+ // / If the instruction \p inst is dead, delete it immediately along with its
456
+ // / destroys and scope-ending uses, and record its operands so that they can
457
+ // / be cleaned up later.
458
+ // /
459
+ // / Calls callbacks.notifyWillBeDeleted().
460
+ bool deleteIfDead (SILInstruction *inst);
401
461
402
462
// / Delete the instruction \p inst and record instructions that may become
403
463
// / dead because of the removal of \c inst. This function will add necessary
@@ -411,10 +471,8 @@ class InstructionDeleter {
411
471
// / \pre the instruction to be deleted must not have any use other than
412
472
// / incidental uses.
413
473
// /
414
- // / \p callback is called on each deleted instruction before deleting any
415
- // / instructions. This way, the SIL is valid in the callback. However, the
416
- // / callback cannot be used to update instruction iterators since other
417
- // / instructions to be deleted remain in the instruction list.
474
+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will be
475
+ // / called for any other instructions that become dead as a result.
418
476
void forceDeleteAndFixLifetimes (SILInstruction *inst);
419
477
420
478
// / Delete the instruction \p inst and record instructions that may become
@@ -429,11 +487,19 @@ class InstructionDeleter {
429
487
// /
430
488
// / \pre the instruction to be deleted must not have any use other than
431
489
// / incidental uses.
490
+ // /
491
+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will be
492
+ // / called for any other instructions that become dead as a result.
432
493
void forceDelete (SILInstruction *inst);
433
494
434
- // / Force track this instruction as dead. Used to enable the deletion of a
435
- // / bunch of instructions at the same time.
436
- void forceTrackAsDead (SILInstruction *inst);
495
+ // / Recursively delete all of the uses of the instruction before deleting the
496
+ // / instruction itself. Does not fix lifetimes.
497
+ // /
498
+ // / callbacks.notifyWillBeDeleted will not be called for \p inst but will
499
+ // / be called for any other instructions that become dead as a result.
500
+ void forceDeleteWithUsers (SILInstruction *inst) {
501
+ deleteWithUses (inst, /* fixLifetimes*/ false , /* forceDeleteUsers*/ true );
502
+ }
437
503
438
504
// / Clean up dead instructions that are tracked by this instance and all
439
505
// / instructions that transitively become dead.
@@ -442,19 +508,30 @@ class InstructionDeleter {
442
508
// / under or over releases). Note that if \c forceDelete call leaves the
443
509
// / function body in an inconsistent state, it needs to be made consistent
444
510
// / before this method is invoked.
445
- void cleanUpDeadInstructions ();
511
+ // /
512
+ // / callbacks.notifyWillBeDeletedFunc will only be called for instructions
513
+ // / that become dead during cleanup but were not already tracked.
514
+ void cleanupDeadInstructions ();
446
515
447
- // / Recursively visit users of \c inst (including \c inst)and delete
448
- // / instructions that are dead (including \c inst).
516
+ // / Recursively visit users of \p inst and delete instructions that are dead
517
+ // / including \p inst.
518
+ // /
519
+ // / callbacks.notifyWillBeDeletedFunc will be called for any dead
520
+ // / instructions.
449
521
void recursivelyDeleteUsersIfDead (SILInstruction *inst);
450
522
451
- // / Recursively visit users of \c inst (including \c inst) and force delete
452
- // / them . Also, destroy the consumed operands of the deleted instructions
523
+ // / Recursively visit users of \p inst and force delete them including \p
524
+ // / inst . Also, destroy the consumed operands of the deleted instructions
453
525
// / whenever necessary.
526
+ // /
527
+ // / callbacks.notifyWillBeDeletedFunc will not be called for \p inst or its
528
+ // / users but will be called for any other instructions that become dead as a
529
+ // / result.
454
530
void recursivelyForceDeleteUsersAndFixLifetimes (SILInstruction *inst);
455
531
456
532
private:
457
- void deleteInstruction (SILInstruction *inst, bool fixOperandLifetimes);
533
+ void deleteWithUses (SILInstruction *inst, bool fixLifetimes,
534
+ bool forceDeleteUsers = false );
458
535
};
459
536
460
537
// / If \c inst is dead, delete it and recursively eliminate all code that
0 commit comments