mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-22 10:29:35 +00:00
MC/AsmParser: Add support for 'a + 4@GOTPCREL' and friends, by reconsing the
expression to include the modifier. - Gross, but this a corner case we don't expect to see often in practice, but it is worth accepting. - Also improves diagnostics on invalid modifiers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@114154 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
96b5f7113a
commit
cceba83893
@ -204,6 +204,9 @@ private:
|
||||
/// ParseEscapedString - Parse the current token as a string which may include
|
||||
/// escaped characters and return the string contents.
|
||||
bool ParseEscapedString(std::string &Data);
|
||||
|
||||
const MCExpr *ApplyModifierToExpr(const MCExpr *E,
|
||||
MCSymbolRefExpr::VariantKind Variant);
|
||||
};
|
||||
|
||||
/// \brief Generic implementations of directive handling, etc. which is shared
|
||||
@ -485,8 +488,13 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
|
||||
|
||||
// Lookup the symbol variant if used.
|
||||
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
||||
if (Split.first.size() != Identifier.size())
|
||||
if (Split.first.size() != Identifier.size()) {
|
||||
Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
|
||||
if (Variant == MCSymbolRefExpr::VK_Invalid) {
|
||||
Variant = MCSymbolRefExpr::VK_None;
|
||||
TokError("invalid variant '" + Split.second + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an absolute variable reference, substitute it now to preserve
|
||||
// semantics in the face of reassignment.
|
||||
@ -564,6 +572,52 @@ bool AsmParser::ParseExpression(const MCExpr *&Res) {
|
||||
return ParseExpression(Res, EndLoc);
|
||||
}
|
||||
|
||||
const MCExpr *
|
||||
AsmParser::ApplyModifierToExpr(const MCExpr *E,
|
||||
MCSymbolRefExpr::VariantKind Variant) {
|
||||
// Recurse over the given expression, rebuilding it to apply the given variant
|
||||
// if there is exactly one symbol.
|
||||
switch (E->getKind()) {
|
||||
case MCExpr::Target:
|
||||
case MCExpr::Constant:
|
||||
return 0;
|
||||
|
||||
case MCExpr::SymbolRef: {
|
||||
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);
|
||||
|
||||
if (SRE->getKind() != MCSymbolRefExpr::VK_None) {
|
||||
TokError("invalid variant on expression '" +
|
||||
getTok().getIdentifier() + "' (already modified)");
|
||||
return E;
|
||||
}
|
||||
|
||||
return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext());
|
||||
}
|
||||
|
||||
case MCExpr::Unary: {
|
||||
const MCUnaryExpr *UE = cast<MCUnaryExpr>(E);
|
||||
const MCExpr *Sub = ApplyModifierToExpr(UE->getSubExpr(), Variant);
|
||||
if (!Sub)
|
||||
return 0;
|
||||
return MCUnaryExpr::Create(UE->getOpcode(), Sub, getContext());
|
||||
}
|
||||
|
||||
case MCExpr::Binary: {
|
||||
const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);
|
||||
const MCExpr *LHS = ApplyModifierToExpr(BE->getLHS(), Variant);
|
||||
const MCExpr *RHS = ApplyModifierToExpr(BE->getRHS(), Variant);
|
||||
|
||||
if (!LHS && !RHS)
|
||||
return 0;
|
||||
|
||||
if (!LHS) LHS = BE->getLHS();
|
||||
if (!RHS) RHS = BE->getRHS();
|
||||
|
||||
return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseExpression - Parse an expression and return it.
|
||||
///
|
||||
/// expr ::= expr +,- expr -> lowest.
|
||||
@ -577,6 +631,31 @@ bool AsmParser::ParseExpression(const MCExpr *&Res, SMLoc &EndLoc) {
|
||||
if (ParsePrimaryExpr(Res, EndLoc) || ParseBinOpRHS(1, Res, EndLoc))
|
||||
return true;
|
||||
|
||||
// As a special case, we support 'a op b @ modifier' by rewriting the
|
||||
// expression to include the modifier. This is inefficient, but in general we
|
||||
// expect users to use 'a@modifier op b'.
|
||||
if (Lexer.getKind() == AsmToken::At) {
|
||||
Lex();
|
||||
|
||||
if (Lexer.isNot(AsmToken::Identifier))
|
||||
return TokError("unexpected symbol modifier following '@'");
|
||||
|
||||
MCSymbolRefExpr::VariantKind Variant =
|
||||
MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier());
|
||||
if (Variant == MCSymbolRefExpr::VK_Invalid)
|
||||
return TokError("invalid variant '" + getTok().getIdentifier() + "'");
|
||||
|
||||
const MCExpr *ModifiedRes = ApplyModifierToExpr(Res, Variant);
|
||||
if (!ModifiedRes) {
|
||||
return TokError("invalid modifier '" + getTok().getIdentifier() +
|
||||
"' (no symbols present)");
|
||||
return true;
|
||||
}
|
||||
|
||||
Res = ModifiedRes;
|
||||
Lex();
|
||||
}
|
||||
|
||||
// Try to constant fold it up front, if possible.
|
||||
int64_t Value;
|
||||
if (Res->EvaluateAsAbsolute(Value))
|
||||
@ -610,7 +689,7 @@ static unsigned getBinOpPrecedence(AsmToken::TokenKind K,
|
||||
default:
|
||||
return 0; // not a binop.
|
||||
|
||||
// Lowest Precedence: &&, ||
|
||||
// Lowest Precedence: &&, ||, @
|
||||
case AsmToken::AmpAmp:
|
||||
Kind = MCBinaryExpr::LAnd;
|
||||
return 1;
|
||||
|
14
test/MC/AsmParser/expr_symbol_modifiers.s
Normal file
14
test/MC/AsmParser/expr_symbol_modifiers.s
Normal file
@ -0,0 +1,14 @@
|
||||
// RUN: not llvm-mc -triple x86_64-unknown-unknown %s > %t 2> %t.err
|
||||
// RUN: FileCheck < %t %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-STDERR < %t.err %s
|
||||
|
||||
// CHECK: .long 1
|
||||
.long 1
|
||||
// CHECK-STDERR: invalid modifier 'GOTPCREL' (no symbols present)
|
||||
.long 10 + 4@GOTPCREL
|
||||
// CHECK: .long a@GOTPCREL+4
|
||||
.long a + 4@GOTPCREL
|
||||
// CHECK: .long a@GOTPCREL+b@GOTPCREL
|
||||
.long (a + b)@GOTPCREL
|
||||
// CHECK: .long (10+b@GOTPCREL)+4
|
||||
.long 10 + b + 4@GOTPCREL
|
Loading…
Reference in New Issue
Block a user