aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMAddressingModes.h37
-rw-r--r--lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp2
-rw-r--r--test/MC/Disassembler/arm-tests.txt3
3 files changed, 41 insertions, 1 deletions
diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h
index ea62c3330e..45b37b1cef 100644
--- a/lib/Target/ARM/ARMAddressingModes.h
+++ b/lib/Target/ARM/ARMAddressingModes.h
@@ -193,6 +193,43 @@ namespace ARM_AM {
return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
}
+ /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter
+ /// operand, computing the rotate amount to use. If this immediate value
+ /// cannot be handled with a single shifter-op, return 0.
+ static unsigned getSOImmValOneRotate(unsigned Imm) {
+ // A5.2.4 Constants with multiple encodings
+ // The lowest unsigned value of rotation wins!
+ for (unsigned R = 1; R <= 15; ++R)
+ if ((Imm & rotr32(~255U, 2*R)) == 0)
+ return 2*R;
+
+ // Failed to find a suitable rotate amount.
+ return 0;
+ }
+
+ /// getSOImmValOneOrNoRotate - Given a 32-bit immediate, if it is something
+ /// that can fit into a shifter_operand immediate operand, return the 12-bit
+ /// encoding for it. If not, return -1. This is different from getSOImmVal()
+ /// in that getSOImmVal() is used during codegen, for example,
+ /// rewriteARMFrameIndex() where return value of -1 is not considered fatal.
+ ///
+ /// The current consumer of this API is printSOImm() within ARMInstPrinter.cpp
+ /// where return value of -1 indicates that the Arg is not a valid so_imm val!
+ static inline int getSOImmValOneOrNoRotate(unsigned Arg) {
+ // 8-bit (or less) immediates are trivially shifter_operands with a rotate
+ // of zero.
+ if ((Arg & ~255U) == 0) return Arg;
+
+ unsigned RotAmt = getSOImmValOneRotate(Arg);
+
+ // If this cannot be handled with a single shifter_op, bail out.
+ if (rotr32(~255U, RotAmt) & Arg)
+ return -1;
+
+ // Encode this correctly.
+ return rotl32(Arg, RotAmt) | ((RotAmt>>1) << 8);
+ }
+
/// isSOImmTwoPartVal - Return true if the specified value can be obtained by
/// or'ing together two SOImmVal's.
static inline bool isSOImmTwoPartVal(unsigned V) {
diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp
index ef5ead6e47..c73fa13091 100644
--- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp
+++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp
@@ -225,7 +225,7 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm,
const MCAsmInfo *MAI) {
// Break it up into two parts that make up a shifter immediate.
- V = ARM_AM::getSOImmVal(V);
+ V = ARM_AM::getSOImmValOneOrNoRotate(V);
assert(V != -1 && "Not a valid so_imm value!");
unsigned Imm = ARM_AM::getSOImmValImm(V);
diff --git a/test/MC/Disassembler/arm-tests.txt b/test/MC/Disassembler/arm-tests.txt
index 094a2d7372..7d10107bad 100644
--- a/test/MC/Disassembler/arm-tests.txt
+++ b/test/MC/Disassembler/arm-tests.txt
@@ -27,6 +27,9 @@
# CHECK: movt r8, #65535
0xff 0x8f 0x4f 0xe3
+# CHECK: mvnpls r7, #245, 2
+0xf5 0x71 0xf0 0x53
+
# CHECK: pkhbt r8, r9, r10, lsl #4
0x1a 0x82 0x89 0xe6