summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp24
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp33
-rw-r--r--test/MC/ARM/complex-operands.s40
3 files changed, 81 insertions, 16 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 47f7eca09a..c4f7b01352 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -8775,12 +8775,24 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp,
// If the kind is a token for a literal immediate, check if our asm
// operand matches. This is for InstAliases which have a fixed-value
// immediate in the syntax.
- if (Kind == MCK__35_0 && Op->isImm()) {
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
- if (!CE)
- return Match_InvalidOperand;
- if (CE->getValue() == 0)
- return Match_Success;
+ switch (Kind) {
+ default: break;
+ case MCK__35_0:
+ if (Op->isImm())
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm()))
+ if (CE->getValue() == 0)
+ return Match_Success;
+ break;
+ case MCK_ARMSOImm:
+ if (Op->isImm()) {
+ const MCExpr *SOExpr = Op->getImm();
+ int64_t Value;
+ if (!SOExpr->EvaluateAsAbsolute(Value))
+ return Match_Success;
+ assert((Value >= INT32_MIN && Value <= INT32_MAX) &&
+ "expression value must be representiable in 32 bits");
+ }
+ break;
}
return Match_InvalidOperand;
}
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
index f89702853d..da3fe016d0 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
@@ -307,17 +307,30 @@ void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
<< markup(">");
} else {
assert(Op.isExpr() && "unknown operand kind in printOperand");
- // If a symbolic branch target was added as a constant expression then print
- // that address in hex. And only print 32 unsigned bits for the address.
- const MCConstantExpr *BranchTarget = dyn_cast<MCConstantExpr>(Op.getExpr());
- int64_t Address;
- if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) {
- O << "0x";
- O.write_hex((uint32_t)Address);
+ const MCExpr *Expr = Op.getExpr();
+ switch (Expr->getKind()) {
+ case MCExpr::Binary:
+ O << '#' << *Expr;
+ break;
+ case MCExpr::Constant: {
+ // If a symbolic branch target was added as a constant expression then
+ // print that address in hex. And only print 32 unsigned bits for the
+ // address.
+ const MCConstantExpr *Constant = cast<MCConstantExpr>(Expr);
+ int64_t TargetAddress;
+ if (!Constant->EvaluateAsAbsolute(TargetAddress)) {
+ O << '#' << *Expr;
+ } else {
+ O << "0x";
+ O.write_hex(static_cast<uint32_t>(TargetAddress));
+ }
+ break;
}
- else {
- // Otherwise, just print the expression.
- O << *Op.getExpr();
+ default:
+ // FIXME: Should we always treat this as if it is a constant literal and
+ // prefix it with '#'?
+ O << *Expr;
+ break;
}
}
}
diff --git a/test/MC/ARM/complex-operands.s b/test/MC/ARM/complex-operands.s
new file mode 100644
index 0000000000..2a721c4e10
--- /dev/null
+++ b/test/MC/ARM/complex-operands.s
@@ -0,0 +1,40 @@
+@ RUN: llvm-mc -triple armv7-eabi -filetype asm -o - %s | FileCheck %s
+
+ .syntax unified
+
+ .data
+
+ .type .L_table_begin,%object
+.L_table_begin:
+ .rep 2
+ .long 0xd15ab1ed
+ .long 0x0ff1c1a1
+ .endr
+.L_table_end:
+
+ .text
+
+ .type return,%function
+return:
+ bx lr
+
+ .global arm_function
+ .type arm_function,%function
+arm_function:
+ mov r0, #(.L_table_end - .L_table_begin) >> 2
+ blx return
+
+@ CHECK-LABEL: arm_function
+@ CHECK: movw r0, #(.L_table_end-.L_table_begin)>>2
+@ CHECK: blx return
+
+ .global thumb_function
+ .type thumb_function,%function
+thumb_function:
+ mov r0, #(.L_table_end - .L_table_begin) >> 2
+ blx return
+
+@ CHECK-LABEL: thumb_function
+@ CHECK: movw r0, #(.L_table_end-.L_table_begin)>>2
+@ CHECK: blx return
+