From 9000a72a4b723513499d97fb88a25a860132c323 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 10 Jun 2019 04:50:12 +0000 Subject: [PATCH] [X86] When promoting i16 compare with immediate to i32, try to use sign_extend for eq/ne if the input is truncated from a type with enough sign its. Summary: Our default behavior is to use sign_extend for signed comparisons and zero_extend for everything else. But for equality we have the freedom to use either extension. If we can prove the input has been truncated from something with enough sign bits, we can use sign_extend instead and let DAG combine optimize it out. A similar rule is used by type legalization in LegalizeIntegerTypes. This gets rid of the movzx in PR42189. The immediate will still take 4 bytes instead of the 2 bytes plus 0x66 prefix a cmp di, 32767 would get, but it avoids a length changing prefix. Reviewers: RKSimon, spatel, xbolva00 Reviewed By: xbolva00 Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D63032 llvm-svn: 362920 --- llvm/lib/Target/X86/X86ISelLowering.cpp | 61 +++++++++++++++++++++++---------- llvm/test/CodeGen/X86/cmp.ll | 39 +++++++++++++++++++++ 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index c4db693..2b655dc 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -19491,29 +19491,52 @@ SDValue X86TargetLowering::EmitCmp(SDValue Op0, SDValue Op1, unsigned X86CC, if (isNullConstant(Op1)) return EmitTest(Op0, X86CC, dl, DAG, Subtarget); - if ((Op0.getValueType() == MVT::i8 || Op0.getValueType() == MVT::i16 || - Op0.getValueType() == MVT::i32 || Op0.getValueType() == MVT::i64)) { - // Only promote the compare up to I32 if it is a 16 bit operation - // with an immediate. 16 bit immediates are to be avoided. - if (Op0.getValueType() == MVT::i16 && - ((isa(Op0) && - !cast(Op0)->getAPIntValue().isSignedIntN(8)) || - (isa(Op1) && - !cast(Op1)->getAPIntValue().isSignedIntN(8))) && - !DAG.getMachineFunction().getFunction().hasMinSize() && - !Subtarget.isAtom()) { + EVT CmpVT = Op0.getValueType(); + + if (CmpVT.isFloatingPoint()) + return DAG.getNode(X86ISD::CMP, dl, MVT::i32, Op0, Op1); + + assert((CmpVT == MVT::i8 || CmpVT == MVT::i16 || + CmpVT == MVT::i32 || CmpVT == MVT::i64) && "Unexpected VT!"); + + // Only promote the compare up to I32 if it is a 16 bit operation + // with an immediate. 16 bit immediates are to be avoided. + if (CmpVT == MVT::i16 && !Subtarget.isAtom() && + !DAG.getMachineFunction().getFunction().hasMinSize()) { + ConstantSDNode *COp0 = dyn_cast(Op0); + ConstantSDNode *COp1 = dyn_cast(Op1); + // Don't do this if the immediate can fit in 8-bits. + if ((COp0 && !COp0->getAPIntValue().isSignedIntN(8)) || + (COp1 && !COp1->getAPIntValue().isSignedIntN(8))) { unsigned ExtendOp = isX86CCUnsigned(X86CC) ? ISD::ZERO_EXTEND : ISD::SIGN_EXTEND; - Op0 = DAG.getNode(ExtendOp, dl, MVT::i32, Op0); - Op1 = DAG.getNode(ExtendOp, dl, MVT::i32, Op1); + if (X86CC == X86::COND_E || X86CC == X86::COND_NE) { + // For equality comparisons try to use SIGN_EXTEND if the input was + // truncate from something with enough sign bits. + if (Op0.getOpcode() == ISD::TRUNCATE) { + SDValue In = Op0.getOperand(0); + unsigned EffBits = + In.getScalarValueSizeInBits() - DAG.ComputeNumSignBits(In) + 1; + if (EffBits <= 16) + ExtendOp = ISD::SIGN_EXTEND; + } else if (Op1.getOpcode() == ISD::TRUNCATE) { + SDValue In = Op1.getOperand(0); + unsigned EffBits = + In.getScalarValueSizeInBits() - DAG.ComputeNumSignBits(In) + 1; + if (EffBits <= 16) + ExtendOp = ISD::SIGN_EXTEND; + } + } + + CmpVT = MVT::i32; + Op0 = DAG.getNode(ExtendOp, dl, CmpVT, Op0); + Op1 = DAG.getNode(ExtendOp, dl, CmpVT, Op1); } - // Use SUB instead of CMP to enable CSE between SUB and CMP. - SDVTList VTs = DAG.getVTList(Op0.getValueType(), MVT::i32); - SDValue Sub = DAG.getNode(X86ISD::SUB, dl, VTs, Op0, Op1); - return SDValue(Sub.getNode(), 1); } - assert(Op0.getValueType().isFloatingPoint() && "Unexpected VT!"); - return DAG.getNode(X86ISD::CMP, dl, MVT::i32, Op0, Op1); + // Use SUB instead of CMP to enable CSE between SUB and CMP. + SDVTList VTs = DAG.getVTList(CmpVT, MVT::i32); + SDValue Sub = DAG.getNode(X86ISD::SUB, dl, VTs, Op0, Op1); + return Sub.getValue(1); } /// Convert a comparison if required by the subtarget. diff --git a/llvm/test/CodeGen/X86/cmp.ll b/llvm/test/CodeGen/X86/cmp.ll index 2747eca..d13fecb 100644 --- a/llvm/test/CodeGen/X86/cmp.ll +++ b/llvm/test/CodeGen/X86/cmp.ll @@ -483,3 +483,42 @@ define { i64, i64 } @pr39968(i64, i64, i32) { %9 = insertvalue { i64, i64 } %8, i64 %6, 1 ret { i64, i64 } %9 } + +; Make sure we use a 32-bit comparison without an extend based on the input +; being pre-sign extended by caller. +define i32 @pr42189(i16 signext %c) { +; CHECK-LABEL: pr42189: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: cmpl $32767, %edi # encoding: [0x81,0xff,0xff,0x7f,0x00,0x00] +; CHECK-NEXT: # imm = 0x7FFF +; CHECK-NEXT: jne .LBB26_2 # encoding: [0x75,A] +; CHECK-NEXT: # fixup A - offset: 1, value: .LBB26_2-1, kind: FK_PCRel_1 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: jmp g # TAILCALL +; CHECK-NEXT: # encoding: [0xeb,A] +; CHECK-NEXT: # fixup A - offset: 1, value: g-1, kind: FK_PCRel_1 +; CHECK-NEXT: .LBB26_2: # %if.end +; CHECK-NEXT: jmp f # TAILCALL +; CHECK-NEXT: # encoding: [0xeb,A] +; CHECK-NEXT: # fixup A - offset: 1, value: f-1, kind: FK_PCRel_1 +entry: + %cmp = icmp eq i16 %c, 32767 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %call = tail call i32 @g() + br label %return + +if.end: ; preds = %entry + %call2 = tail call i32 @f() + br label %return + +return: ; preds = %if.end, %if.then + %retval.0 = phi i32 [ %call, %if.then ], [ %call2, %if.end ] + ret i32 %retval.0 +} + +declare i32 @g() + +declare i32 @f() + -- 2.7.4