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
This commit is contained in:
Christopher Lamb 2007-08-10 21:48:46 +00:00
parent f0c236fb8a
commit b372abab14
5 changed files with 101 additions and 51 deletions

View File

@ -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;

View File

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

View File

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

View File

@ -0,0 +1,10 @@
; RUN: llvm-as < %s | llc -march=x86 | grep {movsbl .al, .eax}
@X = global i32 0 ; <i32*> [#uses=1]
define i8 @_Z3fooi(i32 %x) signext {
entry:
store i32 %x, i32* @X, align 4
%retval67 = trunc i32 %x to i8 ; <i8> [#uses=1]
ret i8 %retval67
}

View File

@ -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 ; <i64> [#uses=1]