diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 47f7eca09a1..c4f7b01352a 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(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(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 f89702853d4..da3fe016d0f 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(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(Expr); + int64_t TargetAddress; + if (!Constant->EvaluateAsAbsolute(TargetAddress)) { + O << '#' << *Expr; + } else { + O << "0x"; + O.write_hex(static_cast(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 00000000000..2a721c4e101 --- /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 +