[X86] Generate testl instruction through truncates.

Summary:
This was introduced in D42646 but ended up being reverted because the original implementation was buggy.

Depends on D42646

Reviewers: craig.topper, niravd, spatel, hfinkel

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D42741

llvm-svn: 323899
This commit is contained in:
Amaury Sechet 2018-01-31 19:20:06 +00:00
parent 598a327133
commit d76ae2bede
3 changed files with 47 additions and 66 deletions

View File

@ -3052,70 +3052,55 @@ void X86DAGToDAGISel::Select(SDNode *Node) {
if (!C) break;
uint64_t Mask = C->getZExtValue();
// For example, convert "testl %eax, $8" to "testb %al, $8"
MVT VT;
int SubRegOp;
unsigned Op;
if (isUInt<8>(Mask) &&
(!(Mask & 0x80) || hasNoSignedComparisonUses(Node))) {
SDValue Imm = CurDAG->getTargetConstant(Mask, dl, MVT::i8);
SDValue Reg = N0.getOperand(0);
// Extract the l-register.
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::sub_8bit, dl,
MVT::i8, Reg);
// Emit a testb.
SDNode *NewNode = CurDAG->getMachineNode(X86::TEST8ri, dl, MVT::i32,
Subreg, Imm);
// Replace SUB|CMP with TEST, since SUB has two outputs while TEST has
// one, do not call ReplaceAllUsesWith.
ReplaceUses(SDValue(Node, (Opcode == X86ISD::SUB ? 1 : 0)),
SDValue(NewNode, 0));
CurDAG->RemoveDeadNode(Node);
return;
// For example, convert "testl %eax, $8" to "testb %al, $8"
VT = MVT::i8;
SubRegOp = X86::sub_8bit;
Op = X86::TEST8ri;
} else if (OptForMinSize && isUInt<16>(Mask) &&
(!(Mask & 0x8000) || hasNoSignedComparisonUses(Node))) {
// For example, "testl %eax, $32776" to "testw %ax, $32776".
// NOTE: We only want to form TESTW instructions if optimizing for
// min size. Otherwise we only save one byte and possibly get a length
// changing prefix penalty in the decoders.
VT = MVT::i16;
SubRegOp = X86::sub_16bit;
Op = X86::TEST16ri;
} else if (isUInt<32>(Mask) && N0.getValueType() != MVT::i16 &&
(!(Mask & 0x80000000) || hasNoSignedComparisonUses(Node))) {
// For example, "testq %rax, $268468232" to "testl %eax, $268468232".
// NOTE: We only want to run that transform if N0 is 32 or 64 bits.
// Otherwize, we find ourselves in a position where we have to do
// promotion. If previous passes did not promote the and, we assume
// they had a good reason not to and do not promote here.
VT = MVT::i32;
SubRegOp = X86::sub_32bit;
Op = X86::TEST32ri;
} else {
// No eligible transformation was found.
break;
}
// For example, "testl %eax, $32776" to "testw %ax, $32776".
// NOTE: We only want to form TESTW instructions if optimizing for
// min size. Otherwise we only save one byte and possibly get a length
// changing prefix penalty in the decoders.
if (OptForMinSize && isUInt<16>(Mask) && N0.getValueType() != MVT::i16 &&
(!(Mask & 0x8000) || hasNoSignedComparisonUses(Node))) {
SDValue Imm = CurDAG->getTargetConstant(Mask, dl, MVT::i16);
SDValue Reg = N0.getOperand(0);
SDValue Imm = CurDAG->getTargetConstant(Mask, dl, VT);
SDValue Reg = N0.getOperand(0);
// Extract the 16-bit subregister.
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::sub_16bit, dl,
MVT::i16, Reg);
// Extract the subregister if necessary.
if (N0.getValueType() != VT)
Reg = CurDAG->getTargetExtractSubreg(SubRegOp, dl, VT, Reg);
// Emit a testw.
SDNode *NewNode = CurDAG->getMachineNode(X86::TEST16ri, dl, MVT::i32,
Subreg, Imm);
// Replace SUB|CMP with TEST, since SUB has two outputs while TEST has
// one, do not call ReplaceAllUsesWith.
ReplaceUses(SDValue(Node, (Opcode == X86ISD::SUB ? 1 : 0)),
SDValue(NewNode, 0));
CurDAG->RemoveDeadNode(Node);
return;
}
// For example, "testq %rax, $268468232" to "testl %eax, $268468232".
if (isUInt<32>(Mask) && N0.getValueType() == MVT::i64 &&
(!(Mask & 0x80000000) || hasNoSignedComparisonUses(Node))) {
SDValue Imm = CurDAG->getTargetConstant(Mask, dl, MVT::i32);
SDValue Reg = N0.getOperand(0);
// Extract the 32-bit subregister.
SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::sub_32bit, dl,
MVT::i32, Reg);
// Emit a testl.
SDNode *NewNode = CurDAG->getMachineNode(X86::TEST32ri, dl, MVT::i32,
Subreg, Imm);
// Replace SUB|CMP with TEST, since SUB has two outputs while TEST has
// one, do not call ReplaceAllUsesWith.
ReplaceUses(SDValue(Node, (Opcode == X86ISD::SUB ? 1 : 0)),
SDValue(NewNode, 0));
CurDAG->RemoveDeadNode(Node);
return;
}
// Emit a testl or testw.
SDNode *NewNode = CurDAG->getMachineNode(Op, dl, MVT::i32, Reg, Imm);
// Replace SUB|CMP with TEST, since SUB has two outputs while TEST has
// one, do not call ReplaceAllUsesWith.
ReplaceUses(SDValue(Node, (Opcode == X86ISD::SUB ? 1 : 0)),
SDValue(NewNode, 0));
CurDAG->RemoveDeadNode(Node);
return;
}
break;
}

View File

@ -51,8 +51,7 @@ define void @fail(i16 %a, <2 x i8> %b) {
; CHECK-X86-NEXT: movzwl {{[0-9]+}}(%esp), %ecx
; CHECK-X86-NEXT: cmpb $123, {{[0-9]+}}(%esp)
; CHECK-X86-NEXT: sete %al
; CHECK-X86-NEXT: andl $263, %ecx ## imm = 0x107
; CHECK-X86-NEXT: testw %cx, %cx
; CHECK-X86-NEXT: testl $263, %ecx ## imm = 0x107
; CHECK-X86-NEXT: je LBB1_2
; CHECK-X86-NEXT: ## %bb.1:
; CHECK-X86-NEXT: testb %al, %al

View File

@ -484,8 +484,7 @@ no:
define void @truncand32(i16 inreg %x) nounwind {
; CHECK-LINUX64-LABEL: truncand32:
; CHECK-LINUX64: # %bb.0:
; CHECK-LINUX64-NEXT: andl $2049, %edi # imm = 0x801
; CHECK-LINUX64-NEXT: testw %di, %di
; CHECK-LINUX64-NEXT: testl $2049, %edi # imm = 0x801
; CHECK-LINUX64-NEXT: je .LBB11_1
; CHECK-LINUX64-NEXT: # %bb.2: # %no
; CHECK-LINUX64-NEXT: retq
@ -498,8 +497,7 @@ define void @truncand32(i16 inreg %x) nounwind {
; CHECK-WIN32-64-LABEL: truncand32:
; CHECK-WIN32-64: # %bb.0:
; CHECK-WIN32-64-NEXT: subq $40, %rsp
; CHECK-WIN32-64-NEXT: andl $2049, %ecx # imm = 0x801
; CHECK-WIN32-64-NEXT: testw %cx, %cx
; CHECK-WIN32-64-NEXT: testl $2049, %ecx # imm = 0x801
; CHECK-WIN32-64-NEXT: je .LBB11_1
; CHECK-WIN32-64-NEXT: # %bb.2: # %no
; CHECK-WIN32-64-NEXT: addq $40, %rsp
@ -511,8 +509,7 @@ define void @truncand32(i16 inreg %x) nounwind {
;
; CHECK-X86-LABEL: truncand32:
; CHECK-X86: # %bb.0:
; CHECK-X86-NEXT: andl $2049, %eax # imm = 0x801
; CHECK-X86-NEXT: testw %ax, %ax
; CHECK-X86-NEXT: testl $2049, %eax # imm = 0x801
; CHECK-X86-NEXT: je .LBB11_1
; CHECK-X86-NEXT: # %bb.2: # %no
; CHECK-X86-NEXT: retl