1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

[LLVM][inline-asm] Altmacro absolute expression '%' feature

In this patch, I introduce a new alt macro feature.
This feature adds meaning for the % when using it as a prefix to the calling macro arguments.

In the altmacro mode, the percent sign '%' before an absolute expression convert the expression first to a string. 
As described in the https://sourceware.org/binutils/docs-2.27/as/Altmacro.html
"Expression results as strings
You can write `%expr' to evaluate the expression expr and use the result as a string."

expression assumptions:

1. '%' can only evaluate an absolute expression.
2. Altmacro '%' must be the first character of the evaluated expression.
3. If no '%' is located before the expression, a regular module operation is expected.
4. The result of Absolute Expressions can be only integer.

Differential Revision: https://reviews.llvm.org/D32526

llvm-svn: 301797
This commit is contained in:
Michael Zuckerman 2017-05-01 13:20:12 +00:00
parent 01c4c20127
commit db35bad707
5 changed files with 159 additions and 7 deletions

View File

@ -161,6 +161,7 @@ protected: // Can only create subclasses.
bool IsAtStartOfStatement = true;
AsmCommentConsumer *CommentConsumer = nullptr;
bool AltMacroMode;
MCAsmLexer();
virtual AsmToken LexToken() = 0;
@ -175,6 +176,14 @@ public:
MCAsmLexer &operator=(const MCAsmLexer &) = delete;
virtual ~MCAsmLexer();
bool IsaAltMacroMode() {
return AltMacroMode;
}
void SetAltMacroMode(bool AltMacroSet) {
AltMacroMode = AltMacroSet;
}
/// Consume the next token from the input stream and return it.
///
/// The lexer will continuosly return the end-of-file token once the end of

View File

@ -412,7 +412,7 @@ private:
DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE,
DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED,
DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE,
DK_MACROS_ON, DK_MACROS_OFF,
DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, DK_NOALTMACRO,
DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM,
DK_SLEB128, DK_ULEB128,
DK_ERR, DK_ERROR, DK_WARNING,
@ -484,7 +484,8 @@ private:
bool parseDirectiveEndMacro(StringRef Directive);
bool parseDirectiveMacro(SMLoc DirectiveLoc);
bool parseDirectiveMacrosOnOff(StringRef Directive);
// alternate macro mode directives
bool parseDirectiveAltmacro(StringRef Directive);
// ".bundle_align_mode"
bool parseDirectiveBundleAlignMode();
// ".bundle_lock"
@ -1922,6 +1923,9 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveMacrosOnOff(IDVal);
case DK_MACRO:
return parseDirectiveMacro(IDLoc);
case DK_ALTMACRO:
case DK_NOALTMACRO:
return parseDirectiveAltmacro(IDVal);
case DK_EXITM:
return parseDirectiveExitMacro(IDVal);
case DK_ENDM:
@ -2270,9 +2274,18 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
} else {
bool VarargParameter = HasVararg && Index == (NParameters - 1);
for (const AsmToken &Token : A[Index])
// For altmacro mode, you can write '%expr'.
// The prefix '%' evaluates the expression 'expr'
// and uses the result as a string (e.g. replace %(1+2) with the string "3").
// Here, we identify the integer token which is the result of the
// absolute expression evaluation and replace it with its string representation.
if ((Lexer.IsaAltMacroMode()) &&
(*(Token.getString().begin()) == '%') && Token.is(AsmToken::Integer))
// Emit an integer value to the buffer.
OS << Token.getIntVal();
// We expect no quotes around the string's contents when
// parsing for varargs.
if (Token.getKind() != AsmToken::String || VarargParameter)
else if (Token.isNot(AsmToken::String) || VarargParameter)
OS << Token.getString();
else
OS << Token.getStringContents();
@ -2443,13 +2456,29 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
NamedParametersFound = true;
}
bool Vararg = HasVararg && Parameter == (NParameters - 1);
if (NamedParametersFound && FA.Name.empty())
return Error(IDLoc, "cannot mix positional and keyword arguments");
bool Vararg = HasVararg && Parameter == (NParameters - 1);
if (parseMacroArgument(FA.Value, Vararg))
return true;
if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Percent)) {
SMLoc StrLoc = Lexer.getLoc();
SMLoc EndLoc;
const MCExpr *AbsoluteExp;
int64_t Value;
/// Eat '%'
Lex();
if (parseExpression(AbsoluteExp, EndLoc))
return false;
if (!AbsoluteExp->evaluateAsAbsolute(Value))
return Error(StrLoc, "expected absolute expression");
const char *StrChar = StrLoc.getPointer();
const char *EndChar = EndLoc.getPointer();
AsmToken newToken(AsmToken::Integer, StringRef(StrChar , EndChar - StrChar), Value);
FA.Value.push_back(newToken);
}
else if(parseMacroArgument(FA.Value, Vararg))
return true;
unsigned PI = Parameter;
if (!FA.Name.empty()) {
@ -3841,6 +3870,19 @@ bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
return false;
}
/// parseDirectiveAltmacro
/// ::= .altmacro
/// ::= .noaltmacro
bool AsmParser::parseDirectiveAltmacro(StringRef Directive) {
if (getLexer().isNot(AsmToken::EndOfStatement))
return TokError("unexpected token in '" + Directive + "' directive");
if (Directive == ".altmacro")
getLexer().SetAltMacroMode(true);
else
getLexer().SetAltMacroMode(false);
return false;
}
/// parseDirectiveMacrosOnOff
/// ::= .macros_on
/// ::= .macros_off
@ -4938,6 +4980,8 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".err"] = DK_ERR;
DirectiveKindMap[".error"] = DK_ERROR;
DirectiveKindMap[".warning"] = DK_WARNING;
DirectiveKindMap[".altmacro"] = DK_ALTMACRO;
DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;
DirectiveKindMap[".reloc"] = DK_RELOC;
DirectiveKindMap[".dc"] = DK_DC;
DirectiveKindMap[".dc.a"] = DK_DC_A;

View File

@ -13,7 +13,7 @@
using namespace llvm;
MCAsmLexer::MCAsmLexer() {
MCAsmLexer::MCAsmLexer() : AltMacroMode(false) {
CurTok.emplace_back(AsmToken::Space, StringRef());
}

View File

@ -0,0 +1,65 @@
# RUN: llvm-mc %s| FileCheck %s
# Checking that the '%' was evaluated as a string first
# In a fail scenario: The asmprint will print: addl $%(1+4), %eax
# CHECK: addl $5, %eax
.altmacro
.macro percent_expr arg
addl $\arg, %eax
.endm
percent_expr %(1+4)
# Checking that the second '%' acts as modulo operator
# The altmacro percent '%' must be located before the first argument
# If a percent is located in the middle of the estimated argument without any
# '%' in the beginning , error will be generated.
# The second percent '%' after the first altmacro percent '%' is a regular operator.
# CHECK: addl $1, %eax
.macro inner_percent arg
addl $\arg, %eax
.endm
inner_percent %(1%4)
# Checking for nested macro
# The first argument use is for the calling function and the second use is for the evaluation.
# CHECK: addl $1, %eax
.macro macro_call_0 number
addl $\number, %eax
.endm
.macro macro_call_1 number
macro_call_\number %(\number + 1)
.endm
macro_call_1 %(1-1)
# Checking the ability to pass a number of arguments.
# The arguments can be separated by ',' or not.
# CHECK: label013:
# CHECK: addl $0, %eax
# CHECK: addl $1, %eax
# CHECK: addl $3, %eax
# CHECK: label014:
# CHECK: addl $0, %eax
# CHECK: addl $1, %eax
# CHECK: addl $4, %eax
.macro multi_args_macro arg1 arg2 arg3
label\arg1\arg2\arg3:
addl $\arg1, %eax
addl $\arg2, %eax
addl $\arg3, %eax
.endm
multi_args_macro %(1+4-5) 1 %2+1
multi_args_macro %(1+4-5),1,%4%10

View File

@ -0,0 +1,34 @@
# RUN: not llvm-mc %s 2>&1 | FileCheck %s
# This test is a negative test for the altmacro expression.
# In this test we check the '.noaltmacro' directive.
# We expect that '.altmacro' and '.noaltmacro' will act as a switch on/off directives to the alternate macro mode.
# .noaltmacro returns the format into a regular macro handling.
# The defult mode is ".noaltmacro" as first test checks.
# CHECK: error: unknown token in expression
# CHECK-NEXT: addl $%(1%4), %eax
.macro inner_percent arg
addl $\arg, %eax
.endm
inner_percent %(1%4)
.altmacro
.noaltmacro
# CHECK: multi_args_macro %(1+4-5) 1 %2+1
# CHECK: error: unknown token in expression
# CHECK-NEXT: addl $%(1+4-5), %eax
# CHECK: multi_args_macro %(1+4-5),1,%4%10
# CHECK: error: unknown token in expression
# CHECK-NEXT: addl $%(1+4-5), %eax
.macro multi_args_macro arg1 arg2 arg3
label\arg1\arg2\arg3:
addl $\arg1, %eax
.endm
multi_args_macro %(1+4-5) 1 %2+1
multi_args_macro %(1+4-5),1,%4%10