diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 59f78a8ca306c5..4345b8e66f6a0b 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -880,30 +880,73 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const MipsSubtarget &Subtarget) { - // Pattern match INS. - // $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1), - // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 - // => ins $dst, $src, size, pos, $src1 if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert()) return SDValue(); - SDValue And0 = N->getOperand(0), And1 = N->getOperand(1); + SDValue FirstOperand = N->getOperand(0), SecondOperand = N->getOperand(1); unsigned SMPos0, SMSize0, SMPos1, SMSize1; ConstantSDNode *CN, *CN1; + if ((FirstOperand.getOpcode() == ISD::AND && + SecondOperand.getOpcode() == ISD::SHL) || + (FirstOperand.getOpcode() == ISD::SHL && + SecondOperand.getOpcode() == ISD::AND)) { + // Pattern match INS. + // $dst = or (and $src1, (2**size0 - 1)), (shl $src2, size0) + // ==> ins $src1, $src2, pos, size, pos = size0, size = 32 - pos; + // Or: + // $dst = or (shl $src2, size0), (and $src1, (2**size0 - 1)) + // ==> ins $src1, $src2, pos, size, pos = size0, size = 32 - pos; + SDValue AndOperand0 = FirstOperand.getOpcode() == ISD::AND + ? FirstOperand.getOperand(0) + : SecondOperand.getOperand(0); + SDValue ShlOperand0 = FirstOperand.getOpcode() == ISD::AND + ? SecondOperand.getOperand(0) + : FirstOperand.getOperand(0); + SDValue AndMask = FirstOperand.getOpcode() == ISD::AND + ? FirstOperand.getOperand(1) + : SecondOperand.getOperand(1); + if (!(CN = dyn_cast(AndMask)) || + !isShiftedMask_64(CN->getZExtValue(), SMPos0, SMSize0)) + return SDValue(); + + SDValue ShlShift = FirstOperand.getOpcode() == ISD::AND + ? SecondOperand.getOperand(1) + : FirstOperand.getOperand(1); + if (!(CN = dyn_cast(ShlShift))) + return SDValue(); + uint64_t ShlShiftValue = CN->getZExtValue(); + + if (SMPos0 != 0 || SMSize0 != ShlShiftValue) + return SDValue(); + + SDLoc DL(N); + EVT ValTy = N->getValueType(0); + SMPos1 = ShlShiftValue; + assert(SMPos1 < ValTy.getSizeInBits()); + SMSize1 = (ValTy == MVT::i64 ? 64 : 32) - SMPos1; + return DAG.getNode(MipsISD::Ins, DL, ValTy, ShlOperand0, + DAG.getConstant(SMPos1, DL, MVT::i32), + DAG.getConstant(SMSize1, DL, MVT::i32), AndOperand0); + } + // See if Op's first operand matches (and $src1 , mask0). - if (And0.getOpcode() != ISD::AND) + if (FirstOperand.getOpcode() != ISD::AND) return SDValue(); - if (!(CN = dyn_cast(And0.getOperand(1))) || + // Pattern match INS. + // $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1), + // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 + // => ins $dst, $src, size, pos, $src1 + if (!(CN = dyn_cast(FirstOperand.getOperand(1))) || !isShiftedMask_64(~CN->getSExtValue(), SMPos0, SMSize0)) return SDValue(); // See if Op's second operand matches (and (shl $src, pos), mask1). - if (And1.getOpcode() == ISD::AND && - And1.getOperand(0).getOpcode() == ISD::SHL) { + if (SecondOperand.getOpcode() == ISD::AND && + SecondOperand.getOperand(0).getOpcode() == ISD::SHL) { - if (!(CN = dyn_cast(And1.getOperand(1))) || + if (!(CN = dyn_cast(SecondOperand.getOperand(1))) || !isShiftedMask_64(CN->getZExtValue(), SMPos1, SMSize1)) return SDValue(); @@ -911,7 +954,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, if (SMPos0 != SMPos1 || SMSize0 != SMSize1) return SDValue(); - SDValue Shl = And1.getOperand(0); + SDValue Shl = SecondOperand.getOperand(0); if (!(CN = dyn_cast(Shl.getOperand(1)))) return SDValue(); @@ -928,7 +971,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, return DAG.getNode(MipsISD::Ins, DL, ValTy, Shl.getOperand(0), DAG.getConstant(SMPos0, DL, MVT::i32), DAG.getConstant(SMSize0, DL, MVT::i32), - And0.getOperand(0)); + FirstOperand.getOperand(0)); } else { // Pattern match DINS. // $dst = or (and $src, mask0), mask1 @@ -938,9 +981,9 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, ((SMSize0 + SMPos0 <= 64 && Subtarget.hasMips64r2()) || (SMSize0 + SMPos0 <= 32))) { // Check if AND instruction has constant as argument - bool isConstCase = And1.getOpcode() != ISD::AND; - if (And1.getOpcode() == ISD::AND) { - if (!(CN1 = dyn_cast(And1->getOperand(1)))) + bool isConstCase = SecondOperand.getOpcode() != ISD::AND; + if (SecondOperand.getOpcode() == ISD::AND) { + if (!(CN1 = dyn_cast(SecondOperand->getOperand(1)))) return SDValue(); } else { if (!(CN1 = dyn_cast(N->getOperand(1)))) @@ -957,7 +1000,8 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, SDValue SrlX; if (!isConstCase) { Const1 = DAG.getConstant(SMPos0, DL, MVT::i32); - SrlX = DAG.getNode(ISD::SRL, DL, And1->getValueType(0), And1, Const1); + SrlX = DAG.getNode(ISD::SRL, DL, SecondOperand->getValueType(0), + SecondOperand, Const1); } return DAG.getNode( MipsISD::Ins, DL, N->getValueType(0), @@ -968,8 +1012,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, DAG.getConstant(ValTy.getSizeInBits() / 8 < 8 ? SMSize0 & 31 : SMSize0, DL, MVT::i32), - And0->getOperand(0)); - + FirstOperand->getOperand(0)); } return SDValue(); } diff --git a/llvm/test/CodeGen/Mips/ins.ll b/llvm/test/CodeGen/Mips/ins.ll new file mode 100644 index 00000000000000..615dc8f3d6ac5a --- /dev/null +++ b/llvm/test/CodeGen/Mips/ins.ll @@ -0,0 +1,60 @@ +; RUN: llc -O3 -mcpu=mips32r2 -mtriple=mipsel-linux-gnu < %s -o - \ +; RUN: | FileCheck %s --check-prefixes=MIPS32R2 +; RUN: llc -O3 -mcpu=mips64r2 -march=mips64el < %s \ +; RUN: | FileCheck %s --check-prefixes=MIPS64R2 + +define i32 @or_and_shl(i32 %a, i32 %b) { +; MIPS32R2-LABEL: or_and_shl: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: ins $4, $5, 31, 1 +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: move $2, $4 + +entry: + %shl = shl i32 %b, 31 + %and = and i32 %a, 2147483647 + %or = or i32 %and, %shl + ret i32 %or +} + +define i32 @or_shl_and(i32 %a, i32 %b) { +; MIPS32R2-LABEL: or_shl_and: +; MIPS32R2: # %bb.0: # %entry +; MIPS32R2-NEXT: ins $4, $5, 31, 1 +; MIPS32R2-NEXT: jr $ra +; MIPS32R2-NEXT: move $2, $4 + +entry: + %shl = shl i32 %b, 31 + %and = and i32 %a, 2147483647 + %or = or i32 %shl, %and + ret i32 %or +} + +define i64 @dinsm(i64 %a, i64 %b) { +; MIPS64R2-LABEL: dinsm: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: dinsm $4, $5, 17, 47 +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: move $2, $4 + +entry: + %shl = shl i64 %b, 17 + %and = and i64 %a, 131071 + %or = or i64 %shl, %and + ret i64 %or +} + +define i64 @dinsu(i64 %a, i64 %b) { +; MIPS64R2-LABEL: dinsu: +; MIPS64R2: # %bb.0: # %entry +; MIPS64R2-NEXT: dinsu $4, $5, 35, 29 +; MIPS64R2-NEXT: jr $ra +; MIPS64R2-NEXT: move $2, $4 + +entry: + %shl = shl i64 %b, 35 + %and = and i64 %a, 34359738367 + %or = or i64 %shl, %and + ret i64 %or +}