Skip to content

Commit

Permalink
[AsmParser][SystemZ][z/OS] Implement HLASM location counter syntax ("…
Browse files Browse the repository at this point in the history
…*") for Z PC-relative instructions.

- This patch attempts to implement the location counter syntax (*) for the HLASM variant for PC-relative instructions.
- In the HLASM variant, for purely constant relocatable values, we expect a * token preceding it, with special support for " *" which is parsed as "<pc-rel-insn 0>"
- For combinations of absolute values and relocatable values, we don't expect the "*" preceding the token.

When you have a " * "  what’s accepted is:

```
*<space>.*{.*} -> <pc-rel-insn> 0
*[+|-][constant-value] -> <pc-rel-insn> [+|-]constant-value
```

When you don’t have a " * " what’s accepted is:

```
brasl  1,func           is allowed (MCSymbolRef type)
brasl  1,func+4         is allowed (MCBinary type)
brasl  1,4+func         is allowed (MCBinary type)
brasl  1,-4+func        is allowed (MCBinary type)
brasl  1,func-4         is allowed (MCBinary type)
brasl  1,*func          is not allowed (* cannot be used for non-MCConstantExprs)
brasl  1,*+func         is not allowed (* cannot be used for non-MCConstantExprs)
brasl  1,*+func+4       is not allowed (* cannot be used for non-MCConstantExprs)
brasl  1,*+4+func       is not allowed (* cannot be used for non-MCConstantExprs)
brasl  1,*-4+8+func     is not allowed (* cannot be used for non-MCConstantExprs)
```

Reviewed By: Kai

Differential Revision: https://reviews.llvm.org/D100987
  • Loading branch information
aniprasad committed May 3, 2021
1 parent e8f7241 commit ca02fab
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 15 deletions.
5 changes: 5 additions & 0 deletions llvm/include/llvm/MC/MCAsmInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ class MCAsmInfo {
/// to the current PC. Defaults to true.
bool DotIsPC = true;

/// Whether the '*' token refers to the current PC. This is used for the
/// HLASM dialect.
bool StarIsPC = false;

/// This string, if specified, is used to separate instructions from each
/// other when on the same line. Defaults to ';'
const char *SeparatorString;
Expand Down Expand Up @@ -598,6 +602,7 @@ class MCAsmInfo {
unsigned getMinInstAlignment() const { return MinInstAlignment; }
bool getDollarIsPC() const { return DollarIsPC; }
bool getDotIsPC() const { return DotIsPC; }
bool getStarIsPC() const { return StarIsPC; }
const char *getSeparatorString() const { return SeparatorString; }

/// This indicates the column (zero-based) at which asm comments should be
Expand Down
36 changes: 22 additions & 14 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1110,25 +1110,33 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,
Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);
return false;
case AsmToken::Dollar:
case AsmToken::Star:
case AsmToken::At:
case AsmToken::String:
case AsmToken::Identifier: {
StringRef Identifier;
if (parseIdentifier(Identifier)) {
// We may have failed but $ may be a valid token.
if (getTok().is(AsmToken::Dollar)) {
if (Lexer.getMAI().getDollarIsPC()) {
Lex();
// This is a '$' reference, which references the current PC. Emit a
// temporary label to the streamer and refer to it.
MCSymbol *Sym = Ctx.createTempSymbol();
Out.emitLabel(Sym);
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
getContext());
EndLoc = FirstTokenLoc;
return false;
}
return Error(FirstTokenLoc, "invalid token in expression");
// We may have failed but '$'|'*' may be a valid token in context of
// the current PC.
if (getTok().is(AsmToken::Dollar) || getTok().is(AsmToken::Star)) {
bool ShouldGenerateTempSymbol = false;
if ((getTok().is(AsmToken::Dollar) && MAI.getDollarIsPC()) ||
(getTok().is(AsmToken::Star) && MAI.getStarIsPC()))
ShouldGenerateTempSymbol = true;

if (!ShouldGenerateTempSymbol)
return Error(FirstTokenLoc, "invalid token in expression");

// Eat the '$'|'*' token.
Lex();
// This is either a '$'|'*' reference, which references the current PC.
// Emit a temporary label to the streamer and refer to it.
MCSymbol *Sym = Ctx.createTempSymbol();
Out.emitLabel(Sym);
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
getContext());
EndLoc = FirstTokenLoc;
return false;
}
}
// Parse symbol variant
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,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;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ SystemZMCAsmInfo::SystemZMCAsmInfo(const Triple &TT) {
AllowDollarAtStartOfIdentifier = (AssemblerDialect == AD_HLASM);
AllowHashAtStartOfIdentifier = (AssemblerDialect == AD_HLASM);
DotIsPC = (AssemblerDialect == AD_ATT);
StarIsPC = (AssemblerDialect == AD_HLASM);

ZeroDirective = "\t.space\t";
Data64bitsDirective = "\t.quad\t";
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/AsmParser/directive_rept-diagnostics.s
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
invalid_expression:
.rept *

# CHECK: error: unknown token in expression
# CHECK: error: invalid token in expression
# CHECK: .rept *
# CHECK: ^

Expand Down
15 changes: 15 additions & 0 deletions llvm/unittests/MC/SystemZ/SystemZAsmLexerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,4 +685,19 @@ TEST_F(SystemZAsmLexerTest, CheckRejectDotAsCurrentPC) {
EXPECT_EQ(ParsePrimaryExpr, true);
EXPECT_EQ(Parser->hasPendingError(), true);
}

TEST_F(SystemZAsmLexerTest, CheckRejectStarAsCurrentPC) {
StringRef AsmStr = "*-4";

// Setup.
setupCallToAsmParser(AsmStr);

// Lex initially to get the string.
Parser->getLexer().Lex();

const MCExpr *Expr;
bool ParsePrimaryExpr = Parser->parseExpression(Expr);
EXPECT_EQ(ParsePrimaryExpr, true);
EXPECT_EQ(Parser->hasPendingError(), true);
}
} // end anonymous namespace

0 comments on commit ca02fab

Please sign in to comment.