//===-- LVLGen.cpp - LVL instruction generator ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "VE.h" #include "VESubtarget.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; #define DEBUG_TYPE "lvl-gen" namespace { struct LVLGen : public MachineFunctionPass { const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; static char ID; LVLGen() : MachineFunctionPass(ID) {} bool runOnMachineBasicBlock(MachineBasicBlock &MBB); bool runOnMachineFunction(MachineFunction &F) override; unsigned getVL(const MachineInstr &MI); int getVLIndex(unsigned Opcode); }; char LVLGen::ID = 0; } // end of anonymous namespace FunctionPass *llvm::createLVLGenPass() { return new LVLGen; } int LVLGen::getVLIndex(unsigned Opcode) { const MCInstrDesc &MCID = TII->get(Opcode); // If an instruction has VLIndex information, return it. if (HAS_VLINDEX(MCID.TSFlags)) return GET_VLINDEX(MCID.TSFlags); return -1; } // returns a register holding a vector length. NoRegister is returned when // this MI does not have a vector length. unsigned LVLGen::getVL(const MachineInstr &MI) { int Index = getVLIndex(MI.getOpcode()); if (Index >= 0) return MI.getOperand(Index).getReg(); return VE::NoRegister; } bool LVLGen::runOnMachineBasicBlock(MachineBasicBlock &MBB) { #define RegName(no) \ (MBB.getParent()->getSubtarget().getRegisterInfo()->getName(no)) bool Changed = false; bool HasRegForVL = false; unsigned RegForVL; for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end();) { MachineBasicBlock::iterator MI = I; // Check whether MI uses a vector length operand. If so, we prepare for VL // register. We would like to reuse VL register as much as possible. We // also would like to keep the number of LEA instructions as fewer as // possible. Therefore, we use a regular scalar register to hold immediate // values to load VL register. And try to reuse identical scalar registers // to avoid new LVLr instructions as much as possible. unsigned Reg = getVL(*MI); if (Reg != VE::NoRegister) { LLVM_DEBUG(dbgs() << "Vector instruction found: "); LLVM_DEBUG(MI->dump()); LLVM_DEBUG(dbgs() << "Vector length is " << RegName(Reg) << ". "); LLVM_DEBUG(dbgs() << "Current VL is " << (HasRegForVL ? RegName(RegForVL) : "unknown") << ". "); if (!HasRegForVL || RegForVL != Reg) { // Use VL, but a different value in a different scalar register. // So, generate new LVL instruction just before the current instruction. LLVM_DEBUG(dbgs() << "Generate a LVL instruction to load " << RegName(Reg) << ".\n"); BuildMI(MBB, I, MI->getDebugLoc(), TII->get(VE::LVLr)).addReg(Reg); HasRegForVL = true; RegForVL = Reg; Changed = true; } else { LLVM_DEBUG(dbgs() << "Reuse current VL.\n"); } } // Check the update of a given scalar register holding an immediate value // for VL register. Also, a call doesn't preserve VL register. if (HasRegForVL) { if (MI->definesRegister(RegForVL, TRI) || MI->modifiesRegister(RegForVL, TRI) || MI->killsRegister(RegForVL, TRI) || MI->isCall()) { // The latest VL is needed to be updated, so disable HasRegForVL. LLVM_DEBUG(dbgs() << RegName(RegForVL) << " is needed to be updated: "); LLVM_DEBUG(MI->dump()); HasRegForVL = false; } } ++I; } return Changed; } bool LVLGen::runOnMachineFunction(MachineFunction &F) { LLVM_DEBUG(dbgs() << "********** Begin LVLGen **********\n"); LLVM_DEBUG(dbgs() << "********** Function: " << F.getName() << '\n'); LLVM_DEBUG(F.dump()); bool Changed = false; const VESubtarget &Subtarget = F.getSubtarget(); TII = Subtarget.getInstrInfo(); TRI = Subtarget.getRegisterInfo(); for (MachineBasicBlock &MBB : F) Changed |= runOnMachineBasicBlock(MBB); if (Changed) { LLVM_DEBUG(dbgs() << "\n"); LLVM_DEBUG(F.dump()); } LLVM_DEBUG(dbgs() << "********** End LVLGen **********\n"); return Changed; }