mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:19:57 +00:00
[ms] [llvm-ml] Support built-in text macros
Add support for all built-in text macros supported by ML64: @Date, @Time, @FileName, @FileCur, and @CurSeg. Reviewed By: thakis Differential Revision: https://reviews.llvm.org/D104965
This commit is contained in:
parent
7dfafaa71e
commit
2b759c7f74
@ -18,6 +18,7 @@
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@ -348,7 +349,7 @@ MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer &,
|
||||
|
||||
/// Create an MCAsmParser instance for parsing Microsoft MASM-style assembly
|
||||
MCAsmParser *createMCMasmParser(SourceMgr &, MCContext &, MCStreamer &,
|
||||
const MCAsmInfo &, unsigned CB = 0);
|
||||
const MCAsmInfo &, struct tm, unsigned CB = 0);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
@ -56,6 +57,7 @@
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -65,6 +67,7 @@
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@ -372,6 +375,10 @@ private:
|
||||
/// This is the current buffer index we're lexing from as managed by the
|
||||
/// SourceMgr object.
|
||||
unsigned CurBuffer;
|
||||
|
||||
/// time of assembly
|
||||
struct tm TM;
|
||||
|
||||
std::vector<bool> EndStatementAtEOFStack;
|
||||
|
||||
AsmCond TheCondState;
|
||||
@ -448,7 +455,7 @@ private:
|
||||
|
||||
public:
|
||||
MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
|
||||
const MCAsmInfo &MAI, unsigned CB);
|
||||
const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0);
|
||||
MasmParser(const MasmParser &) = delete;
|
||||
MasmParser &operator=(const MasmParser &) = delete;
|
||||
~MasmParser() override;
|
||||
@ -823,6 +830,9 @@ private:
|
||||
|
||||
const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc);
|
||||
|
||||
llvm::Optional<std::string> evaluateBuiltinTextMacro(BuiltinSymbol Symbol,
|
||||
SMLoc StartLoc);
|
||||
|
||||
// ".ascii", ".asciz", ".string"
|
||||
bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
|
||||
|
||||
@ -1060,9 +1070,9 @@ extern MCAsmParserExtension *createCOFFMasmParser();
|
||||
enum { DEFAULT_ADDRSPACE = 0 };
|
||||
|
||||
MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
|
||||
const MCAsmInfo &MAI, unsigned CB = 0)
|
||||
const MCAsmInfo &MAI, struct tm TM, unsigned CB)
|
||||
: Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),
|
||||
CurBuffer(CB ? CB : SM.getMainFileID()) {
|
||||
CurBuffer(CB ? CB : SM.getMainFileID()), TM(TM) {
|
||||
HadError = false;
|
||||
// Save the old handler.
|
||||
SavedDiagHandler = SrcMgr.getDiagHandler();
|
||||
@ -1154,25 +1164,9 @@ void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer,
|
||||
|
||||
bool MasmParser::expandMacros() {
|
||||
const AsmToken &Tok = getTok();
|
||||
const std::string IDLower = Tok.getIdentifier().lower();
|
||||
|
||||
auto VarIt = Variables.find(Tok.getIdentifier().lower());
|
||||
if (VarIt != Variables.end() && VarIt->second.IsText) {
|
||||
std::unique_ptr<MemoryBuffer> Instantiation =
|
||||
MemoryBuffer::getMemBufferCopy(VarIt->second.TextValue,
|
||||
"<instantiation>");
|
||||
|
||||
// Jump to the macro instantiation and prime the lexer.
|
||||
CurBuffer =
|
||||
SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());
|
||||
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,
|
||||
/*EndStatementAtEOF=*/false);
|
||||
EndStatementAtEOFStack.push_back(false);
|
||||
Lexer.Lex();
|
||||
return false;
|
||||
}
|
||||
|
||||
const llvm::MCAsmMacro *M =
|
||||
getContext().lookupMacro(Tok.getIdentifier().lower());
|
||||
const llvm::MCAsmMacro *M = getContext().lookupMacro(IDLower);
|
||||
if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) {
|
||||
// This is a macro function invocation; expand it in place.
|
||||
const SMLoc MacroLoc = Tok.getLoc();
|
||||
@ -1185,7 +1179,31 @@ bool MasmParser::expandMacros() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
llvm::Optional<std::string> ExpandedValue;
|
||||
auto BuiltinIt = BuiltinSymbolMap.find(IDLower);
|
||||
if (BuiltinIt != BuiltinSymbolMap.end()) {
|
||||
ExpandedValue =
|
||||
evaluateBuiltinTextMacro(BuiltinIt->getValue(), Tok.getLoc());
|
||||
} else {
|
||||
auto VarIt = Variables.find(IDLower);
|
||||
if (VarIt != Variables.end() && VarIt->getValue().IsText) {
|
||||
ExpandedValue = VarIt->getValue().TextValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ExpandedValue.hasValue())
|
||||
return true;
|
||||
std::unique_ptr<MemoryBuffer> Instantiation =
|
||||
MemoryBuffer::getMemBufferCopy(*ExpandedValue, "<instantiation>");
|
||||
|
||||
// Jump to the macro instantiation and prime the lexer.
|
||||
CurBuffer =
|
||||
SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());
|
||||
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,
|
||||
/*EndStatementAtEOF=*/false);
|
||||
EndStatementAtEOFStack.push_back(false);
|
||||
Lexer.Lex();
|
||||
return false;
|
||||
}
|
||||
|
||||
const AsmToken &MasmParser::Lex(ExpandKind ExpandNextToken) {
|
||||
@ -2938,16 +2956,17 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
|
||||
|
||||
const char *Begin = Body.data() + Pos;
|
||||
StringRef Argument(Begin, I - Pos);
|
||||
const std::string ArgumentLower = Argument.lower();
|
||||
unsigned Index = 0;
|
||||
|
||||
for (; Index < NParameters; ++Index)
|
||||
if (Parameters[Index].Name == Argument)
|
||||
if (Parameters[Index].Name.equals_insensitive(ArgumentLower))
|
||||
break;
|
||||
|
||||
if (Index == NParameters) {
|
||||
if (InitialAmpersand)
|
||||
OS << '&';
|
||||
auto it = LocalSymbols.find(Argument.lower());
|
||||
auto it = LocalSymbols.find(ArgumentLower);
|
||||
if (it != LocalSymbols.end())
|
||||
OS << it->second;
|
||||
else
|
||||
@ -3602,28 +3621,50 @@ bool MasmParser::parseTextItem(std::string &Data) {
|
||||
case AsmToken::Identifier: {
|
||||
// This must be a text macro; we need to expand it accordingly.
|
||||
StringRef ID;
|
||||
SMLoc StartLoc = getTok().getLoc();
|
||||
if (parseIdentifier(ID))
|
||||
return true;
|
||||
Data = ID.str();
|
||||
|
||||
auto it = Variables.find(ID.lower());
|
||||
if (it == Variables.end()) {
|
||||
// Not a variable; since we haven't used the token, put it back for better
|
||||
// error recovery.
|
||||
getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));
|
||||
return true;
|
||||
bool Expanded = false;
|
||||
while (true) {
|
||||
// Try to resolve as a built-in text macro
|
||||
auto BuiltinIt = BuiltinSymbolMap.find(ID.lower());
|
||||
if (BuiltinIt != BuiltinSymbolMap.end()) {
|
||||
llvm::Optional<std::string> BuiltinText =
|
||||
evaluateBuiltinTextMacro(BuiltinIt->getValue(), StartLoc);
|
||||
if (!BuiltinText.hasValue()) {
|
||||
// Not a text macro; break without substituting
|
||||
break;
|
||||
}
|
||||
Data = std::move(*BuiltinText);
|
||||
ID = StringRef(Data);
|
||||
Expanded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to resolve as a variable text macro
|
||||
auto VarIt = Variables.find(ID.lower());
|
||||
if (VarIt != Variables.end()) {
|
||||
const Variable &Var = VarIt->getValue();
|
||||
if (!Var.IsText) {
|
||||
// Not a text macro; break without substituting
|
||||
break;
|
||||
}
|
||||
Data = Var.TextValue;
|
||||
ID = StringRef(Data);
|
||||
Expanded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
while (it != Variables.end()) {
|
||||
const Variable &Var = it->second;
|
||||
if (!Var.IsText) {
|
||||
// Not a text macro; not usable in TextItem context. Since we haven't
|
||||
// used the token, put it back for better error recovery.
|
||||
getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));
|
||||
return true;
|
||||
}
|
||||
Data = Var.TextValue;
|
||||
it = Variables.find(StringRef(Data).lower());
|
||||
if (!Expanded) {
|
||||
// Not a text macro; not usable in TextItem context. Since we haven't used
|
||||
// the token, put it back for better error recovery.
|
||||
getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -6857,16 +6898,36 @@ bool MasmParser::expandStatement(SMLoc Loc) {
|
||||
|
||||
MCAsmMacroParameters Parameters;
|
||||
MCAsmMacroArguments Arguments;
|
||||
|
||||
StringMap<std::string> BuiltinValues;
|
||||
for (const auto &S : BuiltinSymbolMap) {
|
||||
const BuiltinSymbol &Sym = S.getValue();
|
||||
if (llvm::Optional<std::string> Text = evaluateBuiltinTextMacro(Sym, Loc)) {
|
||||
BuiltinValues[S.getKey().lower()] = std::move(*Text);
|
||||
}
|
||||
}
|
||||
for (const auto &B : BuiltinValues) {
|
||||
MCAsmMacroParameter P;
|
||||
MCAsmMacroArgument A;
|
||||
P.Name = B.getKey();
|
||||
P.Required = true;
|
||||
A.push_back(AsmToken(AsmToken::String, B.getValue()));
|
||||
|
||||
Parameters.push_back(std::move(P));
|
||||
Arguments.push_back(std::move(A));
|
||||
}
|
||||
|
||||
for (const auto &V : Variables) {
|
||||
const Variable &Var = V.getValue();
|
||||
if (Var.IsText) {
|
||||
Parameters.emplace_back();
|
||||
Arguments.emplace_back();
|
||||
MCAsmMacroParameter &P = Parameters.back();
|
||||
MCAsmMacroArgument &A = Arguments.back();
|
||||
MCAsmMacroParameter P;
|
||||
MCAsmMacroArgument A;
|
||||
P.Name = Var.Name;
|
||||
P.Required = true;
|
||||
A.push_back(AsmToken(AsmToken::String, Var.TextValue));
|
||||
|
||||
Parameters.push_back(std::move(P));
|
||||
Arguments.push_back(std::move(A));
|
||||
}
|
||||
}
|
||||
MacroLikeBodies.emplace_back(StringRef(), Body, Parameters);
|
||||
@ -7595,11 +7656,11 @@ void MasmParser::initializeBuiltinSymbolMap() {
|
||||
BuiltinSymbolMap["@line"] = BI_LINE;
|
||||
|
||||
// Text built-ins (supported in all versions)
|
||||
// BuiltinSymbolMap["@date"] = BI_DATE;
|
||||
// BuiltinSymbolMap["@time"] = BI_TIME;
|
||||
// BuiltinSymbolMap["@filecur"] = BI_FILECUR;
|
||||
// BuiltinSymbolMap["@filename"] = BI_FILENAME;
|
||||
// BuiltinSymbolMap["@curseg"] = BI_CURSEG;
|
||||
BuiltinSymbolMap["@date"] = BI_DATE;
|
||||
BuiltinSymbolMap["@time"] = BI_TIME;
|
||||
BuiltinSymbolMap["@filecur"] = BI_FILECUR;
|
||||
BuiltinSymbolMap["@filename"] = BI_FILENAME;
|
||||
BuiltinSymbolMap["@curseg"] = BI_CURSEG;
|
||||
|
||||
// Some built-ins exist only for MASM32 (32-bit x86)
|
||||
if (getContext().getSubtargetInfo()->getTargetTriple().getArch() ==
|
||||
@ -7641,9 +7702,42 @@ const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,
|
||||
llvm_unreachable("unhandled built-in symbol");
|
||||
}
|
||||
|
||||
llvm::Optional<std::string>
|
||||
MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {
|
||||
switch (Symbol) {
|
||||
default:
|
||||
return {};
|
||||
case BI_DATE: {
|
||||
// Current local date, formatted MM/DD/YY
|
||||
char TmpBuffer[sizeof("mm/dd/yy")];
|
||||
const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%D", &TM);
|
||||
return std::string(TmpBuffer, Len);
|
||||
}
|
||||
case BI_TIME: {
|
||||
// Current local time, formatted HH:MM:SS (24-hour clock)
|
||||
char TmpBuffer[sizeof("hh:mm:ss")];
|
||||
const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%T", &TM);
|
||||
return std::string(TmpBuffer, Len);
|
||||
}
|
||||
case BI_FILECUR:
|
||||
return SrcMgr
|
||||
.getMemoryBuffer(
|
||||
ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)
|
||||
->getBufferIdentifier()
|
||||
.str();
|
||||
case BI_FILENAME:
|
||||
return sys::path::stem(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())
|
||||
->getBufferIdentifier())
|
||||
.upper();
|
||||
case BI_CURSEG:
|
||||
return getStreamer().getCurrentSectionOnly()->getName().str();
|
||||
}
|
||||
llvm_unreachable("unhandled built-in symbol");
|
||||
}
|
||||
|
||||
/// Create an MCAsmParser instance.
|
||||
MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,
|
||||
MCStreamer &Out, const MCAsmInfo &MAI,
|
||||
unsigned CB) {
|
||||
return new MasmParser(SM, C, Out, MAI, CB);
|
||||
struct tm TM, unsigned CB) {
|
||||
return new MasmParser(SM, C, Out, MAI, TM, CB);
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
; RUN: llvm-ml -filetype=s %s /Fo /dev/null 2>&1 | FileCheck %s
|
||||
; RUN: llvm-ml -filetype=s %s /I %S /Fo /dev/null 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-REALTIME
|
||||
; RUN: llvm-ml -filetype=s %s /I %S /Fo /dev/null --timestamp=0 --utc 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-FIXEDTIME
|
||||
|
||||
.code
|
||||
|
||||
version_val TEXTEQU %@Version
|
||||
|
||||
@ -33,3 +36,24 @@ ECHO t4:
|
||||
%ECHO @Line = line_val
|
||||
; CHECK-LABEL: t4:
|
||||
; CHECK-NEXT: @Line = [[# @LINE - 5]]
|
||||
|
||||
ECHO t5:
|
||||
include builtin_symbols_t5.inc
|
||||
; CHECK-LABEL: t5:
|
||||
; CHECK: FileCur = {{.*}}builtin_symbols_t5.inc
|
||||
; CHECK: FileName = BUILTIN_SYMBOLS
|
||||
; CHECK-NOT: _T5
|
||||
|
||||
ECHO t6:
|
||||
%ECHO Date = @Date
|
||||
%ECHO Time = @Time
|
||||
|
||||
; CHECK-LABEL: t6:
|
||||
; CHECK-REALTIME: Date = {{([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{2})}}
|
||||
; CHECK-FIXEDTIME: Date = 01/01/70
|
||||
; CHECK-NOT: {{[[:digit:]]}}
|
||||
; CHECK-REALTIME: Time = {{([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2})}}
|
||||
; CHECK-FIXEDTIME: Time = 00:00:00
|
||||
; CHECK-NOT: {{[[:digit:]]}}
|
||||
|
||||
end
|
||||
|
2
test/tools/llvm-ml/builtin_symbols_t5.inc
Normal file
2
test/tools/llvm-ml/builtin_symbols_t5.inc
Normal file
@ -0,0 +1,2 @@
|
||||
%echo FileCur = @FileCur
|
||||
%echo FileName = @FileName
|
@ -51,6 +51,12 @@ def preserve_comments : LLVMFlag<"preserve-comments">,
|
||||
HelpText<"Preserve comments in output assembly">;
|
||||
def save_temp_labels : LLVMFlag<"save-temp-labels">,
|
||||
HelpText<"Don't discard temporary labels">;
|
||||
def timestamp : LLVMJoined<"timestamp=">,
|
||||
HelpText<"Specify the assembly timestamp (used for @Date and "
|
||||
"@Time built-ins)">;
|
||||
def utc : LLVMFlag<"utc">,
|
||||
HelpText<"Render @Date and @Time built-ins in GMT/UTC">;
|
||||
def gmtime : LLVMFlag<"gmtime">, Alias<utc>;
|
||||
|
||||
def help : MLFlag<"?">,
|
||||
HelpText<"Display available options">;
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include <ctime>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::opt;
|
||||
@ -130,8 +131,31 @@ static int AssembleInput(StringRef ProgName, const Target *TheTarget,
|
||||
MCAsmInfo &MAI, MCSubtargetInfo &STI,
|
||||
MCInstrInfo &MCII, MCTargetOptions &MCOptions,
|
||||
const opt::ArgList &InputArgs) {
|
||||
struct tm TM;
|
||||
time_t Timestamp;
|
||||
if (InputArgs.hasArg(OPT_timestamp)) {
|
||||
StringRef TimestampStr = InputArgs.getLastArgValue(OPT_timestamp);
|
||||
int64_t IntTimestamp;
|
||||
if (TimestampStr.getAsInteger(10, IntTimestamp)) {
|
||||
WithColor::error(errs(), ProgName)
|
||||
<< "invalid timestamp '" << TimestampStr
|
||||
<< "'; must be expressed in seconds since the UNIX epoch.\n";
|
||||
return 1;
|
||||
}
|
||||
Timestamp = IntTimestamp;
|
||||
} else {
|
||||
Timestamp = time(nullptr);
|
||||
}
|
||||
if (InputArgs.hasArg(OPT_utc)) {
|
||||
// Not thread-safe.
|
||||
TM = *gmtime(&Timestamp);
|
||||
} else {
|
||||
// Not thread-safe.
|
||||
TM = *localtime(&Timestamp);
|
||||
}
|
||||
|
||||
std::unique_ptr<MCAsmParser> Parser(
|
||||
createMCMasmParser(SrcMgr, Ctx, Str, MAI, 0));
|
||||
createMCMasmParser(SrcMgr, Ctx, Str, MAI, TM, 0));
|
||||
std::unique_ptr<MCTargetAsmParser> TAP(
|
||||
TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user