[llvm] [RISCV] Add combine for shadd family of instructions. (PR #130829)
Stefan Pintilie via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 12 13:20:07 PDT 2025
https://github.com/stefanp-synopsys updated https://github.com/llvm/llvm-project/pull/130829
>From df5bcbf5db3df3bf02869c0fab5f7ba541c7097d Mon Sep 17 00:00:00 2001
From: Stefan Pintilie <pintilie at synopsys.com>
Date: Tue, 11 Mar 2025 13:41:31 -0700
Subject: [PATCH 1/2] [RISCV] Add combine for shadd family of instructions.
For example for the following situation:
%6:gpr = SLLI %2:gpr, 2
%7:gpr = ADDI killed %6:gpr, 24
%8:gpr = ADD %0:gpr, %7:gpr
If we swap the two add instrucions we can merge the shift and add.
The final code will look something like this:
%7 = SH2ADD %0, %2
%8 = ADDI %7, 24
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 92 +++++++++++++-
.../CodeGen/RISCV/reassoc-shl-addi-add.ll | 113 ++++++++++++++++++
2 files changed, 204 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 27a4bbce1f5fc..6334eab8c96ec 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -79,6 +79,12 @@ static cl::opt<int>
"use for creating a floating-point immediate value"),
cl::init(2));
+static cl::opt<bool>
+ ReassocShlAddiAdd("reassoc-shl-addi-add", cl::Hidden,
+ cl::desc("Swap add and addi in cases where the add may "
+ "be combined with a shift"),
+ cl::init(true));
+
RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
const RISCVSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
@@ -14306,6 +14312,87 @@ static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::SHL, DL, VT, SHADD, DAG.getConstant(Bits, DL, VT));
}
+// Check if this SDValue is an add immediate and then
+static bool checkAddiForShift(SDValue AddI) {
+ // Based on testing it seems that performance degrades if the ADDI has
+ // more than 2 uses.
+ if (AddI->use_size() > 2)
+ return false;
+
+ ConstantSDNode *AddConst = dyn_cast<ConstantSDNode>(AddI->getOperand(1));
+ if (!AddConst)
+ return false;
+
+ SDValue SHLVal = AddI->getOperand(0);
+ if (SHLVal->getOpcode() != ISD::SHL)
+ return false;
+
+ ConstantSDNode *ShiftNode = dyn_cast<ConstantSDNode>(SHLVal->getOperand(1));
+ if (!ShiftNode)
+ return false;
+
+ auto ShiftVal = ShiftNode->getSExtValue();
+ if (ShiftVal != 1 && ShiftVal != 2 && ShiftVal != 3)
+ return false;
+
+ return true;
+}
+
+// Optimize (add (add (shl x, c0), c1), y) ->
+// (ADDI (SH*ADD y, x), c1), if c0 equals to [1|2|3].
+static SDValue combineShlAddIAdd(SDNode *N, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ if (!ReassocShlAddiAdd)
+ return SDValue();
+
+ // Perform this optimization only in the zba extension.
+ if (!Subtarget.hasStdExtZba())
+ return SDValue();
+
+ // Skip for vector types and larger types.
+ EVT VT = N->getValueType(0);
+ if (VT.isVector() || VT.getSizeInBits() > Subtarget.getXLen())
+ return SDValue();
+
+ // Looking for a reg-reg add and not an addi.
+ auto *Op1 = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (Op1)
+ return SDValue();
+ SDValue AddI;
+ SDValue Other;
+
+ if (N->getOperand(0)->getOpcode() == ISD::ADD &&
+ N->getOperand(1)->getOpcode() == ISD::ADD) {
+ AddI = N->getOperand(0);
+ Other = N->getOperand(1);
+ if (!checkAddiForShift(AddI)) {
+ AddI = N->getOperand(1);
+ Other = N->getOperand(0);
+ }
+ } else if (N->getOperand(0)->getOpcode() == ISD::ADD) {
+ AddI = N->getOperand(0);
+ Other = N->getOperand(1);
+ } else if (N->getOperand(1)->getOpcode() == ISD::ADD) {
+ AddI = N->getOperand(1);
+ Other = N->getOperand(0);
+ } else
+ return SDValue();
+
+ if (!checkAddiForShift(AddI))
+ return SDValue();
+
+ auto *AddConst = dyn_cast<ConstantSDNode>(AddI->getOperand(1));
+ SDValue SHLVal = AddI->getOperand(0);
+ auto *ShiftNode = dyn_cast<ConstantSDNode>(SHLVal->getOperand(1));
+ auto ShiftVal = ShiftNode->getSExtValue();
+ SDLoc DL(N);
+
+ SDValue SHADD = DAG.getNode(RISCVISD::SHL_ADD, DL, VT, SHLVal->getOperand(0),
+ DAG.getConstant(ShiftVal, DL, VT), Other);
+ return DAG.getNode(ISD::ADD, DL, VT, SHADD,
+ DAG.getConstant(AddConst->getSExtValue(), DL, VT));
+}
+
// Combine a constant select operand into its use:
//
// (and (select cond, -1, c), x)
@@ -14547,9 +14634,12 @@ static SDValue performADDCombine(SDNode *N,
return V;
if (SDValue V = transformAddImmMulImm(N, DAG, Subtarget))
return V;
- if (!DCI.isBeforeLegalize() && !DCI.isCalledByLegalizer())
+ if (!DCI.isBeforeLegalize() && !DCI.isCalledByLegalizer()) {
if (SDValue V = transformAddShlImm(N, DAG, Subtarget))
return V;
+ if (SDValue V = combineShlAddIAdd(N, DAG, Subtarget))
+ return V;
+ }
if (SDValue V = combineBinOpToReduce(N, DAG, Subtarget))
return V;
if (SDValue V = combineBinOpOfExtractToReduceTree(N, DAG, Subtarget))
diff --git a/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll b/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
new file mode 100644
index 0000000000000..e1fa408706c4e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
@@ -0,0 +1,113 @@
+; RUN: llc -mtriple=riscv32-pc-unknown-gnu -mattr=+zba %s -o - | FileCheck %s
+
+declare dso_local i32 @callee1(i32 noundef) local_unnamed_addr
+declare dso_local i32 @callee2(i32 noundef, i32 noundef) local_unnamed_addr
+declare dso_local i32 @callee(i32 noundef, i32 noundef, i32 noundef, i32 noundef) local_unnamed_addr
+
+; CHECK-LABEL: t1:
+; CHECK: sh2add
+; CHECK: sh2add
+; CHECK: sh2add
+; CHECK: tail callee
+
+define dso_local void @t1(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 45
+ %add1 = add nsw i32 %add, %b
+ %add3 = add nsw i32 %add, %c
+ %add5 = add nsw i32 %shl, %d
+ %call = tail call i32 @callee(i32 noundef %add1, i32 noundef %add1, i32 noundef %add3, i32 noundef %add5)
+ ret void
+}
+
+; CHECK-LABEL: t2:
+; CHECK: slli
+; CHECK-NOT: sh2add
+; CHECK: tail callee
+
+define dso_local void @t2(i32 noundef %a, i32 noundef %b, i32 noundef %c) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add4 = add nsw i32 %add, %b
+ %add7 = add nsw i32 %add, %c
+ %call = tail call i32 @callee(i32 noundef %shl, i32 noundef %add, i32 noundef %add4, i32 noundef %add7)
+ ret void
+}
+
+; CHECK-LABEL: t3
+; CHECK slli
+; CHECK-NOT: sh2add
+; CHECK: tail callee
+
+define dso_local void @t3(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add1 = add nsw i32 %add, %b
+ %add2 = add nsw i32 %add, %c
+ %add3 = add nsw i32 %add, %d
+ %add4 = add nsw i32 %add, %e
+ %call = tail call i32 @callee(i32 noundef %add1, i32 noundef %add2, i32 noundef %add3, i32 noundef %add4)
+ ret void
+}
+
+; CHECK-LABEL: t4
+; CHECK: sh2add
+; CHECK-NEXT: addi
+; CHECK-NEXT: tail callee1
+
+define dso_local void @t4(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add1 = add nsw i32 %add, %b
+ %call = tail call i32 @callee1(i32 noundef %add1)
+ ret void
+}
+
+; CHECK-LABEL: t5
+; CHECK: sh2add
+; CHECK: sh2add
+; CHECK: tail callee2
+
+define dso_local void @t5(i32 noundef %a, i32 noundef %b, i32 noundef %c) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add1 = add nsw i32 %add, %b
+ %add2 = add nsw i32 %add, %c
+ %call = tail call i32 @callee2(i32 noundef %add1, i32 noundef %add2)
+ ret void
+}
+
+; CHECK-LABEL: t6
+; CHECK-DAG: sh2add
+; CHECK-DAG: slli
+; CHECK: tail callee
+
+define dso_local void @t6(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add1 = add nsw i32 %add, %b
+ %call = tail call i32 @callee(i32 noundef %add1, i32 noundef %shl, i32 noundef %shl, i32 noundef %shl)
+ ret void
+}
+
+; CHECK-LABEL: t7
+; CHECK: slli
+; CHECK-NOT: sh2add
+; CHECK: tail callee
+
+define dso_local void @t7(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+entry:
+ %shl = shl i32 %a, 2
+ %add = add nsw i32 %shl, 42
+ %add1 = add nsw i32 %add, %b
+ %call = tail call i32 @callee(i32 noundef %add1, i32 noundef %add, i32 noundef %add, i32 noundef %add)
+ ret void
+}
+
+attributes #0 = { nounwind optsize }
>From 38cfa7903edae28654f789b8287da2bdf66f95a6 Mon Sep 17 00:00:00 2001
From: Stefan Pintilie <pintilie at synopsys.com>
Date: Wed, 12 Mar 2025 13:17:54 -0700
Subject: [PATCH 2/2] Simplified the code as per comments.
Also, cleaned up and auto generated the test case.
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 68 +++++------
.../CodeGen/RISCV/reassoc-shl-addi-add.ll | 110 +++++++++++-------
2 files changed, 95 insertions(+), 83 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6334eab8c96ec..fae6353aa6a88 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -14312,27 +14312,28 @@ static SDValue transformAddShlImm(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(ISD::SHL, DL, VT, SHADD, DAG.getConstant(Bits, DL, VT));
}
-// Check if this SDValue is an add immediate and then
-static bool checkAddiForShift(SDValue AddI) {
+// Check if this SDValue is an add immediate that is fed by a shift of 1, 2, or 3.
+static bool checkAddiForShift(SDValue AddI, int64_t &AddConst, int64_t &ShlConst) {
// Based on testing it seems that performance degrades if the ADDI has
// more than 2 uses.
if (AddI->use_size() > 2)
return false;
- ConstantSDNode *AddConst = dyn_cast<ConstantSDNode>(AddI->getOperand(1));
- if (!AddConst)
+ auto *AddConstNode = dyn_cast<ConstantSDNode>(AddI->getOperand(1));
+ if (!AddConstNode)
return false;
+ AddConst = AddConstNode->getSExtValue();
SDValue SHLVal = AddI->getOperand(0);
if (SHLVal->getOpcode() != ISD::SHL)
return false;
- ConstantSDNode *ShiftNode = dyn_cast<ConstantSDNode>(SHLVal->getOperand(1));
+ auto *ShiftNode = dyn_cast<ConstantSDNode>(SHLVal->getOperand(1));
if (!ShiftNode)
return false;
- auto ShiftVal = ShiftNode->getSExtValue();
- if (ShiftVal != 1 && ShiftVal != 2 && ShiftVal != 3)
+ ShlConst = ShiftNode->getSExtValue();
+ if (ShlConst < 1 || ShlConst > 3)
return false;
return true;
@@ -14342,11 +14343,8 @@ static bool checkAddiForShift(SDValue AddI) {
// (ADDI (SH*ADD y, x), c1), if c0 equals to [1|2|3].
static SDValue combineShlAddIAdd(SDNode *N, SelectionDAG &DAG,
const RISCVSubtarget &Subtarget) {
- if (!ReassocShlAddiAdd)
- return SDValue();
-
// Perform this optimization only in the zba extension.
- if (!Subtarget.hasStdExtZba())
+ if (!ReassocShlAddiAdd || !Subtarget.hasStdExtZba())
return SDValue();
// Skip for vector types and larger types.
@@ -14355,42 +14353,36 @@ static SDValue combineShlAddIAdd(SDNode *N, SelectionDAG &DAG,
return SDValue();
// Looking for a reg-reg add and not an addi.
- auto *Op1 = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (Op1)
- return SDValue();
- SDValue AddI;
- SDValue Other;
-
- if (N->getOperand(0)->getOpcode() == ISD::ADD &&
- N->getOperand(1)->getOpcode() == ISD::ADD) {
- AddI = N->getOperand(0);
- Other = N->getOperand(1);
- if (!checkAddiForShift(AddI)) {
- AddI = N->getOperand(1);
- Other = N->getOperand(0);
- }
- } else if (N->getOperand(0)->getOpcode() == ISD::ADD) {
- AddI = N->getOperand(0);
- Other = N->getOperand(1);
- } else if (N->getOperand(1)->getOpcode() == ISD::ADD) {
- AddI = N->getOperand(1);
- Other = N->getOperand(0);
- } else
+ if (isa<ConstantSDNode>(N->getOperand(1)))
return SDValue();
- if (!checkAddiForShift(AddI))
+ SDValue AddI = N->getOperand(0);
+ SDValue Other = N->getOperand(1);
+ bool LHSIsAdd = AddI.getOpcode() == ISD::ADD;
+ bool RHSIsAdd = Other.getOpcode() == ISD::ADD;
+ int64_t AddConst;
+ int64_t ShlConst;
+
+ // At least one add is required.
+ if (!(LHSIsAdd || RHSIsAdd))
return SDValue();
- auto *AddConst = dyn_cast<ConstantSDNode>(AddI->getOperand(1));
+ // If the LHS is not the result of an add or both sides are results of an add, but
+ // the LHS does not have the desired structure with a shift, swap the operands.
+ if (!LHSIsAdd || (LHSIsAdd && RHSIsAdd && !checkAddiForShift(AddI, AddConst, ShlConst)))
+ std::swap(AddI, Other);
+
+ // We simply need to ensure AddI has the desired structure.
+ if (!checkAddiForShift(AddI, AddConst, ShlConst))
+ return SDValue();
+
SDValue SHLVal = AddI->getOperand(0);
- auto *ShiftNode = dyn_cast<ConstantSDNode>(SHLVal->getOperand(1));
- auto ShiftVal = ShiftNode->getSExtValue();
SDLoc DL(N);
SDValue SHADD = DAG.getNode(RISCVISD::SHL_ADD, DL, VT, SHLVal->getOperand(0),
- DAG.getConstant(ShiftVal, DL, VT), Other);
+ DAG.getConstant(ShlConst, DL, VT), Other);
return DAG.getNode(ISD::ADD, DL, VT, SHADD,
- DAG.getConstant(AddConst->getSExtValue(), DL, VT));
+ DAG.getConstant(AddConst, DL, VT));
}
// Combine a constant select operand into its use:
diff --git a/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll b/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
index e1fa408706c4e..ff95328de1ebb 100644
--- a/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
+++ b/llvm/test/CodeGen/RISCV/reassoc-shl-addi-add.ll
@@ -1,16 +1,20 @@
-; RUN: llc -mtriple=riscv32-pc-unknown-gnu -mattr=+zba %s -o - | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32-unknown-elf -mattr=+zba %s -o - | FileCheck %s
-declare dso_local i32 @callee1(i32 noundef) local_unnamed_addr
-declare dso_local i32 @callee2(i32 noundef, i32 noundef) local_unnamed_addr
-declare dso_local i32 @callee(i32 noundef, i32 noundef, i32 noundef, i32 noundef) local_unnamed_addr
+declare i32 @callee1(i32 noundef)
+declare i32 @callee2(i32 noundef, i32 noundef)
+declare i32 @callee(i32 noundef, i32 noundef, i32 noundef, i32 noundef)
+define void @t1(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d) #0 {
; CHECK-LABEL: t1:
-; CHECK: sh2add
-; CHECK: sh2add
-; CHECK: sh2add
-; CHECK: tail callee
-
-define dso_local void @t1(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d) local_unnamed_addr #0 {
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sh2add a2, a0, a2
+; CHECK-NEXT: sh2add a1, a0, a1
+; CHECK-NEXT: addi a1, a1, 45
+; CHECK-NEXT: addi a2, a2, 45
+; CHECK-NEXT: sh2add a3, a0, a3
+; CHECK-NEXT: mv a0, a1
+; CHECK-NEXT: tail callee
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 45
@@ -21,12 +25,16 @@ entry:
ret void
}
+define void @t2(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 {
; CHECK-LABEL: t2:
-; CHECK: slli
-; CHECK-NOT: sh2add
-; CHECK: tail callee
-
-define dso_local void @t2(i32 noundef %a, i32 noundef %b, i32 noundef %c) local_unnamed_addr #0 {
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: slli a0, a0, 2
+; CHECK-NEXT: addi a5, a0, 42
+; CHECK-NEXT: add a4, a5, a1
+; CHECK-NEXT: add a3, a5, a2
+; CHECK-NEXT: mv a1, a5
+; CHECK-NEXT: mv a2, a4
+; CHECK-NEXT: tail callee
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
@@ -36,12 +44,16 @@ entry:
ret void
}
-; CHECK-LABEL: t3
-; CHECK slli
-; CHECK-NOT: sh2add
-; CHECK: tail callee
-
-define dso_local void @t3(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e) local_unnamed_addr #0 {
+define void @t3(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e) #0 {
+; CHECK-LABEL: t3:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: slli a0, a0, 2
+; CHECK-NEXT: addi a5, a0, 42
+; CHECK-NEXT: add a0, a5, a1
+; CHECK-NEXT: add a1, a5, a2
+; CHECK-NEXT: add a2, a5, a3
+; CHECK-NEXT: add a3, a5, a4
+; CHECK-NEXT: tail callee
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
@@ -53,12 +65,12 @@ entry:
ret void
}
-; CHECK-LABEL: t4
-; CHECK: sh2add
-; CHECK-NEXT: addi
-; CHECK-NEXT: tail callee1
-
-define dso_local void @t4(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+define void @t4(i32 noundef %a, i32 noundef %b) #0 {
+; CHECK-LABEL: t4:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sh2add a0, a0, a1
+; CHECK-NEXT: addi a0, a0, 42
+; CHECK-NEXT: tail callee1
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
@@ -67,12 +79,14 @@ entry:
ret void
}
-; CHECK-LABEL: t5
-; CHECK: sh2add
-; CHECK: sh2add
-; CHECK: tail callee2
-
-define dso_local void @t5(i32 noundef %a, i32 noundef %b, i32 noundef %c) local_unnamed_addr #0 {
+define void @t5(i32 noundef %a, i32 noundef %b, i32 noundef %c) #0 {
+; CHECK-LABEL: t5:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: sh2add a2, a0, a2
+; CHECK-NEXT: sh2add a0, a0, a1
+; CHECK-NEXT: addi a0, a0, 42
+; CHECK-NEXT: addi a1, a2, 42
+; CHECK-NEXT: tail callee2
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
@@ -82,12 +96,15 @@ entry:
ret void
}
-; CHECK-LABEL: t6
-; CHECK-DAG: sh2add
-; CHECK-DAG: slli
-; CHECK: tail callee
-
-define dso_local void @t6(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+define void @t6(i32 noundef %a, i32 noundef %b) #0 {
+; CHECK-LABEL: t6:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: slli a2, a0, 2
+; CHECK-NEXT: sh2add a0, a0, a1
+; CHECK-NEXT: addi a0, a0, 42
+; CHECK-NEXT: mv a1, a2
+; CHECK-NEXT: mv a3, a2
+; CHECK-NEXT: tail callee
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
@@ -96,12 +113,15 @@ entry:
ret void
}
-; CHECK-LABEL: t7
-; CHECK: slli
-; CHECK-NOT: sh2add
-; CHECK: tail callee
-
-define dso_local void @t7(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
+define void @t7(i32 noundef %a, i32 noundef %b) #0 {
+; CHECK-LABEL: t7:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: slli a0, a0, 2
+; CHECK-NEXT: addi a2, a0, 42
+; CHECK-NEXT: add a0, a2, a1
+; CHECK-NEXT: mv a1, a2
+; CHECK-NEXT: mv a3, a2
+; CHECK-NEXT: tail callee
entry:
%shl = shl i32 %a, 2
%add = add nsw i32 %shl, 42
More information about the llvm-commits
mailing list