-
Notifications
You must be signed in to change notification settings - Fork 11.5k
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
Promote the Pseudo Opcode of instructions that deduce the sign extension for extsw from 32 bits to 64 bits when eliminating the extsw instruction in PPCMIPeepholes optimization. #85451
base: main
Are you sure you want to change the base?
Changes from 7 commits
79aaf13
d4b4abc
affb9bf
75494c3
489cccc
1ece68c
56b04f5
692138b
95267f5
4482b29
8e98ab8
9b0b9c8
8550317
9a4e4d0
3798b03
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,244 @@ 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; | ||||||
|
||||||
// The `PromoteInstr32To64ForEmliEXTSW` function is recursive. The parameter | ||||||
// BinOpDepth does not count all of the recursions. The parameter BinOpDepth is | ||||||
// incremented only when `PromoteInstr32To64ForEmliEXTSW` calls itself more | ||||||
// than once. This is done to prevent exponential recursion. The function will | ||||||
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 probably only mention the recursion after explaining how we follow the register uses below. |
||||||
// promote the instruction which defines the register `Reg` in the parameter | ||||||
// from a 32-bit to a 64-bit instruction if needed. Additionally, all the used | ||||||
// and defined registers in the instruction may also need to be promoted from | ||||||
// 32-bit to 64-bit based on the promoted instruction description. If a used | ||||||
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 mention the tablegen flag used to map PPC instructions and the opcodes defined by the 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. I put the new adding comment in the code which is in the middle of the function instead of the description of the function. |
||||||
// register is promoted to 64-bit, the instruction which defines the promoted | ||||||
// register also needs to be promoted. After an instruction is promoted to 64 | ||||||
// bits, the defined register of the promoted instruction is also 64-bit. A | ||||||
// defined register may be used by other instructions; in such cases, | ||||||
// we need to extract the 32-bit register used by other | ||||||
// non-promoted 32-bit instructions from the promoted 64-bit register. | ||||||
void PPCInstrInfo::PromoteInstr32To64ForEmliEXTSW(const Register &Reg, | ||||||
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.
Suggested change
|
||||||
MachineRegisterInfo *MRI, | ||||||
unsigned BinOpDepth, | ||||||
LiveVariables *LV) const { | ||||||
MachineInstr *MI = MRI->getVRegDef(Reg); | ||||||
if (!MI) | ||||||
return; | ||||||
|
||||||
unsigned Opcode = MI->getOpcode(); | ||||||
bool IsNonSignedExtInstrPromoted = false; | ||||||
int NewOpcode = -1; | ||||||
|
||||||
auto CheckAndSetNewOpcode = [&](int NewOpc) { | ||||||
if (!IsNonSignedExtInstrPromoted) { | ||||||
NewOpcode = NewOpc; | ||||||
IsNonSignedExtInstrPromoted = true; | ||||||
} | ||||||
}; | ||||||
|
||||||
auto SetNewOpcode = [&](int NewOpc) { | ||||||
NewOpcode = NewOpc; | ||||||
IsNonSignedExtInstrPromoted = true; | ||||||
}; | ||||||
|
||||||
switch (Opcode) { | ||||||
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. Are all the cases for opcode switch statements in PromoteInstr32To64ForEmliEXTSW coming from the union of definedBySignExtendingOp() and isSignExtended()/isSignOrZeroExtended()? 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. yes,
--> --> |
||||||
case PPC::OR: | ||||||
CheckAndSetNewOpcode(PPC::OR8); | ||||||
[[fallthrough]]; | ||||||
case PPC::ISEL: | ||||||
CheckAndSetNewOpcode(PPC::ISEL8); | ||||||
[[fallthrough]]; | ||||||
case PPC::OR8: | ||||||
case PPC::PHI: | ||||||
if (BinOpDepth < MAX_BINOP_DEPTH) { | ||||||
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"); | ||||||
Register SrcReg = MI->getOperand(I).getReg(); | ||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg, MRI, BinOpDepth + 1, LV); | ||||||
} | ||||||
|
||||||
if (!IsNonSignedExtInstrPromoted) | ||||||
return; | ||||||
} | ||||||
break; | ||||||
case PPC::COPY: { | ||||||
Register SrcReg = MI->getOperand(1).getReg(); | ||||||
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 |
||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg, MRI, BinOpDepth, LV); | ||||||
return; | ||||||
} | ||||||
// From here on everything is SVR4ABI | ||||||
if (MI->getParent()->getBasicBlock() == &MF->getFunction().getEntryBlock()) | ||||||
return; | ||||||
|
||||||
if (SrcReg != PPC::X3) { | ||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg, MRI, BinOpDepth, LV); | ||||||
return; | ||||||
} | ||||||
} | ||||||
return; | ||||||
case PPC::ORI: | ||||||
CheckAndSetNewOpcode(PPC::ORI8); | ||||||
[[fallthrough]]; | ||||||
case PPC::XORI: | ||||||
CheckAndSetNewOpcode(PPC::XORI8); | ||||||
[[fallthrough]]; | ||||||
case PPC::ORIS: | ||||||
CheckAndSetNewOpcode(PPC::ORIS8); | ||||||
[[fallthrough]]; | ||||||
case PPC::XORIS: | ||||||
CheckAndSetNewOpcode(PPC::XORIS8); | ||||||
[[fallthrough]]; | ||||||
case PPC::ORI8: | ||||||
case PPC::XORI8: | ||||||
case PPC::ORIS8: | ||||||
case PPC::XORIS8: { | ||||||
Register SrcReg = MI->getOperand(1).getReg(); | ||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg, MRI, BinOpDepth, LV); | ||||||
// If Opcode is PPC::ORI8, PPC::XORI8, PPC::ORIS8, or PPC::XORIS8, | ||||||
// the instruction does not need to be promoted. | ||||||
if (!IsNonSignedExtInstrPromoted) | ||||||
return; | ||||||
break; | ||||||
} | ||||||
case PPC::AND: | ||||||
CheckAndSetNewOpcode(PPC::AND8); | ||||||
[[fallthrough]]; | ||||||
case PPC::AND8: { | ||||||
if (BinOpDepth < MAX_BINOP_DEPTH) { | ||||||
Register SrcReg1 = MI->getOperand(1).getReg(); | ||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg1, MRI, BinOpDepth, LV); | ||||||
Register SrcReg2 = MI->getOperand(2).getReg(); | ||||||
PromoteInstr32To64ForEmliEXTSW(SrcReg2, MRI, BinOpDepth, LV); | ||||||
// If Opcode is PPC::AND8, the instruction does not need to be promoted. | ||||||
if (!IsNonSignedExtInstrPromoted) | ||||||
return; | ||||||
} | ||||||
break; | ||||||
} | ||||||
case PPC::RLWINM: | ||||||
SetNewOpcode(PPC::RLWINM8); | ||||||
break; | ||||||
case PPC::RLWINM_rec: | ||||||
SetNewOpcode(PPC::RLWINM8_rec); | ||||||
break; | ||||||
case PPC::RLWNM: | ||||||
SetNewOpcode(PPC ::RLWNM8); | ||||||
break; | ||||||
case PPC::RLWNM_rec: | ||||||
SetNewOpcode(PPC::RLWNM8_rec); | ||||||
break; | ||||||
case PPC::ANDC_rec: | ||||||
SetNewOpcode(PPC::ANDC8_rec); | ||||||
break; | ||||||
case PPC::ANDIS_rec: | ||||||
SetNewOpcode(PPC::ANDIS8_rec); | ||||||
break; | ||||||
default: | ||||||
break; | ||||||
} | ||||||
|
||||||
amy-kwan marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
const PPCInstrInfo *TII = | ||||||
MI->getMF()->getSubtarget<PPCSubtarget>().getInstrInfo(); | ||||||
amy-kwan marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if ((definedBySignExtendingOp(Reg, MRI) && !TII->isZExt32To64(Opcode) && | ||||||
!isOpZeroOfSubwordPreincLoad(Opcode)) || | ||||||
IsNonSignedExtInstrPromoted) { | ||||||
|
||||||
const TargetRegisterClass *RC = MRI->getRegClass(Reg); | ||||||
|
||||||
if (RC == &PPC::G8RCRegClass || RC == &PPC::G8RC_and_G8RC_NOX0RegClass) | ||||||
return; | ||||||
|
||||||
if (!IsNonSignedExtInstrPromoted) | ||||||
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 operand 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; | ||||||
DenseMap<unsigned, Register> ReCalRegs; | ||||||
for (unsigned i = 1; i < MI->getNumOperands(); i++) { | ||||||
MachineOperand &Operand = MI->getOperand(i); | ||||||
if (Operand.isReg()) { | ||||||
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; | ||||||
ReCalRegs[i] = DstTmpReg; | ||||||
} else { | ||||||
ReCalRegs[i] = OperandReg; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
Register NewDefinedReg = MRI->createVirtualRegister(NewRC); | ||||||
|
||||||
BuildMI(*MBB, MI, DL, TII->get(NewOpcode), NewDefinedReg); | ||||||
MachineBasicBlock::instr_iterator Iter(MI); | ||||||
--Iter; | ||||||
for (unsigned i = 1; i < MI->getNumOperands(); i++) | ||||||
if (PromoteRegs.find(i) != PromoteRegs.end()) | ||||||
MachineInstrBuilder(*Iter->getMF(), Iter) | ||||||
.addReg(PromoteRegs[i], RegState::Kill); | ||||||
else | ||||||
Iter->addOperand(MI->getOperand(i)); | ||||||
|
||||||
for (auto Iter = ReCalRegs.begin(); Iter != ReCalRegs.end(); Iter++) | ||||||
LV->recomputeForSingleDefVirtReg(Iter->second); | ||||||
MI->eraseFromParent(); | ||||||
|
||||||
// Demote the 64-bit defined regster 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; | ||||||
} | ||||||
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 | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1050,7 +1050,16 @@ bool PPCMIPeephole::simplifyCode() { | |
} else if (MI.getOpcode() == PPC::EXTSW_32_64 && | ||
TII->isSignExtended(NarrowReg, MRI)) { | ||
// We can eliminate EXTSW if the input is known to be already | ||
// sign-extended. | ||
// sign-extended. but we are not sure whether a spill will occur | ||
// during register allocation. All these instructions in the chain | ||
// used to deduce sign extension to eliminate the 'extsw' will need to | ||
// be promoted to 64-bit pseudo instructions when the 'extsw' is | ||
// eliminated. If there is no promotion, it will use the 'stw' instead | ||
// of 'std', and 'lwz' instead of 'ld' when spilling, since the | ||
// register class is 32-bits. Consequently, the high 32-bit | ||
// information will be lost. | ||
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. It might flow nicer if we put the what will happen if we don't promote first and then say how we promote after. |
||
TII->PromoteInstr32To64ForEmliEXTSW(NarrowReg, MRI, 0, LV); | ||
|
||
LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n"); | ||
Register TmpReg = | ||
MF->getRegInfo().createVirtualRegister(&PPC::G8RCRegClass); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "form a column" mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
means we will deal with the instruction which only has flag
SExt32To64
means that if two instruction has the same Pseduo Opcode will be on the same row.
means that the instruction for 64bit is one column, 32-bit is another column.
it will generate something like this