summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp')
-rw-r--r--llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp133
1 files changed, 125 insertions, 8 deletions
diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index 2b815a366ccd..0de24245cfcc 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -7,11 +7,13 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/SystemZInstPrinter.h"
+#include "MCTargetDesc/SystemZMCAsmInfo.h"
#include "MCTargetDesc/SystemZMCTargetDesc.h"
#include "TargetInfo/SystemZTargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
@@ -428,6 +430,42 @@ private:
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
+ // Both the hlasm and att variants still rely on the basic gnu asm
+ // format with respect to inputs, clobbers, outputs etc.
+ //
+ // However, calling the overriden getAssemblerDialect() method in
+ // AsmParser is problematic. It either returns the AssemblerDialect field
+ // in the MCAsmInfo instance if the AssemblerDialect field in AsmParser is
+ // unset, otherwise it returns the private AssemblerDialect field in
+ // AsmParser.
+ //
+ // The problematic part is because, we forcibly set the inline asm dialect
+ // in the AsmParser instance in AsmPrinterInlineAsm.cpp. Soo any query
+ // to the overriden getAssemblerDialect function in AsmParser.cpp, will
+ // not return the assembler dialect set in the respective MCAsmInfo instance.
+ //
+ // For this purpose, we explicitly query the SystemZMCAsmInfo instance
+ // here, to get the "correct" assembler dialect, and use it in various
+ // functions.
+ unsigned getMAIAssemblerDialect() {
+ return Parser.getContext().getAsmInfo()->getAssemblerDialect();
+ }
+
+ // An alphabetic character in HLASM is a letter from 'A' through 'Z',
+ // or from 'a' through 'z', or '$', '_','#', or '@'.
+ inline bool isHLASMAlpha(char C) {
+ return isAlpha(C) || llvm::is_contained("_@#$", C);
+ }
+
+ // A digit in HLASM is a number from 0 to 9.
+ inline bool isHLASMAlnum(char C) { return isHLASMAlpha(C) || isDigit(C); }
+
+ // Are we parsing using the AD_HLASM dialect?
+ inline bool isParsingHLASM() { return getMAIAssemblerDialect() == AD_HLASM; }
+
+ // Are we parsing using the AD_ATT dialect?
+ inline bool isParsingATT() { return getMAIAssemblerDialect() == AD_ATT; }
+
public:
SystemZAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser,
const MCInstrInfo &MII,
@@ -455,6 +493,7 @@ public:
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
+ bool isLabel(AsmToken &Token) override;
// Used by the TableGen code to parse particular operand types.
OperandMatchResultTy parseGR32(OperandVector &Operands) {
@@ -791,7 +830,7 @@ SystemZAsmParser::parseRegister(OperandVector &Operands, RegisterKind Kind) {
}
// Handle register names of the form %<prefix><number>
- if (Parser.getTok().is(AsmToken::Percent)) {
+ if (isParsingATT() && Parser.getTok().is(AsmToken::Percent)) {
if (parseRegister(Reg))
return MatchOperand_ParseFail;
@@ -873,6 +912,9 @@ SystemZAsmParser::parseAnyRegister(OperandVector &Operands) {
Operands.push_back(SystemZOperand::createImm(Register, StartLoc, EndLoc));
}
else {
+ if (isParsingHLASM())
+ return MatchOperand_NoMatch;
+
Register Reg;
if (parseRegister(Reg))
return MatchOperand_ParseFail;
@@ -980,7 +1022,7 @@ bool SystemZAsmParser::parseAddress(bool &HaveReg1, Register &Reg1,
if (getLexer().is(AsmToken::LParen)) {
Parser.Lex();
- if (getLexer().is(AsmToken::Percent)) {
+ if (isParsingATT() && getLexer().is(AsmToken::Percent)) {
// Parse the first register.
HaveReg1 = true;
if (parseRegister(Reg1))
@@ -1023,7 +1065,7 @@ bool SystemZAsmParser::parseAddress(bool &HaveReg1, Register &Reg1,
if (parseIntegerRegister(Reg2, RegGR))
return true;
} else {
- if (parseRegister(Reg2))
+ if (isParsingATT() && parseRegister(Reg2))
return true;
}
}
@@ -1325,7 +1367,7 @@ bool SystemZAsmParser::ParseInstruction(ParseInstructionInfo &Info,
// Apply mnemonic aliases first, before doing anything else, in
// case the target uses it.
- applyMnemonicAliases(Name, getAvailableFeatures(), 0 /*VariantID*/);
+ applyMnemonicAliases(Name, getAvailableFeatures(), getMAIAssemblerDialect());
Operands.push_back(SystemZOperand::createToken(Name, NameLoc));
@@ -1339,10 +1381,38 @@ bool SystemZAsmParser::ParseInstruction(ParseInstructionInfo &Info,
// Read any subsequent operands.
while (getLexer().is(AsmToken::Comma)) {
Parser.Lex();
+
+ if (isParsingHLASM() && getLexer().is(AsmToken::Space))
+ return Error(
+ Parser.getTok().getLoc(),
+ "No space allowed between comma that separates operand entries");
+
if (parseOperand(Operands, Name)) {
return true;
}
}
+
+ // Under the HLASM variant, we could have the remark field
+ // The remark field occurs after the operation entries
+ // There is a space that separates the operation entries and the
+ // remark field.
+ if (isParsingHLASM() && getTok().is(AsmToken::Space)) {
+ // We've confirmed that there is a Remark field.
+ StringRef Remark(getLexer().LexUntilEndOfStatement());
+ Parser.Lex();
+
+ // If there is nothing after the space, then there is nothing to emit
+ // We could have a situation as this:
+ // " \n"
+ // After lexing above, we will have
+ // "\n"
+ // This isn't an explicit remark field, so we don't have to output
+ // this as a comment.
+ if (Remark.size())
+ // Output the entire Remarks Field as a comment
+ getStreamer().AddComment(Remark);
+ }
+
if (getLexer().isNot(AsmToken::EndOfStatement)) {
SMLoc Loc = getLexer().getLoc();
return Error(Loc, "unexpected token in argument list");
@@ -1380,7 +1450,7 @@ bool SystemZAsmParser::parseOperand(OperandVector &Operands,
// a context-dependent parse routine, which gives the required register
// class. The code is here to mop up other cases, like those where
// the instruction isn't recognized.
- if (Parser.getTok().is(AsmToken::Percent)) {
+ if (isParsingATT() && Parser.getTok().is(AsmToken::Percent)) {
Register Reg;
if (parseRegister(Reg))
return true;
@@ -1428,9 +1498,11 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
MCInst Inst;
unsigned MatchResult;
+ unsigned Dialect = getMAIAssemblerDialect();
+
FeatureBitset MissingFeatures;
- MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
- MissingFeatures, MatchingInlineAsm);
+ MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
+ MatchingInlineAsm, Dialect);
switch (MatchResult) {
case Match_Success:
Inst.setLoc(IDLoc);
@@ -1467,7 +1539,7 @@ bool SystemZAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_MnemonicFail: {
FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
std::string Suggestion = SystemZMnemonicSpellCheck(
- ((SystemZOperand &)*Operands[0]).getToken(), FBS);
+ ((SystemZOperand &)*Operands[0]).getToken(), FBS, Dialect);
return Error(IDLoc, "invalid instruction" + Suggestion,
((SystemZOperand &)*Operands[0]).getLocRange());
}
@@ -1498,6 +1570,10 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
// For consistency with the GNU assembler, treat immediates as offsets
// from ".".
if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
+ if (isParsingHLASM()) {
+ Error(StartLoc, "Expected PC-relative expression");
+ return MatchOperand_ParseFail;
+ }
if (isOutOfRangeConstant(CE)) {
Error(StartLoc, "offset out of range");
return MatchOperand_ParseFail;
@@ -1570,6 +1646,47 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal,
return MatchOperand_Success;
}
+bool SystemZAsmParser::isLabel(AsmToken &Token) {
+ if (isParsingATT())
+ return true;
+
+ // HLASM labels are ordinary symbols.
+ // An HLASM label always starts at column 1.
+ // An ordinary symbol syntax is laid out as follows:
+ // Rules:
+ // 1. Has to start with an "alphabetic character". Can be followed by up to
+ // 62 alphanumeric characters. An "alphabetic character", in this scenario,
+ // is a letter from 'A' through 'Z', or from 'a' through 'z',
+ // or '$', '_', '#', or '@'
+ // 2. Labels are case-insensitive. E.g. "lab123", "LAB123", "lAb123", etc.
+ // are all treated as the same symbol. However, the processing for the case
+ // folding will not be done in this function.
+ StringRef RawLabel = Token.getString();
+ SMLoc Loc = Token.getLoc();
+
+ // An HLASM label cannot be empty.
+ if (!RawLabel.size())
+ return !Error(Loc, "HLASM Label cannot be empty");
+
+ // An HLASM label cannot exceed greater than 63 characters.
+ if (RawLabel.size() > 63)
+ return !Error(Loc, "Maximum length for HLASM Label is 63 characters");
+
+ // A label must start with an "alphabetic character".
+ if (!isHLASMAlpha(RawLabel[0]))
+ return !Error(Loc, "HLASM Label has to start with an alphabetic "
+ "character or the underscore character");
+
+ // Now, we've established that the length is valid
+ // and the first character is alphabetic.
+ // Check whether remaining string is alphanumeric.
+ for (unsigned I = 1; I < RawLabel.size(); ++I)
+ if (!isHLASMAlnum(RawLabel[I]))
+ return !Error(Loc, "HLASM Label has to be alphanumeric");
+
+ return true;
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZAsmParser() {
RegisterMCAsmParser<SystemZAsmParser> X(getTheSystemZTarget());