@@ -2172,10 +2172,10 @@ namespace {
2172
2172
unsigned &NewOpc, Register &EvenReg, Register &OddReg,
2173
2173
Register &BaseReg, int &Offset, Register &PredReg,
2174
2174
ARMCC::CondCodes &Pred, bool &isT2);
2175
- bool RescheduleOps (MachineBasicBlock *MBB,
2176
- SmallVectorImpl<MachineInstr *> &Ops,
2177
- unsigned Base, bool isLd,
2178
- DenseMap <MachineInstr*, unsigned > &MI2LocMap );
2175
+ bool RescheduleOps (
2176
+ MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops,
2177
+ unsigned Base, bool isLd, DenseMap<MachineInstr *, unsigned > &MI2LocMap ,
2178
+ SmallDenseMap<Register, SmallVector <MachineInstr *>, 8 > &RegisterMap );
2179
2179
bool RescheduleLoadStoreInstrs (MachineBasicBlock *MBB);
2180
2180
bool DistributeIncrements ();
2181
2181
bool DistributeIncrements (Register Base);
@@ -2324,10 +2324,10 @@ bool ARMPreAllocLoadStoreOpt::CanFormLdStDWord(
2324
2324
return true ;
2325
2325
}
2326
2326
2327
- bool ARMPreAllocLoadStoreOpt::RescheduleOps (MachineBasicBlock *MBB,
2328
- SmallVectorImpl<MachineInstr *> &Ops,
2329
- unsigned Base, bool isLd ,
2330
- DenseMap <MachineInstr*, unsigned > &MI2LocMap ) {
2327
+ bool ARMPreAllocLoadStoreOpt::RescheduleOps (
2328
+ MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops, unsigned Base ,
2329
+ bool isLd, DenseMap<MachineInstr *, unsigned > &MI2LocMap ,
2330
+ SmallDenseMap<Register, SmallVector <MachineInstr *>, 8 > &RegisterMap ) {
2331
2331
bool RetVal = false ;
2332
2332
2333
2333
// Sort by offset (in reverse order).
@@ -2476,6 +2476,12 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
2476
2476
} else {
2477
2477
for (unsigned i = 0 ; i != NumMove; ++i) {
2478
2478
MachineInstr *Op = Ops.pop_back_val ();
2479
+ if (isLd) {
2480
+ // Populate RegisterMap with all Registers defined by loads.
2481
+ Register Reg = Op->getOperand (0 ).getReg ();
2482
+ RegisterMap[Reg];
2483
+ }
2484
+
2479
2485
MBB->splice (InsertPos, MBB, Op);
2480
2486
}
2481
2487
}
@@ -2489,6 +2495,44 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
2489
2495
return RetVal;
2490
2496
}
2491
2497
2498
+ static void forEachDbgRegOperand (MachineInstr *MI,
2499
+ std::function<void (MachineOperand &)> Fn) {
2500
+ if (MI->isNonListDebugValue ()) {
2501
+ auto &Op = MI->getOperand (0 );
2502
+ if (Op.isReg ())
2503
+ Fn (Op);
2504
+ } else {
2505
+ for (unsigned I = 2 ; I < MI->getNumOperands (); I++) {
2506
+ auto &Op = MI->getOperand (I);
2507
+ if (Op.isReg ())
2508
+ Fn (Op);
2509
+ }
2510
+ }
2511
+ }
2512
+
2513
+ // Update the RegisterMap with the instruction that was moved because a
2514
+ // DBG_VALUE_LIST may need to be moved again.
2515
+ static void updateRegisterMapForDbgValueListAfterMove (
2516
+ SmallDenseMap<Register, SmallVector<MachineInstr *>, 8 > &RegisterMap,
2517
+ MachineInstr *DbgValueListInstr, MachineInstr *InstrToReplace) {
2518
+
2519
+ forEachDbgRegOperand (DbgValueListInstr, [&](MachineOperand &Op) {
2520
+ auto RegIt = RegisterMap.find (Op.getReg ());
2521
+ if (RegIt == RegisterMap.end ())
2522
+ return ;
2523
+ auto &InstrVec = RegIt->getSecond ();
2524
+ for (unsigned I = 0 ; I < InstrVec.size (); I++)
2525
+ if (InstrVec[I] == InstrToReplace)
2526
+ InstrVec[I] = DbgValueListInstr;
2527
+ });
2528
+ }
2529
+
2530
+ static DebugVariable createDebugVariableFromMachineInstr (MachineInstr *MI) {
2531
+ auto DbgVar = DebugVariable (MI->getDebugVariable (), MI->getDebugExpression (),
2532
+ MI->getDebugLoc ()->getInlinedAt ());
2533
+ return DbgVar;
2534
+ }
2535
+
2492
2536
bool
2493
2537
ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs (MachineBasicBlock *MBB) {
2494
2538
bool RetVal = false ;
@@ -2501,6 +2545,10 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
2501
2545
Base2InstMap Base2StsMap;
2502
2546
BaseVec LdBases;
2503
2547
BaseVec StBases;
2548
+ // This map is used to track the relationship between the virtual
2549
+ // register that is the result of a load that is moved and the DBG_VALUE
2550
+ // MachineInstr pointer that uses that virtual register.
2551
+ SmallDenseMap<Register, SmallVector<MachineInstr *>, 8 > RegisterMap;
2504
2552
2505
2553
unsigned Loc = 0 ;
2506
2554
MachineBasicBlock::iterator MBBI = MBB->begin ();
@@ -2563,15 +2611,15 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
2563
2611
unsigned Base = LdBases[i];
2564
2612
SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[Base];
2565
2613
if (Lds.size () > 1 )
2566
- RetVal |= RescheduleOps (MBB, Lds, Base, true , MI2LocMap);
2614
+ RetVal |= RescheduleOps (MBB, Lds, Base, true , MI2LocMap, RegisterMap );
2567
2615
}
2568
2616
2569
2617
// Re-schedule stores.
2570
2618
for (unsigned i = 0 , e = StBases.size (); i != e; ++i) {
2571
2619
unsigned Base = StBases[i];
2572
2620
SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[Base];
2573
2621
if (Sts.size () > 1 )
2574
- RetVal |= RescheduleOps (MBB, Sts, Base, false , MI2LocMap);
2622
+ RetVal |= RescheduleOps (MBB, Sts, Base, false , MI2LocMap, RegisterMap );
2575
2623
}
2576
2624
2577
2625
if (MBBI != E) {
@@ -2582,6 +2630,257 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
2582
2630
}
2583
2631
}
2584
2632
2633
+ // Reschedule DBG_VALUEs to match any loads that were moved. When a load is
2634
+ // sunk beyond a DBG_VALUE that is referring to it, the DBG_VALUE becomes a
2635
+ // use-before-def, resulting in a loss of debug info.
2636
+
2637
+ // Example:
2638
+ // Before the Pre Register Allocation Load Store Pass
2639
+ // inst_a
2640
+ // %2 = ld ...
2641
+ // inst_b
2642
+ // DBG_VALUE %2, "x", ...
2643
+ // %3 = ld ...
2644
+
2645
+ // After the Pass:
2646
+ // inst_a
2647
+ // inst_b
2648
+ // DBG_VALUE %2, "x", ...
2649
+ // %2 = ld ...
2650
+ // %3 = ld ...
2651
+
2652
+ // The code below addresses this by moving the DBG_VALUE to the position
2653
+ // immediately after the load.
2654
+
2655
+ // Example:
2656
+ // After the code below:
2657
+ // inst_a
2658
+ // inst_b
2659
+ // %2 = ld ...
2660
+ // DBG_VALUE %2, "x", ...
2661
+ // %3 = ld ...
2662
+
2663
+ // The algorithm works in two phases: First RescheduleOps() populates the
2664
+ // RegisterMap with registers that were moved as keys, there is no value
2665
+ // inserted. In the next phase, every MachineInstr in a basic block is
2666
+ // iterated over. If it is a valid DBG_VALUE or DBG_VALUE_LIST and it uses one
2667
+ // or more registers in the RegisterMap, the RegisterMap and InstrMap are
2668
+ // populated with the MachineInstr. If the DBG_VALUE or DBG_VALUE_LIST
2669
+ // describes debug information for a variable that already exists in the
2670
+ // DbgValueSinkCandidates, the MachineInstr in the DbgValueSinkCandidates must
2671
+ // be set to undef. If the current MachineInstr is a load that was moved,
2672
+ // undef the corresponding DBG_VALUE or DBG_VALUE_LIST and clone it to below
2673
+ // the load.
2674
+
2675
+ // To illustrate the above algorithm visually let's take this example.
2676
+
2677
+ // Before the Pre Register Allocation Load Store Pass:
2678
+ // %2 = ld ...
2679
+ // DBG_VALUE %2, A, .... # X
2680
+ // DBG_VALUE 0, A, ... # Y
2681
+ // %3 = ld ...
2682
+ // DBG_VALUE %3, A, ..., # Z
2683
+ // %4 = ld ...
2684
+
2685
+ // After Pre Register Allocation Load Store Pass:
2686
+ // DBG_VALUE %2, A, .... # X
2687
+ // DBG_VALUE 0, A, ... # Y
2688
+ // DBG_VALUE %3, A, ..., # Z
2689
+ // %2 = ld ...
2690
+ // %3 = ld ...
2691
+ // %4 = ld ...
2692
+
2693
+ // The algorithm below does the following:
2694
+
2695
+ // In the beginning, the RegisterMap will have been populated with the virtual
2696
+ // registers %2, and %3, the DbgValueSinkCandidates and the InstrMap will be
2697
+ // empty. DbgValueSinkCandidates = {}, RegisterMap = {2 -> {}, 3 -> {}},
2698
+ // InstrMap {}
2699
+ // -> DBG_VALUE %2, A, .... # X
2700
+ // DBG_VALUE 0, A, ... # Y
2701
+ // DBG_VALUE %3, A, ..., # Z
2702
+ // %2 = ld ...
2703
+ // %3 = ld ...
2704
+ // %4 = ld ...
2705
+
2706
+ // After the first DBG_VALUE (denoted with an X) is processed, the
2707
+ // DbgValueSinkCandidates and InstrMap will be populated and the RegisterMap
2708
+ // entry for %2 will be populated as well. DbgValueSinkCandidates = {A -> X},
2709
+ // RegisterMap = {2 -> {X}, 3 -> {}}, InstrMap {X -> 2}
2710
+ // DBG_VALUE %2, A, .... # X
2711
+ // -> DBG_VALUE 0, A, ... # Y
2712
+ // DBG_VALUE %3, A, ..., # Z
2713
+ // %2 = ld ...
2714
+ // %3 = ld ...
2715
+ // %4 = ld ...
2716
+
2717
+ // After the DBG_VALUE Y is processed, the DbgValueSinkCandidates is updated
2718
+ // to now hold Y for A and the RegisterMap is also updated to remove X from
2719
+ // %2, this is because both X and Y describe the same debug variable A. X is
2720
+ // also updated to have a $noreg as the first operand.
2721
+ // DbgValueSinkCandidates = {A -> {Y}}, RegisterMap = {2 -> {}, 3 -> {}},
2722
+ // InstrMap = {X-> 2}
2723
+ // DBG_VALUE $noreg, A, .... # X
2724
+ // DBG_VALUE 0, A, ... # Y
2725
+ // -> DBG_VALUE %3, A, ..., # Z
2726
+ // %2 = ld ...
2727
+ // %3 = ld ...
2728
+ // %4 = ld ...
2729
+
2730
+ // After DBG_VALUE Z is processed, the DbgValueSinkCandidates is updated to
2731
+ // hold Z fr A, the RegisterMap is updated to hold Z for %3, and the InstrMap
2732
+ // is updated to have Z mapped to %3. This is again because Z describes the
2733
+ // debug variable A, Y is not updated to have $noreg as first operand because
2734
+ // its first operand is an immediate, not a register.
2735
+ // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2736
+ // InstrMap = {X -> 2, Z -> 3}
2737
+ // DBG_VALUE $noreg, A, .... # X
2738
+ // DBG_VALUE 0, A, ... # Y
2739
+ // DBG_VALUE %3, A, ..., # Z
2740
+ // -> %2 = ld ...
2741
+ // %3 = ld ...
2742
+ // %4 = ld ...
2743
+
2744
+ // Nothing happens here since the RegisterMap for %2 contains no value.
2745
+ // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2746
+ // InstrMap = {X -> 2, Z -> 3}
2747
+ // DBG_VALUE $noreg, A, .... # X
2748
+ // DBG_VALUE 0, A, ... # Y
2749
+ // DBG_VALUE %3, A, ..., # Z
2750
+ // %2 = ld ...
2751
+ // -> %3 = ld ...
2752
+ // %4 = ld ...
2753
+
2754
+ // Since the RegisterMap contains Z as a value for %3, the MachineInstr
2755
+ // pointer Z is copied to come after the load for %3 and the old Z's first
2756
+ // operand is changed to $noreg the Basic Block iterator is moved to after the
2757
+ // DBG_VALUE Z's new position.
2758
+ // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2759
+ // InstrMap = {X -> 2, Z -> 3}
2760
+ // DBG_VALUE $noreg, A, .... # X
2761
+ // DBG_VALUE 0, A, ... # Y
2762
+ // DBG_VALUE $noreg, A, ..., # Old Z
2763
+ // %2 = ld ...
2764
+ // %3 = ld ...
2765
+ // DBG_VALUE %3, A, ..., # Z
2766
+ // -> %4 = ld ...
2767
+
2768
+ // Nothing happens for %4 and the algorithm exits having processed the entire
2769
+ // Basic Block.
2770
+ // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2771
+ // InstrMap = {X -> 2, Z -> 3}
2772
+ // DBG_VALUE $noreg, A, .... # X
2773
+ // DBG_VALUE 0, A, ... # Y
2774
+ // DBG_VALUE $noreg, A, ..., # Old Z
2775
+ // %2 = ld ...
2776
+ // %3 = ld ...
2777
+ // DBG_VALUE %3, A, ..., # Z
2778
+ // %4 = ld ...
2779
+
2780
+ // This map is used to track the relationship between
2781
+ // a Debug Variable and the DBG_VALUE MachineInstr pointer that describes the
2782
+ // debug information for that Debug Variable.
2783
+ SmallDenseMap<DebugVariable, MachineInstr *, 8 > DbgValueSinkCandidates;
2784
+ // This map is used to track the relationship between a DBG_VALUE or
2785
+ // DBG_VALUE_LIST MachineInstr pointer and Registers that it uses.
2786
+ SmallDenseMap<MachineInstr *, SmallVector<Register>, 8 > InstrMap;
2787
+ for (MBBI = MBB->begin (), E = MBB->end (); MBBI != E; ++MBBI) {
2788
+ MachineInstr &MI = *MBBI;
2789
+
2790
+ auto PopulateRegisterAndInstrMapForDebugInstr = [&](Register Reg) {
2791
+ auto RegIt = RegisterMap.find (Reg);
2792
+ if (RegIt == RegisterMap.end ())
2793
+ return ;
2794
+ auto &InstrVec = RegIt->getSecond ();
2795
+ InstrVec.push_back (&MI);
2796
+ InstrMap[&MI].push_back (Reg);
2797
+ };
2798
+
2799
+ if (MI.isDebugValue ()) {
2800
+ auto *DILocalVar = MI.getDebugVariable ();
2801
+ // TODO: This should not happen, have to fix the MIR verifier to check for
2802
+ // such instances and fix them.
2803
+ if (!DILocalVar)
2804
+ continue ;
2805
+ auto DbgVar = createDebugVariableFromMachineInstr (&MI);
2806
+ // If the first operand is a register and it exists in the RegisterMap, we
2807
+ // know this is a DBG_VALUE that uses the result of a load that was moved,
2808
+ // and is therefore a candidate to also be moved, add it to the
2809
+ // RegisterMap and InstrMap.
2810
+ forEachDbgRegOperand (&MI, [&](MachineOperand &Op) {
2811
+ PopulateRegisterAndInstrMapForDebugInstr (Op.getReg ());
2812
+ });
2813
+
2814
+ // If the current DBG_VALUE describes the same variable as one of the
2815
+ // in-flight DBG_VALUEs, remove the candidate from the list and set it to
2816
+ // undef. Moving one DBG_VALUE past another would result in the variable's
2817
+ // value going back in time when stepping through the block in the
2818
+ // debugger.
2819
+ auto InstrIt = DbgValueSinkCandidates.find (DbgVar);
2820
+ if (InstrIt != DbgValueSinkCandidates.end ()) {
2821
+ auto *Instr = InstrIt->getSecond ();
2822
+ auto RegIt = InstrMap.find (Instr);
2823
+ if (RegIt != InstrMap.end ()) {
2824
+ const auto &RegVec = RegIt->getSecond ();
2825
+ // For every Register in the RegVec, remove the MachineInstr in the
2826
+ // RegisterMap that describes the DbgVar.
2827
+ for (auto &Reg : RegVec) {
2828
+ auto RegIt = RegisterMap.find (Reg);
2829
+ if (RegIt == RegisterMap.end ())
2830
+ continue ;
2831
+ auto &InstrVec = RegIt->getSecond ();
2832
+ auto IsDbgVar = [&](MachineInstr *I) -> bool {
2833
+ auto Var = createDebugVariableFromMachineInstr (I);
2834
+ return Var == DbgVar;
2835
+ };
2836
+
2837
+ InstrVec.erase (
2838
+ std::remove_if (InstrVec.begin (), InstrVec.end (), IsDbgVar),
2839
+ InstrVec.end ());
2840
+ }
2841
+ forEachDbgRegOperand (Instr,
2842
+ [&](MachineOperand &Op) { Op.setReg (0 ); });
2843
+ }
2844
+ }
2845
+ DbgValueSinkCandidates[DbgVar] = &MI;
2846
+ } else {
2847
+ // If the first operand of a load matches with a DBG_VALUE in RegisterMap,
2848
+ // then move that DBG_VALUE to below the load.
2849
+ auto Opc = MI.getOpcode ();
2850
+ if (!isLoadSingle (Opc))
2851
+ continue ;
2852
+ auto Reg = MI.getOperand (0 ).getReg ();
2853
+ auto RegIt = RegisterMap.find (Reg);
2854
+ if (RegIt == RegisterMap.end ())
2855
+ continue ;
2856
+ auto &DbgInstrVec = RegIt->getSecond ();
2857
+ if (!DbgInstrVec.size ())
2858
+ continue ;
2859
+ for (auto *DbgInstr : DbgInstrVec) {
2860
+ MachineBasicBlock::iterator InsertPos = std::next (MBBI);
2861
+ auto *ClonedMI = MI.getMF ()->CloneMachineInstr (DbgInstr);
2862
+ MBB->insert (InsertPos, ClonedMI);
2863
+ MBBI++;
2864
+ // Erase the entry into the DbgValueSinkCandidates for the DBG_VALUE
2865
+ // that was moved.
2866
+ auto DbgVar = createDebugVariableFromMachineInstr (DbgInstr);
2867
+ auto DbgIt = DbgValueSinkCandidates.find (DbgVar);
2868
+ // If the instruction is a DBG_VALUE_LIST, it may have already been
2869
+ // erased from the DbgValueSinkCandidates. Only erase if it exists in
2870
+ // the DbgValueSinkCandidates.
2871
+ if (DbgIt != DbgValueSinkCandidates.end ())
2872
+ DbgValueSinkCandidates.erase (DbgIt);
2873
+ // Zero out original dbg instr
2874
+ forEachDbgRegOperand (DbgInstr,
2875
+ [&](MachineOperand &Op) { Op.setReg (0 ); });
2876
+ // Update RegisterMap with ClonedMI because it might have to be moved
2877
+ // again.
2878
+ if (DbgInstr->isDebugValueList ())
2879
+ updateRegisterMapForDbgValueListAfterMove (RegisterMap, ClonedMI,
2880
+ DbgInstr);
2881
+ }
2882
+ }
2883
+ }
2585
2884
return RetVal;
2586
2885
}
2587
2886
0 commit comments