summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Grosbach <grosbach@apple.com>2010-04-22 23:24:18 +0000
committerJim Grosbach <grosbach@apple.com>2010-04-22 23:24:18 +0000
commit3a1287b470bde29d10e7c6998fb69b74d2265b6c (patch)
treed00a44ac8e3298c397a18e44107ddec9c03e82ed
parentfff6c5332f748d477e6ad0bd9b60b49ae867ab42 (diff)
downloadllvm-3a1287b470bde29d10e7c6998fb69b74d2265b6c.tar.gz
llvm-3a1287b470bde29d10e7c6998fb69b74d2265b6c.tar.bz2
llvm-3a1287b470bde29d10e7c6998fb69b74d2265b6c.tar.xz
Update ARM DAGtoDAG for matching UBFX instruction for unsigned bitfield
extraction. This fixes PR5998. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@102144 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp46
-rw-r--r--test/CodeGen/ARM/bfx.ll28
-rw-r--r--test/CodeGen/Thumb2/bfx.ll28
3 files changed, 96 insertions, 6 deletions
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 859d30ea48..36a1827ce6 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -142,7 +142,7 @@ private:
unsigned *QOpcodes1);
/// SelectV6T2BitfieldExtractOp - Select SBFX/UBFX instructions for ARM.
- SDNode *SelectV6T2BitfieldExtractOp(SDNode *N, unsigned Opc);
+ SDNode *SelectV6T2BitfieldExtractOp(SDNode *N, bool isSigned);
/// SelectCMOVOp - Select CMOV instructions for ARM.
SDNode *SelectCMOVOp(SDNode *N);
@@ -1248,10 +1248,42 @@ SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad,
}
SDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDNode *N,
- unsigned Opc) {
+ bool isSigned) {
if (!Subtarget->hasV6T2Ops())
return NULL;
+ unsigned Opc = isSigned ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX)
+ : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX);
+
+
+ // For unsigned extracts, check for a shift right and mask
+ unsigned And_imm = 0;
+ if (N->getOpcode() == ISD::AND) {
+ if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) {
+
+ // The immediate is a mask of the low bits iff imm & (imm+1) == 0
+ if (And_imm & (And_imm + 1))
+ return NULL;
+
+ unsigned Srl_imm = 0;
+ if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL,
+ Srl_imm)) {
+ assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
+
+ unsigned Width = CountTrailingOnes_32(And_imm);
+ unsigned LSB = Srl_imm;
+ SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+ SDValue Ops[] = { N->getOperand(0).getOperand(0),
+ CurDAG->getTargetConstant(LSB, MVT::i32),
+ CurDAG->getTargetConstant(Width, MVT::i32),
+ getAL(CurDAG), Reg0 };
+ return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5);
+ }
+ }
+ return NULL;
+ }
+
+ // Otherwise, we're looking for a shift of a shift
unsigned Shl_imm = 0;
if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {
assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!");
@@ -1515,13 +1547,11 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
}
}
case ISD::SRL:
- if (SDNode *I = SelectV6T2BitfieldExtractOp(N,
- Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX))
+ if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false))
return I;
break;
case ISD::SRA:
- if (SDNode *I = SelectV6T2BitfieldExtractOp(N,
- Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX))
+ if (SDNode *I = SelectV6T2BitfieldExtractOp(N, true))
return I;
break;
case ISD::MUL:
@@ -1565,6 +1595,10 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
}
break;
case ISD::AND: {
+ // Check for unsigned bitfield extract
+ if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false))
+ return I;
+
// (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits
// of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits
// are entirely contributed by c2 and lower 16-bits are entirely contributed
diff --git a/test/CodeGen/ARM/bfx.ll b/test/CodeGen/ARM/bfx.ll
new file mode 100644
index 0000000000..fcca191a01
--- /dev/null
+++ b/test/CodeGen/ARM/bfx.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s -march=arm -mattr=+v7a | FileCheck %s
+
+define i32 @sbfx1(i32 %a) {
+; CHECK: sbfx1
+; CHECK: sbfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = trunc i32 %t1 to i11
+ %t3 = sext i11 %t2 to i32
+ ret i32 %t3
+}
+
+define i32 @ubfx1(i32 %a) {
+; CHECK: ubfx1
+; CHECK: ubfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = trunc i32 %t1 to i11
+ %t3 = zext i11 %t2 to i32
+ ret i32 %t3
+}
+
+define i32 @ubfx2(i32 %a) {
+; CHECK: ubfx2
+; CHECK: ubfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = and i32 %t1, 2047
+ ret i32 %t2
+}
+
diff --git a/test/CodeGen/Thumb2/bfx.ll b/test/CodeGen/Thumb2/bfx.ll
new file mode 100644
index 0000000000..489349d615
--- /dev/null
+++ b/test/CodeGen/Thumb2/bfx.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s -march=thumb -mattr=+thumb2 | FileCheck %s
+
+define i32 @sbfx1(i32 %a) {
+; CHECK: sbfx1
+; CHECK: sbfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = trunc i32 %t1 to i11
+ %t3 = sext i11 %t2 to i32
+ ret i32 %t3
+}
+
+define i32 @ubfx1(i32 %a) {
+; CHECK: ubfx1
+; CHECK: ubfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = trunc i32 %t1 to i11
+ %t3 = zext i11 %t2 to i32
+ ret i32 %t3
+}
+
+define i32 @ubfx2(i32 %a) {
+; CHECK: ubfx2
+; CHECK: ubfx r0, r0, #7, #11
+ %t1 = lshr i32 %a, 7
+ %t2 = and i32 %t1, 2047
+ ret i32 %t2
+}
+