Index: lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- lib/Target/X86/X86ISelDAGToDAG.cpp +++ lib/Target/X86/X86ISelDAGToDAG.cpp @@ -3052,70 +3052,50 @@ 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))) { + 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); - - // Extract the 16-bit subregister. - SDValue Subreg = CurDAG->getTargetExtractSubreg(X86::sub_16bit, dl, - MVT::i16, 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; - } + SDValue Imm = CurDAG->getTargetConstant(Mask, dl, VT); + SDValue Reg = N0.getOperand(0); - // 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; - } + // Extract the subregister if necessary. + if (N0.getValueType() != VT) + Reg = CurDAG->getTargetExtractSubreg(SubRegOp, dl, VT, Reg); + + // 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; } Index: test/CodeGen/X86/test-shrink-bug.ll =================================================================== --- test/CodeGen/X86/test-shrink-bug.ll +++ test/CodeGen/X86/test-shrink-bug.ll @@ -51,8 +51,7 @@ ; 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 Index: test/CodeGen/X86/test-shrink.ll =================================================================== --- test/CodeGen/X86/test-shrink.ll +++ test/CodeGen/X86/test-shrink.ll @@ -484,8 +484,7 @@ 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 @@ ; 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 @@ ; ; 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