From 856bf594338567a592086fe782f2f51650e4e294 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 13 Sep 2013 09:09:50 +0000 Subject: [PATCH] [SystemZ] Try to fold shifts into TMxx E.g. "SRL %r2, 2; TMLL %r2, 1" => "TMLL %r2, 4". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190672 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SystemZ/SystemZISelLowering.cpp | 77 ++++++++++++++++------ test/CodeGen/SystemZ/int-cmp-46.ll | 40 +++++++++++ test/CodeGen/SystemZ/int-cmp-47.ll | 40 +++++++++++ 3 files changed, 137 insertions(+), 20 deletions(-) diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 5528404a195..131fd5cf7ae 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1135,17 +1135,37 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, return false; } -// Check whether the CC value produced by TEST UNDER MASK is descriptive -// enough to handle an AND with Mask followed by a comparison of type Opcode -// with CmpVal. CCMask says which comparison result is being tested and -// BitSize is the number of bits in the operands. Return the CC mask that -// should be used for the TEST UNDER MASK result, or 0 if the condition is -// too complex. +// Return true if shift operation N has an in-range constant shift value. +// Store it in ShiftVal if so. +static bool isSimpleShift(SDValue N, unsigned &ShiftVal) { + ConstantSDNode *Shift = dyn_cast(N.getOperand(1)); + if (!Shift) + return false; + + uint64_t Amount = Shift->getZExtValue(); + if (Amount >= N.getValueType().getSizeInBits()) + return false; + + ShiftVal = Amount; + return true; +} + +// Check whether an AND with Mask is suitable for a TEST UNDER MASK +// instruction and whether the CC value is descriptive enough to handle +// a comparison of type Opcode between the AND result and CmpVal. +// CCMask says which comparison result is being tested and BitSize is +// the number of bits in the operands. If TEST UNDER MASK can be used, +// return the corresponding CC mask, otherwise return 0. static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask, uint64_t Mask, uint64_t CmpVal, unsigned ICmpType) { assert(Mask != 0 && "ANDs with zero should have been removed by now"); + // Check whether the mask is suitable for TMHH, TMHL, TMLH or TMLL. + if (!SystemZ::isImmLL(Mask) && !SystemZ::isImmLH(Mask) && + !SystemZ::isImmHL(Mask) && !SystemZ::isImmHH(Mask)) + return 0; + // Work out the masks for the lowest and highest bits. unsigned HighShift = 63 - countLeadingZeros(Mask); uint64_t High = uint64_t(1) << HighShift; @@ -1230,13 +1250,15 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask, // implemented as a TEST UNDER MASK instruction when the condition being // tested is as described by CCValid and CCMask. Update the arguments // with the TM version if so. -static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, - SDValue &CmpOp1, unsigned &CCValid, - unsigned &CCMask, unsigned &ICmpType) { +static void adjustForTestUnderMask(SelectionDAG &DAG, unsigned &Opcode, + SDValue &CmpOp0, SDValue &CmpOp1, + unsigned &CCValid, unsigned &CCMask, + unsigned &ICmpType) { // Check that we have a comparison with a constant. ConstantSDNode *ConstCmpOp1 = dyn_cast(CmpOp1); if (!ConstCmpOp1) return; + uint64_t CmpVal = ConstCmpOp1->getZExtValue(); // Check whether the nonconstant input is an AND with a constant mask. if (CmpOp0.getOpcode() != ISD::AND) @@ -1246,21 +1268,35 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, ConstantSDNode *Mask = dyn_cast(AndOp1.getNode()); if (!Mask) return; - - // Check whether the mask is suitable for TMHH, TMHL, TMLH or TMLL. uint64_t MaskVal = Mask->getZExtValue(); - if (!SystemZ::isImmLL(MaskVal) && !SystemZ::isImmLH(MaskVal) && - !SystemZ::isImmHL(MaskVal) && !SystemZ::isImmHH(MaskVal)) - return; // Check whether the combination of mask, comparison value and comparison // type are suitable. unsigned BitSize = CmpOp0.getValueType().getSizeInBits(); - unsigned NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal, - ConstCmpOp1->getZExtValue(), - ICmpType); - if (!NewCCMask) - return; + unsigned NewCCMask, ShiftVal; + if (ICmpType != SystemZICMP::SignedOnly && + AndOp0.getOpcode() == ISD::SHL && + isSimpleShift(AndOp0, ShiftVal) && + (NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal >> ShiftVal, + CmpVal >> ShiftVal, + SystemZICMP::Any))) { + AndOp0 = AndOp0.getOperand(0); + AndOp1 = DAG.getConstant(MaskVal >> ShiftVal, AndOp0.getValueType()); + } else if (ICmpType != SystemZICMP::SignedOnly && + AndOp0.getOpcode() == ISD::SRL && + isSimpleShift(AndOp0, ShiftVal) && + (NewCCMask = getTestUnderMaskCond(BitSize, CCMask, + MaskVal << ShiftVal, + CmpVal << ShiftVal, + SystemZICMP::UnsignedOnly))) { + AndOp0 = AndOp0.getOperand(0); + AndOp1 = DAG.getConstant(MaskVal << ShiftVal, AndOp0.getValueType()); + } else { + NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal, CmpVal, + ICmpType); + if (!NewCCMask) + return; + } // Go ahead and make the change. Opcode = SystemZISD::TM; @@ -1316,7 +1352,8 @@ static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG, (CCMask & SystemZ::CCMASK_CMP_UO)); } - adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType); + adjustForTestUnderMask(DAG, Opcode, CmpOp0, CmpOp1, CCValid, CCMask, + ICmpType); if (Opcode == SystemZISD::ICMP || Opcode == SystemZISD::TM) return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1, DAG.getConstant(ICmpType, MVT::i32)); diff --git a/test/CodeGen/SystemZ/int-cmp-46.ll b/test/CodeGen/SystemZ/int-cmp-46.ll index 339ba11694a..f311942b9f8 100644 --- a/test/CodeGen/SystemZ/int-cmp-46.ll +++ b/test/CodeGen/SystemZ/int-cmp-46.ll @@ -449,3 +449,43 @@ store: exit: ret void } + +; Check that we can fold an SHL into a TMxx mask. +define void @f24(i32 %a) { +; CHECK-LABEL: f24: +; CHECK: tmll %r2, 255 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %shl = shl i32 %a, 12 + %and = and i32 %shl, 1044480 + %cmp = icmp ne i32 %and, 0 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can fold an SHR into a TMxx mask. +define void @f25(i32 %a) { +; CHECK-LABEL: f25: +; CHECK: tmlh %r2, 512 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %shr = lshr i32 %a, 25 + %and = and i32 %shr, 1 + %cmp = icmp ne i32 %and, 0 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} diff --git a/test/CodeGen/SystemZ/int-cmp-47.ll b/test/CodeGen/SystemZ/int-cmp-47.ll index bf206ed9db6..c770ccdbb96 100644 --- a/test/CodeGen/SystemZ/int-cmp-47.ll +++ b/test/CodeGen/SystemZ/int-cmp-47.ll @@ -191,3 +191,43 @@ store: exit: ret void } + +; Check that we can fold an SHL into a TMxx mask. +define void @f11(i64 %a) { +; CHECK-LABEL: f11: +; CHECK: tmhl %r2, 32768 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %shl = shl i64 %a, 1 + %and = and i64 %shl, 281474976710656 + %cmp = icmp ne i64 %and, 0 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +} + +; Check that we can fold an SHR into a TMxx mask. +define void @f12(i64 %a) { +; CHECK-LABEL: f12: +; CHECK: tmhh %r2, 256 +; CHECK: jne {{\.L.*}} +; CHECK: br %r14 +entry: + %shr = lshr i64 %a, 56 + %and = and i64 %shr, 1 + %cmp = icmp ne i64 %and, 0 + br i1 %cmp, label %exit, label %store + +store: + store i32 1, i32 *@g + br label %exit + +exit: + ret void +}