diff --git a/lib/Target/SystemZ/CMakeLists.txt b/lib/Target/SystemZ/CMakeLists.txt index ab657f648b0..8a4eaa35e92 100644 --- a/lib/Target/SystemZ/CMakeLists.txt +++ b/lib/Target/SystemZ/CMakeLists.txt @@ -24,6 +24,7 @@ add_llvm_target(SystemZCodeGen SystemZMCInstLower.cpp SystemZRegisterInfo.cpp SystemZSelectionDAGInfo.cpp + SystemZShortenInst.cpp SystemZSubtarget.cpp SystemZTargetMachine.cpp ) diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp index 3653192d855..cb97bcaaa11 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -69,6 +69,23 @@ const unsigned SystemZMC::FP128Regs[16] = { SystemZ::F12Q, SystemZ::F13Q, 0, 0 }; +unsigned SystemZMC::getFirstReg(unsigned Reg) { + static unsigned Map[SystemZ::NUM_TARGET_REGS]; + static bool Initialized = false; + if (!Initialized) { + for (unsigned I = 0; I < 16; ++I) { + Map[GR32Regs[I]] = I; + Map[GR64Regs[I]] = I; + Map[GR128Regs[I]] = I; + Map[FP32Regs[I]] = I; + Map[FP64Regs[I]] = I; + Map[FP128Regs[I]] = I; + } + } + assert(Reg < SystemZ::NUM_TARGET_REGS); + return Map[Reg]; +} + static MCAsmInfo *createSystemZMCAsmInfo(const MCRegisterInfo &MRI, StringRef TT) { MCAsmInfo *MAI = new SystemZMCAsmInfo(TT); diff --git a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h index 01ef0939928..84184af6766 100644 --- a/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h +++ b/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h @@ -47,6 +47,15 @@ namespace SystemZMC { extern const unsigned FP32Regs[16]; extern const unsigned FP64Regs[16]; extern const unsigned FP128Regs[16]; + + // Return the 0-based number of the first architectural register that + // contains the given LLVM register. E.g. R1D -> 1. + unsigned getFirstReg(unsigned Reg); + + // Return the given register as a GR64. + inline unsigned getRegAsGR64(unsigned Reg) { + return GR64Regs[getFirstReg(Reg)]; + } } MCCodeEmitter *createSystemZMCCodeEmitter(const MCInstrInfo &MCII, diff --git a/lib/Target/SystemZ/SystemZ.h b/lib/Target/SystemZ/SystemZ.h index 1647d93c02d..4a6b4db9d69 100644 --- a/lib/Target/SystemZ/SystemZ.h +++ b/lib/Target/SystemZ/SystemZ.h @@ -106,6 +106,7 @@ namespace llvm { FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel); FunctionPass *createSystemZElimComparePass(SystemZTargetMachine &TM); + FunctionPass *createSystemZShortenInstPass(SystemZTargetMachine &TM); FunctionPass *createSystemZLongBranchPass(SystemZTargetMachine &TM); } // end namespace llvm; #endif diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index d0284616fb7..ca678ab7559 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1212,14 +1212,6 @@ def : Pat<(ctlz GR64:$src), def : Pat<(i64 (anyext GR32:$src)), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GR32:$src, subreg_32bit)>; -// There are no 32-bit equivalents of LLILL and LLILH, so use a full -// 64-bit move followed by a subreg. This preserves the invariant that -// all GR32 operations only modify the low 32 bits. -def : Pat<(i32 imm32ll16:$src), - (EXTRACT_SUBREG (LLILL (LL16 imm:$src)), subreg_32bit)>; -def : Pat<(i32 imm32lh16:$src), - (EXTRACT_SUBREG (LLILH (LH16 imm:$src)), subreg_32bit)>; - // Extend GR32s and GR64s to GR128s. let usesCustomInserter = 1 in { def AEXT128_64 : Pseudo<(outs GR128:$dst), (ins GR64:$src), []>; diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.h b/lib/Target/SystemZ/SystemZRegisterInfo.h index c447e4d5b84..edd107ddd03 100644 --- a/lib/Target/SystemZ/SystemZRegisterInfo.h +++ b/lib/Target/SystemZ/SystemZRegisterInfo.h @@ -48,6 +48,10 @@ public: LLVM_OVERRIDE { return true; } + virtual bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const + LLVM_OVERRIDE { + return true; + } virtual const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const LLVM_OVERRIDE; virtual BitVector getReservedRegs(const MachineFunction &MF) diff --git a/lib/Target/SystemZ/SystemZShortenInst.cpp b/lib/Target/SystemZ/SystemZShortenInst.cpp new file mode 100644 index 00000000000..526ae5c1e8c --- /dev/null +++ b/lib/Target/SystemZ/SystemZShortenInst.cpp @@ -0,0 +1,159 @@ +//===-- SystemZShortenInst.cpp - Instruction-shortening pass --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass tries to replace instructions with shorter forms. For example, +// IILF can be replaced with LLILL or LLILH if the constant fits and if the +// other 32 bits of the GR64 destination are not live. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "systemz-shorten-inst" + +#include "SystemZTargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +using namespace llvm; + +namespace { + class SystemZShortenInst : public MachineFunctionPass { + public: + static char ID; + SystemZShortenInst(const SystemZTargetMachine &tm); + + virtual const char *getPassName() const { + return "SystemZ Instruction Shortening"; + } + + bool processBlock(MachineBasicBlock *MBB); + bool runOnMachineFunction(MachineFunction &F); + + private: + bool shortenIIF(MachineInstr &MI, unsigned *GPRMap, unsigned LiveOther, + unsigned LLIxL, unsigned LLIxH); + + const SystemZInstrInfo *TII; + + // LowGPRs[I] has bit N set if LLVM register I includes the low + // word of GPR N. HighGPRs is the same for the high word. + unsigned LowGPRs[SystemZ::NUM_TARGET_REGS]; + unsigned HighGPRs[SystemZ::NUM_TARGET_REGS]; + }; + + char SystemZShortenInst::ID = 0; +} // end of anonymous namespace + +FunctionPass *llvm::createSystemZShortenInstPass(SystemZTargetMachine &TM) { + return new SystemZShortenInst(TM); +} + +SystemZShortenInst::SystemZShortenInst(const SystemZTargetMachine &tm) + : MachineFunctionPass(ID), TII(0), LowGPRs(), HighGPRs() { + // Set up LowGPRs and HighGPRs. + for (unsigned I = 0; I < 16; ++I) { + LowGPRs[SystemZMC::GR32Regs[I]] |= 1 << I; + LowGPRs[SystemZMC::GR64Regs[I]] |= 1 << I; + HighGPRs[SystemZMC::GR64Regs[I]] |= 1 << I; + if (unsigned GR128 = SystemZMC::GR128Regs[I]) { + LowGPRs[GR128] |= 3 << I; + HighGPRs[GR128] |= 3 << I; + } + } +} + +// MI loads one word of a GPR using an IIxF instruction and LLIxL and LLIxH +// are the halfword immediate loads for the same word. Try to use one of them +// instead of IIxF. If MI loads the high word, GPRMap[X] is the set of high +// words referenced by LLVM register X while LiveOther is the mask of low +// words that are currently live, and vice versa. +bool SystemZShortenInst::shortenIIF(MachineInstr &MI, unsigned *GPRMap, + unsigned LiveOther, unsigned LLIxL, + unsigned LLIxH) { + unsigned Reg = MI.getOperand(0).getReg(); + assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number"); + unsigned GPRs = GPRMap[Reg]; + assert(GPRs != 0 && "Register must be a GPR"); + if (GPRs & LiveOther) + return false; + + uint64_t Imm = MI.getOperand(1).getImm(); + if (SystemZ::isImmLL(Imm)) { + MI.setDesc(TII->get(LLIxL)); + MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg)); + return true; + } + if (SystemZ::isImmLH(Imm)) { + MI.setDesc(TII->get(LLIxH)); + MI.getOperand(0).setReg(SystemZMC::getRegAsGR64(Reg)); + MI.getOperand(1).setImm(Imm >> 16); + return true; + } + return false; +} + +// Process all instructions in MBB. Return true if something changed. +bool SystemZShortenInst::processBlock(MachineBasicBlock *MBB) { + bool Changed = false; + + // Work out which words are live on exit from the block. + unsigned LiveLow = 0; + unsigned LiveHigh = 0; + for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); SI != SE; ++SI) { + for (MachineBasicBlock::livein_iterator LI = (*SI)->livein_begin(), + LE = (*SI)->livein_end(); LI != LE; ++LI) { + unsigned Reg = *LI; + assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number"); + LiveLow |= LowGPRs[Reg]; + LiveHigh |= HighGPRs[Reg]; + } + } + + // Iterate backwards through the block looking for instructions to change. + for (MachineBasicBlock::reverse_iterator MBBI = MBB->rbegin(), + MBBE = MBB->rend(); MBBI != MBBE; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SystemZ::IILF32) + Changed |= shortenIIF(MI, LowGPRs, LiveHigh, SystemZ::LLILL, + SystemZ::LLILH); + unsigned UsedLow = 0; + unsigned UsedHigh = 0; + for (MachineInstr::mop_iterator MOI = MI.operands_begin(), + MOE = MI.operands_end(); MOI != MOE; ++MOI) { + MachineOperand &MO = *MOI; + if (MO.isReg()) { + if (unsigned Reg = MO.getReg()) { + assert(Reg < SystemZ::NUM_TARGET_REGS && "Invalid register number"); + if (MO.isDef()) { + LiveLow &= ~LowGPRs[Reg]; + LiveHigh &= ~HighGPRs[Reg]; + } else if (!MO.isUndef()) { + UsedLow |= LowGPRs[Reg]; + UsedHigh |= HighGPRs[Reg]; + } + } + } + } + LiveLow |= UsedLow; + LiveHigh |= UsedHigh; + } + + return Changed; +} + +bool SystemZShortenInst::runOnMachineFunction(MachineFunction &F) { + TII = static_cast<const SystemZInstrInfo *>(F.getTarget().getInstrInfo()); + + bool Changed = false; + for (MachineFunction::iterator MFI = F.begin(), MFE = F.end(); + MFI != MFE; ++MFI) + Changed |= processBlock(MFI); + + return Changed; +} diff --git a/lib/Target/SystemZ/SystemZTargetMachine.cpp b/lib/Target/SystemZ/SystemZTargetMachine.cpp index f2761520cdb..dee92e960c5 100644 --- a/lib/Target/SystemZ/SystemZTargetMachine.cpp +++ b/lib/Target/SystemZ/SystemZTargetMachine.cpp @@ -97,6 +97,8 @@ bool SystemZPassConfig::addPreEmitPass() { // preventing that would be a win or not. if (getOptLevel() != CodeGenOpt::None) addPass(createSystemZElimComparePass(getSystemZTargetMachine())); + if (getOptLevel() != CodeGenOpt::None) + addPass(createSystemZShortenInstPass(getSystemZTargetMachine())); addPass(createSystemZLongBranchPass(getSystemZTargetMachine())); return true; }