summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason W Kim <jason.w.kim.2009@gmail.com>2011-01-11 23:53:41 +0000
committerJason W Kim <jason.w.kim.2009@gmail.com>2011-01-11 23:53:41 +0000
commit9081b4b4cf89a161246e037f4817c69de2fcdf82 (patch)
tree6bd034b86d24ae18940c927a145bb26c9a88a97e
parent2df5458535c54c1e214da65191ef86c38b57da39 (diff)
downloadllvm-9081b4b4cf89a161246e037f4817c69de2fcdf82.tar.gz
llvm-9081b4b4cf89a161246e037f4817c69de2fcdf82.tar.bz2
llvm-9081b4b4cf89a161246e037f4817c69de2fcdf82.tar.xz
Workaround for bug 8721.
.s Test added. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123292 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp106
-rw-r--r--test/MC/ARM/elf-movt.s14
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 190be65121..b51e351172 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -55,6 +55,10 @@ class ARMAsmParser : public TargetAsmParser {
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &);
+ bool ParsePrefix(MCSymbolRefExpr::VariantKind &RefKind);
+ const MCExpr *ApplyPrefixToExpr(const MCExpr *E,
+ MCSymbolRefExpr::VariantKind Variant);
+
bool ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted,
@@ -864,9 +868,111 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands){
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E));
return false;
+ case AsmToken::Colon: {
+ // ":lower16:" and ":upper16:" expression prefixes
+ MCSymbolRefExpr::VariantKind RefKind;
+ if (ParsePrefix(RefKind))
+ return true;
+
+ const MCExpr *ExprVal;
+ if (getParser().ParseExpression(ExprVal))
+ return true;
+
+ // TODO: Attach the prefix to the entire expression
+ // instead of just the first symbol.
+ const MCExpr *ModExprVal = ApplyPrefixToExpr(ExprVal, RefKind);
+ if (!ModExprVal) {
+ return TokError("invalid modifier '" + getTok().getIdentifier() +
+ "' (no symbols present)");
+ }
+
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Operands.push_back(ARMOperand::CreateImm(ModExprVal, S, E));
+ return false;
+ }
}
}
+// FIXME: The next 2 routines are hacks to get ARMAsmParser to understand
+// :lower16: and :upper16:
+// It still attaches VK_ARM_HI/LO16 to MCSymbolRefExpr, but it really
+// should be attached to the entire MCExpr as a whole - perhaps using
+// MCTargetExpr?
+bool ARMAsmParser::ParsePrefix(MCSymbolRefExpr::VariantKind &RefKind) {
+ RefKind = MCSymbolRefExpr::VK_None;
+
+ // :lower16: and :upper16: modifiers
+ if (getLexer().isNot(AsmToken::Colon)) {
+ Error(Parser.getTok().getLoc(), "expected :");
+ return true;
+ }
+ Parser.Lex(); // Eat ':'
+
+ if (getLexer().isNot(AsmToken::Identifier)) {
+ Error(Parser.getTok().getLoc(), "expected prefix identifier in operand");
+ return true;
+ }
+
+ StringRef IDVal = Parser.getTok().getIdentifier();
+ if (IDVal == "lower16") {
+ RefKind = MCSymbolRefExpr::VK_ARM_LO16;
+ } else if (IDVal == "upper16") {
+ RefKind = MCSymbolRefExpr::VK_ARM_HI16;
+ } else {
+ Error(Parser.getTok().getLoc(), "unexpected prefix in operand");
+ return true;
+ }
+ Parser.Lex();
+
+ if (getLexer().isNot(AsmToken::Colon)) {
+ Error(Parser.getTok().getLoc(), "unexpected token after prefix");
+ return true;
+ }
+ Parser.Lex(); // Eat the last ':'
+ return false;
+}
+
+const MCExpr *
+ARMAsmParser::ApplyPrefixToExpr(const MCExpr *E,
+ MCSymbolRefExpr::VariantKind Variant) {
+ // Recurse over the given expression, rebuilding it to apply the given variant
+ // to the leftmost symbol.
+ if (Variant == MCSymbolRefExpr::VK_None)
+ return E;
+
+ switch (E->getKind()) {
+ case MCExpr::Target:
+ llvm_unreachable("Can't handle target expr yet");
+ case MCExpr::Constant:
+ llvm_unreachable("Can't handle lower16/upper16 of constant yet");
+
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);
+
+ if (SRE->getKind() != MCSymbolRefExpr::VK_None)
+ return 0;
+
+ return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext());
+ }
+
+ case MCExpr::Unary:
+ llvm_unreachable("Can't handle unary expressions yet");
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);
+ const MCExpr *LHS = ApplyPrefixToExpr(BE->getLHS(), Variant);
+ const MCExpr *RHS = BE->getRHS();
+ if (!LHS)
+ return 0;
+
+ return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext());
+ }
+ }
+
+ assert(0 && "Invalid expression kind!");
+ return 0;
+}
+
/// \brief Given a mnemonic, split out possible predication code and carry
/// setting letters to form a canonical mnemonic and flags.
//
diff --git a/test/MC/ARM/elf-movt.s b/test/MC/ARM/elf-movt.s
new file mode 100644
index 0000000000..51c54298de
--- /dev/null
+++ b/test/MC/ARM/elf-movt.s
@@ -0,0 +1,14 @@
+@ RUN: llvm-mc %s -triple=armv7-linux-gnueabi | FileCheck -check-prefix=ASM %s
+ .syntax unified
+ .text
+ .globl barf
+ .align 2
+ .type barf,%function
+barf: @ @barf
+@ BB#0: @ %entry
+ movw r0, :lower16:GOT-(.LPC0_2+8)
+ movt r0, :upper16:GOT-(.LPC0_2+16)
+.LPC0_2:
+@ ASM: movw r0, :lower16:GOT-(.LPC0_2+8)
+@ ASM-NEXT: movt r0, :upper16:GOT-(.LPC0_2+16)
+