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:
Daniel Dunbar 2010-09-17 02:47:07 +00:00
parent 96b5f7113a
commit cceba83893
2 changed files with 95 additions and 2 deletions

View File

@ -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;

View 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