Index: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -2418,6 +2418,27 @@ } } + // Or we are looking for a shift of an and, with a mask operand + if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, And_imm) && + isShiftedMask_32(And_imm)) { + unsigned Srl_imm = 0; + unsigned LSB = countTrailingZeros(And_imm); + // Shift must be the same as the ands lsb + if (isInt32Immediate(N->getOperand(1), Srl_imm) && Srl_imm == LSB) { + assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); + unsigned MSB = 31 - countLeadingZeros(And_imm); + // Note: The width operand is encoded as width-1. + unsigned Width = MSB - LSB; + SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); + SDValue Ops[] = { N->getOperand(0).getOperand(0), + CurDAG->getTargetConstant(Srl_imm, dl, MVT::i32), + CurDAG->getTargetConstant(Width, dl, MVT::i32), + getAL(CurDAG, dl), Reg0 }; + CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops); + return true; + } + } + if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) { unsigned Width = cast(N->getOperand(1))->getVT().getSizeInBits(); unsigned LSB = 0; Index: llvm/trunk/test/CodeGen/ARM/bfx.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/bfx.ll +++ llvm/trunk/test/CodeGen/ARM/bfx.ll @@ -51,3 +51,19 @@ %add7 = add i32 %add, %2 ret i32 %add7 } + +define i32 @ubfx3(i32 %a) { +; CHECK: ubfx3 +; CHECK: ubfx r0, r0, #11, #1 + %t1 = and i32 %a, 2048 + %t2 = lshr i32 %t1, 11 + ret i32 %t2 +} + +define i32 @ubfx4(i32 %a) { +; CHECK: ubfx4 +; CHECK: ubfx r0, r0, #7, #3 + %t1 = and i32 %a, 896 + %t2 = lshr i32 %t1, 7 + ret i32 %t2 +}