divb / mulb outputs to ah. Under x86-64 it's not legal to read ah if the instruction...
authorEvan Cheng <evan.cheng@apple.com>
Thu, 9 Aug 2007 21:59:35 +0000 (21:59 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Thu, 9 Aug 2007 21:59:35 +0000 (21:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40972 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/README-X86-64.txt
lib/Target/X86/X86ISelDAGToDAG.cpp

index 191904ac51f29a8b839e6a2da89ec7756567c68c..bc19986eba43efdbdc768e54270325a15d3bf4e8 100644 (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).
+
index 0caf7a5bd3d596898bfb609ac3fd658c36effa49..a8516708005209aaea9163bc62daafe0a121c5c1 100644 (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, ' ') << "=> ";