[llvm] [RISCV] Add support for QC.E.LI in RISCVMergeBaseOffset (PR #175310)

Sudharsan Veeravalli via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 10 06:17:27 PST 2026


https://github.com/svs-quic created https://github.com/llvm/llvm-project/pull/175310

When we have `Xqcili` enabled and it is the `small code model`, we use the `QC.E.LI` instruction to materialize addresses. Add support for `QC.E.LI` in the `RISCVMergeBaseOffset` pass to merge the offset of the address calculation into the offset field in a global address lowering sequence.

>From 3a07605f47ade17c80ccc603bf4ace1e09c93805 Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Sat, 10 Jan 2026 18:36:17 +0530
Subject: [PATCH 1/2] Pre-commit test

---
 .../CodeGen/RISCV/hoist-global-addr-base.ll   | 626 ++++++++++++++----
 1 file changed, 486 insertions(+), 140 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll b/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
index d9c2a8cff3123..3f29b00c4b409 100644
--- a/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
+++ b/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
@@ -1,8 +1,10 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv32  < %s | FileCheck  %s --check-prefixes=CHECK,RV32
-; RUN: llc -mtriple=riscv64  < %s | FileCheck  %s --check-prefixes=CHECK,RV64
-; RUN: llc -mtriple=riscv32 -mattr=+zba < %s | FileCheck  %s --check-prefixes=CHECK,RV32
-; RUN: llc -mtriple=riscv64 -mattr=+zba < %s | FileCheck  %s --check-prefixes=CHECK,RV64
+; RUN: llc -mtriple=riscv32  < %s | FileCheck  %s --check-prefixes=RV32
+; RUN: llc -mtriple=riscv32  -mattr=+xqcili,+xqcilia < %s | FileCheck  %s --check-prefixes=RV32XQCI
+; RUN: llc -mtriple=riscv64  < %s | FileCheck  %s --check-prefixes=RV64
+; RUN: llc -mtriple=riscv32 -mattr=+zba < %s | FileCheck  %s --check-prefixes=RV32
+; RUN: llc -mtriple=riscv32 -mattr=+zba,+xqcili,+xqcilia  < %s | FileCheck  %s --check-prefixes=RV32XQCI
+; RUN: llc -mtriple=riscv64 -mattr=+zba < %s | FileCheck  %s --check-prefixes=RV64
 
 %struct.S = type { [40 x i32], i32, i32, i32, [4100 x i32], i32, i32, i32 }
 @s = common dso_local global %struct.S zeroinitializer, align 4
@@ -12,15 +14,34 @@
 
 
 define dso_local void @multiple_stores() local_unnamed_addr nounwind {
-; CHECK-LABEL: multiple_stores:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s)
-; CHECK-NEXT:    addi a0, a0, %lo(s)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    li a2, 20
-; CHECK-NEXT:    sw a1, 160(a0)
-; CHECK-NEXT:    sw a2, 164(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: multiple_stores:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s)
+; RV32-NEXT:    addi a0, a0, %lo(s)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    li a2, 20
+; RV32-NEXT:    sw a1, 160(a0)
+; RV32-NEXT:    sw a2, 164(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: multiple_stores:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    li a2, 20
+; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:    sw a2, 164(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: multiple_stores:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s)
+; RV64-NEXT:    addi a0, a0, %lo(s)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    li a2, 20
+; RV64-NEXT:    sw a1, 160(a0)
+; RV64-NEXT:    sw a2, 164(a0)
+; RV64-NEXT:    ret
 entry:
   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
   store i32 20, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
@@ -28,17 +49,40 @@ entry:
 }
 
 define dso_local void @control_flow_with_mem_access() local_unnamed_addr nounwind {
-; CHECK-LABEL: control_flow_with_mem_access:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s)
-; CHECK-NEXT:    addi a0, a0, %lo(s)
-; CHECK-NEXT:    lw a1, 164(a0)
-; CHECK-NEXT:    blez a1, .LBB1_2
-; CHECK-NEXT:  # %bb.1: # %if.then
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sw a1, 160(a0)
-; CHECK-NEXT:  .LBB1_2: # %if.end
-; CHECK-NEXT:    ret
+; RV32-LABEL: control_flow_with_mem_access:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s)
+; RV32-NEXT:    addi a0, a0, %lo(s)
+; RV32-NEXT:    lw a1, 164(a0)
+; RV32-NEXT:    blez a1, .LBB1_2
+; RV32-NEXT:  # %bb.1: # %if.then
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sw a1, 160(a0)
+; RV32-NEXT:  .LBB1_2: # %if.end
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: control_flow_with_mem_access:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    lw a1, 164(a0)
+; RV32XQCI-NEXT:    blez a1, .LBB1_2
+; RV32XQCI-NEXT:  # %bb.1: # %if.then
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:  .LBB1_2: # %if.end
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: control_flow_with_mem_access:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s)
+; RV64-NEXT:    addi a0, a0, %lo(s)
+; RV64-NEXT:    lw a1, 164(a0)
+; RV64-NEXT:    blez a1, .LBB1_2
+; RV64-NEXT:  # %bb.1: # %if.then
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sw a1, 160(a0)
+; RV64-NEXT:  .LBB1_2: # %if.end
+; RV64-NEXT:    ret
 entry:
   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
   %cmp = icmp sgt i32 %0, 0
@@ -61,11 +105,23 @@ if.end:                                           ; preds = %if.then, %entry
 ; addi a0, a0, -160
 ; add  a0, a0, a1  ---> base + offset.
 define ptr @big_offset_neg_addi() nounwind {
-; CHECK-LABEL: big_offset_neg_addi:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(g+73568)
-; CHECK-NEXT:    addi a0, a0, %lo(g+73568)
-; CHECK-NEXT:    ret
+; RV32-LABEL: big_offset_neg_addi:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(g+73568)
+; RV32-NEXT:    addi a0, a0, %lo(g+73568)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: big_offset_neg_addi:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, g
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 73568
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: big_offset_neg_addi:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(g+73568)
+; RV64-NEXT:    addi a0, a0, %lo(g+73568)
+; RV64-NEXT:    ret
   ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 73568)
 }
 
@@ -76,56 +132,129 @@ define ptr @big_offset_neg_addi() nounwind {
 ; lui  a1, 128     ---> offset
 ; add  a0, a0, a1  ---> base + offset.
 define ptr @big_offset_lui_tail() nounwind {
-; CHECK-LABEL: big_offset_lui_tail:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(g+524288)
-; CHECK-NEXT:    addi a0, a0, %lo(g+524288)
-; CHECK-NEXT:    ret
+; RV32-LABEL: big_offset_lui_tail:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(g+524288)
+; RV32-NEXT:    addi a0, a0, %lo(g+524288)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: big_offset_lui_tail:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, g
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 524288
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: big_offset_lui_tail:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(g+524288)
+; RV64-NEXT:    addi a0, a0, %lo(g+524288)
+; RV64-NEXT:    ret
   ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 524288)
 }
 
 define ptr @big_offset_neg_lui_tail() {
-; CHECK-LABEL: big_offset_neg_lui_tail:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar-8192)
-; CHECK-NEXT:    addi a0, a0, %lo(bar-8192)
-; CHECK-NEXT:    ret
+; RV32-LABEL: big_offset_neg_lui_tail:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar-8192)
+; RV32-NEXT:    addi a0, a0, %lo(bar-8192)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: big_offset_neg_lui_tail:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, -8192
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: big_offset_neg_lui_tail:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar-8192)
+; RV64-NEXT:    addi a0, a0, %lo(bar-8192)
+; RV64-NEXT:    ret
   ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8192)
 }
 
 define dso_local ptr @big_offset_one_use() local_unnamed_addr nounwind {
-; CHECK-LABEL: big_offset_one_use:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s+16572)
-; CHECK-NEXT:    addi a0, a0, %lo(s+16572)
-; CHECK-NEXT:    ret
+; RV32-LABEL: big_offset_one_use:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s+16572)
+; RV32-NEXT:    addi a0, a0, %lo(s+16572)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: big_offset_one_use:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 16572
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: big_offset_one_use:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s+16572)
+; RV64-NEXT:    addi a0, a0, %lo(s+16572)
+; RV64-NEXT:    ret
 entry:
   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 5)
 }
 
 define dso_local ptr @small_offset_one_use() local_unnamed_addr nounwind {
-; CHECK-LABEL: small_offset_one_use:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s+160)
-; CHECK-NEXT:    addi a0, a0, %lo(s+160)
-; CHECK-NEXT:    ret
+; RV32-LABEL: small_offset_one_use:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s+160)
+; RV32-NEXT:    addi a0, a0, %lo(s+160)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: small_offset_one_use:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    addi a0, a0, 160
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: small_offset_one_use:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s+160)
+; RV64-NEXT:    addi a0, a0, %lo(s+160)
+; RV64-NEXT:    ret
 entry:
   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1)
 }
 
 define dso_local ptr @control_flow_no_mem(i32 %n) local_unnamed_addr nounwind {
-; CHECK-LABEL: control_flow_no_mem:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s)
-; CHECK-NEXT:    addi a0, a0, %lo(s)
-; CHECK-NEXT:    lw a1, 164(a0)
-; CHECK-NEXT:    beqz a1, .LBB7_2
-; CHECK-NEXT:  # %bb.1: # %if.end
-; CHECK-NEXT:    addi a0, a0, 168
-; CHECK-NEXT:    ret
-; CHECK-NEXT:  .LBB7_2: # %if.then
-; CHECK-NEXT:    addi a0, a0, 160
-; CHECK-NEXT:    ret
+; RV32-LABEL: control_flow_no_mem:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s)
+; RV32-NEXT:    addi a0, a0, %lo(s)
+; RV32-NEXT:    lw a1, 164(a0)
+; RV32-NEXT:    beqz a1, .LBB7_2
+; RV32-NEXT:  # %bb.1: # %if.end
+; RV32-NEXT:    addi a0, a0, 168
+; RV32-NEXT:    ret
+; RV32-NEXT:  .LBB7_2: # %if.then
+; RV32-NEXT:    addi a0, a0, 160
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: control_flow_no_mem:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    lw a1, 164(a0)
+; RV32XQCI-NEXT:    beqz a1, .LBB7_2
+; RV32XQCI-NEXT:  # %bb.1: # %if.end
+; RV32XQCI-NEXT:    addi a0, a0, 168
+; RV32XQCI-NEXT:    ret
+; RV32XQCI-NEXT:  .LBB7_2: # %if.then
+; RV32XQCI-NEXT:    addi a0, a0, 160
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: control_flow_no_mem:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s)
+; RV64-NEXT:    addi a0, a0, %lo(s)
+; RV64-NEXT:    lw a1, 164(a0)
+; RV64-NEXT:    beqz a1, .LBB7_2
+; RV64-NEXT:  # %bb.1: # %if.end
+; RV64-NEXT:    addi a0, a0, 168
+; RV64-NEXT:    ret
+; RV64-NEXT:  .LBB7_2: # %if.then
+; RV64-NEXT:    addi a0, a0, 160
+; RV64-NEXT:    ret
 entry:
   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
   %cmp = icmp eq i32 %0, 0
@@ -151,6 +280,20 @@ define dso_local i32 @load_half() nounwind {
 ; RV32-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
 ; RV32-NEXT:    call abort
 ;
+; RV32XQCI-LABEL: load_half:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, foo
+; RV32XQCI-NEXT:    lhu a0, 8(a0)
+; RV32XQCI-NEXT:    li a1, 140
+; RV32XQCI-NEXT:    bne a0, a1, .LBB8_2
+; RV32XQCI-NEXT:  # %bb.1: # %if.end
+; RV32XQCI-NEXT:    li a0, 0
+; RV32XQCI-NEXT:    ret
+; RV32XQCI-NEXT:  .LBB8_2: # %if.then
+; RV32XQCI-NEXT:    addi sp, sp, -16
+; RV32XQCI-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32XQCI-NEXT:    call abort
+;
 ; RV64-LABEL: load_half:
 ; RV64:       # %bb.0: # %entry
 ; RV64-NEXT:    lui a0, %hi(foo+8)
@@ -180,23 +323,49 @@ if.end:
 declare void @abort()
 
 define dso_local void @one_store() local_unnamed_addr nounwind {
-; CHECK-LABEL: one_store:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s+160)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sw a1, %lo(s+160)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: one_store:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s+160)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sw a1, %lo(s+160)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: one_store:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: one_store:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s+160)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sw a1, %lo(s+160)(a0)
+; RV64-NEXT:    ret
 entry:
   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
   ret void
 }
 
 define ptr @neg_offset() {
-; CHECK-LABEL: neg_offset:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar-8191)
-; CHECK-NEXT:    addi a0, a0, %lo(bar-8191)
-; CHECK-NEXT:    ret
+; RV32-LABEL: neg_offset:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar-8191)
+; RV32-NEXT:    addi a0, a0, %lo(bar-8191)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: neg_offset:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, -8191
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: neg_offset:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar-8191)
+; RV64-NEXT:    addi a0, a0, %lo(bar-8191)
+; RV64-NEXT:    ret
     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8191)
 }
 
@@ -209,6 +378,12 @@ define ptr @neg_offset_not_simm32() {
 ; RV32-NEXT:    addi a0, a0, %lo(bar+2147482283)
 ; RV32-NEXT:    ret
 ;
+; RV32XQCI-LABEL: neg_offset_not_simm32:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addai a0, 2147482283
+; RV32XQCI-NEXT:    ret
+;
 ; RV64-LABEL: neg_offset_not_simm32:
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    lui a0, %hi(bar)
@@ -221,51 +396,115 @@ define ptr @neg_offset_not_simm32() {
 }
 
 define ptr @offset_addi_addi() {
-; CHECK-LABEL: offset_addi_addi:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+3211)
-; CHECK-NEXT:    addi a0, a0, %lo(bar+3211)
-; CHECK-NEXT:    ret
+; RV32-LABEL: offset_addi_addi:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+3211)
+; RV32-NEXT:    addi a0, a0, %lo(bar+3211)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: offset_addi_addi:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 3211
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: offset_addi_addi:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+3211)
+; RV64-NEXT:    addi a0, a0, %lo(bar+3211)
+; RV64-NEXT:    ret
     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
 }
 
 define ptr @offset_addi_addi_neg() {
-; CHECK-LABEL: offset_addi_addi_neg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar-4000)
-; CHECK-NEXT:    addi a0, a0, %lo(bar-4000)
-; CHECK-NEXT:    ret
+; RV32-LABEL: offset_addi_addi_neg:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar-4000)
+; RV32-NEXT:    addi a0, a0, %lo(bar-4000)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: offset_addi_addi_neg:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, -4000
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: offset_addi_addi_neg:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar-4000)
+; RV64-NEXT:    addi a0, a0, %lo(bar-4000)
+; RV64-NEXT:    ret
     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000)
 }
 
 ; With Zba the constant 6424 is created with LI+SH2ADD.
 define ptr @offset_sh2add() {
-; CHECK-LABEL: offset_sh2add:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+6424)
-; CHECK-NEXT:    addi a0, a0, %lo(bar+6424)
-; CHECK-NEXT:    ret
+; RV32-LABEL: offset_sh2add:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+6424)
+; RV32-NEXT:    addi a0, a0, %lo(bar+6424)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: offset_sh2add:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 6424
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: offset_sh2add:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+6424)
+; RV64-NEXT:    addi a0, a0, %lo(bar+6424)
+; RV64-NEXT:    ret
     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424)
 }
 
 ; With Zba the constant 12848 is created with LI+SH3ADD.
 define ptr @offset_sh3add() {
-; CHECK-LABEL: offset_sh3add:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+12848)
-; CHECK-NEXT:    addi a0, a0, %lo(bar+12848)
-; CHECK-NEXT:    ret
+; RV32-LABEL: offset_sh3add:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+12848)
+; RV32-NEXT:    addi a0, a0, %lo(bar+12848)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: offset_sh3add:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    qc.e.addi a0, a0, 12848
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: offset_sh3add:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+12848)
+; RV64-NEXT:    addi a0, a0, %lo(bar+12848)
+; RV64-NEXT:    ret
     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848)
 }
 
 define dso_local void @read_modify_write() local_unnamed_addr nounwind {
-; CHECK-LABEL: read_modify_write:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s+160)
-; CHECK-NEXT:    lw a1, %lo(s+160)(a0)
-; CHECK-NEXT:    addi a1, a1, 10
-; CHECK-NEXT:    sw a1, %lo(s+160)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: read_modify_write:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s+160)
+; RV32-NEXT:    lw a1, %lo(s+160)(a0)
+; RV32-NEXT:    addi a1, a1, 10
+; RV32-NEXT:    sw a1, %lo(s+160)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: read_modify_write:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    lw a1, 160(a0)
+; RV32XQCI-NEXT:    addi a1, a1, 10
+; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: read_modify_write:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s+160)
+; RV64-NEXT:    lw a1, %lo(s+160)(a0)
+; RV64-NEXT:    addi a1, a1, 10
+; RV64-NEXT:    sw a1, %lo(s+160)(a0)
+; RV64-NEXT:    ret
 entry:
   %x = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
   %y = add i32 %x, 10
@@ -274,16 +513,38 @@ entry:
 }
 
 define dso_local void @rmw_with_control_flow() nounwind {
-; CHECK-LABEL: rmw_with_control_flow:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(s+164)
-; CHECK-NEXT:    lw a1, %lo(s+164)(a0)
-; CHECK-NEXT:    blez a1, .LBB17_2
-; CHECK-NEXT:  # %bb.1: # %if.then
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sw a1, %lo(s+164)(a0)
-; CHECK-NEXT:  .LBB17_2: # %if.end
-; CHECK-NEXT:    ret
+; RV32-LABEL: rmw_with_control_flow:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(s+164)
+; RV32-NEXT:    lw a1, %lo(s+164)(a0)
+; RV32-NEXT:    blez a1, .LBB17_2
+; RV32-NEXT:  # %bb.1: # %if.then
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sw a1, %lo(s+164)(a0)
+; RV32-NEXT:  .LBB17_2: # %if.end
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: rmw_with_control_flow:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    lw a1, 164(a0)
+; RV32XQCI-NEXT:    blez a1, .LBB17_2
+; RV32XQCI-NEXT:  # %bb.1: # %if.then
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sw a1, 164(a0)
+; RV32XQCI-NEXT:  .LBB17_2: # %if.end
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: rmw_with_control_flow:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(s+164)
+; RV64-NEXT:    lw a1, %lo(s+164)(a0)
+; RV64-NEXT:    blez a1, .LBB17_2
+; RV64-NEXT:  # %bb.1: # %if.then
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sw a1, %lo(s+164)(a0)
+; RV64-NEXT:  .LBB17_2: # %if.end
+; RV64-NEXT:    ret
 entry:
   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
   %cmp = icmp sgt i32 %0, 0
@@ -310,6 +571,12 @@ define void @self_store() {
 ; RV32-NEXT:    sw a0, 4(a0)
 ; RV32-NEXT:    ret
 ;
+; RV32XQCI-LABEL: self_store:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, f
+; RV32XQCI-NEXT:    sw a0, 4(a0)
+; RV32XQCI-NEXT:    ret
+;
 ; RV64-LABEL: self_store:
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    lui a0, %hi(f)
@@ -321,59 +588,138 @@ define void @self_store() {
 }
 
 define void @store_addi_addi() {
-; CHECK-LABEL: store_addi_addi:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+3211)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sb a1, %lo(bar+3211)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: store_addi_addi:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+3211)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sb a1, %lo(bar+3211)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: store_addi_addi:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    addi a0, a0, 2047
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sb a1, 1164(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: store_addi_addi:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+3211)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sb a1, %lo(bar+3211)(a0)
+; RV64-NEXT:    ret
   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
   ret void
 }
 
 define void @store_addi_addi_neg() {
-; CHECK-LABEL: store_addi_addi_neg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar-4000)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sb a1, %lo(bar-4000)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: store_addi_addi_neg:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar-4000)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sb a1, %lo(bar-4000)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: store_addi_addi_neg:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    addi a0, a0, -2048
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sb a1, -1952(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: store_addi_addi_neg:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar-4000)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sb a1, %lo(bar-4000)(a0)
+; RV64-NEXT:    ret
   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000)
   ret void
 }
 
 ; With Zba the constant 6424 is created with LI+SH2ADD.
 define void @store_sh2add() {
-; CHECK-LABEL: store_sh2add:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+6424)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sb a1, %lo(bar+6424)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: store_sh2add:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+6424)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sb a1, %lo(bar+6424)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: store_sh2add:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    lui a0, 2
+; RV32XQCI-NEXT:    qc.e.li a1, bar
+; RV32XQCI-NEXT:    add a0, a0, a1
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sb a1, -1768(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: store_sh2add:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+6424)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sb a1, %lo(bar+6424)(a0)
+; RV64-NEXT:    ret
   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424)
   ret void
 }
 
 ; With Zba the constant 12848 is created with LI+SH3ADD.
 define void @store_sh3add() {
-; CHECK-LABEL: store_sh3add:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    lui a0, %hi(bar+12848)
-; CHECK-NEXT:    li a1, 10
-; CHECK-NEXT:    sb a1, %lo(bar+12848)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: store_sh3add:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(bar+12848)
+; RV32-NEXT:    li a1, 10
+; RV32-NEXT:    sb a1, %lo(bar+12848)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: store_sh3add:
+; RV32XQCI:       # %bb.0:
+; RV32XQCI-NEXT:    lui a0, 3
+; RV32XQCI-NEXT:    qc.e.li a1, bar
+; RV32XQCI-NEXT:    add a0, a0, a1
+; RV32XQCI-NEXT:    li a1, 10
+; RV32XQCI-NEXT:    sb a1, 560(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: store_sh3add:
+; RV64:       # %bb.0:
+; RV64-NEXT:    lui a0, %hi(bar+12848)
+; RV64-NEXT:    li a1, 10
+; RV64-NEXT:    sb a1, %lo(bar+12848)(a0)
+; RV64-NEXT:    ret
   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848)
   ret void
 }
 
 define dso_local void @rmw_addi_addi() nounwind {
-; CHECK-LABEL: rmw_addi_addi:
-; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lui a0, %hi(bar+3211)
-; CHECK-NEXT:    lbu a1, %lo(bar+3211)(a0)
-; CHECK-NEXT:    addi a1, a1, 10
-; CHECK-NEXT:    sb a1, %lo(bar+3211)(a0)
-; CHECK-NEXT:    ret
+; RV32-LABEL: rmw_addi_addi:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lui a0, %hi(bar+3211)
+; RV32-NEXT:    lbu a1, %lo(bar+3211)(a0)
+; RV32-NEXT:    addi a1, a1, 10
+; RV32-NEXT:    sb a1, %lo(bar+3211)(a0)
+; RV32-NEXT:    ret
+;
+; RV32XQCI-LABEL: rmw_addi_addi:
+; RV32XQCI:       # %bb.0: # %entry
+; RV32XQCI-NEXT:    qc.e.li a0, bar
+; RV32XQCI-NEXT:    addi a0, a0, 2047
+; RV32XQCI-NEXT:    lbu a1, 1164(a0)
+; RV32XQCI-NEXT:    addi a1, a1, 10
+; RV32XQCI-NEXT:    sb a1, 1164(a0)
+; RV32XQCI-NEXT:    ret
+;
+; RV64-LABEL: rmw_addi_addi:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lui a0, %hi(bar+3211)
+; RV64-NEXT:    lbu a1, %lo(bar+3211)(a0)
+; RV64-NEXT:    addi a1, a1, 10
+; RV64-NEXT:    sb a1, %lo(bar+3211)(a0)
+; RV64-NEXT:    ret
 entry:
   %0 = load i8, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
   %1 = add i8 %0, 10

>From 52efe22840cc8063fea1e872f31e1ed2ad44cf6b Mon Sep 17 00:00:00 2001
From: Sudharsan Veeravalli <quic_svs at quicinc.com>
Date: Sat, 10 Jan 2026 18:47:13 +0530
Subject: [PATCH 2/2] Merge-base offset for Xqcili

---
 .../lib/Target/RISCV/RISCVMergeBaseOffset.cpp | 93 +++++++++++--------
 .../test/CodeGen/RISCV/fold-addi-loadstore.ll | 14 ++-
 .../CodeGen/RISCV/hoist-global-addr-base.ll   | 79 +++++++---------
 3 files changed, 92 insertions(+), 94 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
index f3adac84f41c0..8f11a9f2748d4 100644
--- a/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
+++ b/llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
@@ -68,8 +68,12 @@ INITIALIZE_PASS(RISCVMergeBaseOffsetOpt, DEBUG_TYPE,
 // Detect either of the patterns:
 //
 // 1. (medlow pattern):
-//   lui   vreg1, %hi(s)
-//   addi  vreg2, vreg1, %lo(s)
+//   a. lui   vreg1, %hi(s)
+//      addi  vreg2, vreg1, %lo(s)
+//
+//   or
+//
+//   b.  qc.e.li vreg1, s
 //
 // 2. (medany pattern):
 // .Lpcrel_hi1:
@@ -85,12 +89,13 @@ bool RISCVMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi,
                                              MachineInstr *&Lo) {
   auto HiOpc = Hi.getOpcode();
   if (HiOpc != RISCV::LUI && HiOpc != RISCV::AUIPC &&
-      HiOpc != RISCV::PseudoMovAddr)
+      HiOpc != RISCV::PseudoMovAddr && HiOpc != RISCV::QC_E_LI)
     return false;
 
   const MachineOperand &HiOp1 = Hi.getOperand(1);
-  unsigned ExpectedFlags =
-      HiOpc == RISCV::AUIPC ? RISCVII::MO_PCREL_HI : RISCVII::MO_HI;
+  unsigned ExpectedFlags = HiOpc == RISCV::AUIPC     ? RISCVII::MO_PCREL_HI
+                           : HiOpc == RISCV::QC_E_LI ? RISCVII::MO_None
+                                                     : RISCVII::MO_HI;
   if (HiOp1.getTargetFlags() != ExpectedFlags)
     return false;
 
@@ -98,9 +103,9 @@ bool RISCVMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi,
       HiOp1.getOffset() != 0)
     return false;
 
-  if (HiOpc == RISCV::PseudoMovAddr) {
+  if (HiOpc == RISCV::PseudoMovAddr || HiOpc == RISCV::QC_E_LI) {
     // Most of the code should handle it correctly without modification by
-    // setting Lo and Hi both point to PseudoMovAddr
+    // setting Lo and Hi both point to PseudoMovAddr/QC_E_LI
     Lo = &Hi;
   } else {
     Register HiDestReg = Hi.getOperand(0).getReg();
@@ -112,17 +117,19 @@ bool RISCVMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi,
       return false;
   }
 
-  const MachineOperand &LoOp2 = Lo->getOperand(2);
-  if (HiOpc == RISCV::LUI || HiOpc == RISCV::PseudoMovAddr) {
-    if (LoOp2.getTargetFlags() != RISCVII::MO_LO ||
-        !(LoOp2.isGlobal() || LoOp2.isCPI() || LoOp2.isBlockAddress()) ||
-        LoOp2.getOffset() != 0)
-      return false;
-  } else {
-    assert(HiOpc == RISCV::AUIPC);
-    if (LoOp2.getTargetFlags() != RISCVII::MO_PCREL_LO ||
-        LoOp2.getType() != MachineOperand::MO_MCSymbol)
-      return false;
+  if (HiOpc != RISCV::QC_E_LI) {
+    const MachineOperand &LoOp2 = Lo->getOperand(2);
+    if (HiOpc == RISCV::LUI || HiOpc == RISCV::PseudoMovAddr) {
+      if (LoOp2.getTargetFlags() != RISCVII::MO_LO ||
+          !(LoOp2.isGlobal() || LoOp2.isCPI() || LoOp2.isBlockAddress()) ||
+          LoOp2.getOffset() != 0)
+        return false;
+    } else {
+      assert(HiOpc == RISCV::AUIPC);
+      if (LoOp2.getTargetFlags() != RISCVII::MO_PCREL_LO ||
+          LoOp2.getType() != MachineOperand::MO_MCSymbol)
+        return false;
+    }
   }
 
   if (HiOp1.isGlobal()) {
@@ -160,7 +167,7 @@ bool RISCVMergeBaseOffsetOpt::foldOffset(MachineInstr &Hi, MachineInstr &Lo,
 
   // Put the offset back in Hi and the Lo
   Hi.getOperand(1).setOffset(Offset);
-  if (HiOpc != RISCV::AUIPC)
+  if (Hi.getOpcode() != RISCV::AUIPC && Hi.getOpcode() != RISCV::QC_E_LI)
     Lo.getOperand(2).setOffset(Offset);
   // Delete the tail instruction.
   Register LoOp0Reg = Lo.getOperand(0).getReg();
@@ -335,21 +342,23 @@ bool RISCVMergeBaseOffsetOpt::detectAndFoldOffset(MachineInstr &Hi,
     LLVM_DEBUG(dbgs() << "Don't know how to get offset from this instr:"
                       << Tail);
     break;
-  case RISCV::ADDI: {
+  case RISCV::ADDI:
+  case RISCV::QC_E_ADDI: {
     // Offset is simply an immediate operand.
     int64_t Offset = Tail.getOperand(2).getImm();
-
-    // We might have two ADDIs in a row.
-    Register TailDestReg = Tail.getOperand(0).getReg();
-    if (MRI->hasOneUse(TailDestReg)) {
-      MachineInstr &TailTail = *MRI->use_instr_begin(TailDestReg);
-      if (TailTail.getOpcode() == RISCV::ADDI) {
-        Offset += TailTail.getOperand(2).getImm();
-        LLVM_DEBUG(dbgs() << "  Offset Instrs: " << Tail << TailTail);
-        if (!foldOffset(Hi, Lo, TailTail, Offset))
-          return false;
-        Tail.eraseFromParent();
-        return true;
+    if (Tail.getOpcode() == RISCV::ADDI) {
+      // We might have two ADDIs in a row.
+      Register TailDestReg = Tail.getOperand(0).getReg();
+      if (MRI->hasOneUse(TailDestReg)) {
+        MachineInstr &TailTail = *MRI->use_instr_begin(TailDestReg);
+        if (TailTail.getOpcode() == RISCV::ADDI) {
+          Offset += TailTail.getOperand(2).getImm();
+          LLVM_DEBUG(dbgs() << "  Offset Instrs: " << Tail << TailTail);
+          if (!foldOffset(Hi, Lo, TailTail, Offset))
+            return false;
+          Tail.eraseFromParent();
+          return true;
+        }
       }
     }
 
@@ -385,9 +394,12 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
   // If all the uses are memory ops with the same offset, we can transform:
   //
   // 1. (medlow pattern):
-  // Hi:   lui vreg1, %hi(foo)          --->  lui vreg1, %hi(foo+8)
-  // Lo:   addi vreg2, vreg1, %lo(foo)  --->  lw vreg3, lo(foo+8)(vreg1)
-  // Tail: lw vreg3, 8(vreg2)
+  //   a. Hi:   lui vreg1, %hi(foo)          --->  lui vreg1, %hi(foo+8)
+  //      Lo:   addi vreg2, vreg1, %lo(foo)  --->  lw vreg3, lo(foo+8)(vreg1)
+  //      Tail: lw vreg3, 8(vreg2)
+  //
+  //   b. Hi:   qc.e.li vreg1, foo           ---> qc.e.li vreg1, foo+8
+  //      Tail: lw vreg2, 8(vreg1)           ---> lw vreg2, 0(vreg1)
   //
   // 2. (medany pattern):
   // Hi: 1:auipc vreg1, %pcrel_hi(s)         ---> auipc vreg1, %pcrel_hi(foo+8)
@@ -505,7 +517,8 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
     return false;
 
   Hi.getOperand(1).setOffset(NewOffset);
-  MachineOperand &ImmOp = Lo.getOperand(2);
+  MachineOperand &ImmOp =
+      Hi.getOpcode() == RISCV::QC_E_LI ? Lo.getOperand(1) : Lo.getOperand(2);
   auto HiOpc = Hi.getOpcode();
   // Expand PseudoMovAddr into LUI
   if (HiOpc == RISCV::PseudoMovAddr) {
@@ -544,8 +557,12 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
         }
       }
     } else {
-      UseMI.removeOperand(2);
-      UseMI.addOperand(ImmOp);
+      if (Hi.getOpcode() == RISCV::QC_E_LI)
+        UseMI.getOperand(2).ChangeToImmediate(0);
+      else {
+        UseMI.removeOperand(2);
+        UseMI.addOperand(ImmOp);
+      }
     }
   }
 
diff --git a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
index d7e91986b539c..de8ae49dfbb7d 100644
--- a/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
+++ b/llvm/test/CodeGen/RISCV/fold-addi-loadstore.ll
@@ -502,8 +502,8 @@ define dso_local i32 @load_ga() local_unnamed_addr #0 {
 ;
 ; RV32IXQCILI-LABEL: load_ga:
 ; RV32IXQCILI:       # %bb.0:
-; RV32IXQCILI-NEXT:    qc.e.li a0, ga
-; RV32IXQCILI-NEXT:    lw a0, 4(a0)
+; RV32IXQCILI-NEXT:    qc.e.li a0, ga+4
+; RV32IXQCILI-NEXT:    lw a0, 0(a0)
 ; RV32IXQCILI-NEXT:    ret
 ;
 ; RV32I-MEDIUM-LABEL: load_ga:
@@ -713,8 +713,8 @@ define dso_local ptr @load_ba_2() nounwind {
 ; RV32IXQCILI:       # %bb.0: # %entry
 ; RV32IXQCILI-NEXT:  .Ltmp1: # Block address taken
 ; RV32IXQCILI-NEXT:  # %bb.1: # %label
-; RV32IXQCILI-NEXT:    qc.e.li a0, .Ltmp1
-; RV32IXQCILI-NEXT:    lw a0, 8(a0)
+; RV32IXQCILI-NEXT:    qc.e.li a0, .Ltmp1+8
+; RV32IXQCILI-NEXT:    lw a0, 0(a0)
 ; RV32IXQCILI-NEXT:    ret
 ;
 ; RV32I-MEDIUM-LABEL: load_ba_2:
@@ -1383,10 +1383,8 @@ define i32 @crash() {
 ;
 ; RV32IXQCILI-LABEL: crash:
 ; RV32IXQCILI:       # %bb.0: # %entry
-; RV32IXQCILI-NEXT:    li a0, 1
-; RV32IXQCILI-NEXT:    qc.e.li a1, g
-; RV32IXQCILI-NEXT:    add a0, a0, a1
-; RV32IXQCILI-NEXT:    lbu a0, 400(a0)
+; RV32IXQCILI-NEXT:    qc.e.li a0, g+401
+; RV32IXQCILI-NEXT:    lbu a0, 0(a0)
 ; RV32IXQCILI-NEXT:    seqz a0, a0
 ; RV32IXQCILI-NEXT:    sw a0, 0(zero)
 ; RV32IXQCILI-NEXT:    li a0, 0
diff --git a/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll b/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
index 3f29b00c4b409..3d5abfa2ef1ef 100644
--- a/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
+++ b/llvm/test/CodeGen/RISCV/hoist-global-addr-base.ll
@@ -113,8 +113,7 @@ define ptr @big_offset_neg_addi() nounwind {
 ;
 ; RV32XQCI-LABEL: big_offset_neg_addi:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, g
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 73568
+; RV32XQCI-NEXT:    qc.e.li a0, g+73568
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: big_offset_neg_addi:
@@ -140,8 +139,7 @@ define ptr @big_offset_lui_tail() nounwind {
 ;
 ; RV32XQCI-LABEL: big_offset_lui_tail:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, g
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 524288
+; RV32XQCI-NEXT:    qc.e.li a0, g+524288
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: big_offset_lui_tail:
@@ -161,8 +159,7 @@ define ptr @big_offset_neg_lui_tail() {
 ;
 ; RV32XQCI-LABEL: big_offset_neg_lui_tail:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, -8192
+; RV32XQCI-NEXT:    qc.e.li a0, bar-8192
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: big_offset_neg_lui_tail:
@@ -182,8 +179,7 @@ define dso_local ptr @big_offset_one_use() local_unnamed_addr nounwind {
 ;
 ; RV32XQCI-LABEL: big_offset_one_use:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, s
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 16572
+; RV32XQCI-NEXT:    qc.e.li a0, s+16572
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: big_offset_one_use:
@@ -204,8 +200,7 @@ define dso_local ptr @small_offset_one_use() local_unnamed_addr nounwind {
 ;
 ; RV32XQCI-LABEL: small_offset_one_use:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, s
-; RV32XQCI-NEXT:    addi a0, a0, 160
+; RV32XQCI-NEXT:    qc.e.li a0, s+160
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: small_offset_one_use:
@@ -282,8 +277,8 @@ define dso_local i32 @load_half() nounwind {
 ;
 ; RV32XQCI-LABEL: load_half:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, foo
-; RV32XQCI-NEXT:    lhu a0, 8(a0)
+; RV32XQCI-NEXT:    qc.e.li a0, foo+8
+; RV32XQCI-NEXT:    lhu a0, 0(a0)
 ; RV32XQCI-NEXT:    li a1, 140
 ; RV32XQCI-NEXT:    bne a0, a1, .LBB8_2
 ; RV32XQCI-NEXT:  # %bb.1: # %if.end
@@ -332,9 +327,9 @@ define dso_local void @one_store() local_unnamed_addr nounwind {
 ;
 ; RV32XQCI-LABEL: one_store:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, s
+; RV32XQCI-NEXT:    qc.e.li a0, s+160
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:    sw a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: one_store:
@@ -357,8 +352,7 @@ define ptr @neg_offset() {
 ;
 ; RV32XQCI-LABEL: neg_offset:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, -8191
+; RV32XQCI-NEXT:    qc.e.li a0, bar-8191
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: neg_offset:
@@ -404,8 +398,7 @@ define ptr @offset_addi_addi() {
 ;
 ; RV32XQCI-LABEL: offset_addi_addi:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 3211
+; RV32XQCI-NEXT:    qc.e.li a0, bar+3211
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: offset_addi_addi:
@@ -425,8 +418,7 @@ define ptr @offset_addi_addi_neg() {
 ;
 ; RV32XQCI-LABEL: offset_addi_addi_neg:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, -4000
+; RV32XQCI-NEXT:    qc.e.li a0, bar-4000
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: offset_addi_addi_neg:
@@ -447,8 +439,7 @@ define ptr @offset_sh2add() {
 ;
 ; RV32XQCI-LABEL: offset_sh2add:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 6424
+; RV32XQCI-NEXT:    qc.e.li a0, bar+6424
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: offset_sh2add:
@@ -469,8 +460,7 @@ define ptr @offset_sh3add() {
 ;
 ; RV32XQCI-LABEL: offset_sh3add:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    qc.e.addi a0, a0, 12848
+; RV32XQCI-NEXT:    qc.e.li a0, bar+12848
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: offset_sh3add:
@@ -492,10 +482,10 @@ define dso_local void @read_modify_write() local_unnamed_addr nounwind {
 ;
 ; RV32XQCI-LABEL: read_modify_write:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, s
-; RV32XQCI-NEXT:    lw a1, 160(a0)
+; RV32XQCI-NEXT:    qc.e.li a0, s+160
+; RV32XQCI-NEXT:    lw a1, 0(a0)
 ; RV32XQCI-NEXT:    addi a1, a1, 10
-; RV32XQCI-NEXT:    sw a1, 160(a0)
+; RV32XQCI-NEXT:    sw a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: read_modify_write:
@@ -526,12 +516,12 @@ define dso_local void @rmw_with_control_flow() nounwind {
 ;
 ; RV32XQCI-LABEL: rmw_with_control_flow:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, s
-; RV32XQCI-NEXT:    lw a1, 164(a0)
+; RV32XQCI-NEXT:    qc.e.li a0, s+164
+; RV32XQCI-NEXT:    lw a1, 0(a0)
 ; RV32XQCI-NEXT:    blez a1, .LBB17_2
 ; RV32XQCI-NEXT:  # %bb.1: # %if.then
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sw a1, 164(a0)
+; RV32XQCI-NEXT:    sw a1, 0(a0)
 ; RV32XQCI-NEXT:  .LBB17_2: # %if.end
 ; RV32XQCI-NEXT:    ret
 ;
@@ -597,10 +587,9 @@ define void @store_addi_addi() {
 ;
 ; RV32XQCI-LABEL: store_addi_addi:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    addi a0, a0, 2047
+; RV32XQCI-NEXT:    qc.e.li a0, bar+3211
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sb a1, 1164(a0)
+; RV32XQCI-NEXT:    sb a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: store_addi_addi:
@@ -623,10 +612,9 @@ define void @store_addi_addi_neg() {
 ;
 ; RV32XQCI-LABEL: store_addi_addi_neg:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    addi a0, a0, -2048
+; RV32XQCI-NEXT:    qc.e.li a0, bar-4000
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sb a1, -1952(a0)
+; RV32XQCI-NEXT:    sb a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: store_addi_addi_neg:
@@ -650,11 +638,9 @@ define void @store_sh2add() {
 ;
 ; RV32XQCI-LABEL: store_sh2add:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    lui a0, 2
-; RV32XQCI-NEXT:    qc.e.li a1, bar
-; RV32XQCI-NEXT:    add a0, a0, a1
+; RV32XQCI-NEXT:    qc.e.li a0, bar+6424
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sb a1, -1768(a0)
+; RV32XQCI-NEXT:    sb a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: store_sh2add:
@@ -678,11 +664,9 @@ define void @store_sh3add() {
 ;
 ; RV32XQCI-LABEL: store_sh3add:
 ; RV32XQCI:       # %bb.0:
-; RV32XQCI-NEXT:    lui a0, 3
-; RV32XQCI-NEXT:    qc.e.li a1, bar
-; RV32XQCI-NEXT:    add a0, a0, a1
+; RV32XQCI-NEXT:    qc.e.li a0, bar+12848
 ; RV32XQCI-NEXT:    li a1, 10
-; RV32XQCI-NEXT:    sb a1, 560(a0)
+; RV32XQCI-NEXT:    sb a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: store_sh3add:
@@ -706,11 +690,10 @@ define dso_local void @rmw_addi_addi() nounwind {
 ;
 ; RV32XQCI-LABEL: rmw_addi_addi:
 ; RV32XQCI:       # %bb.0: # %entry
-; RV32XQCI-NEXT:    qc.e.li a0, bar
-; RV32XQCI-NEXT:    addi a0, a0, 2047
-; RV32XQCI-NEXT:    lbu a1, 1164(a0)
+; RV32XQCI-NEXT:    qc.e.li a0, bar+3211
+; RV32XQCI-NEXT:    lbu a1, 0(a0)
 ; RV32XQCI-NEXT:    addi a1, a1, 10
-; RV32XQCI-NEXT:    sb a1, 1164(a0)
+; RV32XQCI-NEXT:    sb a1, 0(a0)
 ; RV32XQCI-NEXT:    ret
 ;
 ; RV64-LABEL: rmw_addi_addi:



More information about the llvm-commits mailing list