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:
Evan Cheng 2007-08-09 21:59:35 +00:00
parent f2369f2042
commit f7ef26e701
2 changed files with 46 additions and 4 deletions

View File

@ -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).

View File

@ -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, ' ') << "=> ";