[llvm] d045f1d - [RISCV] Allow LI with symbol difference as constant

Job Noorman via llvm-commits llvm-commits at lists.llvm.org
Wed May 17 02:35:39 PDT 2023


Author: Job Noorman
Date: 2023-05-17T11:35:20+02:00
New Revision: d045f1d393317962251ba6dc58e3f8edc7e2fd99

URL: https://github.com/llvm/llvm-project/commit/d045f1d393317962251ba6dc58e3f8edc7e2fd99
DIFF: https://github.com/llvm/llvm-project/commit/d045f1d393317962251ba6dc58e3f8edc7e2fd99.diff

LOG: [RISCV] Allow LI with symbol difference as constant

This patch lets the assembler accept code like the following:

.Lbuf: ...
.set .Lbuf_len, . - .Lbuf
li a0, .Lbuf_len

It works by translating such instances of LI into an ADDI and inserting
the correct constant value via a new fixup.

Note that this means that the constant value is restricted to 12 bits
since we cannot insert new instructions during the relaxation stage.
Binutils seems to have the same restriction though.

This patch also fixes a small issue where the SMLoc of an LI wasn't
propagated when translated to ADDI. While this is technically unrelated
to the main functionality of this patch, it improves error messages
related to the new use of LI.

This patch does _not_ allow I-type instructions to take such symbolic
constants as well. While technically possible (and allowed by binutils),
it's probably better to implement this in another patch.

Fixes #57461

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D135960

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
    llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
    llvm/test/MC/RISCV/fixups-invalid.s
    llvm/test/MC/RISCV/rv32i-aliases-valid.s
    llvm/test/MC/RISCV/rv64i-aliases-valid.s

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 9d45b7299a6e8..4c1bd2a6e6ff1 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -246,6 +246,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
 
   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 @@ struct RISCVOperand final : public MCParsedAsmOperand {
       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 @@ bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr,
   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
index 8ec2ae918335c..68dfb6852631c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -53,6 +53,7 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
       // 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 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
   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
index d254f3a06e264..5727aab3cd4ca 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -20,6 +20,8 @@ enum Fixups {
   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
index 831c1e788dd45..9de4178e7bdef 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -448,6 +448,8 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
       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
index 55ced21e1c9d3..44313e0164e36 100644
--- 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 
diff erence 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
index fb4004d9fe75b..c0e4be1f2d0ac 100644
--- 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 
diff erence
+.Lbuf: .skip 8
+.Lbuf_end:
+
 # CHECK-INST: addi a0, zero, 0
 # CHECK-ALIAS: li a0, 0
 li x10, 0
@@ -103,6 +107,12 @@ li a0, CONST+1
 # 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
index acdc083135554..b62ee3824e232 100644
--- 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 
diff erence
+.Lbuf: .skip 8
+.Lbuf_end:
+
 # CHECK-INST: addi a0, zero, 0
 # CHECK-ALIAS: li a0, 0
 li x10, 0
@@ -215,6 +219,12 @@ li a0, CONST
 # 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


        


More information about the llvm-commits mailing list