From 71386b0e04902e6b68148f17872b80051c38d5c2 Mon Sep 17 00:00:00 2001 From: Pawel Bylica <chfast@gmail.com> Date: Thu, 9 Jul 2015 08:01:36 +0000 Subject: [PATCH] Fix shift legalization and lowering for big constants. Summary: If shift amount is a constant value > 64 bit it is handled incorrectly during type legalization and X86 lowering. This patch the type of shift amount argument in function DAGTypeLegalizer::ExpandShiftByConstant from unsigned to APInt. Reviewers: nadav, majnemer, sanjoy, RKSimon Subscribers: RKSimon, llvm-commits Differential Revision: http://reviews.llvm.org/D10767 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241790 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../SelectionDAG/LegalizeIntegerTypes.cpp | 31 +++++++------ lib/CodeGen/SelectionDAG/LegalizeTypes.h | 4 +- lib/Target/X86/X86ISelLowering.cpp | 2 +- test/CodeGen/X86/legalize-shl-vec.ll | 44 +++++++++++++++++++ 4 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 test/CodeGen/X86/legalize-shl-vec.ll diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index f97e0d6fb06..f234e005b32 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1358,9 +1358,9 @@ std::pair <SDValue, SDValue> DAGTypeLegalizer::ExpandAtomic(SDNode *Node) { return ExpandChainLibCall(LC, Node, false); } -/// ExpandShiftByConstant - N is a shift by a value that needs to be expanded, +/// N is a shift by a value that needs to be expanded, /// and the shift amount is a constant 'Amt'. Expand the operation. -void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, +void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, const APInt &Amt, SDValue &Lo, SDValue &Hi) { SDLoc DL(N); // Expand the incoming operand to be shifted, so that we have its parts @@ -1381,12 +1381,12 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, EVT ShTy = N->getOperand(1).getValueType(); if (N->getOpcode() == ISD::SHL) { - if (Amt > VTBits) { + if (Amt.ugt(VTBits)) { Lo = Hi = DAG.getConstant(0, DL, NVT); - } else if (Amt > NVTBits) { + } else if (Amt.ugt(NVTBits)) { Lo = DAG.getConstant(0, DL, NVT); Hi = DAG.getNode(ISD::SHL, DL, - NVT, InL, DAG.getConstant(Amt - NVTBits, DL, ShTy)); + NVT, InL, DAG.getConstant(-Amt + NVTBits, DL, ShTy)); } else if (Amt == NVTBits) { Lo = DAG.getConstant(0, DL, NVT); Hi = InL; @@ -1405,16 +1405,15 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SRL, DL, NVT, InL, - DAG.getConstant(NVTBits - Amt, DL, ShTy))); + DAG.getConstant(-Amt + NVTBits, DL, ShTy))); } return; } if (N->getOpcode() == ISD::SRL) { - if (Amt > VTBits) { - Lo = DAG.getConstant(0, DL, NVT); - Hi = DAG.getConstant(0, DL, NVT); - } else if (Amt > NVTBits) { + if (Amt.ugt(VTBits)) { + Lo = Hi = DAG.getConstant(0, DL, NVT); + } else if (Amt.ugt(NVTBits)) { Lo = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt - NVTBits, DL, ShTy)); Hi = DAG.getConstant(0, DL, NVT); @@ -1426,19 +1425,19 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SHL, DL, NVT, InH, - DAG.getConstant(NVTBits - Amt, DL, ShTy))); + DAG.getConstant(-Amt + NVTBits, DL, ShTy))); Hi = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)); } return; } assert(N->getOpcode() == ISD::SRA && "Unknown shift!"); - if (Amt > VTBits) { + if (Amt.ugt(VTBits)) { Hi = Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits - 1, DL, ShTy)); - } else if (Amt > NVTBits) { + } else if (Amt.ugt(NVTBits)) { Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, - DAG.getConstant(Amt-NVTBits, DL, ShTy)); + DAG.getConstant(Amt - NVTBits, DL, ShTy)); Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits - 1, DL, ShTy)); } else if (Amt == NVTBits) { @@ -1450,7 +1449,7 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SHL, DL, NVT, InH, - DAG.getConstant(NVTBits - Amt, DL, ShTy))); + DAG.getConstant(-Amt + NVTBits, DL, ShTy))); Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)); } } @@ -2178,7 +2177,7 @@ void DAGTypeLegalizer::ExpandIntRes_Shift(SDNode *N, // If we can emit an efficient shift operation, do so now. Check to see if // the RHS is a constant. if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) - return ExpandShiftByConstant(N, CN->getZExtValue(), Lo, Hi); + return ExpandShiftByConstant(N, CN->getAPIntValue(), Lo, Hi); // If we can determine that the high bit of the shift is zero or one, even if // the low bits are variable, emit this shift in an optimized form. diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 496639b5fb8..d1131a74cf1 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -167,7 +167,7 @@ private: SDValue GetVectorElementPointer(SDValue VecPtr, EVT EltVT, SDValue Index); SDValue JoinIntegers(SDValue Lo, SDValue Hi); SDValue LibCallify(RTLIB::Libcall LC, SDNode *N, bool isSigned); - + std::pair<SDValue, SDValue> ExpandChainLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned); std::pair<SDValue, SDValue> ExpandAtomic(SDNode *Node); @@ -347,7 +347,7 @@ private: void ExpandIntRes_ATOMIC_LOAD (SDNode *N, SDValue &Lo, SDValue &Hi); - void ExpandShiftByConstant(SDNode *N, unsigned Amt, + void ExpandShiftByConstant(SDNode *N, const APInt &Amt, SDValue &Lo, SDValue &Hi); bool ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi); bool ExpandShiftWithUnknownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi); diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index e58189f55c1..559056d6b2f 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -23167,7 +23167,7 @@ static SDValue PerformSHLCombine(SDNode *N, SelectionDAG &DAG) { // We shift all of the values by one. In many cases we do not have // hardware support for this operation. This is better expressed as an ADD // of two values. - if (N1SplatC->getZExtValue() == 1) + if (N1SplatC->getAPIntValue() == 1) return DAG.getNode(ISD::ADD, SDLoc(N), VT, N0, N0); } diff --git a/test/CodeGen/X86/legalize-shl-vec.ll b/test/CodeGen/X86/legalize-shl-vec.ll new file mode 100644 index 00000000000..7ec2a663513 --- /dev/null +++ b/test/CodeGen/X86/legalize-shl-vec.ll @@ -0,0 +1,44 @@ +; RUN: llc < %s -march=x86-64 | FileCheck %s + +define <2 x i256> @test_shl(<2 x i256> %In) { + %Amt = insertelement <2 x i256> undef, i256 -1, i32 0 + %Out = shl <2 x i256> %In, %Amt + ret <2 x i256> %Out + + ; CHECK-LABEL: test_shl + ; CHECK: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK: retq +} + +define <2 x i256> @test_srl(<2 x i256> %In) { + %Amt = insertelement <2 x i256> undef, i256 -1, i32 0 + %Out = lshr <2 x i256> %In, %Amt + ret <2 x i256> %Out + + ; CHECK-LABEL: test_srl + ; CHECK: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK-NEXT: movq $0 + ; CHECK: retq +} + +define <2 x i256> @test_sra(<2 x i256> %In) { + %Amt = insertelement <2 x i256> undef, i256 -1, i32 0 + %Out = ashr <2 x i256> %In, %Amt + ret <2 x i256> %Out + + ; CHECK-LABEL: test_sra + ; CHECK: sarq $63 +} -- 2.34.1