138 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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<VESubtarget>().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<VESubtarget>();
 | 
						|
  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;
 | 
						|
}
 |