[llvm] [RISCV] Extend legal addressing modes to support 26-bit addi/Xqcilo offsets (PR #204734)
Garvit Gupta via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 05:55:22 PDT 2026
https://github.com/quic-garvgupt updated https://github.com/llvm/llvm-project/pull/204734
>From 5ad338f3ee05e34390574af45d5cee288c8fd5cc Mon Sep 17 00:00:00 2001
From: Garvit Gupta <garvgupt at qti.qualcomm.com>
Date: Thu, 18 Jun 2026 05:36:25 -0700
Subject: [PATCH 1/3] [RISCV] Add pre-commit tests for 26-bit immediate/offset
legality
Add pre-commit tests capturing the current codegen for large (26-bit)
immediates and offsets under the Qualcomm uC Large Immediate Arithmetic
(Xqcilia) and Large Offset Load Store (Xqcilo) extensions. These exercise the
pre-ISel passes that query RISCVTargetLowering::isLegalAddImmediate and
isLegalAddressingMode:
---
llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll | 56 +++++++++++++++++++
.../Transforms/CodeGenPrepare/RISCV/xqcilo.ll | 44 +++++++++++++++
.../ConstantHoisting/RISCV/xqcilia.ll | 28 ++++++++++
3 files changed, 128 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
create mode 100644 llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
create mode 100644 llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
diff --git a/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll b/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
new file mode 100644
index 0000000000000..c9414cf235e32
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+
+; CodeGenPrepare's splitLargeGEPOffsets queries
+; RISCVTargetLowering::isLegalAddressingMode to decide whether a large constant
+; GEP offset must be split into a separate base address. Currently, with Xqcilo
+; enabled, the offset is reported as not foldable, so the base address is
+; computed separately and each access uses a plain lw with a small offset. A
+; follow-up extends isLegalAddressingMode to accept 26-bit offsets, after which
+; each access folds its full offset into a single qc.e.lw.
+
+; RUN: llc < %s -mtriple=riscv32 | FileCheck %s -check-prefix=RV32I
+; RUN: llc < %s -mtriple=riscv32 -mattr=+xqcilo | FileCheck %s -check-prefix=RV32XQCILO
+
+define i32 @split_large_geps(ptr %p, i1 %c) {
+; RV32I-LABEL: split_large_geps:
+; RV32I: # %bb.0: # %entry
+; RV32I-NEXT: andi a1, a1, 1
+; RV32I-NEXT: lui a2, 5
+; RV32I-NEXT: add a0, a0, a2
+; RV32I-NEXT: beqz a1, .LBB0_2
+; RV32I-NEXT: # %bb.1: # %a
+; RV32I-NEXT: lw a0, -480(a0)
+; RV32I-NEXT: ret
+; RV32I-NEXT: .LBB0_2: # %b
+; RV32I-NEXT: lw a0, -476(a0)
+; RV32I-NEXT: ret
+;
+; RV32XQCILO-LABEL: split_large_geps:
+; RV32XQCILO: # %bb.0: # %entry
+; RV32XQCILO-NEXT: andi a1, a1, 1
+; RV32XQCILO-NEXT: lui a2, 5
+; RV32XQCILO-NEXT: add a0, a0, a2
+; RV32XQCILO-NEXT: beqz a1, .LBB0_2
+; RV32XQCILO-NEXT: # %bb.1: # %a
+; RV32XQCILO-NEXT: lw a0, -480(a0)
+; RV32XQCILO-NEXT: ret
+; RV32XQCILO-NEXT: .LBB0_2: # %b
+; RV32XQCILO-NEXT: lw a0, -476(a0)
+; RV32XQCILO-NEXT: ret
+entry:
+ br i1 %c, label %a, label %b
+
+a:
+ %g0 = getelementptr i8, ptr %p, i32 20000
+ %v0 = load i32, ptr %g0
+ br label %merge
+
+b:
+ %g1 = getelementptr i8, ptr %p, i32 20004
+ %v1 = load i32, ptr %g1
+ br label %merge
+
+merge:
+ %r = phi i32 [ %v0, %a ], [ %v1, %b ]
+ ret i32 %r
+}
diff --git a/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll b/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
new file mode 100644
index 0000000000000..52af6eaf0fa69
--- /dev/null
+++ b/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes='require<profile-summary>,function(codegenprepare)' \
+; RUN: -mtriple=riscv32 -mattr=+xqcilo < %s | FileCheck %s --check-prefix=XQCILO
+
+; Two loads in separate blocks share a base pointer with large (26-bit) byte
+; offsets. CodeGenPrepare's splitLargeGEPOffsets queries
+; RISCVTargetLowering::isLegalAddressingMode to decide whether the offsets can
+; be folded into the addressing mode. isLegalAddressingMode only accepts 12-bit
+; offsets, so the large offset is split out into a separate base address
+; (%splitgep) and the second access uses a small offset relative to it.
+define i32 @split_large_geps(ptr %p, i1 %c) {
+; XQCILO-LABEL: define i32 @split_large_geps(
+; XQCILO-SAME: ptr [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; XQCILO-NEXT: [[ENTRY:.*:]]
+; XQCILO-NEXT: [[SPLITGEP:%.*]] = getelementptr i8, ptr [[P]], i32 20000
+; XQCILO-NEXT: br i1 [[C]], label %[[A:.*]], label %[[B:.*]]
+; XQCILO: [[A]]:
+; XQCILO-NEXT: [[V0:%.*]] = load i32, ptr [[SPLITGEP]], align 4
+; XQCILO-NEXT: br label %[[MERGE:.*]]
+; XQCILO: [[B]]:
+; XQCILO-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[SPLITGEP]], i32 4
+; XQCILO-NEXT: [[V1:%.*]] = load i32, ptr [[TMP0]], align 4
+; XQCILO-NEXT: br label %[[MERGE]]
+; XQCILO: [[MERGE]]:
+; XQCILO-NEXT: [[R:%.*]] = phi i32 [ [[V0]], %[[A]] ], [ [[V1]], %[[B]] ]
+; XQCILO-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %c, label %a, label %b
+
+a:
+ %g0 = getelementptr i8, ptr %p, i32 20000
+ %v0 = load i32, ptr %g0
+ br label %merge
+
+b:
+ %g1 = getelementptr i8, ptr %p, i32 20004
+ %v1 = load i32, ptr %g1
+ br label %merge
+
+merge:
+ %r = phi i32 [ %v0, %a ], [ %v1, %b ]
+ ret i32 %r
+}
diff --git a/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll b/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
new file mode 100644
index 0000000000000..f6e76867a63b0
--- /dev/null
+++ b/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -mtriple=riscv32 -mattr=+xqcilia -passes=consthoist -S < %s \
+; RUN: | FileCheck %s --check-prefix=XQCILIA
+
+; A 26-bit constant used several times. RISCVTargetLowering::isLegalAddImmediate
+; only accepts 12-bit immediates, so constant hoisting (which queries it via
+; getIntImmCostInst) considers the constant expensive and hoists it into a
+; register shared by all the adds.
+define void @hoist_simm26(i32 %a, i32 %b, i32 %c, ptr %p, ptr %q, ptr %r) {
+; XQCILIA-LABEL: define void @hoist_simm26(
+; XQCILIA-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0:[0-9]+]] {
+; XQCILIA-NEXT: [[CONST:%.*]] = bitcast i32 32766 to i32
+; XQCILIA-NEXT: [[TMP1:%.*]] = add i32 [[A]], [[CONST]]
+; XQCILIA-NEXT: [[TMP2:%.*]] = add i32 [[B]], [[CONST]]
+; XQCILIA-NEXT: [[TMP3:%.*]] = add i32 [[C]], [[CONST]]
+; XQCILIA-NEXT: store i32 [[TMP1]], ptr [[P]], align 4
+; XQCILIA-NEXT: store i32 [[TMP2]], ptr [[Q]], align 4
+; XQCILIA-NEXT: store i32 [[TMP3]], ptr [[R]], align 4
+; XQCILIA-NEXT: ret void
+;
+ %1 = add i32 %a, 32766
+ %2 = add i32 %b, 32766
+ %3 = add i32 %c, 32766
+ store i32 %1, ptr %p
+ store i32 %2, ptr %q
+ store i32 %3, ptr %r
+ ret void
+}
>From 7f6d41cb89a0199112b6bfed0069f731af1f2f20 Mon Sep 17 00:00:00 2001
From: Garvit Gupta <garvgupt at qti.qualcomm.com>
Date: Thu, 18 Jun 2026 05:57:18 -0700
Subject: [PATCH 2/3] [RISCV] Extend addressing-mode and add-immediate legality
to 26-bit immediates
Extend `RISCVTargetLowering::isLegalAddImmediate` and `isLegalAddressingMode` to
accept 26-bit signed immediates/offsets when the corresponding Qualcomm uC
extensions are enabled:
These callbacks are queried by some pre-ISel passes. Adding support for the wider
range lets those passes keep large immediates inline and large offsets folded
into addressing modes:
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 14 ++++++++++++--
llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll | 6 ++----
.../Transforms/CodeGenPrepare/RISCV/xqcilo.ll | 10 +++++-----
.../Transforms/ConstantHoisting/RISCV/xqcilia.ll | 16 ++++++++--------
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 7a2b9611683c6..6847145ba97dc 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -2463,9 +2463,15 @@ bool RISCVTargetLowering::isLegalAddressingMode(const DataLayout &DL,
if (Subtarget.hasVInstructions() && isa<VectorType>(Ty))
return AM.HasBaseReg && AM.Scale == 0 && !AM.BaseOffs;
- // Require a 12-bit signed offset.
- if (!isInt<12>(AM.BaseOffs))
+ // The Xqcilo extension provides load/store instructions with a 26-bit signed
+ // offset.
+ if (Subtarget.hasVendorXqcilo()) {
+ if (!isInt<26>(AM.BaseOffs))
+ return false;
+ } else if (!isInt<12>(AM.BaseOffs)) {
+ // Otherwise require a 12-bit signed offset.
return false;
+ }
switch (AM.Scale) {
case 0: // "r+i" or just "i", depending on HasBaseReg.
@@ -2486,6 +2492,10 @@ bool RISCVTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
}
bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const {
+ // The Xqcilia extension provides add-immediate instructions with a 26-bit
+ // signed immediate.
+ if (Subtarget.hasVendorXqcilia())
+ return isInt<26>(Imm);
return isInt<12>(Imm);
}
diff --git a/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll b/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
index c9414cf235e32..1d96ad4d13665 100644
--- a/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
+++ b/llvm/test/CodeGen/RISCV/xqcilo-split-gep.ll
@@ -28,14 +28,12 @@ define i32 @split_large_geps(ptr %p, i1 %c) {
; RV32XQCILO-LABEL: split_large_geps:
; RV32XQCILO: # %bb.0: # %entry
; RV32XQCILO-NEXT: andi a1, a1, 1
-; RV32XQCILO-NEXT: lui a2, 5
-; RV32XQCILO-NEXT: add a0, a0, a2
; RV32XQCILO-NEXT: beqz a1, .LBB0_2
; RV32XQCILO-NEXT: # %bb.1: # %a
-; RV32XQCILO-NEXT: lw a0, -480(a0)
+; RV32XQCILO-NEXT: qc.e.lw a0, 20000(a0)
; RV32XQCILO-NEXT: ret
; RV32XQCILO-NEXT: .LBB0_2: # %b
-; RV32XQCILO-NEXT: lw a0, -476(a0)
+; RV32XQCILO-NEXT: qc.e.lw a0, 20004(a0)
; RV32XQCILO-NEXT: ret
entry:
br i1 %c, label %a, label %b
diff --git a/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll b/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
index 52af6eaf0fa69..e33865e209685 100644
--- a/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/RISCV/xqcilo.ll
@@ -5,20 +5,20 @@
; Two loads in separate blocks share a base pointer with large (26-bit) byte
; offsets. CodeGenPrepare's splitLargeGEPOffsets queries
; RISCVTargetLowering::isLegalAddressingMode to decide whether the offsets can
-; be folded into the addressing mode. isLegalAddressingMode only accepts 12-bit
-; offsets, so the large offset is split out into a separate base address
-; (%splitgep) and the second access uses a small offset relative to it.
+; be folded into the addressing mode. With Xqcilo, isLegalAddressingMode now
+; accepts 26-bit offsets, so the GEPs are left intact and each access keeps its
+; full offset instead of being split out into a separate base address.
define i32 @split_large_geps(ptr %p, i1 %c) {
; XQCILO-LABEL: define i32 @split_large_geps(
; XQCILO-SAME: ptr [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
; XQCILO-NEXT: [[ENTRY:.*:]]
-; XQCILO-NEXT: [[SPLITGEP:%.*]] = getelementptr i8, ptr [[P]], i32 20000
; XQCILO-NEXT: br i1 [[C]], label %[[A:.*]], label %[[B:.*]]
; XQCILO: [[A]]:
+; XQCILO-NEXT: [[SPLITGEP:%.*]] = getelementptr i8, ptr [[P]], i32 20000
; XQCILO-NEXT: [[V0:%.*]] = load i32, ptr [[SPLITGEP]], align 4
; XQCILO-NEXT: br label %[[MERGE:.*]]
; XQCILO: [[B]]:
-; XQCILO-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[SPLITGEP]], i32 4
+; XQCILO-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[P]], i32 20004
; XQCILO-NEXT: [[V1:%.*]] = load i32, ptr [[TMP0]], align 4
; XQCILO-NEXT: br label %[[MERGE]]
; XQCILO: [[MERGE]]:
diff --git a/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll b/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
index f6e76867a63b0..8e4bb42355a1d 100644
--- a/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
+++ b/llvm/test/Transforms/ConstantHoisting/RISCV/xqcilia.ll
@@ -2,17 +2,17 @@
; RUN: opt -mtriple=riscv32 -mattr=+xqcilia -passes=consthoist -S < %s \
; RUN: | FileCheck %s --check-prefix=XQCILIA
-; A 26-bit constant used several times. RISCVTargetLowering::isLegalAddImmediate
-; only accepts 12-bit immediates, so constant hoisting (which queries it via
-; getIntImmCostInst) considers the constant expensive and hoists it into a
-; register shared by all the adds.
+; A 26-bit constant used several times. With Xqcilia,
+; RISCVTargetLowering::isLegalAddImmediate now accepts 26-bit immediates, so
+; constant hoisting (which queries it via getIntImmCostInst) considers the
+; constant free and leaves it inline in each add instead of hoisting it into a
+; shared register.
define void @hoist_simm26(i32 %a, i32 %b, i32 %c, ptr %p, ptr %q, ptr %r) {
; XQCILIA-LABEL: define void @hoist_simm26(
; XQCILIA-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]]) #[[ATTR0:[0-9]+]] {
-; XQCILIA-NEXT: [[CONST:%.*]] = bitcast i32 32766 to i32
-; XQCILIA-NEXT: [[TMP1:%.*]] = add i32 [[A]], [[CONST]]
-; XQCILIA-NEXT: [[TMP2:%.*]] = add i32 [[B]], [[CONST]]
-; XQCILIA-NEXT: [[TMP3:%.*]] = add i32 [[C]], [[CONST]]
+; XQCILIA-NEXT: [[TMP1:%.*]] = add i32 [[A]], 32766
+; XQCILIA-NEXT: [[TMP2:%.*]] = add i32 [[B]], 32766
+; XQCILIA-NEXT: [[TMP3:%.*]] = add i32 [[C]], 32766
; XQCILIA-NEXT: store i32 [[TMP1]], ptr [[P]], align 4
; XQCILIA-NEXT: store i32 [[TMP2]], ptr [[Q]], align 4
; XQCILIA-NEXT: store i32 [[TMP3]], ptr [[R]], align 4
>From f89b6f55090c5cbed19f7336a6e93d394db7e357 Mon Sep 17 00:00:00 2001
From: Garvit Gupta <garvgupt at qti.qualcomm.com>
Date: Thu, 25 Jun 2026 05:38:15 -0700
Subject: [PATCH 3/3] [RISCV] Fix infinite loop due to hardcoded isInt<12>
check in transformAddImmMulImm
The generic DAGCombiner fold add(mul(add(A, CA), CM), CB) -> add(mul(A, CM), CA*CM+CB)
is gated on isLegalAddImmediate(CA*CM+CB). The RISC-V combine
transformAddImmMulImm does the inverse split
add(mul x, c0), c1) -> add(mul(add x, c1/c0), c0), c1%c0)
and previously bailed out only when c1 was a 12-bit immediate. For a
merged constant in (simm12, simm26] (e.g. 2049), the generic fold would merge
and transformAddImmMulImm would split it straight back, looping forever. The
fix makes transformAddImmMulImm bail when c1 is a legal add immediate
(isLegalAddImmediate), so the two folds agree and the combiner
terminates.
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 8 +++-
.../RISCV/xqcilia-addimm-mulimm-loop.ll | 45 +++++++++++++++++++
2 files changed, 52 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/RISCV/xqcilia-addimm-mulimm-loop.ll
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6847145ba97dc..e61c4f4f3be22 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -16460,7 +16460,13 @@ static SDValue transformAddImmMulImm(SDNode *N, SelectionDAG &DAG,
int64_t C0 = N0C->getSExtValue();
int64_t C1 = N1C->getSExtValue();
int64_t CA, CB;
- if (C0 == -1 || C0 == 0 || C0 == 1 || isInt<12>(C1))
+ // If C1 already fits in an add immediate, there is nothing to split out: the
+ // (add (mul x, c0), c1) form is already canonical/cheap. Splitting it would
+ // fight the generic DAGCombiner fold add(mul(add(A, CA), CM), CB) ->
+ // add(mul(A, CM), CM*CA+CB) (which is gated on isLegalAddImmediate) and cause
+ // an infinite loop.
+ if (C0 == -1 || C0 == 0 || C0 == 1 ||
+ Subtarget.getTargetLowering()->isLegalAddImmediate(C1))
return SDValue();
// Search for proper CA (non-zero) and CB that both are simm12.
if ((C1 / C0) != 0 && isInt<12>(C1 / C0) && isInt<12>(C1 % C0) &&
diff --git a/llvm/test/CodeGen/RISCV/xqcilia-addimm-mulimm-loop.ll b/llvm/test/CodeGen/RISCV/xqcilia-addimm-mulimm-loop.ll
new file mode 100644
index 0000000000000..239bd6f890d9b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/xqcilia-addimm-mulimm-loop.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Regression test for an infinite DAGCombine loop that occurred once
+; isLegalAddImmediate was extended to accept 26-bit immediates (Xqcilia).
+;
+; RUN: llc -mtriple=riscv32 -mattr=+xqcilia -verify-machineinstrs < %s \
+; RUN: | FileCheck %s --check-prefix=RV32XQCILIA
+
+; (a + 1024) * 2 + 1 = 2*a + 2049. 2049 is simm26 but not simm12.
+define i32 @add_mul_add_simm26(i32 %a) {
+; RV32XQCILIA-LABEL: add_mul_add_simm26:
+; RV32XQCILIA: # %bb.0:
+; RV32XQCILIA-NEXT: slli a0, a0, 1
+; RV32XQCILIA-NEXT: qc.e.addi a0, a0, 2049
+; RV32XQCILIA-NEXT: ret
+ %add1 = add i32 %a, 1024
+ %mul = mul i32 %add1, 2
+ %add2 = add i32 %mul, 1
+ ret i32 %add2
+}
+
+; A constant past 26 bits (still i32) is materialized by qc.e.addai; it must not
+; be split by transformAddImmMulImm (no loop).
+define i32 @mul_add_simm32(i32 %a) {
+; RV32XQCILIA-LABEL: mul_add_simm32:
+; RV32XQCILIA: # %bb.0:
+; RV32XQCILIA-NEXT: slli a1, a0, 1
+; RV32XQCILIA-NEXT: add a0, a0, a1
+; RV32XQCILIA-NEXT: qc.e.addai a0, 70000000
+; RV32XQCILIA-NEXT: ret
+ %mul = mul i32 %a, 3
+ %add = add i32 %mul, 70000000
+ ret i32 %add
+}
+
+; Direct (add (mul x, c0), c1) shape with c1 in the (simm12, simm26] window.
+define i32 @mul_add_simm26(i32 %a) {
+; RV32XQCILIA-LABEL: mul_add_simm26:
+; RV32XQCILIA: # %bb.0:
+; RV32XQCILIA-NEXT: slli a0, a0, 1
+; RV32XQCILIA-NEXT: qc.e.addi a0, a0, 2049
+; RV32XQCILIA-NEXT: ret
+ %mul = mul i32 %a, 2
+ %add = add i32 %mul, 2049
+ ret i32 %add
+}
More information about the llvm-commits
mailing list