diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 22efa48709e..f4a12ed77c5 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -4727,16 +4727,37 @@ static SDValue PerformORCombine(SDNode *N, // Case (1): or (and A, mask), val => ARMbfi A, val, mask if ((C = dyn_cast(N1))) { unsigned Val = C->getZExtValue(); - if (!ARM::isBitFieldInvertedMask(Mask) || (Val & ~Mask) != Val) + if ((Val & ~Mask) != Val) return SDValue(); - Val >>= CountTrailingZeros_32(~Mask); - Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), - DAG.getConstant(Val, MVT::i32), - DAG.getConstant(Mask, MVT::i32)); + if (ARM::isBitFieldInvertedMask(Mask)) { + Val >>= CountTrailingZeros_32(~Mask); - // Do not add new nodes to DAG combiner worklist. - DCI.CombineTo(N, Res, false); + Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), + DAG.getConstant(Val, MVT::i32), + DAG.getConstant(Mask, MVT::i32)); + + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } else if (N0.getOperand(0).getOpcode() == ISD::SHL && + isa(N0.getOperand(0).getOperand(1)) && + ARM::isBitFieldInvertedMask(~Mask)) { + // Case (3): or (and (shl A, #shamt), mask), B => ARMbfi B, A, ~mask + // where lsb(mask) == #shamt + SDValue ShAmt = N0.getOperand(0).getOperand(1); + unsigned ShAmtC = cast(ShAmt)->getZExtValue(); + unsigned LSB = CountTrailingZeros_32(Mask); + if (ShAmtC != LSB) + return SDValue(); + //unsigned Width = (32 - CountLeadingZeros_32(Mask)) - LSB; + + Res = DAG.getNode(ARMISD::BFI, DL, VT, N1, + N0.getOperand(0).getOperand(0), + DAG.getConstant(~Mask, MVT::i32)); + + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } } else if (N1.getOpcode() == ISD::AND) { // case (2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask C = dyn_cast(N1.getOperand(1)); diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 4da445f5882..f93d8ff2e30 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -225,16 +225,6 @@ def sext_16_node : PatLeaf<(i32 GPR:$a), [{ return CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17; }]>; -/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield -/// e.g., 0xf000ffff -def bf_inv_mask_imm : Operand, - PatLeaf<(imm), [{ - return ARM::isBitFieldInvertedMask(N->getZExtValue()); -}] > { - let EncoderMethod = "getBitfieldInvertedMaskOpValue"; - let PrintMethod = "printBitfieldInvMaskImmOperand"; -} - /// Split a 32-bit immediate into two 16 bit parts. def hi16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32); @@ -462,6 +452,16 @@ def movt_imm : Operand { let EncoderMethod = "getMovtImmOpValue"; } +/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield +/// e.g., 0xf000ffff +def bf_inv_mask_imm : Operand, + PatLeaf<(imm), [{ + return ARM::isBitFieldInvertedMask(N->getZExtValue()); +}] > { + let EncoderMethod = "getBitfieldInvertedMaskOpValue"; + let PrintMethod = "printBitfieldInvMaskImmOperand"; +} + // Define ARM specific addressing modes. diff --git a/test/CodeGen/ARM/bfi.ll b/test/CodeGen/ARM/bfi.ll index 0e36283a39f..157c90c7531 100644 --- a/test/CodeGen/ARM/bfi.ll +++ b/test/CodeGen/ARM/bfi.ll @@ -16,7 +16,7 @@ entry: ret void } -define i32 @f2(i32 %A, i32 %B) nounwind readnone optsize { +define i32 @f2(i32 %A, i32 %B) nounwind { entry: ; CHECK: f2 ; CHECK: lsr{{.*}}#7 @@ -27,7 +27,7 @@ entry: ret i32 %or } -define i32 @f3(i32 %A, i32 %B) nounwind readnone optsize { +define i32 @f3(i32 %A, i32 %B) nounwind { entry: ; CHECK: f3 ; CHECK: lsr{{.*}} #7 @@ -38,3 +38,14 @@ entry: %or = or i32 %and2, %and ; [#uses=1] ret i32 %or } + +; rdar://8752056 +define i32 @f4(i32 %a) nounwind { +; CHECK: f4 +; CHECK: movw r1, #3137 +; CHECK: bfi r1, r0, #15, #5 + %1 = shl i32 %a, 15 + %ins7 = and i32 %1, 1015808 + %ins12 = or i32 %ins7, 3137 + ret i32 %ins12 +} diff --git a/test/CodeGen/Thumb2/bfi.ll b/test/CodeGen/Thumb2/bfi.ll index 22473bb35a0..6fb2fc888d9 100644 --- a/test/CodeGen/Thumb2/bfi.ll +++ b/test/CodeGen/Thumb2/bfi.ll @@ -38,3 +38,14 @@ entry: %or = or i32 %and2, %and ; [#uses=1] ret i32 %or } + +; rdar://8752056 +define i32 @f4(i32 %a) nounwind { +; CHECK: f4 +; CHECK: movw r1, #3137 +; CHECK: bfi r1, r0, #15, #5 + %1 = shl i32 %a, 15 + %ins7 = and i32 %1, 1015808 + %ins12 = or i32 %ins7, 3137 + ret i32 %ins12 +}