diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -235,6 +235,7 @@ static bool classifySymbolRef(const MCExpr *Expr, RISCVMCExpr::VariantKind &Kind); + static bool isSymbolDiff(const MCExpr *Expr); RISCVAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) @@ -518,8 +519,12 @@ return true; // Given only Imm, ensuring that the actually specified constant is either // a signed or unsigned 64-bit number is unfortunately impossible. - return IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None && - (isRV64() || (isInt<32>(Imm) || isUInt<32>(Imm))); + if (IsConstantImm) { + return VK == RISCVMCExpr::VK_RISCV_None && + (isRV64() || (isInt<32>(Imm) || isUInt<32>(Imm))); + } + + return RISCVAsmParser::isSymbolDiff(getImm()); } bool isUImmLog2XLen() const { @@ -2022,6 +2027,16 @@ return false; } +bool RISCVAsmParser::isSymbolDiff(const MCExpr *Expr) { + MCValue Res; + MCFixup Fixup; + if (Expr->evaluateAsRelocatable(Res, nullptr, &Fixup)) { + return Res.getRefKind() == RISCVMCExpr::VK_RISCV_None && Res.getSymA() && + Res.getSymB(); + } + return false; +} + bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { // This returns false if this function recognizes the directive // regardless of whether it is successfully handles or reports an @@ -2651,10 +2666,12 @@ if (Op1.isExpr()) { // We must have li reg, %lo(sym) or li reg, %pcrel_lo(sym) or similar. // Just convert to an addi. This allows compatibility with gas. - emitToStreamer(Out, MCInstBuilder(RISCV::ADDI) - .addReg(Reg) - .addReg(RISCV::X0) - .addExpr(Op1.getExpr())); + MCInst Addi = MCInstBuilder(RISCV::ADDI) + .addReg(Reg) + .addReg(RISCV::X0) + .addExpr(Op1.getExpr()); + Addi.setLoc(IDLoc); + emitToStreamer(Out, Addi); return false; } int64_t Imm = Inst.getOperand(1).getImm(); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -53,6 +53,7 @@ // name offset bits flags {"fixup_riscv_hi20", 12, 20, 0}, {"fixup_riscv_lo12_i", 20, 12, 0}, + {"fixup_riscv_12_i", 20, 12, 0}, {"fixup_riscv_lo12_s", 0, 32, 0}, {"fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget}, @@ -411,6 +412,12 @@ case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_tprel_lo12_i: return Value & 0xfff; + case RISCV::fixup_riscv_12_i: + if (!isInt<12>(Value)) { + Ctx.reportError(Fixup.getLoc(), + "operand must be a constant 12-bit integer"); + } + return Value; case RISCV::fixup_riscv_lo12_s: case RISCV::fixup_riscv_pcrel_lo12_s: case RISCV::fixup_riscv_tprel_lo12_s: diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -19,6 +19,8 @@ fixup_riscv_hi20 = FirstTargetFixupKind, // 12-bit fixup corresponding to %lo(foo) for instructions like addi fixup_riscv_lo12_i, + // 12-bit fixup corresponding to foo-bar for instructions like addi + fixup_riscv_12_i, // 12-bit fixup corresponding to %lo(foo) for the S-type store instructions fixup_riscv_lo12_s, // 20-bit fixup corresponding to %pcrel_hi(foo) for instructions like auipc diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -355,6 +355,8 @@ FixupKind = RISCV::fixup_riscv_rvc_jump; } else if (MIFrm == RISCVII::InstFormatCB) { FixupKind = RISCV::fixup_riscv_rvc_branch; + } else if (MIFrm == RISCVII::InstFormatI) { + FixupKind = RISCV::fixup_riscv_12_i; } } diff --git a/llvm/test/MC/RISCV/rv32i-aliases-valid.s b/llvm/test/MC/RISCV/rv32i-aliases-valid.s --- a/llvm/test/MC/RISCV/rv32i-aliases-valid.s +++ b/llvm/test/MC/RISCV/rv32i-aliases-valid.s @@ -1,7 +1,7 @@ # RUN: llvm-mc %s -triple=riscv32 -riscv-no-aliases \ -# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-INST,CHECK-ASM-NOALIAS %s # RUN: llvm-mc %s -triple=riscv32 \ -# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-ALIAS,CHECK-ASM %s # RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ # RUN: | llvm-objdump -M no-aliases -d -r - \ # RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-EXPAND,CHECK-INST %s @@ -17,6 +17,10 @@ # Needed for testing valid %pcrel_lo expressions .Lpcrel_hi0: auipc a0, %pcrel_hi(foo) +# Needed for testing li with a symbol difference +.Lbuf: .skip 8 +.Lbuf_end: + # CHECK-INST: addi a0, zero, 0 # CHECK-ALIAS: li a0, 0 li x10, 0 @@ -101,6 +105,12 @@ # CHECK-EXPAND: addi a0, a0, 801 li a0, CONST +.equ CONST, .Lbuf_end - .Lbuf +# CHECK-ASM: li a0, CONST +# CHECK-ASM-NOALIAS: addi a0, zero, CONST +# CHECK-OBJ-NOALIAS: addi a0, zero, 8 +li a0, CONST + # CHECK-INST: csrrs t4, instreth, zero # CHECK-ALIAS: rdinstreth t4 rdinstreth x29 diff --git a/llvm/test/MC/RISCV/rv64i-aliases-valid.s b/llvm/test/MC/RISCV/rv64i-aliases-valid.s --- a/llvm/test/MC/RISCV/rv64i-aliases-valid.s +++ b/llvm/test/MC/RISCV/rv64i-aliases-valid.s @@ -1,7 +1,7 @@ # RUN: llvm-mc %s -triple=riscv64 -riscv-no-aliases \ -# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-INST %s +# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-INST,CHECK-ASM-NOALIAS %s # RUN: llvm-mc %s -triple=riscv64 \ -# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-ALIAS %s +# RUN: | FileCheck -check-prefixes=CHECK-EXPAND,CHECK-ALIAS,CHECK-ASM %s # RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ # RUN: | llvm-objdump -M no-aliases -d - \ # RUN: | FileCheck -check-prefixes=CHECK-OBJ-NOALIAS,CHECK-EXPAND,CHECK-INST %s @@ -20,6 +20,10 @@ # Needed for testing valid %pcrel_lo expressions .Lpcrel_hi0: auipc a0, %pcrel_hi(foo) +# Needed for testing li with a symbol difference +.Lbuf: .skip 8 +.Lbuf_end: + # CHECK-INST: addi a0, zero, 0 # CHECK-ALIAS: li a0, 0 li x10, 0 @@ -213,6 +217,12 @@ # CHECK-EXPAND: addiw a0, a0, 801 li a0, CONST +.equ CONST, .Lbuf_end - .Lbuf +# CHECK-ASM: li a0, CONST +# CHECK-ASM-NOALIAS: addi a0, zero, CONST +# CHECK-OBJ-NOALIAS: addi a0, zero, 8 +li a0, CONST + # CHECK-INST: subw t6, zero, ra # CHECK-ALIAS: negw t6, ra negw x31, x1