[ARM] Add additional matching for UBFX instructions

This adds an additional matcher to select UBFX(..) from SRL(AND(..)) in
ARMISelDAGToDAG to help with code size.

Patch by David Green.

Differential Revision: http://reviews.llvm.org/D20667



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271384 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Oliver Stannard 2016-06-01 12:01:01 +00:00
parent 6e55ed9516
commit 0144de5262
2 changed files with 37 additions and 0 deletions

View File

@ -2418,6 +2418,27 @@ bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
}
}
// 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<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
unsigned LSB = 0;

View File

@ -51,3 +51,19 @@ entry:
%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
}