[llvm] [InstCombine] Fold bitwise logic with funnel shifts (PR #77460)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 9 08:19:32 PST 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/77460

>From 73ba755d448d4103c64344767604da46ab138ab4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 9 Jan 2024 20:22:34 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 .../InstCombine/bitwiselogic-funnelshift.ll   | 133 ++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll

diff --git a/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll b/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll
new file mode 100644
index 00000000000000..a74827823acb00
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll
@@ -0,0 +1,133 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i32 @test_or_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_or_fshl(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = or i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_and_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_and_fshl(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = and i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_xor_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_xor_fshl(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = xor i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_or_fshr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_or_fshr(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshr.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshr.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshr.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = or i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_or_fshl_cascade(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: define i32 @test_or_fshl_cascade(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
+; CHECK-NEXT:    [[FSHL1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[A]], i32 24)
+; CHECK-NEXT:    [[FSHL2:%.*]] = call i32 @llvm.fshl.i32(i32 [[B]], i32 [[B]], i32 24)
+; CHECK-NEXT:    [[FSHL3:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[C]], i32 24)
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[FSHL1]], [[FSHL2]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[FSHL3]]
+; CHECK-NEXT:    ret i32 [[OR2]]
+;
+  %fshl1 = call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 24)
+  %fshl2 = call i32 @llvm.fshl.i32(i32 %b, i32 %b, i32 24)
+  %fshl3 = call i32 @llvm.fshl.i32(i32 %c, i32 %c, i32 24)
+  %or1 = or i32 %fshl1, %fshl2
+  %or2 = or i32 %or1, %fshl3
+  ret i32 %or2
+}
+
+; Negative tests
+
+define i32 @test_or_fshl_fshr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_or_fshl_fshr(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshr.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshr.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = or i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_or_fshl_mismatched_shamt(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh1, i32 %sh2) {
+; CHECK-LABEL: define i32 @test_or_fshl_mismatched_shamt(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH1:%.*]], i32 [[SH2:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH1]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH2]])
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh1)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh2)
+  %ret = or i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_add_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_add_fshl(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = add i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = add i32 %xor1, %xor2
+  ret i32 %ret
+}
+define i32 @test_or_fshl_multiuse(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
+; CHECK-LABEL: define i32 @test_or_fshl_multiuse(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
+; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
+; CHECK-NEXT:    call void @use(i32 [[XOR1]])
+; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
+; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
+  call void @use(i32 %xor1)
+  %xor2 = call i32 @llvm.fshl.i32(i32 %c, i32 %d, i32 %sh)
+  %ret = or i32 %xor1, %xor2
+  ret i32 %ret
+}
+
+declare void @use(i32)
+declare i32 @llvm.fshl.i32(i32, i32, i32)
+declare i32 @llvm.fshr.i32(i32, i32, i32)

>From c21135e80363fbf5fff1f5d13a4383ce4a04734f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 9 Jan 2024 20:23:51 +0800
Subject: [PATCH 2/2] [InstCombine] Fold bitwise logic with funnel shifts

---
 .../InstCombine/InstCombineAndOrXor.cpp       | 38 +++++++++++++++++++
 .../InstCombine/bitwiselogic-funnelshift.ll   | 34 ++++++++---------
 2 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index c03f50d75814d8..6df899e2069089 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2159,6 +2159,35 @@ Instruction *InstCombinerImpl::foldBinOpOfDisplacedShifts(BinaryOperator &I) {
   return BinaryOperator::Create(ShiftOp, NewC, ShAmt);
 }
 
+static Instruction *
+foldBitwiseLogicWithFunnelShift(BinaryOperator &I,
+                                InstCombiner::BuilderTy &Builder) {
+  assert(I.isBitwiseLogicOp() && "Should and/or/xor");
+  Value *X = I.getOperand(0);
+  Value *Y = I.getOperand(1);
+  Value *Op0, *Op1, *Op2, *Op3, *ShAmt;
+  if (match(X, m_OneUse(m_FShl(m_Value(Op0), m_Value(Op1), m_Value(ShAmt)))) &&
+      match(Y,
+            m_OneUse(m_FShl(m_Value(Op2), m_Value(Op3), m_Specific(ShAmt))))) {
+    Value *NewOp0 = Builder.CreateBinOp(I.getOpcode(), Op0, Op2);
+    Value *NewOp1 = Builder.CreateBinOp(I.getOpcode(), Op1, Op3);
+    Function *F =
+        Intrinsic::getDeclaration(I.getModule(), Intrinsic::fshl, I.getType());
+    return CallInst::Create(F, {NewOp0, NewOp1, ShAmt});
+  }
+  if (match(X, m_OneUse(m_FShr(m_Value(Op0), m_Value(Op1), m_Value(ShAmt)))) &&
+      match(Y,
+            m_OneUse(m_FShr(m_Value(Op2), m_Value(Op3), m_Specific(ShAmt))))) {
+    Value *NewOp0 = Builder.CreateBinOp(I.getOpcode(), Op0, Op2);
+    Value *NewOp1 = Builder.CreateBinOp(I.getOpcode(), Op1, Op3);
+    Function *F =
+        Intrinsic::getDeclaration(I.getModule(), Intrinsic::fshr, I.getType());
+    return CallInst::Create(F, {NewOp0, NewOp1, ShAmt});
+  }
+
+  return nullptr;
+}
+
 // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
 // here. We should standardize that construct where it is needed or choose some
 // other way to ensure that commutated variants of patterns are not missed.
@@ -2688,6 +2717,9 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
   if (Instruction *Res = foldBinOpOfDisplacedShifts(I))
     return Res;
 
+  if (Instruction *Res = foldBitwiseLogicWithFunnelShift(I, Builder))
+    return Res;
+
   return nullptr;
 }
 
@@ -3884,6 +3916,9 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
       return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, *C1 | *C2));
   }
 
+  if (Instruction *Res = foldBitwiseLogicWithFunnelShift(I, Builder))
+    return Res;
+
   return nullptr;
 }
 
@@ -4799,5 +4834,8 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
   if (Instruction *Res = foldBinOpOfDisplacedShifts(I))
     return Res;
 
+  if (Instruction *Res = foldBitwiseLogicWithFunnelShift(I, Builder))
+    return Res;
+
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll b/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll
index a74827823acb00..31d82a53b38009 100644
--- a/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll
+++ b/llvm/test/Transforms/InstCombine/bitwiselogic-funnelshift.ll
@@ -4,9 +4,9 @@
 define i32 @test_or_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 ; CHECK-LABEL: define i32 @test_or_fshl(
 ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
-; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
-; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
-; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[A]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[B]], [[D]]
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP1]], i32 [[TMP2]], i32 [[SH]])
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
@@ -17,9 +17,9 @@ define i32 @test_or_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 define i32 @test_and_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 ; CHECK-LABEL: define i32 @test_and_fshl(
 ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
-; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
-; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
-; CHECK-NEXT:    [[RET:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[B]], [[D]]
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP1]], i32 [[TMP2]], i32 [[SH]])
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
@@ -30,9 +30,9 @@ define i32 @test_and_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 define i32 @test_xor_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 ; CHECK-LABEL: define i32 @test_xor_fshl(
 ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
-; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
-; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
-; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[B]], [[D]]
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP1]], i32 [[TMP2]], i32 [[SH]])
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %xor1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %sh)
@@ -43,9 +43,9 @@ define i32 @test_xor_fshl(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 define i32 @test_or_fshr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 ; CHECK-LABEL: define i32 @test_or_fshr(
 ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]], i32 [[SH:%.*]]) {
-; CHECK-NEXT:    [[XOR1:%.*]] = call i32 @llvm.fshr.i32(i32 [[A]], i32 [[B]], i32 [[SH]])
-; CHECK-NEXT:    [[XOR2:%.*]] = call i32 @llvm.fshr.i32(i32 [[C]], i32 [[D]], i32 [[SH]])
-; CHECK-NEXT:    [[RET:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[A]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[B]], [[D]]
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.fshr.i32(i32 [[TMP1]], i32 [[TMP2]], i32 [[SH]])
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %xor1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %sh)
@@ -56,11 +56,11 @@ define i32 @test_or_fshr(i32 %a, i32 %b, i32 %c, i32 %d, i32 %sh) {
 define i32 @test_or_fshl_cascade(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: define i32 @test_or_fshl_cascade(
 ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
-; CHECK-NEXT:    [[FSHL1:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[A]], i32 24)
-; CHECK-NEXT:    [[FSHL2:%.*]] = call i32 @llvm.fshl.i32(i32 [[B]], i32 [[B]], i32 24)
-; CHECK-NEXT:    [[FSHL3:%.*]] = call i32 @llvm.fshl.i32(i32 [[C]], i32 [[C]], i32 24)
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[FSHL1]], [[FSHL2]]
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[FSHL3]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[A]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[A]], [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = or i32 [[TMP1]], [[C]]
+; CHECK-NEXT:    [[TMP4:%.*]] = or i32 [[TMP2]], [[C]]
+; CHECK-NEXT:    [[OR2:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP3]], i32 [[TMP4]], i32 24)
 ; CHECK-NEXT:    ret i32 [[OR2]]
 ;
   %fshl1 = call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 24)



More information about the llvm-commits mailing list