Skip to content

[RISCV] Add ISel patterns for Xqciac QC.MULIADD instruction #147661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 11, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15895,6 +15895,13 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
// X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
uint64_t MulAmt) {
// Don't do this is if the Xqciac extension is enabled and the MulAmt is
// simm12.
const RISCVSubtarget &Subtarget =
DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
if (Subtarget.hasVendorXqciac() && isInt<12>(MulAmt))
return SDValue();

uint64_t MulAmtLowBit = MulAmt & (-MulAmt);
ISD::NodeType Op;
uint64_t ShiftAmt1;
Expand Down Expand Up @@ -23700,6 +23707,10 @@ bool RISCVTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT,
auto *ConstNode = cast<ConstantSDNode>(C);
const APInt &Imm = ConstNode->getAPIntValue();

// Don't do this if the Xqciac extension is enabled and the Imm in simm12.
if (Subtarget.hasVendorXqciac() && Imm.isSignedIntN(12))
return false;

// Break the MUL to a SLLI and an ADD/SUB.
if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
(1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,11 @@ class SelectQCbi<CondCode Cond, DAGOperand InTyImm, Pseudo OpNode >
(OpNode GPRNoX0:$lhs, InTyImm:$Constant,
(IntCCtoRISCVCC $cc), GPRNoX0:$truev, GPRNoX0:$falsev)>;

let Predicates = [HasVendorXqciac, IsRV32] in {
def : Pat<(XLenVT (add GPRNoX0:$rd, (mul GPRNoX0:$rs1, simm12:$imm12))),
(QC_MULIADD GPRNoX0:$rd, GPRNoX0:$rs1, simm12:$imm12)>;
} // Predicates = [HasVendorXqciac, IsRV32]

/// Simple arithmetic operations

let Predicates = [HasVendorXqcilia, IsRV32] in {
Expand Down
177 changes: 177 additions & 0 deletions llvm/test/CodeGen/RISCV/xqciac.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=riscv32 -mattr=+m -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefix=RV32IM
; RUN: llc -mtriple=riscv32 -mattr=+m,+experimental-xqciac -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefix=RV32IMXQCIAC
; RUN: llc -mtriple=riscv32 -mattr=+m,+experimental-xqciac,+zba -verify-machineinstrs < %s \
; RUN: | FileCheck %s -check-prefix=RV32IZBAMXQCIAC

define dso_local i32 @mul(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: mul:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: slli a0, a1, 5
; RV32IM-NEXT: add a0, a0, a1
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: mul:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: li a0, 33
; RV32IMXQCIAC-NEXT: mul a0, a1, a0
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: mul:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: li a0, 33
; RV32IZBAMXQCIAC-NEXT: mul a0, a1, a0
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 33
ret i32 %mul
}

define dso_local i32 @muliadd(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: muliadd:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: li a2, 165
; RV32IM-NEXT: mul a1, a1, a2
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: muliadd:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: qc.muliadd a0, a1, 165
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: muliadd:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: qc.muliadd a0, a1, 165
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 165
%add = add nsw i32 %mul, %a
ret i32 %add
}

define dso_local i32 @muliadd_neg(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: muliadd_neg:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: li a2, -165
; RV32IM-NEXT: mul a1, a1, a2
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: muliadd_neg:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: qc.muliadd a0, a1, -165
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: muliadd_neg:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: qc.muliadd a0, a1, -165
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, -165
%add = add nsw i32 %mul, %a
ret i32 %add
}

define dso_local i32 @pow2immplus1(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: pow2immplus1:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: slli a2, a1, 5
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: add a0, a2, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: pow2immplus1:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: qc.muliadd a0, a1, 33
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: pow2immplus1:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: qc.muliadd a0, a1, 33
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 33
%add = add nsw i32 %mul, %a
ret i32 %add
}

define dso_local i32 @gtsimm12(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: gtsimm12:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: lui a2, 1
; RV32IM-NEXT: addi a2, a2, 477
; RV32IM-NEXT: mul a1, a1, a2
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: gtsimm12:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: lui a2, 1
; RV32IMXQCIAC-NEXT: addi a2, a2, 477
; RV32IMXQCIAC-NEXT: mul a1, a1, a2
; RV32IMXQCIAC-NEXT: add a0, a0, a1
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: gtsimm12:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: lui a2, 1
; RV32IZBAMXQCIAC-NEXT: addi a2, a2, 477
; RV32IZBAMXQCIAC-NEXT: mul a1, a1, a2
; RV32IZBAMXQCIAC-NEXT: add a0, a0, a1
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 4573
%add = add nsw i32 %mul, %a
ret i32 %add
}

; NOTE: This will become qc.shladd once support is added
define dso_local i32 @pow2(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: pow2:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: slli a1, a1, 5
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: pow2:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: slli a1, a1, 5
; RV32IMXQCIAC-NEXT: add a0, a0, a1
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: pow2:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: slli a1, a1, 5
; RV32IZBAMXQCIAC-NEXT: add a0, a0, a1
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 32
%add = add nsw i32 %mul, %a
ret i32 %add
}

define dso_local i32 @shxadd(i32 %a, i32 %b) local_unnamed_addr #0 {
; RV32IM-LABEL: shxadd:
; RV32IM: # %bb.0: # %entry
; RV32IM-NEXT: slli a1, a1, 1
; RV32IM-NEXT: add a0, a1, a0
; RV32IM-NEXT: ret
;
; RV32IMXQCIAC-LABEL: shxadd:
; RV32IMXQCIAC: # %bb.0: # %entry
; RV32IMXQCIAC-NEXT: slli a1, a1, 1
; RV32IMXQCIAC-NEXT: add a0, a0, a1
; RV32IMXQCIAC-NEXT: ret
;
; RV32IZBAMXQCIAC-LABEL: shxadd:
; RV32IZBAMXQCIAC: # %bb.0: # %entry
; RV32IZBAMXQCIAC-NEXT: sh1add a0, a1, a0
; RV32IZBAMXQCIAC-NEXT: ret
entry:
%mul = mul nsw i32 %b, 2
%add = add nsw i32 %mul, %a
ret i32 %add
}