Increase efficiency of sign_extend_inreg by using subregisters for truncation. As the README suggests sign_extend_subreg is selected to (sext(trunc)).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41010 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/X86/README.txt b/lib/Target/X86/README.txt
index 7786f17..073e2da 100644
--- a/lib/Target/X86/README.txt
+++ b/lib/Target/X86/README.txt
@@ -473,21 +473,6 @@
 
 //===---------------------------------------------------------------------===//
 
-Bad codegen:
-
-char foo(int x) { return x; }
-
-_foo:
-	movl 4(%esp), %eax
-	shll $24, %eax
-	sarl $24, %eax
-	ret
-
-SIGN_EXTEND_INREG can be implemented as (sext (trunc)) to take advantage of 
-sub-registers.
-
-//===---------------------------------------------------------------------===//
-
 Consider this:
 
 typedef struct pair { float A, B; } pair;
diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp
index a851670..97da290 100644
--- a/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -208,6 +208,10 @@
     /// base register.  Return the virtual register that holds this value.
     SDNode *getGlobalBaseReg();
 
+    /// getTruncate - return an SDNode that implements a subreg based truncate
+    /// of the specified operand to the the specified value type.
+    SDNode *getTruncate(SDOperand N0, MVT::ValueType VT);
+
 #ifndef NDEBUG
     unsigned Indent;
 #endif
@@ -979,6 +983,44 @@
   return FindCallStartFromCall(Node->getOperand(0).Val);
 }
 
+SDNode *X86DAGToDAGISel::getTruncate(SDOperand N0, MVT::ValueType VT) {
+    SDOperand SRIdx;
+    switch (VT) {
+    case MVT::i8:
+      SRIdx = CurDAG->getTargetConstant(1, MVT::i32); // SubRegSet 1
+      // Ensure that the source register has an 8-bit subreg on 32-bit targets
+      if (!Subtarget->is64Bit()) { 
+        unsigned Opc;
+        MVT::ValueType VT;
+        switch (N0.getValueType()) {
+        default: assert(0 && "Unknown truncate!");
+        case MVT::i16:
+          Opc = X86::MOV16to16_;
+          VT = MVT::i16;
+          break;
+        case MVT::i32:
+          Opc = X86::MOV32to32_;
+          VT = MVT::i32;
+          break;
+        }
+        N0 = 
+          SDOperand(CurDAG->getTargetNode(Opc, VT, N0), 0);
+      }
+      break;
+    case MVT::i16:
+      SRIdx = CurDAG->getTargetConstant(2, MVT::i32); // SubRegSet 2
+      break;
+    case MVT::i32:
+      SRIdx = CurDAG->getTargetConstant(3, MVT::i32); // SubRegSet 3
+      break;
+    default: assert(0 && "Unknown truncate!");
+    }
+    return CurDAG->getTargetNode(X86::EXTRACT_SUBREG, 
+                                 VT, 
+                                 N0, SRIdx);
+}
+
+
 SDNode *X86DAGToDAGISel::Select(SDOperand N) {
   SDNode *Node = N.Val;
   MVT::ValueType NVT = Node->getValueType(0);
@@ -1330,44 +1372,57 @@
 
       return NULL;
     }
+    
+    case ISD::SIGN_EXTEND_INREG: {
+      SDOperand N0 = Node->getOperand(0);
+      AddToISelQueue(N0);
       
-    case ISD::TRUNCATE: {
-      SDOperand Tmp;
-      SDOperand Input = Node->getOperand(0);
-      AddToISelQueue(Node->getOperand(0));
+      MVT::ValueType SVT = cast<VTSDNode>(Node->getOperand(1))->getVT();
+      SDOperand TruncOp = SDOperand(getTruncate(N0, SVT), 0);
+      unsigned Opc;
       switch (NVT) {
-      case MVT::i8:
-        Tmp = CurDAG->getTargetConstant(1, MVT::i32); // SubRegSet 1
-        // Ensure that the source register has an 8-bit subreg on 32-bit targets
-        if (!Subtarget->is64Bit()) { 
-          unsigned Opc;
-          MVT::ValueType VT;
-          switch (Node->getOperand(0).getValueType()) {
-          default: assert(0 && "Unknown truncate!");
-          case MVT::i16:
-            Opc = X86::MOV16to16_;
-            VT = MVT::i16;
-            break;
-          case MVT::i32:
-            Opc = X86::MOV32to32_;
-            VT = MVT::i32;
-            break;
-          }
-          Input = 
-            SDOperand(CurDAG->getTargetNode(Opc, VT, Node->getOperand(0)), 0);
-        }
-        break;
       case MVT::i16:
-        Tmp = CurDAG->getTargetConstant(2, MVT::i32); // SubRegSet 2
+        if (SVT == MVT::i8) Opc = X86::MOVSX16rr8;
+        else assert(0 && "Unknown sign_extend_inreg!");
         break;
       case MVT::i32:
-        Tmp = CurDAG->getTargetConstant(3, MVT::i32); // SubRegSet 3
+        switch (SVT) {
+        case MVT::i8:  Opc = X86::MOVSX32rr8;  break;
+        case MVT::i16: Opc = X86::MOVSX32rr16; break;
+        default: assert(0 && "Unknown sign_extend_inreg!");
+        }
         break;
-      default: assert(0 && "Unknown truncate!");
+      case MVT::i64:
+        switch (SVT) {
+        case MVT::i8:  Opc = X86::MOVSX64rr8;  break;
+        case MVT::i16: Opc = X86::MOVSX64rr16; break;
+        case MVT::i32: Opc = X86::MOVSX64rr32; break;
+        default: assert(0 && "Unknown sign_extend_inreg!");
+        }
+        break;
+      default: assert(0 && "Unknown sign_extend_inreg!");
       }
-      SDNode *ResNode = CurDAG->getTargetNode(X86::EXTRACT_SUBREG, 
-                                              NVT, 
-                                              Input, Tmp);
+      
+      SDNode *ResNode = CurDAG->getTargetNode(Opc, NVT, TruncOp);
+      
+#ifndef NDEBUG
+      DOUT << std::string(Indent-2, ' ') << "=> ";
+      DEBUG(TruncOp.Val->dump(CurDAG));
+      DOUT << "\n";
+      DOUT << std::string(Indent-2, ' ') << "=> ";
+      DEBUG(ResNode->dump(CurDAG));
+      DOUT << "\n";
+      Indent -= 2;
+#endif
+      return ResNode;
+      break;
+    }
+    
+    case ISD::TRUNCATE: {
+      SDOperand Input = Node->getOperand(0);
+      AddToISelQueue(Node->getOperand(0));
+      SDNode *ResNode = getTruncate(Input, NVT);
+      
 #ifndef NDEBUG
         DOUT << std::string(Indent-2, ' ') << "=> ";
         DEBUG(ResNode->dump(CurDAG));
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 184e355..11b5662 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -157,9 +157,9 @@
   setOperationAction(ISD::SELECT_CC        , MVT::Other, Expand);
   setOperationAction(ISD::MEMMOVE          , MVT::Other, Expand);
   if (Subtarget->is64Bit())
-    setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16  , Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8   , Expand);
+    setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Legal);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16  , Legal);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8   , Legal);
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1   , Expand);
   setOperationAction(ISD::FP_ROUND_INREG   , MVT::f32  , Expand);
   setOperationAction(ISD::FREM             , MVT::f64  , Expand);