//===-- HexagonExpandPredSpillCode.cpp - Expand Predicate Spill Code ------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // The Hexagon processor has no instructions that load or store predicate // registers directly. So, when these registers must be spilled a general // purpose register must be found and the value copied to/from it from/to // the predicate register. This code currently does not use the register // scavenger mechanism available in the allocator. There are two registers // reserved to allow spilling/restoring predicate registers. One is used to // hold the predicate value. The other is used when stack frame offsets are // too large. // //===----------------------------------------------------------------------===// #include "Hexagon.h" #include "HexagonMachineFunctionInfo.h" #include "HexagonSubtarget.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/LatencyPriorityQueue.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/ScheduleHazardRecognizer.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; namespace llvm { void initializeHexagonExpandPredSpillCodePass(PassRegistry&); } namespace { class HexagonExpandPredSpillCode : public MachineFunctionPass { public: static char ID; HexagonExpandPredSpillCode() : MachineFunctionPass(ID) { PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeHexagonExpandPredSpillCodePass(Registry); } const char *getPassName() const override { return "Hexagon Expand Predicate Spill Code"; } bool runOnMachineFunction(MachineFunction &Fn) override; }; char HexagonExpandPredSpillCode::ID = 0; bool HexagonExpandPredSpillCode::runOnMachineFunction(MachineFunction &Fn) { const HexagonSubtarget &QST = Fn.getSubtarget<HexagonSubtarget>(); const HexagonInstrInfo *TII = QST.getInstrInfo(); // Loop over all of the basic blocks. for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end(); MBBb != MBBe; ++MBBb) { MachineBasicBlock* MBB = MBBb; // Traverse the basic block. for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end(); ++MII) { MachineInstr *MI = MII; int Opc = MI->getOpcode(); if (Opc == Hexagon::S2_storerb_pci_pseudo || Opc == Hexagon::S2_storerh_pci_pseudo || Opc == Hexagon::S2_storeri_pci_pseudo || Opc == Hexagon::S2_storerd_pci_pseudo || Opc == Hexagon::S2_storerf_pci_pseudo) { unsigned Opcode; if (Opc == Hexagon::S2_storerd_pci_pseudo) Opcode = Hexagon::S2_storerd_pci; else if (Opc == Hexagon::S2_storeri_pci_pseudo) Opcode = Hexagon::S2_storeri_pci; else if (Opc == Hexagon::S2_storerh_pci_pseudo) Opcode = Hexagon::S2_storerh_pci; else if (Opc == Hexagon::S2_storerf_pci_pseudo) Opcode = Hexagon::S2_storerf_pci; else if (Opc == Hexagon::S2_storerb_pci_pseudo) Opcode = Hexagon::S2_storerb_pci; else llvm_unreachable("wrong Opc"); MachineOperand &Op0 = MI->getOperand(0); MachineOperand &Op1 = MI->getOperand(1); MachineOperand &Op2 = MI->getOperand(2); MachineOperand &Op3 = MI->getOperand(3); // Modifier value. MachineOperand &Op4 = MI->getOperand(4); // Emit a "C6 = Rn, C6 is the control register for M0". BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr), Hexagon::C6)->addOperand(Op3); // Replace the pseude circ_ldd by the real circ_ldd. MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Opcode)); NewMI->addOperand(Op0); NewMI->addOperand(Op1); NewMI->addOperand(Op4); NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0, false, /*isDef*/ false, /*isImpl*/ true /*isKill*/)); NewMI->addOperand(Op2); MII = MBB->erase(MI); --MII; } else if (Opc == Hexagon::L2_loadrd_pci_pseudo || Opc == Hexagon::L2_loadri_pci_pseudo || Opc == Hexagon::L2_loadrh_pci_pseudo || Opc == Hexagon::L2_loadruh_pci_pseudo|| Opc == Hexagon::L2_loadrb_pci_pseudo || Opc == Hexagon::L2_loadrub_pci_pseudo) { unsigned Opcode; if (Opc == Hexagon::L2_loadrd_pci_pseudo) Opcode = Hexagon::L2_loadrd_pci; else if (Opc == Hexagon::L2_loadri_pci_pseudo) Opcode = Hexagon::L2_loadri_pci; else if (Opc == Hexagon::L2_loadrh_pci_pseudo) Opcode = Hexagon::L2_loadrh_pci; else if (Opc == Hexagon::L2_loadruh_pci_pseudo) Opcode = Hexagon::L2_loadruh_pci; else if (Opc == Hexagon::L2_loadrb_pci_pseudo) Opcode = Hexagon::L2_loadrb_pci; else if (Opc == Hexagon::L2_loadrub_pci_pseudo) Opcode = Hexagon::L2_loadrub_pci; else llvm_unreachable("wrong Opc"); MachineOperand &Op0 = MI->getOperand(0); MachineOperand &Op1 = MI->getOperand(1); MachineOperand &Op2 = MI->getOperand(2); MachineOperand &Op4 = MI->getOperand(4); // Modifier value. MachineOperand &Op5 = MI->getOperand(5); // Emit a "C6 = Rn, C6 is the control register for M0". BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr), Hexagon::C6)->addOperand(Op4); // Replace the pseude circ_ldd by the real circ_ldd. MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Opcode)); NewMI->addOperand(Op1); NewMI->addOperand(Op0); NewMI->addOperand(Op2); NewMI->addOperand(Op5); NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0, false, /*isDef*/ false, /*isImpl*/ true /*isKill*/)); MII = MBB->erase(MI); --MII; } else if (Opc == Hexagon::L2_loadrd_pbr_pseudo || Opc == Hexagon::L2_loadri_pbr_pseudo || Opc == Hexagon::L2_loadrh_pbr_pseudo || Opc == Hexagon::L2_loadruh_pbr_pseudo|| Opc == Hexagon::L2_loadrb_pbr_pseudo || Opc == Hexagon::L2_loadrub_pbr_pseudo) { unsigned Opcode; if (Opc == Hexagon::L2_loadrd_pbr_pseudo) Opcode = Hexagon::L2_loadrd_pbr; else if (Opc == Hexagon::L2_loadri_pbr_pseudo) Opcode = Hexagon::L2_loadri_pbr; else if (Opc == Hexagon::L2_loadrh_pbr_pseudo) Opcode = Hexagon::L2_loadrh_pbr; else if (Opc == Hexagon::L2_loadruh_pbr_pseudo) Opcode = Hexagon::L2_loadruh_pbr; else if (Opc == Hexagon::L2_loadrb_pbr_pseudo) Opcode = Hexagon::L2_loadrb_pbr; else if (Opc == Hexagon::L2_loadrub_pbr_pseudo) Opcode = Hexagon::L2_loadrub_pbr; else llvm_unreachable("wrong Opc"); MachineOperand &Op0 = MI->getOperand(0); MachineOperand &Op1 = MI->getOperand(1); MachineOperand &Op2 = MI->getOperand(2); MachineOperand &Op4 = MI->getOperand(4); // Modifier value. // Emit a "C6 = Rn, C6 is the control register for M0". BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr), Hexagon::C6)->addOperand(Op4); // Replace the pseudo brev_ldd by the real brev_ldd. MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Opcode)); NewMI->addOperand(Op1); NewMI->addOperand(Op0); NewMI->addOperand(Op2); NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0, false, /*isDef*/ false, /*isImpl*/ true /*isKill*/)); MII = MBB->erase(MI); --MII; } else if (Opc == Hexagon::S2_storerd_pbr_pseudo || Opc == Hexagon::S2_storeri_pbr_pseudo || Opc == Hexagon::S2_storerh_pbr_pseudo || Opc == Hexagon::S2_storerb_pbr_pseudo || Opc == Hexagon::S2_storerf_pbr_pseudo) { unsigned Opcode; if (Opc == Hexagon::S2_storerd_pbr_pseudo) Opcode = Hexagon::S2_storerd_pbr; else if (Opc == Hexagon::S2_storeri_pbr_pseudo) Opcode = Hexagon::S2_storeri_pbr; else if (Opc == Hexagon::S2_storerh_pbr_pseudo) Opcode = Hexagon::S2_storerh_pbr; else if (Opc == Hexagon::S2_storerf_pbr_pseudo) Opcode = Hexagon::S2_storerf_pbr; else if (Opc == Hexagon::S2_storerb_pbr_pseudo) Opcode = Hexagon::S2_storerb_pbr; else llvm_unreachable("wrong Opc"); MachineOperand &Op0 = MI->getOperand(0); MachineOperand &Op1 = MI->getOperand(1); MachineOperand &Op2 = MI->getOperand(2); MachineOperand &Op3 = MI->getOperand(3); // Modifier value. // Emit a "C6 = Rn, C6 is the control register for M0". BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_tfrrcr), Hexagon::C6)->addOperand(Op3); // Replace the pseudo brev_ldd by the real brev_ldd. MachineInstr *NewMI = BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Opcode)); NewMI->addOperand(Op0); NewMI->addOperand(Op1); NewMI->addOperand(MachineOperand::CreateReg(Hexagon::M0, false, /*isDef*/ false, /*isImpl*/ true /*isKill*/)); NewMI->addOperand(Op2); MII = MBB->erase(MI); --MII; } else if (Opc == Hexagon::STriw_pred) { // STriw_pred [R30], ofst, SrcReg; unsigned FP = MI->getOperand(0).getReg(); assert(FP == QST.getRegisterInfo()->getFrameRegister() && "Not a Frame Pointer, Nor a Spill Slot"); assert(MI->getOperand(1).isImm() && "Not an offset"); int Offset = MI->getOperand(1).getImm(); int SrcReg = MI->getOperand(2).getReg(); assert(Hexagon::PredRegsRegClass.contains(SrcReg) && "Not a predicate register"); if (!TII->isValidOffset(Hexagon::S2_storeri_io, Offset)) { if (!TII->isValidOffset(Hexagon::A2_addi, Offset)) { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::CONST32_Int_Real), HEXAGON_RESERVED_REG_1).addImm(Offset); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_add), HEXAGON_RESERVED_REG_1) .addReg(FP).addReg(HEXAGON_RESERVED_REG_1); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr), HEXAGON_RESERVED_REG_2).addReg(SrcReg); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::S2_storeri_io)) .addReg(HEXAGON_RESERVED_REG_1) .addImm(0).addReg(HEXAGON_RESERVED_REG_2); } else { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_addi), HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr), HEXAGON_RESERVED_REG_2).addReg(SrcReg); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::S2_storeri_io)) .addReg(HEXAGON_RESERVED_REG_1) .addImm(0) .addReg(HEXAGON_RESERVED_REG_2); } } else { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrpr), HEXAGON_RESERVED_REG_2).addReg(SrcReg); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::S2_storeri_io)). addReg(FP).addImm(Offset).addReg(HEXAGON_RESERVED_REG_2); } MII = MBB->erase(MI); --MII; } else if (Opc == Hexagon::LDriw_pred) { // DstReg = LDriw_pred [R30], ofst. int DstReg = MI->getOperand(0).getReg(); assert(Hexagon::PredRegsRegClass.contains(DstReg) && "Not a predicate register"); unsigned FP = MI->getOperand(1).getReg(); assert(FP == QST.getRegisterInfo()->getFrameRegister() && "Not a Frame Pointer, Nor a Spill Slot"); assert(MI->getOperand(2).isImm() && "Not an offset"); int Offset = MI->getOperand(2).getImm(); if (!TII->isValidOffset(Hexagon::L2_loadri_io, Offset)) { if (!TII->isValidOffset(Hexagon::A2_addi, Offset)) { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::CONST32_Int_Real), HEXAGON_RESERVED_REG_1).addImm(Offset); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_add), HEXAGON_RESERVED_REG_1) .addReg(FP) .addReg(HEXAGON_RESERVED_REG_1); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io), HEXAGON_RESERVED_REG_2) .addReg(HEXAGON_RESERVED_REG_1) .addImm(0); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp), DstReg).addReg(HEXAGON_RESERVED_REG_2); } else { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::A2_addi), HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io), HEXAGON_RESERVED_REG_2) .addReg(HEXAGON_RESERVED_REG_1) .addImm(0); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp), DstReg).addReg(HEXAGON_RESERVED_REG_2); } } else { BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::L2_loadri_io), HEXAGON_RESERVED_REG_2).addReg(FP).addImm(Offset); BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::C2_tfrrp), DstReg).addReg(HEXAGON_RESERVED_REG_2); } MII = MBB->erase(MI); --MII; } } } return true; } } //===----------------------------------------------------------------------===// // Public Constructor Functions //===----------------------------------------------------------------------===// static void initializePassOnce(PassRegistry &Registry) { const char *Name = "Hexagon Expand Predicate Spill Code"; PassInfo *PI = new PassInfo(Name, "hexagon-spill-pred", &HexagonExpandPredSpillCode::ID, nullptr, false, false); Registry.registerPass(*PI, true); } void llvm::initializeHexagonExpandPredSpillCodePass(PassRegistry &Registry) { CALL_ONCE_INITIALIZATION(initializePassOnce) } FunctionPass* llvm::createHexagonExpandPredSpillCode() { return new HexagonExpandPredSpillCode(); }