#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/CodeGen/LazyMachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineSizeOpts.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define FIXUPBW_DESC "X86 Byte/Word Instruction Fixup"
#define FIXUPBW_NAME "x86-fixup-bw-insts"
#define DEBUG_TYPE FIXUPBW_NAME
static cl::opt<bool>
FixupBWInsts("fixup-byte-word-insts",
cl::desc("Change byte and word instructions to larger sizes"),
cl::init(true), cl::Hidden);
namespace {
class FixupBWInstPass : public MachineFunctionPass {
void processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB);
bool getSuperRegDestIfDead(MachineInstr *OrigMI,
Register &SuperDestReg) const;
MachineInstr *tryReplaceLoad(unsigned New32BitOpcode, MachineInstr *MI) const;
MachineInstr *tryReplaceCopy(MachineInstr *MI) const;
MachineInstr *tryReplaceExtend(unsigned New32BitOpcode,
MachineInstr *MI) const;
MachineInstr *tryReplaceInstr(MachineInstr *MI, MachineBasicBlock &MBB) const;
public:
static char ID;
StringRef getPassName() const override { return FIXUPBW_DESC; }
FixupBWInstPass() : MachineFunctionPass(ID) { }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineLoopInfo>(); AU.addRequired<ProfileSummaryInfoWrapperPass>();
AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction &MF) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
private:
MachineFunction *MF = nullptr;
const X86InstrInfo *TII = nullptr;
const TargetRegisterInfo *TRI = nullptr;
bool OptForSize = false;
MachineLoopInfo *MLI = nullptr;
LivePhysRegs LiveRegs;
ProfileSummaryInfo *PSI;
MachineBlockFrequencyInfo *MBFI;
};
char FixupBWInstPass::ID = 0;
}
INITIALIZE_PASS(FixupBWInstPass, FIXUPBW_NAME, FIXUPBW_DESC, false, false)
FunctionPass *llvm::createX86FixupBWInsts() { return new FixupBWInstPass(); }
bool FixupBWInstPass::runOnMachineFunction(MachineFunction &MF) {
if (!FixupBWInsts || skipFunction(MF.getFunction()))
return false;
this->MF = &MF;
TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
TRI = MF.getRegInfo().getTargetRegisterInfo();
MLI = &getAnalysis<MachineLoopInfo>();
PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
MBFI = (PSI && PSI->hasProfileSummary()) ?
&getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI() :
nullptr;
LiveRegs.init(TII->getRegisterInfo());
LLVM_DEBUG(dbgs() << "Start X86FixupBWInsts\n";);
for (auto &MBB : MF)
processBasicBlock(MF, MBB);
LLVM_DEBUG(dbgs() << "End X86FixupBWInsts\n";);
return true;
}
bool FixupBWInstPass::getSuperRegDestIfDead(MachineInstr *OrigMI,
Register &SuperDestReg) const {
const X86RegisterInfo *TRI = &TII->getRegisterInfo();
Register OrigDestReg = OrigMI->getOperand(0).getReg();
SuperDestReg = getX86SubSuperRegister(OrigDestReg, 32);
const auto SubRegIdx = TRI->getSubRegIndex(SuperDestReg, OrigDestReg);
if (SubRegIdx == X86::sub_8bit_hi)
return false;
if (!LiveRegs.contains(SuperDestReg)) {
if (SubRegIdx != X86::sub_8bit)
return true;
if (!LiveRegs.contains(getX86SubSuperRegister(OrigDestReg, 16)) &&
!LiveRegs.contains(getX86SubSuperRegister(SuperDestReg, 8,
true)))
return true;
}
unsigned Opc = OrigMI->getOpcode(); (void)Opc;
if (Opc != X86::MOV8rm && Opc != X86::MOV16rm && Opc != X86::MOV8rr &&
Opc != X86::MOV16rr)
return false;
bool IsDefined = false;
for (auto &MO: OrigMI->implicit_operands()) {
if (!MO.isReg())
continue;
assert((MO.isDef() || MO.isUse()) && "Expected Def or Use only!");
if (MO.isDef() && TRI->isSuperRegisterEq(OrigDestReg, MO.getReg()))
IsDefined = true;
if (MO.isUse() && !TRI->isSubRegisterEq(OrigDestReg, MO.getReg()) &&
TRI->regsOverlap(SuperDestReg, MO.getReg()))
return false;
}
if (!IsDefined)
return false;
return true;
}
MachineInstr *FixupBWInstPass::tryReplaceLoad(unsigned New32BitOpcode,
MachineInstr *MI) const {
Register NewDestReg;
if (!getSuperRegDestIfDead(MI, NewDestReg))
return nullptr;
MachineInstrBuilder MIB =
BuildMI(*MF, MI->getDebugLoc(), TII->get(New32BitOpcode), NewDestReg);
unsigned NumArgs = MI->getNumOperands();
for (unsigned i = 1; i < NumArgs; ++i)
MIB.add(MI->getOperand(i));
MIB.setMemRefs(MI->memoperands());
if (unsigned OldInstrNum = MI->peekDebugInstrNum()) {
unsigned Subreg = TRI->getSubRegIndex(MIB->getOperand(0).getReg(),
MI->getOperand(0).getReg());
unsigned NewInstrNum = MIB->getDebugInstrNum(*MF);
MF->makeDebugValueSubstitution({OldInstrNum, 0}, {NewInstrNum, 0}, Subreg);
}
return MIB;
}
MachineInstr *FixupBWInstPass::tryReplaceCopy(MachineInstr *MI) const {
assert(MI->getNumExplicitOperands() == 2);
auto &OldDest = MI->getOperand(0);
auto &OldSrc = MI->getOperand(1);
Register NewDestReg;
if (!getSuperRegDestIfDead(MI, NewDestReg))
return nullptr;
Register NewSrcReg = getX86SubSuperRegister(OldSrc.getReg(), 32);
const X86RegisterInfo *TRI = &TII->getRegisterInfo();
if (TRI->getSubRegIndex(NewSrcReg, OldSrc.getReg()) !=
TRI->getSubRegIndex(NewDestReg, OldDest.getReg()))
return nullptr;
MachineInstrBuilder MIB =
BuildMI(*MF, MI->getDebugLoc(), TII->get(X86::MOV32rr), NewDestReg)
.addReg(NewSrcReg, RegState::Undef)
.addReg(OldSrc.getReg(), RegState::Implicit);
for (auto &Op : MI->implicit_operands())
if (Op.getReg() != (Op.isDef() ? NewDestReg : NewSrcReg))
MIB.add(Op);
return MIB;
}
MachineInstr *FixupBWInstPass::tryReplaceExtend(unsigned New32BitOpcode,
MachineInstr *MI) const {
Register NewDestReg;
if (!getSuperRegDestIfDead(MI, NewDestReg))
return nullptr;
if (MI->getOpcode() == X86::MOVSX16rr8 &&
MI->getOperand(0).getReg() == X86::AX &&
MI->getOperand(1).getReg() == X86::AL)
return nullptr;
MachineInstrBuilder MIB =
BuildMI(*MF, MI->getDebugLoc(), TII->get(New32BitOpcode), NewDestReg);
unsigned NumArgs = MI->getNumOperands();
for (unsigned i = 1; i < NumArgs; ++i)
MIB.add(MI->getOperand(i));
MIB.setMemRefs(MI->memoperands());
if (unsigned OldInstrNum = MI->peekDebugInstrNum()) {
unsigned Subreg = TRI->getSubRegIndex(MIB->getOperand(0).getReg(),
MI->getOperand(0).getReg());
unsigned NewInstrNum = MIB->getDebugInstrNum(*MF);
MF->makeDebugValueSubstitution({OldInstrNum, 0}, {NewInstrNum, 0}, Subreg);
}
return MIB;
}
MachineInstr *FixupBWInstPass::tryReplaceInstr(MachineInstr *MI,
MachineBasicBlock &MBB) const {
switch (MI->getOpcode()) {
case X86::MOV8rm:
if (!OptForSize)
return tryReplaceLoad(X86::MOVZX32rm8, MI);
break;
case X86::MOV16rm:
return tryReplaceLoad(X86::MOVZX32rm16, MI);
case X86::MOV8rr:
case X86::MOV16rr:
return tryReplaceCopy(MI);
case X86::MOVSX16rr8:
return tryReplaceExtend(X86::MOVSX32rr8, MI);
case X86::MOVSX16rm8:
return tryReplaceExtend(X86::MOVSX32rm8, MI);
case X86::MOVZX16rr8:
return tryReplaceExtend(X86::MOVZX32rr8, MI);
case X86::MOVZX16rm8:
return tryReplaceExtend(X86::MOVZX32rm8, MI);
default:
break;
}
return nullptr;
}
void FixupBWInstPass::processBasicBlock(MachineFunction &MF,
MachineBasicBlock &MBB) {
SmallVector<std::pair<MachineInstr *, MachineInstr *>, 8> MIReplacements;
LiveRegs.clear();
LiveRegs.addLiveOuts(MBB);
OptForSize = MF.getFunction().hasOptSize() ||
llvm::shouldOptimizeForSize(&MBB, PSI, MBFI);
for (MachineInstr &MI : llvm::reverse(MBB)) {
if (MachineInstr *NewMI = tryReplaceInstr(&MI, MBB))
MIReplacements.push_back(std::make_pair(&MI, NewMI));
LiveRegs.stepBackward(MI);
}
while (!MIReplacements.empty()) {
MachineInstr *MI = MIReplacements.back().first;
MachineInstr *NewMI = MIReplacements.back().second;
MIReplacements.pop_back();
MBB.insert(MI, NewMI);
MBB.erase(MI);
}
}