@@ -41,14 +41,18 @@ using namespace llvm;
41
41
42
42
namespace {
43
43
class WebAssemblyRegStackify final : public MachineFunctionPass {
44
+ bool Optimize;
45
+
44
46
StringRef getPassName () const override {
45
47
return " WebAssembly Register Stackify" ;
46
48
}
47
49
48
50
void getAnalysisUsage (AnalysisUsage &AU) const override {
49
51
AU.setPreservesCFG ();
50
- AU.addRequired <MachineDominatorTreeWrapperPass>();
51
- AU.addRequired <LiveIntervalsWrapperPass>();
52
+ if (Optimize) {
53
+ AU.addRequired <LiveIntervalsWrapperPass>();
54
+ AU.addRequired <MachineDominatorTreeWrapperPass>();
55
+ }
52
56
AU.addPreserved <MachineBlockFrequencyInfoWrapperPass>();
53
57
AU.addPreserved <SlotIndexesWrapperPass>();
54
58
AU.addPreserved <LiveIntervalsWrapperPass>();
@@ -61,7 +65,9 @@ class WebAssemblyRegStackify final : public MachineFunctionPass {
61
65
62
66
public:
63
67
static char ID; // Pass identification, replacement for typeid
64
- WebAssemblyRegStackify () : MachineFunctionPass(ID) {}
68
+ WebAssemblyRegStackify (CodeGenOptLevel OptLevel)
69
+ : MachineFunctionPass(ID), Optimize(OptLevel != CodeGenOptLevel::None) {}
70
+ WebAssemblyRegStackify () : WebAssemblyRegStackify(CodeGenOptLevel::Default) {}
65
71
};
66
72
} // end anonymous namespace
67
73
@@ -70,8 +76,8 @@ INITIALIZE_PASS(WebAssemblyRegStackify, DEBUG_TYPE,
70
76
" Reorder instructions to use the WebAssembly value stack" ,
71
77
false , false )
72
78
73
- FunctionPass *llvm::createWebAssemblyRegStackify() {
74
- return new WebAssemblyRegStackify ();
79
+ FunctionPass *llvm::createWebAssemblyRegStackify(CodeGenOptLevel OptLevel ) {
80
+ return new WebAssemblyRegStackify (OptLevel );
75
81
}
76
82
77
83
// Decorate the given instruction with implicit operands that enforce the
@@ -96,8 +102,7 @@ static void imposeStackOrdering(MachineInstr *MI) {
96
102
static void convertImplicitDefToConstZero (MachineInstr *MI,
97
103
MachineRegisterInfo &MRI,
98
104
const TargetInstrInfo *TII,
99
- MachineFunction &MF,
100
- LiveIntervals &LIS) {
105
+ MachineFunction &MF) {
101
106
assert (MI->getOpcode () == TargetOpcode::IMPLICIT_DEF);
102
107
103
108
const auto *RegClass = MRI.getRegClass (MI->getOperand (0 ).getReg ());
@@ -262,36 +267,53 @@ static bool shouldRematerialize(const MachineInstr &Def,
262
267
// LiveIntervals to handle complex cases.
263
268
static MachineInstr *getVRegDef (unsigned Reg, const MachineInstr *Insert,
264
269
const MachineRegisterInfo &MRI,
265
- const LiveIntervals & LIS) {
270
+ const LiveIntervals * LIS) {
266
271
// Most registers are in SSA form here so we try a quick MRI query first.
267
272
if (MachineInstr *Def = MRI.getUniqueVRegDef (Reg))
268
273
return Def;
269
274
270
275
// MRI doesn't know what the Def is. Try asking LIS.
271
- if (const VNInfo *ValNo = LIS.getInterval (Reg).getVNInfoBefore (
272
- LIS.getInstructionIndex (*Insert)))
273
- return LIS.getInstructionFromIndex (ValNo->def );
276
+ if (LIS != nullptr ) {
277
+ SlotIndex InstIndex = LIS->getInstructionIndex (*Insert);
278
+ if (const VNInfo *ValNo = LIS->getInterval (Reg).getVNInfoBefore (InstIndex))
279
+ return LIS->getInstructionFromIndex (ValNo->def );
280
+ }
274
281
275
282
return nullptr ;
276
283
}
277
284
278
285
// Test whether Reg, as defined at Def, has exactly one use. This is a
279
286
// generalization of MachineRegisterInfo::hasOneNonDBGUse that uses
280
- // LiveIntervals to handle complex cases.
281
- static bool hasOneNonDBGUse (unsigned Reg, MachineInstr *Def,
282
- MachineRegisterInfo &MRI, MachineDominatorTree &MDT,
283
- LiveIntervals &LIS) {
287
+ // LiveIntervals to handle complex cases in optimized code.
288
+ static bool hasSingleUse (unsigned Reg, MachineRegisterInfo &MRI,
289
+ WebAssemblyFunctionInfo &MFI, bool Optimize,
290
+ MachineInstr *Def, LiveIntervals *LIS) {
291
+ if (!Optimize) {
292
+ // Using "hasOneUse" instead of "hasOneNonDBGUse" here because we don't
293
+ // want to stackify DBG_VALUE operands - WASM stack locations are less
294
+ // useful and less widely supported than WASM local locations.
295
+ if (!MRI.hasOneUse (Reg))
296
+ return false ;
297
+ // The frame base always has an implicit DBG use as DW_AT_frame_base.
298
+ if (MFI.isFrameBaseVirtual () && MFI.getFrameBaseVreg () == Reg)
299
+ return false ;
300
+ return true ;
301
+ }
302
+
284
303
// Most registers are in SSA form here so we try a quick MRI query first.
285
304
if (MRI.hasOneNonDBGUse (Reg))
286
305
return true ;
287
306
307
+ if (LIS == nullptr )
308
+ return false ;
309
+
288
310
bool HasOne = false ;
289
- const LiveInterval &LI = LIS. getInterval (Reg);
311
+ const LiveInterval &LI = LIS-> getInterval (Reg);
290
312
const VNInfo *DefVNI =
291
- LI.getVNInfoAt (LIS. getInstructionIndex (*Def).getRegSlot ());
313
+ LI.getVNInfoAt (LIS-> getInstructionIndex (*Def).getRegSlot ());
292
314
assert (DefVNI);
293
315
for (auto &I : MRI.use_nodbg_operands (Reg)) {
294
- const auto &Result = LI.Query (LIS. getInstructionIndex (*I.getParent ()));
316
+ const auto &Result = LI.Query (LIS-> getInstructionIndex (*I.getParent ()));
295
317
if (Result.valueIn () == DefVNI) {
296
318
if (!Result.isKill ())
297
319
return false ;
@@ -311,7 +333,7 @@ static bool hasOneNonDBGUse(unsigned Reg, MachineInstr *Def,
311
333
static bool isSafeToMove (const MachineOperand *Def, const MachineOperand *Use,
312
334
const MachineInstr *Insert,
313
335
const WebAssemblyFunctionInfo &MFI,
314
- const MachineRegisterInfo &MRI) {
336
+ const MachineRegisterInfo &MRI, bool Optimize ) {
315
337
const MachineInstr *DefI = Def->getParent ();
316
338
const MachineInstr *UseI = Use->getParent ();
317
339
assert (DefI->getParent () == Insert->getParent ());
@@ -357,6 +379,12 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use,
357
379
if (NextI == Insert)
358
380
return true ;
359
381
382
+ // When not optimizing, we only handle the trivial case above
383
+ // to guarantee no impact to debugging and to avoid spending
384
+ // compile time.
385
+ if (!Optimize)
386
+ return false ;
387
+
360
388
// 'catch' and 'catch_all' should be the first instruction of a BB and cannot
361
389
// move.
362
390
if (WebAssembly::isCatch (DefI->getOpcode ()))
@@ -520,14 +548,15 @@ static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) {
520
548
// / dependencies; move the def down and nest it with the current instruction.
521
549
static MachineInstr *moveForSingleUse (unsigned Reg, MachineOperand &Op,
522
550
MachineInstr *Def, MachineBasicBlock &MBB,
523
- MachineInstr *Insert, LiveIntervals & LIS,
551
+ MachineInstr *Insert, LiveIntervals * LIS,
524
552
WebAssemblyFunctionInfo &MFI,
525
553
MachineRegisterInfo &MRI) {
526
554
LLVM_DEBUG (dbgs () << " Move for single use: " ; Def->dump ());
527
555
528
556
WebAssemblyDebugValueManager DefDIs (Def);
529
557
DefDIs.sink (Insert);
530
- LIS.handleMove (*Def);
558
+ if (LIS != nullptr )
559
+ LIS->handleMove (*Def);
531
560
532
561
if (MRI.hasOneDef (Reg) && MRI.hasOneNonDBGUse (Reg)) {
533
562
// No one else is using this register for anything so we can just stackify
@@ -540,17 +569,18 @@ static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op,
540
569
Op.setReg (NewReg);
541
570
DefDIs.updateReg (NewReg);
542
571
543
- // Tell LiveIntervals about the new register.
544
- LIS.createAndComputeVirtRegInterval (NewReg);
572
+ if (LIS != nullptr ) {
573
+ // Tell LiveIntervals about the new register.
574
+ LIS->createAndComputeVirtRegInterval (NewReg);
545
575
546
- // Tell LiveIntervals about the changes to the old register.
547
- LiveInterval &LI = LIS.getInterval (Reg);
548
- LI.removeSegment (LIS.getInstructionIndex (*Def).getRegSlot (),
549
- LIS.getInstructionIndex (*Op.getParent ()).getRegSlot (),
550
- /* RemoveDeadValNo=*/ true );
576
+ // Tell LiveIntervals about the changes to the old register.
577
+ LiveInterval &LI = LIS->getInterval (Reg);
578
+ LI.removeSegment (LIS->getInstructionIndex (*Def).getRegSlot (),
579
+ LIS->getInstructionIndex (*Op.getParent ()).getRegSlot (),
580
+ /* RemoveDeadValNo=*/ true );
581
+ }
551
582
552
583
MFI.stackifyVReg (MRI, NewReg);
553
-
554
584
LLVM_DEBUG (dbgs () << " - Replaced register: " ; Def->dump ());
555
585
}
556
586
@@ -567,11 +597,12 @@ static MachineInstr *getPrevNonDebugInst(MachineInstr *MI) {
567
597
568
598
// / A trivially cloneable instruction; clone it and nest the new copy with the
569
599
// / current instruction.
570
- static MachineInstr *rematerializeCheapDef (
571
- unsigned Reg, MachineOperand &Op, MachineInstr &Def, MachineBasicBlock &MBB,
572
- MachineBasicBlock::instr_iterator Insert, LiveIntervals &LIS,
573
- WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI,
574
- const WebAssemblyInstrInfo *TII, const WebAssemblyRegisterInfo *TRI) {
600
+ static MachineInstr *
601
+ rematerializeCheapDef (unsigned Reg, MachineOperand &Op, MachineInstr &Def,
602
+ MachineBasicBlock::instr_iterator Insert,
603
+ LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI,
604
+ MachineRegisterInfo &MRI,
605
+ const WebAssemblyInstrInfo *TII) {
575
606
LLVM_DEBUG (dbgs () << " Rematerializing cheap def: " ; Def.dump ());
576
607
LLVM_DEBUG (dbgs () << " - for use in " ; Op.getParent ()->dump ());
577
608
@@ -811,9 +842,12 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
811
842
MachineRegisterInfo &MRI = MF.getRegInfo ();
812
843
WebAssemblyFunctionInfo &MFI = *MF.getInfo <WebAssemblyFunctionInfo>();
813
844
const auto *TII = MF.getSubtarget <WebAssemblySubtarget>().getInstrInfo ();
814
- const auto *TRI = MF.getSubtarget <WebAssemblySubtarget>().getRegisterInfo ();
815
- auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree ();
816
- auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS ();
845
+ MachineDominatorTree *MDT = nullptr ;
846
+ LiveIntervals *LIS = nullptr ;
847
+ if (Optimize) {
848
+ MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree ();
849
+ LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS ();
850
+ }
817
851
818
852
// Walk the instructions from the bottom up. Currently we don't look past
819
853
// block boundaries, and the blocks aren't ordered so the block visitation
@@ -876,23 +910,28 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
876
910
// supports intra-block moves) and it's MachineSink's job to catch all
877
911
// the sinking opportunities anyway.
878
912
bool SameBlock = DefI->getParent () == &MBB;
879
- bool CanMove = SameBlock && isSafeToMove (Def, &Use, Insert, MFI, MRI) &&
913
+ bool CanMove = SameBlock &&
914
+ isSafeToMove (Def, &Use, Insert, MFI, MRI, Optimize) &&
880
915
!TreeWalker.isOnStack (Reg);
881
- if (CanMove && hasOneNonDBGUse (Reg, DefI, MRI, MDT , LIS)) {
916
+ if (CanMove && hasSingleUse (Reg, MRI, MFI, Optimize, DefI , LIS)) {
882
917
Insert = moveForSingleUse (Reg, Use, DefI, MBB, Insert, LIS, MFI, MRI);
883
918
884
919
// If we are removing the frame base reg completely, remove the debug
885
920
// info as well.
886
921
// TODO: Encode this properly as a stackified value.
887
- if (MFI.isFrameBaseVirtual () && MFI.getFrameBaseVreg () == Reg)
922
+ if (MFI.isFrameBaseVirtual () && MFI.getFrameBaseVreg () == Reg) {
923
+ assert (
924
+ Optimize &&
925
+ " Stackifying away frame base in unoptimized code not expected" );
888
926
MFI.clearFrameBaseVreg ();
889
- } else if (shouldRematerialize (*DefI, TII)) {
890
- Insert =
891
- rematerializeCheapDef (Reg, Use, *DefI, MBB, Insert->getIterator (),
892
- LIS, MFI, MRI, TII, TRI);
893
- } else if (CanMove && oneUseDominatesOtherUses (Reg, Use, MBB, MRI, MDT,
894
- LIS, MFI)) {
895
- Insert = moveAndTeeForMultiUse (Reg, Use, DefI, MBB, Insert, LIS, MFI,
927
+ }
928
+ } else if (Optimize && shouldRematerialize (*DefI, TII)) {
929
+ Insert = rematerializeCheapDef (Reg, Use, *DefI, Insert->getIterator (),
930
+ *LIS, MFI, MRI, TII);
931
+ } else if (Optimize && CanMove &&
932
+ oneUseDominatesOtherUses (Reg, Use, MBB, MRI, *MDT, *LIS,
933
+ MFI)) {
934
+ Insert = moveAndTeeForMultiUse (Reg, Use, DefI, MBB, Insert, *LIS, MFI,
896
935
MRI, TII);
897
936
} else {
898
937
// We failed to stackify the operand. If the problem was ordering
@@ -915,7 +954,8 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
915
954
Register DefReg = SubsequentDef->getReg ();
916
955
Register UseReg = SubsequentUse->getReg ();
917
956
// TODO: This single-use restriction could be relaxed by using tees
918
- if (DefReg != UseReg || !MRI.hasOneNonDBGUse (DefReg))
957
+ if (DefReg != UseReg ||
958
+ !hasSingleUse (DefReg, MRI, MFI, Optimize, nullptr , nullptr ))
919
959
break ;
920
960
MFI.stackifyVReg (MRI, DefReg);
921
961
++SubsequentDef;
@@ -926,7 +966,7 @@ bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
926
966
// to a constant 0 so that the def is explicit, and the push/pop
927
967
// correspondence is maintained.
928
968
if (Insert->getOpcode () == TargetOpcode::IMPLICIT_DEF)
929
- convertImplicitDefToConstZero (Insert, MRI, TII, MF, LIS );
969
+ convertImplicitDefToConstZero (Insert, MRI, TII, MF);
930
970
931
971
// We stackified an operand. Add the defining instruction's operands to
932
972
// the worklist stack now to continue to build an ever deeper tree.
0 commit comments