From 450f6815b93c15e4232aa5fb4f0edd8267d92ee7 Mon Sep 17 00:00:00 2001 From: Christopher Lamb Date: Fri, 10 Aug 2007 21:48:46 +0000 Subject: [PATCH] Increase efficiency of sign_extend_inreg by using subregisters for truncation. As the README suggests sign_extend_subreg is selected to (sext(trunc)). llvm-svn: 41010 --- lib/Target/X86/README.txt | 15 --- lib/Target/X86/X86ISelDAGToDAG.cpp | 117 ++++++++++++++----- lib/Target/X86/X86ISelLowering.cpp | 6 +- test/CodeGen/X86/2007-08-10-SignExtSubreg.ll | 10 ++ test/CodeGen/X86/shl_elim.ll | 4 +- 5 files changed, 101 insertions(+), 51 deletions(-) create mode 100644 test/CodeGen/X86/2007-08-10-SignExtSubreg.ll diff --git a/lib/Target/X86/README.txt b/lib/Target/X86/README.txt index 7786f178b77..073e2dacef1 100644 --- a/lib/Target/X86/README.txt +++ b/lib/Target/X86/README.txt @@ -473,21 +473,6 @@ require a copy to be inserted (in X86InstrInfo::convertToThreeAddress). //===---------------------------------------------------------------------===// -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 a8516708005..97da290ffc9 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -208,6 +208,10 @@ namespace { /// 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 @@ static SDNode *FindCallStartFromCall(SDNode *Node) { 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 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) { 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(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 184e355369e..11b56621998 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -157,9 +157,9 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM) 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); diff --git a/test/CodeGen/X86/2007-08-10-SignExtSubreg.ll b/test/CodeGen/X86/2007-08-10-SignExtSubreg.ll new file mode 100644 index 00000000000..c94096a9b7a --- /dev/null +++ b/test/CodeGen/X86/2007-08-10-SignExtSubreg.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc -march=x86 | grep {movsbl .al, .eax} + +@X = global i32 0 ; [#uses=1] + +define i8 @_Z3fooi(i32 %x) signext { +entry: + store i32 %x, i32* @X, align 4 + %retval67 = trunc i32 %x to i8 ; [#uses=1] + ret i8 %retval67 +} \ No newline at end of file diff --git a/test/CodeGen/X86/shl_elim.ll b/test/CodeGen/X86/shl_elim.ll index 3c447f79dd6..d3616f4ac5d 100644 --- a/test/CodeGen/X86/shl_elim.ll +++ b/test/CodeGen/X86/shl_elim.ll @@ -1,6 +1,6 @@ ; RUN: llvm-as < %s | llc -march=x86 | grep {movl 8(.esp), %eax} -; RUN: llvm-as < %s | llc -march=x86 | grep {shll .15, .eax} -; RUN: llvm-as < %s | llc -march=x86 | grep {sarl .16, .eax} +; RUN: llvm-as < %s | llc -march=x86 | grep {shrl .eax} +; RUN: llvm-as < %s | llc -march=x86 | grep {movswl .ax, .eax} define i32 @test1(i64 %a) { %tmp29 = lshr i64 %a, 24 ; [#uses=1]