mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-24 13:06:56 +00:00
divb / mulb outputs to ah. Under x86-64 it's not legal to read ah if the instruction requires a rex prefix (i.e. outputs to r8b, etc.). So issue shift right by 8 on AX and then truncate it to 8 bits instead.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40972 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f2369f2042
commit
f7ef26e701
@ -221,3 +221,16 @@ we were to support medium or larger code models, we need to use the movabs
|
||||
instruction. We should probably introduce something like AbsoluteAddress to
|
||||
distinguish it from GlobalAddress so the asm printer and JIT code emitter can
|
||||
do the right thing.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
It's not possible to reference AH, BH, CH, and DH registers in an instruction
|
||||
requiring REX prefix. However, divb and mulb both produce results in AH. If isel
|
||||
emits a CopyFromReg which gets turned into a movb and that can be allocated a
|
||||
r8b - r15b.
|
||||
|
||||
To get around this, isel emits a CopyFromReg from AX and then right shift it
|
||||
down by 8 and truncate it. It's not pretty but it works. We need some register
|
||||
allocation magic to make the hack go away (e.g. putting additional constraints
|
||||
on the result of the movb).
|
||||
|
||||
|
@ -1159,7 +1159,21 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) {
|
||||
SDOperand(CurDAG->getTargetNode(Opc, MVT::Flag, N1, InFlag), 0);
|
||||
}
|
||||
|
||||
SDOperand Result = CurDAG->getCopyFromReg(Chain, HiReg, NVT, InFlag);
|
||||
SDOperand Result;
|
||||
if (HiReg == X86::AH && Subtarget->is64Bit()) {
|
||||
// Prevent use of AH in a REX instruction by referencing AX instead.
|
||||
// Shift it down 8 bits.
|
||||
Result = CurDAG->getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag);
|
||||
Chain = Result.getValue(1);
|
||||
Result = SDOperand(CurDAG->getTargetNode(X86::SHR16ri, MVT::i16, Result,
|
||||
CurDAG->getTargetConstant(8, MVT::i8)), 0);
|
||||
// Then truncate it down to i8.
|
||||
SDOperand SRIdx = CurDAG->getTargetConstant(1, MVT::i32); // SubRegSet 1
|
||||
Result = SDOperand(CurDAG->getTargetNode(X86::EXTRACT_SUBREG,
|
||||
MVT::i8, Result, SRIdx), 0);
|
||||
} else {
|
||||
Result = CurDAG->getCopyFromReg(Chain, HiReg, NVT, InFlag);
|
||||
}
|
||||
ReplaceUses(N.getValue(0), Result);
|
||||
if (foldedLoad)
|
||||
ReplaceUses(N1.getValue(1), Result.getValue(1));
|
||||
@ -1286,11 +1300,26 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) {
|
||||
SDOperand(CurDAG->getTargetNode(Opc, MVT::Flag, N1, InFlag), 0);
|
||||
}
|
||||
|
||||
SDOperand Result =
|
||||
CurDAG->getCopyFromReg(Chain, isDiv ? LoReg : HiReg, NVT, InFlag);
|
||||
unsigned Reg = isDiv ? LoReg : HiReg;
|
||||
SDOperand Result;
|
||||
if (Reg == X86::AH && Subtarget->is64Bit()) {
|
||||
// Prevent use of AH in a REX instruction by referencing AX instead.
|
||||
// Shift it down 8 bits.
|
||||
Result = CurDAG->getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag);
|
||||
Chain = Result.getValue(1);
|
||||
Result = SDOperand(CurDAG->getTargetNode(X86::SHR16ri, MVT::i16, Result,
|
||||
CurDAG->getTargetConstant(8, MVT::i8)), 0);
|
||||
// Then truncate it down to i8.
|
||||
SDOperand SRIdx = CurDAG->getTargetConstant(1, MVT::i32); // SubRegSet 1
|
||||
Result = SDOperand(CurDAG->getTargetNode(X86::EXTRACT_SUBREG,
|
||||
MVT::i8, Result, SRIdx), 0);
|
||||
} else {
|
||||
Result = CurDAG->getCopyFromReg(Chain, Reg, NVT, InFlag);
|
||||
Chain = Result.getValue(1);
|
||||
}
|
||||
ReplaceUses(N.getValue(0), Result);
|
||||
if (foldedLoad)
|
||||
ReplaceUses(N1.getValue(1), Result.getValue(1));
|
||||
ReplaceUses(N1.getValue(1), Chain);
|
||||
|
||||
#ifndef NDEBUG
|
||||
DOUT << std::string(Indent-2, ' ') << "=> ";
|
||||
|
Loading…
Reference in New Issue
Block a user