diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 7d8d82e381313..4b1a5745308dc 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -1762,6 +1762,19 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { SMLoc S = getLoc(); const MCExpr *Res; + auto SysRegFromConstantInt = [](const MCExpr *E, SMLoc S) { + if (auto *CE = dyn_cast(E)) { + int64_t Imm = CE->getValue(); + if (isUInt<12>(Imm)) { + auto SysReg = RISCVSysReg::lookupSysRegByEncoding(Imm); + // Accept an immediate representing a named or un-named Sys Reg + // if the range is valid, regardless of the required features. + return RISCVOperand::createSysReg(SysReg ? SysReg->Name : "", S, Imm); + } + } + return std::unique_ptr(); + }; + switch (getLexer().getKind()) { default: return ParseStatus::NoMatch; @@ -1775,17 +1788,9 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { if (getParser().parseExpression(Res)) return ParseStatus::Failure; - auto *CE = dyn_cast(Res); - if (CE) { - int64_t Imm = CE->getValue(); - if (isUInt<12>(Imm)) { - auto SysReg = RISCVSysReg::lookupSysRegByEncoding(Imm); - // Accept an immediate representing a named or un-named Sys Reg - // if the range is valid, regardless of the required features. - Operands.push_back( - RISCVOperand::createSysReg(SysReg ? SysReg->Name : "", S, Imm)); - return ParseStatus::Success; - } + if (auto SysOpnd = SysRegFromConstantInt(Res, S)) { + Operands.push_back(std::move(SysOpnd)); + return ParseStatus::Success; } return generateImmOutOfRangeError(S, 0, (1 << 12) - 1); @@ -1851,6 +1856,18 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { return ParseStatus::Success; } + // Accept a symbol name that evaluates to an absolute value. + MCSymbol *Sym = getContext().lookupSymbol(Identifier); + if (Sym && Sym->isVariable()) { + // Pass false for SetUsed, since redefining the value later does not + // affect this instruction. + if (auto SysOpnd = SysRegFromConstantInt( + Sym->getVariableValue(/*SetUsed=*/false), S)) { + Operands.push_back(std::move(SysOpnd)); + return ParseStatus::Success; + } + } + return generateImmOutOfRangeError(S, 0, (1 << 12) - 1, "operand must be a valid system register " "name or an integer in the range"); diff --git a/llvm/test/MC/RISCV/csr-abs-sym.s b/llvm/test/MC/RISCV/csr-abs-sym.s new file mode 100644 index 0000000000000..93ecab0db106b --- /dev/null +++ b/llvm/test/MC/RISCV/csr-abs-sym.s @@ -0,0 +1,48 @@ +## Check that we can use an absolute symbol value as a CSR number +# RUN: llvm-mc -triple riscv32 %s | FileCheck %s +# RUN: not llvm-mc -triple riscv32 %s --defsym=CHECK_BAD=1 2>&1 | FileCheck %s --check-prefix=ERROR + +.set fflags_abs_sym, 1 +csrr a0, fflags_abs_sym +# CHECK: csrr a0, fflags + +csrr a0, (fflags_abs_sym+1) +# CHECK: csrr a0, frm + +.equ fplus_one_abs_sym, fflags_abs_sym + 1 +csrr a0, fplus_one_abs_sym +# CHECK: csrr a0, frm + +## Check that redefining the value is allowed +## If we were to use Sym->getVariableValue(true) this code would assert with +## Assertion `!IsUsed && "Cannot set a variable that has already been used."' failed. +.set csr_index, 1 +# CHECK: csrr a0, fflags +csrr a0, csr_index +.set csr_index, 2 +# CHECK: csrr a0, frm +csrr a0, csr_index + +.ifdef CHECK_BAD +.set out_of_range, 4097 +csrr a0, out_of_range +# ERROR: [[#@LINE-1]]:10: error: operand must be a valid system register name or an integer in the range [0, 4095] + +csrr a0, undef_symbol +# ERROR: [[#@LINE-1]]:10: error: operand must be a valid system register name or an integer in the range [0, 4095] + +local_label: +csrr a0, local_label +# ERROR: [[#@LINE-1]]:10: error: operand must be a valid system register name or an integer in the range [0, 4095] + +.Lstart: +.space 10 +.Lend: +csrr a0, .Lstart-.Lend +# ERROR: [[#@LINE-1]]:10: error: operand must be a valid system register name or an integer in the range [0, 4095] + +.set dot_set_sym_diff, .Lstart-.Lend +csrr a0, dot_set_sym_diff +# ERROR: [[#@LINE-1]]:10: error: operand must be a valid system register name or an integer in the range [0, 4095] + +.endif