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
diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp
index 0caf7a5..a851670 100644
--- a/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -1159,7 +1159,21 @@
           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 @@
           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, ' ') << "=> ";