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 @@ -246,6 +246,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) @@ -562,8 +563,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 && - (isRV64Imm() || (isInt<32>(Imm) || isUInt<32>(Imm))); + if (IsConstantImm) { + return VK == RISCVMCExpr::VK_RISCV_None && + (isRV64Imm() || (isInt<32>(Imm) || isUInt<32>(Imm))); + } + + return RISCVAsmParser::isSymbolDiff(getImm()); } bool isUImmLog2XLen() const { @@ -2547,6 +2552,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 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}, @@ -421,6 +422,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 & 0xfff; 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 @@ -20,6 +20,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 @@ -448,6 +448,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/fixups-invalid.s b/llvm/test/MC/RISCV/fixups-invalid.s --- a/llvm/test/MC/RISCV/fixups-invalid.s +++ b/llvm/test/MC/RISCV/fixups-invalid.s @@ -5,3 +5,11 @@ .byte foo # CHECK: [[@LINE]]:7: error: 1-byte data relocations not supported .2byte foo # CHECK: [[@LINE]]:8: error: 2-byte data relocations not supported + +# Test that using li with a symbol difference constant rejects values that +# cannot fit in a signed 12-bit integer. +.Lbuf: .skip (1 << 11) +.Lbuf_end: +.equ CONST, .Lbuf_end - .Lbuf +# CHECK: error: operand must be a constant 12-bit integer +li a0, CONST 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 @@ -103,6 +107,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 @@ -215,6 +219,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