[Mips] Rework relocation expression parsing

A relocation expression might be used in an immediate operand or a
memory offset. https://reviews.llvm.org/D23110 , which intended to
generalize chained relocation operators (%hi(%neg(%gp_rel(x)))),
inappropriated introduced intrusive changes to the generic code. This
patch drops the intrusive changes and significantly simplifies the code.
The new style is similar to pre-D23110 but much cleaner.

Some weird expressions allowed by gas are not supported for simplicity,
e.g. "%lo foo", "(%lo(foo))", "%lo(foo)+1".
"(%lo(foo))", while previously parsed, is not used in practice.
"%lo(foo)+1" and "%lo(2*4)+foo" were previously parsed but would lead to
an error anyway as the expression is not relocatable
(`evaluateSymbolicAdd` does not fold the Add when RefKind are
different).
This commit is contained in:
Fangrui Song 2025-03-02 11:27:15 -08:00
parent 6d847b1aad
commit 18e09da255
11 changed files with 86 additions and 250 deletions

View File

@ -432,10 +432,6 @@ protected:
/// expressions as logical rather than arithmetic.
bool UseLogicalShr = true;
// If true, then the lexer and expression parser will support %neg(),
// %hi(), and similar unary operators.
bool HasMipsExpressions = false;
// If true, use Motorola-style integers in Assembly (ex. $0ac).
bool UseMotorolaIntegers = false;
@ -723,7 +719,6 @@ public:
bool shouldUseLogicalShr() const { return UseLogicalShr; }
bool hasMipsExpressions() const { return HasMipsExpressions; }
bool shouldUseMotorolaIntegers() const { return UseMotorolaIntegers; }
};

View File

@ -52,14 +52,6 @@ public:
Amp, AmpAmp, Exclaim, ExclaimEqual, Percent, Hash,
Less, LessEqual, LessLess, LessGreater,
Greater, GreaterEqual, GreaterGreater, At, MinusGreater,
// MIPS unary expression operators such as %neg.
PercentCall16, PercentCall_Hi, PercentCall_Lo, PercentDtprel_Hi,
PercentDtprel_Lo, PercentGot, PercentGot_Disp, PercentGot_Hi, PercentGot_Lo,
PercentGot_Ofst, PercentGot_Page, PercentGottprel, PercentGp_Rel, PercentHi,
PercentHigher, PercentHighest, PercentLo, PercentNeg, PercentPcrel_Hi,
PercentPcrel_Lo, PercentTlsgd, PercentTlsldm, PercentTprel_Hi,
PercentTprel_Lo
};
private:

View File

@ -524,12 +524,6 @@ public:
/// output streamer, if the target does not emit them immediately.
virtual void flushPendingInstructions(MCStreamer &Out) {}
virtual const MCExpr *createTargetUnaryExpr(const MCExpr *E,
AsmToken::TokenKind OperatorToken,
MCContext &Ctx) {
return nullptr;
}
// For any initialization at the beginning of parsing.
virtual void onBeginOfFile() {}

View File

@ -879,45 +879,6 @@ AsmToken AsmLexer::LexToken() {
if (LexMotorolaIntegers && (*CurPtr == '0' || *CurPtr == '1')) {
return LexDigit();
}
if (MAI.hasMipsExpressions()) {
AsmToken::TokenKind Operator;
unsigned OperatorLength;
std::tie(Operator, OperatorLength) =
StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>(
StringRef(CurPtr))
.StartsWith("call16", {AsmToken::PercentCall16, 7})
.StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8})
.StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8})
.StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10})
.StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10})
.StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9})
.StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7})
.StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7})
.StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9})
.StartsWith("got_page", {AsmToken::PercentGot_Page, 9})
.StartsWith("gottprel", {AsmToken::PercentGottprel, 9})
.StartsWith("got", {AsmToken::PercentGot, 4})
.StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7})
.StartsWith("higher", {AsmToken::PercentHigher, 7})
.StartsWith("highest", {AsmToken::PercentHighest, 8})
.StartsWith("hi", {AsmToken::PercentHi, 3})
.StartsWith("lo", {AsmToken::PercentLo, 3})
.StartsWith("neg", {AsmToken::PercentNeg, 4})
.StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9})
.StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9})
.StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6})
.StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7})
.StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9})
.StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9})
.Default({AsmToken::Percent, 1});
if (Operator != AsmToken::Percent) {
CurPtr += OperatorLength - 1;
return AsmToken(Operator, StringRef(TokStart, OperatorLength));
}
}
return AsmToken(AsmToken::Percent, StringRef(TokStart, 1));
case '/':
IsAtStartOfStatement = OldIsAtStartOfStatement;

View File

@ -1344,42 +1344,6 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,
return true;
Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);
return false;
// MIPS unary expression operators. The lexer won't generate these tokens if
// MCAsmInfo::HasMipsExpressions is false for the target.
case AsmToken::PercentCall16:
case AsmToken::PercentCall_Hi:
case AsmToken::PercentCall_Lo:
case AsmToken::PercentDtprel_Hi:
case AsmToken::PercentDtprel_Lo:
case AsmToken::PercentGot:
case AsmToken::PercentGot_Disp:
case AsmToken::PercentGot_Hi:
case AsmToken::PercentGot_Lo:
case AsmToken::PercentGot_Ofst:
case AsmToken::PercentGot_Page:
case AsmToken::PercentGottprel:
case AsmToken::PercentGp_Rel:
case AsmToken::PercentHi:
case AsmToken::PercentHigher:
case AsmToken::PercentHighest:
case AsmToken::PercentLo:
case AsmToken::PercentNeg:
case AsmToken::PercentPcrel_Hi:
case AsmToken::PercentPcrel_Lo:
case AsmToken::PercentTlsgd:
case AsmToken::PercentTlsldm:
case AsmToken::PercentTprel_Hi:
case AsmToken::PercentTprel_Lo:
Lex(); // Eat the operator.
if (Lexer.isNot(AsmToken::LParen))
return TokError("expected '(' after operator");
Lex(); // Eat the operator.
if (parseExpression(Res, EndLoc))
return true;
if (parseRParen())
return true;
Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx);
return !Res;
}
}

View File

@ -96,30 +96,6 @@ void AsmToken::dump(raw_ostream &OS) const {
case AsmToken::Space: OS << "Space"; break;
case AsmToken::Star: OS << "Star"; break;
case AsmToken::Tilde: OS << "Tilde"; break;
case AsmToken::PercentCall16: OS << "PercentCall16"; break;
case AsmToken::PercentCall_Hi: OS << "PercentCall_Hi"; break;
case AsmToken::PercentCall_Lo: OS << "PercentCall_Lo"; break;
case AsmToken::PercentDtprel_Hi: OS << "PercentDtprel_Hi"; break;
case AsmToken::PercentDtprel_Lo: OS << "PercentDtprel_Lo"; break;
case AsmToken::PercentGot: OS << "PercentGot"; break;
case AsmToken::PercentGot_Disp: OS << "PercentGot_Disp"; break;
case AsmToken::PercentGot_Hi: OS << "PercentGot_Hi"; break;
case AsmToken::PercentGot_Lo: OS << "PercentGot_Lo"; break;
case AsmToken::PercentGot_Ofst: OS << "PercentGot_Ofst"; break;
case AsmToken::PercentGot_Page: OS << "PercentGot_Page"; break;
case AsmToken::PercentGottprel: OS << "PercentGottprel"; break;
case AsmToken::PercentGp_Rel: OS << "PercentGp_Rel"; break;
case AsmToken::PercentHi: OS << "PercentHi"; break;
case AsmToken::PercentHigher: OS << "PercentHigher"; break;
case AsmToken::PercentHighest: OS << "PercentHighest"; break;
case AsmToken::PercentLo: OS << "PercentLo"; break;
case AsmToken::PercentNeg: OS << "PercentNeg"; break;
case AsmToken::PercentPcrel_Hi: OS << "PercentPcrel_Hi"; break;
case AsmToken::PercentPcrel_Lo: OS << "PercentPcrel_Lo"; break;
case AsmToken::PercentTlsgd: OS << "PercentTlsgd"; break;
case AsmToken::PercentTlsldm: OS << "PercentTlsldm"; break;
case AsmToken::PercentTprel_Hi: OS << "PercentTprel_Hi"; break;
case AsmToken::PercentTprel_Lo: OS << "PercentTprel_Lo"; break;
}
// Print the token string.

View File

@ -1610,42 +1610,6 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,
return true;
Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);
return false;
// MIPS unary expression operators. The lexer won't generate these tokens if
// MCAsmInfo::HasMipsExpressions is false for the target.
case AsmToken::PercentCall16:
case AsmToken::PercentCall_Hi:
case AsmToken::PercentCall_Lo:
case AsmToken::PercentDtprel_Hi:
case AsmToken::PercentDtprel_Lo:
case AsmToken::PercentGot:
case AsmToken::PercentGot_Disp:
case AsmToken::PercentGot_Hi:
case AsmToken::PercentGot_Lo:
case AsmToken::PercentGot_Ofst:
case AsmToken::PercentGot_Page:
case AsmToken::PercentGottprel:
case AsmToken::PercentGp_Rel:
case AsmToken::PercentHi:
case AsmToken::PercentHigher:
case AsmToken::PercentHighest:
case AsmToken::PercentLo:
case AsmToken::PercentNeg:
case AsmToken::PercentPcrel_Hi:
case AsmToken::PercentPcrel_Lo:
case AsmToken::PercentTlsgd:
case AsmToken::PercentTlsldm:
case AsmToken::PercentTprel_Hi:
case AsmToken::PercentTprel_Lo:
Lex(); // Eat the operator.
if (Lexer.isNot(AsmToken::LParen))
return TokError("expected '(' after operator");
Lex(); // Eat the operator.
if (parseExpression(Res, EndLoc))
return true;
if (parseRParen())
return true;
Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx);
return !Res;
}
}

View File

@ -205,6 +205,7 @@ class MipsAsmParser : public MCTargetAsmParser {
ParseStatus parseJumpTarget(OperandVector &Operands);
ParseStatus parseInvNum(OperandVector &Operands);
ParseStatus parseRegisterList(OperandVector &Operands);
const MCExpr *parseRelocExpr();
bool searchSymbolAlias(OperandVector &Operands);
@ -353,8 +354,6 @@ class MipsAsmParser : public MCTargetAsmParser {
bool reportParseError(const Twine &ErrorMsg);
bool reportParseError(SMLoc Loc, const Twine &ErrorMsg);
bool parseMemOffset(const MCExpr *&Res, bool isParenExpr);
bool parseSetMips0Directive();
bool parseSetArchDirective();
bool parseSetFeature(uint64_t Feature);
@ -741,64 +740,6 @@ public:
bool isLittle() const { return IsLittleEndian; }
const MCExpr *createTargetUnaryExpr(const MCExpr *E,
AsmToken::TokenKind OperatorToken,
MCContext &Ctx) override {
switch(OperatorToken) {
default:
llvm_unreachable("Unknown token");
return nullptr;
case AsmToken::PercentCall16:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, E, Ctx);
case AsmToken::PercentCall_Hi:
return MipsMCExpr::create(MipsMCExpr::MEK_CALL_HI16, E, Ctx);
case AsmToken::PercentCall_Lo:
return MipsMCExpr::create(MipsMCExpr::MEK_CALL_LO16, E, Ctx);
case AsmToken::PercentDtprel_Hi:
return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_HI, E, Ctx);
case AsmToken::PercentDtprel_Lo:
return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_LO, E, Ctx);
case AsmToken::PercentGot:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT, E, Ctx);
case AsmToken::PercentGot_Disp:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, E, Ctx);
case AsmToken::PercentGot_Hi:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_HI16, E, Ctx);
case AsmToken::PercentGot_Lo:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_LO16, E, Ctx);
case AsmToken::PercentGot_Ofst:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_OFST, E, Ctx);
case AsmToken::PercentGot_Page:
return MipsMCExpr::create(MipsMCExpr::MEK_GOT_PAGE, E, Ctx);
case AsmToken::PercentGottprel:
return MipsMCExpr::create(MipsMCExpr::MEK_GOTTPREL, E, Ctx);
case AsmToken::PercentGp_Rel:
return MipsMCExpr::create(MipsMCExpr::MEK_GPREL, E, Ctx);
case AsmToken::PercentHi:
return MipsMCExpr::create(MipsMCExpr::MEK_HI, E, Ctx);
case AsmToken::PercentHigher:
return MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, E, Ctx);
case AsmToken::PercentHighest:
return MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, E, Ctx);
case AsmToken::PercentLo:
return MipsMCExpr::create(MipsMCExpr::MEK_LO, E, Ctx);
case AsmToken::PercentNeg:
return MipsMCExpr::create(MipsMCExpr::MEK_NEG, E, Ctx);
case AsmToken::PercentPcrel_Hi:
return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_HI16, E, Ctx);
case AsmToken::PercentPcrel_Lo:
return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_LO16, E, Ctx);
case AsmToken::PercentTlsgd:
return MipsMCExpr::create(MipsMCExpr::MEK_TLSGD, E, Ctx);
case AsmToken::PercentTlsldm:
return MipsMCExpr::create(MipsMCExpr::MEK_TLSLDM, E, Ctx);
case AsmToken::PercentTprel_Hi:
return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_HI, E, Ctx);
case AsmToken::PercentTprel_Lo:
return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_LO, E, Ctx);
}
}
bool areEqualRegs(const MCParsedAsmOperand &Op1,
const MCParsedAsmOperand &Op2) const override;
};
@ -6415,6 +6356,64 @@ MCRegister MipsAsmParser::getReg(int RC, int RegNo) {
return getContext().getRegisterInfo()->getRegClass(RC).getRegister(RegNo);
}
// Parse an expression with optional relocation operator prefixes (e.g. %lo).
// Some weird expressions allowed by gas are not supported for simplicity,
// e.g. "%lo foo", "(%lo(foo))", "%lo(foo)+1".
const MCExpr *MipsAsmParser::parseRelocExpr() {
auto getOp = [](StringRef Op) {
return StringSwitch<MipsMCExpr::MipsExprKind>(Op)
.Case("call16", MipsMCExpr::MEK_GOT_CALL)
.Case("call_hi", MipsMCExpr::MEK_CALL_HI16)
.Case("call_lo", MipsMCExpr::MEK_CALL_LO16)
.Case("dtprel_hi", MipsMCExpr::MEK_DTPREL_HI)
.Case("dtprel_lo", MipsMCExpr::MEK_DTPREL_LO)
.Case("got", MipsMCExpr::MEK_GOT)
.Case("got_disp", MipsMCExpr::MEK_GOT_DISP)
.Case("got_hi", MipsMCExpr::MEK_GOT_HI16)
.Case("got_lo", MipsMCExpr::MEK_GOT_LO16)
.Case("got_ofst", MipsMCExpr::MEK_GOT_OFST)
.Case("got_page", MipsMCExpr::MEK_GOT_PAGE)
.Case("gottprel", MipsMCExpr::MEK_GOTTPREL)
.Case("gp_rel", MipsMCExpr::MEK_GPREL)
.Case("hi", MipsMCExpr::MEK_HI)
.Case("higher", MipsMCExpr::MEK_HIGHER)
.Case("highest", MipsMCExpr::MEK_HIGHEST)
.Case("lo", MipsMCExpr::MEK_LO)
.Case("neg", MipsMCExpr::MEK_NEG)
.Case("pcrel_hi", MipsMCExpr::MEK_PCREL_HI16)
.Case("pcrel_lo", MipsMCExpr::MEK_PCREL_LO16)
.Case("tlsgd", MipsMCExpr::MEK_TLSGD)
.Case("tlsldm", MipsMCExpr::MEK_TLSLDM)
.Case("tprel_hi", MipsMCExpr::MEK_TPREL_HI)
.Case("tprel_lo", MipsMCExpr::MEK_TPREL_LO)
.Default(MipsMCExpr::MEK_None);
};
MCAsmParser &Parser = getParser();
StringRef Name;
const MCExpr *Res = nullptr;
SmallVector<MipsMCExpr::MipsExprKind, 0> Ops;
while (parseOptionalToken(AsmToken::Percent)) {
if (Parser.parseIdentifier(Name) ||
Parser.parseToken(AsmToken::LParen, "expected '('"))
return nullptr;
auto Op = getOp(Name);
if (Op == MipsMCExpr::MEK_None) {
Error(Parser.getTok().getLoc(), "invalid relocation operator");
return nullptr;
}
Ops.push_back(Op);
}
if (Parser.parseExpression(Res))
return nullptr;
while (Ops.size()) {
if (Parser.parseToken(AsmToken::RParen, "expected ')'"))
return nullptr;
Res = MipsMCExpr::create(Ops.pop_back_val(), Res, getContext());
}
return Res;
}
bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
MCAsmParser &Parser = getParser();
LLVM_DEBUG(dbgs() << "parseOperand\n");
@ -6465,15 +6464,11 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
return false;
}
default: {
LLVM_DEBUG(dbgs() << ".. generic integer expression\n");
const MCExpr *Expr;
SMLoc S = Parser.getTok().getLoc(); // Start location of the operand.
if (getParser().parseExpression(Expr))
const MCExpr *Expr = parseRelocExpr();
if (!Expr)
return true;
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(MipsOperand::CreateImm(Expr, S, E, *this));
return false;
}
@ -6512,14 +6507,6 @@ ParseStatus MipsAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
return (Reg == (unsigned)-1) ? ParseStatus::NoMatch : ParseStatus::Success;
}
bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) {
SMLoc S;
if (isParenExpr)
return getParser().parseExpression(Res, S) || getParser().parseRParen();
return getParser().parseExpression(Res);
}
ParseStatus MipsAsmParser::parseMemOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
LLVM_DEBUG(dbgs() << "parseMemOperand\n");
@ -6536,7 +6523,10 @@ ParseStatus MipsAsmParser::parseMemOperand(OperandVector &Operands) {
}
if (getLexer().getKind() != AsmToken::Dollar) {
if (parseMemOffset(IdVal, isParenExpr))
IdVal = parseRelocExpr();
if (!IdVal)
return ParseStatus::Failure;
if (isParenExpr && Parser.parseRParen())
return ParseStatus::Failure;
const AsmToken &Tok = Parser.getTok(); // Get the next token.

View File

@ -49,7 +49,6 @@ MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::DwarfCFI;
DwarfRegNumForCFI = true;
HasMipsExpressions = true;
}
void MipsCOFFMCAsmInfo::anchor() {}

View File

@ -16,13 +16,10 @@
# 32R2-EL: # fixup A - offset: 0, value: %lo(foo+(%lo(8))), kind: fixup_Mips_LO16
# 32R2-EL: lw $4, %lo(12+foo)($4) # encoding: [A,A,0x84,0x8c]
# 32R2-EL: # fixup A - offset: 0, value: %lo(12+foo), kind: fixup_Mips_LO16
# 32R2-EL: lw $4, %lo(16+foo)($4) # encoding: [A,A,0x84,0x8c]
# 32R2-EL: # fixup A - offset: 0, value: %lo(16+foo), kind: fixup_Mips_LO16
# 32R2-EL: lw $4, 10($4) # encoding: [0x0a,0x00,0x84,0x8c]
# 32R2-EL: lw $4, 15($4) # encoding: [0x0f,0x00,0x84,0x8c]
# 32R2-EL: lw $4, 21($4) # encoding: [0x15,0x00,0x84,0x8c]
# 32R2-EL: lw $4, 28($4) # encoding: [0x1c,0x00,0x84,0x8c]
# 32R2-EL: lw $4, 6($4) # encoding: [0x06,0x00,0x84,0x8c]
# 32R2-EL: .space 64
# MM-32R2-EL: .globl foo
@ -37,13 +34,10 @@
# MM-32R2-EL: # fixup A - offset: 0, value: %lo(foo+(%lo(8))), kind: fixup_MICROMIPS_LO16
# MM-32R2-EL: lw $4, %lo(12+foo)($4) # encoding: [0x84'A',0xfc'A',0x00,0x00]
# MM-32R2-EL: # fixup A - offset: 0, value: %lo(12+foo), kind: fixup_MICROMIPS_LO16
# MM-32R2-EL: lw $4, %lo(16+foo)($4) # encoding: [0x84'A',0xfc'A',0x00,0x00]
# MM-32R2-EL: # fixup A - offset: 0, value: %lo(16+foo), kind: fixup_MICROMIPS_LO16
# MM-32R2-EL: lw $4, 10($4) # encoding: [0x84,0xfc,0x0a,0x00]
# MM-32R2-EL: lw $4, 15($4) # encoding: [0x84,0xfc,0x0f,0x00]
# MM-32R2-EL: lw $4, 21($4) # encoding: [0x84,0xfc,0x15,0x00]
# MM-32R2-EL: lw $4, 28($4) # encoding: [0x84,0xfc,0x1c,0x00]
# MM-32R2-EL: lw $4, 6($4) # encoding: [0x84,0xfc,0x06,0x00]
# MM-32R2-EL: .space 64
.globl foo
@ -53,11 +47,18 @@ foo:
lw $4,((10 + 4) * 4)($4)
lw $4,%lo (2 * 4) + foo($4)
lw $4,%lo((3 * 4) + foo)($4)
lw $4,(((%lo ((4 * 4) + foo))))($4)
lw $4, (((1+2)+3)+4)($4)
lw $4, ((((1+2)+3)+4)+5)($4)
lw $4, (((((1+2)+3)+4)+5)+6)($4)
lw $4, ((((((1+2)+3)+4)+5)+6)+7)($4)
lw $4, (%lo((1+2)+65536)+3)($4)
.space 64
.end foo
.ifdef ERR
# ERR: [[#@LINE+2]]:28: error: expected ')'
# ERR: [[#@LINE+1]]:28: error: unexpected token in argument list
lw $4, (%lo((1+2)+65536)+3)($4)
# ERR: [[#@LINE+2]]:13: error: unexpected token in expression
# ERR: [[#@LINE+1]]:13: error: unexpected token in argument list
lw $4,(((%lo ((4 * 4) + foo))))($4)
.endif

View File

@ -14,12 +14,12 @@
subu $4, $a4, $a4 # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, $4, %hi(end) # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, $4, end + 4 # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, $4, end # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, $4, sp # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, $4, end + 4 # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
subu $4, $4, end # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
subu $4, $4, sp # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
subu $4, %lo($start) # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
@ -28,11 +28,11 @@
subu $4, $a4 # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, %hi(end) # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, end + 4 # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, end # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, sp # O32: [[@LINE]]:{{[0-9]+}}: error: unexpected token in argument list
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unexpected token in argument list
subu $4, end + 4 # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
subu $4, end # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
subu $4, sp # O32: [[@LINE]]:{{[0-9]+}}: error: unknown token in expression
# N64: [[@LINE-1]]:{{[0-9]+}}: error: unknown token in expression
$start: