@@ -63,6 +63,7 @@ class AArch64InstructionSelector : public InstructionSelector {
63
63
// cache it here for each run of the selector.
64
64
ProduceNonFlagSettingCondBr =
65
65
!MF.getFunction ().hasFnAttribute (Attribute::SpeculativeLoadHardening);
66
+ processPHIs (MF);
66
67
}
67
68
68
69
private:
@@ -77,6 +78,9 @@ class AArch64InstructionSelector : public InstructionSelector {
77
78
// An early selection function that runs before the selectImpl() call.
78
79
bool earlySelect (MachineInstr &I) const ;
79
80
81
+ // Do some preprocessing of G_PHIs before we begin selection.
82
+ void processPHIs (MachineFunction &MF);
83
+
80
84
bool earlySelectSHL (MachineInstr &I, MachineRegisterInfo &MRI) const ;
81
85
82
86
// / Eliminate same-sized cross-bank copies into stores before selectImpl().
@@ -4755,6 +4759,95 @@ bool AArch64InstructionSelector::isDef32(const MachineInstr &MI) const {
4755
4759
}
4756
4760
}
4757
4761
4762
+
4763
+ // Perform fixups on the given PHI instruction's operands to force them all
4764
+ // to be the same as the destination regbank.
4765
+ static void fixupPHIOpBanks (MachineInstr &MI, MachineRegisterInfo &MRI,
4766
+ const AArch64RegisterBankInfo &RBI) {
4767
+ assert (MI.getOpcode () == TargetOpcode::G_PHI && " Expected a G_PHI" );
4768
+ Register DstReg = MI.getOperand (0 ).getReg ();
4769
+ const RegisterBank *DstRB = MRI.getRegBankOrNull (DstReg);
4770
+ assert (DstRB && " Expected PHI dst to have regbank assigned" );
4771
+ MachineIRBuilder MIB (MI);
4772
+
4773
+ // Go through each operand and ensure it has the same regbank.
4774
+ for (unsigned OpIdx = 1 ; OpIdx < MI.getNumOperands (); ++OpIdx) {
4775
+ MachineOperand &MO = MI.getOperand (OpIdx);
4776
+ if (!MO.isReg ())
4777
+ continue ;
4778
+ Register OpReg = MO.getReg ();
4779
+ const RegisterBank *RB = MRI.getRegBankOrNull (OpReg);
4780
+ if (RB != DstRB) {
4781
+ // Insert a cross-bank copy.
4782
+ auto *OpDef = MRI.getVRegDef (OpReg);
4783
+ const LLT &Ty = MRI.getType (OpReg);
4784
+ MIB.setInsertPt (*OpDef->getParent (), std::next (OpDef->getIterator ()));
4785
+ auto Copy = MIB.buildCopy (Ty, OpReg);
4786
+ MRI.setRegBank (Copy.getReg (0 ), *DstRB);
4787
+ MO.setReg (Copy.getReg (0 ));
4788
+ }
4789
+ }
4790
+ }
4791
+
4792
+ void AArch64InstructionSelector::processPHIs (MachineFunction &MF) {
4793
+ // We're looking for PHIs, build a list so we don't invalidate iterators.
4794
+ MachineRegisterInfo &MRI = MF.getRegInfo ();
4795
+ SmallVector<MachineInstr *, 32 > Phis;
4796
+ for (auto &BB : MF) {
4797
+ for (auto &MI : BB) {
4798
+ if (MI.getOpcode () == TargetOpcode::G_PHI)
4799
+ Phis.emplace_back (&MI);
4800
+ }
4801
+ }
4802
+
4803
+ for (auto *MI : Phis) {
4804
+ // We need to do some work here if the operand types are < 16 bit and they
4805
+ // are split across fpr/gpr banks. Since all types <32b on gpr
4806
+ // end up being assigned gpr32 regclasses, we can end up with PHIs here
4807
+ // which try to select between a gpr32 and an fpr16. Ideally RBS shouldn't
4808
+ // be selecting heterogenous regbanks for operands if possible, but we
4809
+ // still need to be able to deal with it here.
4810
+ //
4811
+ // To fix this, if we have a gpr-bank operand < 32b in size and at least
4812
+ // one other operand is on the fpr bank, then we add cross-bank copies
4813
+ // to homogenize the operand banks. For simplicity the bank that we choose
4814
+ // to settle on is whatever bank the def operand has. For example:
4815
+ //
4816
+ // %endbb:
4817
+ // %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2:fpr(s16), %bb2
4818
+ // =>
4819
+ // %bb2:
4820
+ // ...
4821
+ // %in2_copy:gpr(s16) = COPY %in2:fpr(s16)
4822
+ // ...
4823
+ // %endbb:
4824
+ // %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2_copy:gpr(s16), %bb2
4825
+ bool HasGPROp = false , HasFPROp = false ;
4826
+ for (unsigned OpIdx = 1 ; OpIdx < MI->getNumOperands (); ++OpIdx) {
4827
+ const auto &MO = MI->getOperand (OpIdx);
4828
+ if (!MO.isReg ())
4829
+ continue ;
4830
+ const LLT &Ty = MRI.getType (MO.getReg ());
4831
+ if (!Ty.isValid () || !Ty.isScalar ())
4832
+ break ;
4833
+ if (Ty.getSizeInBits () >= 32 )
4834
+ break ;
4835
+ const RegisterBank *RB = MRI.getRegBankOrNull (MO.getReg ());
4836
+ // If for some reason we don't have a regbank yet. Don't try anything.
4837
+ if (!RB)
4838
+ break ;
4839
+
4840
+ if (RB->getID () == AArch64::GPRRegBankID)
4841
+ HasGPROp = true ;
4842
+ else
4843
+ HasFPROp = true ;
4844
+ }
4845
+ // We have heterogenous regbanks, need to fixup.
4846
+ if (HasGPROp && HasFPROp)
4847
+ fixupPHIOpBanks (*MI, MRI, RBI);
4848
+ }
4849
+ }
4850
+
4758
4851
namespace llvm {
4759
4852
InstructionSelector *
4760
4853
createAArch64InstructionSelector (const AArch64TargetMachine &TM,
0 commit comments