Index: lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -145,7 +145,19 @@ } } + StringRef getExpressionAsToken() const { + assert(isExpr()); + const MCSymbolRefExpr *S = cast(Expr); + return S->getSymbol().getName(); + } + + StringRef getToken() const { + assert(isToken()); + + if (Kind == Expression) + return getExpressionAsToken(); + return StringRef(Tok.Data, Tok.Length); } @@ -156,6 +168,8 @@ void addRegOrImmOperands(MCInst &Inst, unsigned N) const { if (isRegKind()) addRegOperands(Inst, N); + else if (isExpr()) + Inst.addOperand(MCOperand::createExpr(Expr)); else addImmOperands(Inst, N); } @@ -180,7 +194,17 @@ } bool isToken() const override { - return Kind == Token; + if (Kind == Token) + return true; + + if (Kind != Expression || !Expr) + return false; + + // When parsing operands, we can't always tell if something was meant to be + // a token, like 'gds', or an expression that references a global variable. + // In this case, we assume the string is an expression, and if we need to + // interpret is a token, then we treat the symbol name as the token. + return isa(Expr); } bool isImm() const override { @@ -316,7 +340,7 @@ } bool isSSrc32() const { - return isImm() || isSCSrc32(); + return isImm() || isSCSrc32() || isExpr(); } bool isSSrc64() const { @@ -1311,7 +1335,20 @@ return ResTy; if (getLexer().getKind() == AsmToken::Identifier) { + // If this identifier is a symbol, we want to create an expression for it. + // It is a little difficlut to distinguish between a symbol name, and + // an instruction flag like 'gds'. In order to do this, we parse + // all tokens as expressions and then treate the symbol name as the token + // string when we want to interpret the operand as a token. const auto &Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + const MCExpr *Expr = nullptr; + if (!Parser.parseExpression(Expr)) { + Operands.push_back(AMDGPUOperand::CreateExpr(Expr, S)); + Parser.Lex(); + return MatchOperand_Success; + } + Operands.push_back(AMDGPUOperand::CreateToken(Tok.getString(), Tok.getLoc())); Parser.Lex(); return MatchOperand_Success; @@ -2573,6 +2610,14 @@ return Operand.isIdxen() ? Match_Success : Match_InvalidOperand; case MCK_offen: return Operand.isOffen() ? Match_Success : Match_InvalidOperand; + case MCK_SSrc32: + // When operands have expression values, they will return true for isToken, + // because it is not possible to distinguish between a token and an + // expression at parse time. MatchInstructionImpl() will always try to + // match an operand as a token, when isToken returns true, and when the + // name of the expression is not a valid token, the match will fail, + // so we need to handle it here. + return Operand.isSSrc32() ? Match_Success : Match_InvalidOperand; default: return Match_InvalidOperand; } } Index: test/MC/AMDGPU/global-expr.s =================================================================== --- /dev/null +++ test/MC/AMDGPU/global-expr.s @@ -0,0 +1,25 @@ +// RUN: llvm-mc -arch=amdgcn -mcpu=fiji -show-encoding %s | FileCheck %s --check-prefix=VI + + +.globl global +.globl gds + +// Parse a global expression +s_mov_b32 s0, global +// VI: s_mov_b32 s0, global ; encoding: [0xff,0x00,0x80,0xbe,A,A,A,A] +// VI-NEXT: ; fixup A - offset: 4, value: global, kind: FK_PCRel_4 + +// Use a token with the same name as a global +ds_gws_init v2 gds +// VI: ds_gws_init v2 gds ; encoding: [0x00,0x00,0x33,0xd8,0x02,0x00,0x00,0x00] + + +; Use a global with the same name as a token +s_mov_b32 s0, gds +// VI: s_mov_b32 s0, gds ; encoding: [0xff,0x00,0x80,0xbe,A,A,A,A] +// VI-NEXT: ; fixup A - offset: 4, value: gds, kind: FK_PCRel_4 + +; Use a binary expression +s_mov_b32 s0, gds+4 +// VI: s_mov_b32 s0, gds+4 ; encoding: [0xff,0x00,0x80,0xbe,A,A,A,A] +// VI-NEXT: ; fixup A - offset: 4, value: gds+4, kind: FK_PCRel_4