-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Promote 32bit pseudo instr that infer extsw removal to 64bit in PPCMIPeephole #85451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
79aaf13
d4b4abc
affb9bf
75494c3
489cccc
1ece68c
56b04f5
692138b
95267f5
4482b29
8e98ab8
9b0b9c8
8550317
9a4e4d0
3798b03
34b52bb
f0cdc75
1de4b40
9ae473b
910b1b5
095acfc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5234,6 +5234,215 @@ bool PPCInstrInfo::isTOCSaveMI(const MachineInstr &MI) const { | |
// We limit the max depth to track incoming values of PHIs or binary ops | ||
// (e.g. AND) to avoid excessive cost. | ||
const unsigned MAX_BINOP_DEPTH = 1; | ||
|
||
// This function will promote the instruction which defines the register `Reg` | ||
// in the parameter from a 32-bit to a 64-bit instruction if needed. The logic | ||
// used to check whether an instruction needs to be promoted or not is similar | ||
// to the logic used to check whether or not a defined register is sign or zero | ||
// extended within the function PPCInstrInfo::isSignOrZeroExtended. | ||
// Additionally, the `promoteInstr32To64ForElimEXTSW` function is recursive. | ||
// BinOpDepth does not count all of the recursions. The parameter BinOpDepth is | ||
// incremented only when `promoteInstr32To64ForElimEXTSW` calls itself more | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I can see below, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good Catch for AND8 . the logic of BinOpDepth is come from function isSignOrZeroExtended(), when the instructions(e.g., AND, PHI, OR) which has two or more source registers , the instructions which defines these source registers also need to be promoted and so on , without increase the BinOpDepth , it maybe have 2 * 2 * 2 * 2.... recursions of promoteInstr32To64ForElimEXTSW. |
||
// than once. This is done to prevent exponential recursion. | ||
void PPCInstrInfo::promoteInstr32To64ForElimEXTSW(const Register &Reg, | ||
MachineRegisterInfo *MRI, | ||
unsigned BinOpDepth, | ||
LiveVariables *LV) const { | ||
if (!Reg.isVirtual()) | ||
return; | ||
|
||
MachineInstr *MI = MRI->getVRegDef(Reg); | ||
if (!MI) | ||
return; | ||
|
||
unsigned Opcode = MI->getOpcode(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: remove empty line |
||
switch (Opcode) { | ||
lei137 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
case PPC::OR: | ||
case PPC::ISEL: | ||
case PPC::OR8: | ||
case PPC::PHI: { | ||
if (BinOpDepth >= MAX_BINOP_DEPTH) | ||
break; | ||
unsigned OperandEnd = 3, OperandStride = 1; | ||
if (Opcode == PPC::PHI) { | ||
OperandEnd = MI->getNumOperands(); | ||
OperandStride = 2; | ||
} | ||
|
||
for (unsigned I = 1; I < OperandEnd; I += OperandStride) { | ||
assert(MI->getOperand(I).isReg() && "Operand must be register"); | ||
promoteInstr32To64ForElimEXTSW(MI->getOperand(I).getReg(), MRI, | ||
BinOpDepth + 1, LV); | ||
} | ||
|
||
break; | ||
} | ||
case PPC::COPY: { | ||
// Refers to the logic of the `case PPC::COPY` statement in the function | ||
// PPCInstrInfo::isSignOrZeroExtended(). | ||
|
||
Register SrcReg = MI->getOperand(1).getReg(); | ||
// In both ELFv1 and v2 ABI, method parameters and the return value | ||
// are sign- or zero-extended. | ||
const MachineFunction *MF = MI->getMF(); | ||
if (!MF->getSubtarget<PPCSubtarget>().isSVR4ABI()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should copy the explanation comments for these conditions from |
||
// If this is a copy from another register, we recursively promote the | ||
// source. | ||
promoteInstr32To64ForElimEXTSW(SrcReg, MRI, BinOpDepth, LV); | ||
return; | ||
} | ||
|
||
// From here on everything is SVR4ABI. COPY will be eliminated in the other | ||
// pass, we do not need promote the COPY pseudo opcode. | ||
|
||
if (SrcReg != PPC::X3) | ||
// If this is a copy from another register, we recursively promote the | ||
// source. | ||
promoteInstr32To64ForElimEXTSW(SrcReg, MRI, BinOpDepth, LV); | ||
return; | ||
} | ||
case PPC::ORI: | ||
case PPC::XORI: | ||
case PPC::ORIS: | ||
case PPC::XORIS: | ||
case PPC::ORI8: | ||
case PPC::XORI8: | ||
case PPC::ORIS8: | ||
case PPC::XORIS8: | ||
promoteInstr32To64ForElimEXTSW(MI->getOperand(1).getReg(), MRI, BinOpDepth, | ||
LV); | ||
break; | ||
case PPC::AND: | ||
case PPC::AND8: | ||
if (BinOpDepth >= MAX_BINOP_DEPTH) | ||
break; | ||
|
||
promoteInstr32To64ForElimEXTSW(MI->getOperand(1).getReg(), MRI, | ||
BinOpDepth + 1, LV); | ||
promoteInstr32To64ForElimEXTSW(MI->getOperand(2).getReg(), MRI, | ||
BinOpDepth + 1, LV); | ||
break; | ||
} | ||
|
||
amy-kwan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const TargetRegisterClass *RC = MRI->getRegClass(Reg); | ||
if (RC == &PPC::G8RCRegClass || RC == &PPC::G8RC_and_G8RC_NOX0RegClass) | ||
return; | ||
|
||
const PPCInstrInfo *TII = | ||
MI->getMF()->getSubtarget<PPCSubtarget>().getInstrInfo(); | ||
amy-kwan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Map the 32bit to 64bit opcodes for instructions that are not signed or zero | ||
// extended themselves, but may have operands who's destination registers of | ||
// signed or zero extended instructions. | ||
std::unordered_map<unsigned, unsigned> OpcodeMap = { | ||
{PPC::OR, PPC::OR8}, {PPC::ISEL, PPC::ISEL8}, | ||
{PPC::ORI, PPC::ORI8}, {PPC::XORI, PPC::XORI8}, | ||
{PPC::ORIS, PPC::ORIS8}, {PPC::XORIS, PPC::XORIS8}, | ||
{PPC::AND, PPC::AND8}}; | ||
|
||
int NewOpcode = -1; | ||
auto It = OpcodeMap.find(Opcode); | ||
if (It != OpcodeMap.end()) { | ||
// Set the new opcode to the mapped 64-bit version. | ||
NewOpcode = It->second; | ||
} else { | ||
if (!TII->isSExt32To64(Opcode)) | ||
return; | ||
|
||
// The TableGen function `get64BitInstrFromSignedExt32BitInstr` is used to | ||
// map the 32-bit instruction with the `SExt32To64` flag to the 64-bit | ||
// instruction with the same opcode. | ||
NewOpcode = PPC::get64BitInstrFromSignedExt32BitInstr(Opcode); | ||
} | ||
|
||
assert(NewOpcode != -1 && | ||
"Must have a 64-bit opcode to map the 32-bit opcode!"); | ||
|
||
const TargetRegisterInfo *TRI = MRI->getTargetRegisterInfo(); | ||
const MCInstrDesc &MCID = TII->get(NewOpcode); | ||
const TargetRegisterClass *NewRC = | ||
TRI->getRegClass(MCID.operands()[0].RegClass); | ||
|
||
Register SrcReg = MI->getOperand(0).getReg(); | ||
const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg); | ||
|
||
// If the register class of the defined register in the 32-bit instruction | ||
// is the same as the register class of the defined register in the promoted | ||
// 64-bit instruction, we do not need to promote the instruction. | ||
if (NewRC == SrcRC) | ||
return; | ||
|
||
DebugLoc DL = MI->getDebugLoc(); | ||
auto MBB = MI->getParent(); | ||
|
||
// Since the pseudo-opcode of the instruction is promoted from 32-bit to | ||
// 64-bit, if the source reg class of the original instruction belongs to | ||
// PPC::GRCRegClass or PPC::GPRC_and_GPRC_NOR0RegClass, we need to promote | ||
// the operand to PPC::G8CRegClass or PPC::G8RC_and_G8RC_NOR0RegClass, | ||
// respectively. | ||
DenseMap<unsigned, Register> PromoteRegs; | ||
for (unsigned i = 1; i < MI->getNumOperands(); i++) { | ||
MachineOperand &Operand = MI->getOperand(i); | ||
if (!Operand.isReg()) | ||
continue; | ||
|
||
Register OperandReg = Operand.getReg(); | ||
if (!OperandReg.isVirtual()) | ||
continue; | ||
|
||
const TargetRegisterClass *NewUsedRegRC = | ||
TRI->getRegClass(MCID.operands()[i].RegClass); | ||
const TargetRegisterClass *OrgRC = MRI->getRegClass(OperandReg); | ||
if (NewUsedRegRC != OrgRC && (OrgRC == &PPC::GPRCRegClass || | ||
OrgRC == &PPC::GPRC_and_GPRC_NOR0RegClass)) { | ||
// Promote the used 32-bit register to 64-bit register. | ||
Register TmpReg = MRI->createVirtualRegister(NewUsedRegRC); | ||
Register DstTmpReg = MRI->createVirtualRegister(NewUsedRegRC); | ||
BuildMI(*MBB, MI, DL, TII->get(PPC::IMPLICIT_DEF), TmpReg); | ||
BuildMI(*MBB, MI, DL, TII->get(PPC::INSERT_SUBREG), DstTmpReg) | ||
.addReg(TmpReg) | ||
.addReg(OperandReg) | ||
.addImm(PPC::sub_32); | ||
PromoteRegs[i] = DstTmpReg; | ||
} | ||
} | ||
|
||
Register NewDefinedReg = MRI->createVirtualRegister(NewRC); | ||
|
||
BuildMI(*MBB, MI, DL, TII->get(NewOpcode), NewDefinedReg); | ||
MachineBasicBlock::instr_iterator Iter(MI); | ||
--Iter; | ||
MachineInstrBuilder MIBuilder(*Iter->getMF(), Iter); | ||
for (unsigned i = 1; i < MI->getNumOperands(); i++) { | ||
if (PromoteRegs.find(i) != PromoteRegs.end()) | ||
MIBuilder.addReg(PromoteRegs[i], RegState::Kill); | ||
else | ||
Iter->addOperand(MI->getOperand(i)); | ||
} | ||
|
||
for (unsigned i = 1; i < Iter->getNumOperands(); i++) { | ||
MachineOperand &Operand = Iter->getOperand(i); | ||
if (!Operand.isReg()) | ||
continue; | ||
Register OperandReg = Operand.getReg(); | ||
if (!OperandReg.isVirtual()) | ||
continue; | ||
LV->recomputeForSingleDefVirtReg(OperandReg); | ||
} | ||
|
||
MI->eraseFromParent(); | ||
|
||
// A defined register may be used by other instructions that are 32-bit. | ||
// After the defined register is promoted to 64-bit for the promoted | ||
// instruction, we need to demote the 64-bit defined register back to a | ||
// 32-bit register | ||
BuildMI(*MBB, ++Iter, DL, TII->get(PPC::COPY), SrcReg) | ||
.addReg(NewDefinedReg, RegState::Kill, PPC::sub_32); | ||
LV->recomputeForSingleDefVirtReg(NewDefinedReg); | ||
return; | ||
} | ||
|
||
// The isSignOrZeroExtended function is recursive. The parameter BinOpDepth | ||
// does not count all of the recursions. The parameter BinOpDepth is incremented | ||
// only when isSignOrZeroExtended calls itself more than once. This is done to | ||
|
Uh oh!
There was an error while loading. Please reload this page.