[llvm] [CodeGenPrepare] Split x/select(cond,y,C) to select(cond,x/y,x/C) (PR #215967)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 23:34:51 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Le Gia Bao (L3GiaBao)

<details>
<summary>Changes</summary>

Splits
```llvm
define i32 @<!-- -->src(i32 %x, i32 %y, i1 %cond) {
  %sel = select i1 %cond, i32 %y, i32 7
  %r = sdiv i32 %x, %sel
  ret i32 %r
}
```
to
```llvm
define i32 @<!-- -->tgt(i32 %x, i32 %y, i1 %cond) {
  %c = freeze i1 %cond
  br i1 %c, label %true, label %false
true:
  %ty = sdiv i32 %x, %y
  br label %end
false:
  %tc = sdiv i32 %x, 7
  br label %end
end:
  %r = phi i32 [ %ty, %true ], [ %tc, %false ]
  ret i32 %r
}
````
Practically, useful for:
```c
int foo(int x, int y, bool k){
    return k ? x / y: x / 7;
}
```
which merges into `x/select(k, y, 7)`
Alive2: https://alive2.llvm.org/ce/z/qug_BH

Closes #<!-- -->214962

---
Full diff: https://github.com/llvm/llvm-project/pull/215967.diff


3 Files Affected:

- (modified) llvm/lib/CodeGen/CodeGenPrepare.cpp (+143) 
- (added) llvm/test/CodeGen/X86/divrem-by-select-scalar.ll (+100) 
- (added) llvm/test/Transforms/CodeGenPrepare/X86/div-rem-by-select.ll (+165) 


``````````diff
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 9d3f18c8fce63..d05f1c33d5b88 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -558,6 +558,132 @@ PreservedAnalyses CodeGenPreparePass::run(Function &F,
   return PA;
 }
 
+static bool isDivOrRem(unsigned Opcode) {
+  switch (Opcode) {
+  case Instruction::SDiv:
+  case Instruction::UDiv:
+  case Instruction::SRem:
+  case Instruction::URem:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static bool isCheapConstantDivisor(Value *V, const TargetLowering *TLI,
+                                   const DataLayout &DL, AttributeList Attr) {
+  auto *C = dyn_cast<ConstantInt>(V);
+  if (!C || C->isZero())
+    return false;
+  return !TLI->isIntDivCheap(TLI->getValueType(DL, C->getType()), Attr);
+}
+
+/// Fold a div/rem of a select divisor with a cheap constant arm into a
+/// branch with one division per arm:
+///   div X, (select Cond, Y, C) -->
+///   select Cond, (div X, Y), (div X, C)
+/// so the constant arm keeps its cheap lowering instead of being dragged
+/// into a variable divide. Returns true if \p I was replaced.
+static bool splitDivRemBySelectDivisor(Instruction *I,
+                                       const TargetLowering *TLI,
+                                       const DataLayout &DL,
+                                       DomTreeUpdater *DTU, LoopInfo *LI) {
+  if (!isDivOrRem(I->getOpcode()) || I->getType()->isVectorTy())
+    return false;
+
+  // Don't touch loops. foldURemOfLoopIncrement handles that case
+  if (LI && LI->getLoopFor(I->getParent()))
+    return false;
+
+  // If the select has more than one use, there's probably a sibling rem
+  // sharing this divisor and splitting them separately would duplicate the division
+  auto *Sel = dyn_cast<SelectInst>(I->getOperand(1));
+  if (!Sel || !Sel->hasOneUse())
+    return false;
+
+  // If the dividend is also constant, foldBinOpIntoSelect handles it.
+  Value *Dividend = I->getOperand(0);
+  if (isa<Constant>(Dividend))
+    return false;
+
+  AttributeList Attr = I->getFunction()->getAttributes();
+  Value *TrueVal = Sel->getTrueValue();
+  Value *FalseVal = Sel->getFalseValue();
+  if (!isCheapConstantDivisor(TrueVal, TLI, DL, Attr) &&
+      !isCheapConstantDivisor(FalseVal, TLI, DL, Attr))
+    return false;
+
+  BasicBlock *MainBB = I->getParent();
+  Function *F = MainBB->getParent();
+  LLVMContext &Ctx = F->getContext();
+  auto Opcode = static_cast<Instruction::BinaryOps>(I->getOpcode());
+
+  BasicBlock *TailBB = SplitBlock(MainBB, I, DTU, LI, nullptr, "select.end");
+  // Replace the unconditional branch that was created by the split with a
+  // branch on the select's condition.
+  MainBB->back().eraseFromParent();
+
+  auto CreateArmBB = [&](Value *Divisor, const Twine &Name) {
+    BasicBlock *ArmBB = BasicBlock::Create(Ctx, Name, F, TailBB);
+    IRBuilder<> Builder(ArmBB);
+    Builder.SetCurrentDebugLocation(I->getDebugLoc());
+    Value *Op = Builder.CreateBinOp(Opcode, Dividend, Divisor);
+    if (auto *NewI = dyn_cast<Instruction>(Op))
+      NewI->copyIRFlags(I);
+    Builder.CreateBr(TailBB);
+    return std::make_pair(ArmBB, Op);
+  };
+
+  auto [TrueBB, TrueOp] = CreateArmBB(TrueVal, "select.true");
+  auto [FalseBB, FalseOp] = CreateArmBB(FalseVal, "select.false");
+
+  IRBuilder<> HeadBuilder(MainBB, MainBB->end());
+  HeadBuilder.SetCurrentDebugLocation(I->getDebugLoc());
+  Value *Cond = HeadBuilder.CreateFreeze(Sel->getCondition());
+  HeadBuilder.CreateCondBr(Cond, TrueBB, FalseBB);
+
+  IRBuilder<> TailBuilder(TailBB, TailBB->begin());
+  TailBuilder.SetCurrentDebugLocation(I->getDebugLoc());
+  PHINode *Phi = TailBuilder.CreatePHI(I->getType(), 2);
+  Phi->addIncoming(TrueOp, TrueBB);
+  Phi->addIncoming(FalseOp, FalseBB);
+
+  I->replaceAllUsesWith(Phi);
+  I->eraseFromParent();
+  if (Sel->use_empty())
+    Sel->eraseFromParent();
+
+  if (DTU)
+    DTU->applyUpdates({{DominatorTree::Insert, MainBB, TrueBB},
+                       {DominatorTree::Insert, MainBB, FalseBB},
+                       {DominatorTree::Insert, TrueBB, TailBB},
+                       {DominatorTree::Insert, FalseBB, TailBB},
+                       {DominatorTree::Delete, MainBB, TailBB}});
+
+  return true;
+}
+
+/// Scan \p BB for div/rem instructions with a select divisor and split them
+/// (see splitDivRemBySelectDivisor).
+static bool optimizeDivRemBySelectDivisor(BasicBlock *BB,
+                                          const TargetLowering *TLI,
+                                          const DataLayout &DL,
+                                          DomTreeUpdater *DTU, LoopInfo *LI) {
+  bool MadeChange = false;
+  Instruction *Next = &*BB->begin();
+  while (Next != nullptr) {
+    // We may add instructions immediately after I but we want to skip over them.
+    Instruction *I = Next;
+    Next = Next->getNextNode();
+
+    if (I->use_empty())
+      continue;
+
+    MadeChange |= splitDivRemBySelectDivisor(I, TLI, DL, DTU, LI);
+  }
+  return MadeChange;
+}
+
 bool CodeGenPrepare::run(Function &F, FunctionAnalysisManager &AM) {
   DL = &F.getDataLayout();
   SubtargetInfo = TM->getSubtargetImpl(F);
@@ -624,6 +750,23 @@ bool CodeGenPrepare::_run(Function &F) {
     }
   }
 
+  /// Split a div/rem whose divisor is a select with a constant arm the
+  /// target would otherwise strength-reduce, so each arm can reach its own
+  /// cheapest lowering instead of being dragged into a variable divide.
+  /// Unlike the slow-division bypass above, this doesn't depend on the
+  /// target populating a bypass-width table.
+  if (!OptSize) {
+    BasicBlock *BB = &*F.begin();
+    while (BB != nullptr) {
+      // optimizeDivRemBySelectDivisor may create new BBs, but we don't want
+      // to reapply the optimization to those blocks.
+      BasicBlock *Next = BB->getNextNode();
+      if (!llvm::shouldOptimizeForSize(BB, PSI, BFI))
+        EverMadeChange |= optimizeDivRemBySelectDivisor(BB, TLI, *DL, DTU, LI);
+      BB = Next;
+    }
+  }
+
   // Get rid of @llvm.assume builtins before attempting to eliminate empty
   // blocks, since there might be blocks that only contain @llvm.assume calls
   // (plus arguments that we can get rid of).
diff --git a/llvm/test/CodeGen/X86/divrem-by-select-scalar.ll b/llvm/test/CodeGen/X86/divrem-by-select-scalar.ll
new file mode 100644
index 0000000000000..d4bd714ce0b20
--- /dev/null
+++ b/llvm/test/CodeGen/X86/divrem-by-select-scalar.ll
@@ -0,0 +1,100 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
+
+; https://github.com/llvm/llvm-project/issues/214962
+define i32 @sdiv_by_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: sdiv_by_select_const_arm:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %dl
+; CHECK-NEXT:    je .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %select.true
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    cltd
+; CHECK-NEXT:    idivl %esi
+; CHECK-NEXT:    # kill: def $eax killed $eax def $rax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB0_2: # %select.false
+; CHECK-NEXT:    movslq %edi, %rax
+; CHECK-NEXT:    imulq $-1840700269, %rax, %rax # imm = 0x92492493
+; CHECK-NEXT:    shrq $32, %rax
+; CHECK-NEXT:    addl %edi, %eax
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $31, %ecx
+; CHECK-NEXT:    sarl $2, %eax
+; CHECK-NEXT:    addl %ecx, %eax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+define i32 @udiv_by_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: udiv_by_select_const_arm:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %dl
+; CHECK-NEXT:    je .LBB1_2
+; CHECK-NEXT:  # %bb.1: # %select.true
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    xorl %edx, %edx
+; CHECK-NEXT:    divl %esi
+; CHECK-NEXT:    # kill: def $eax killed $eax def $rax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB1_2: # %select.false
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    movabsq $2635249153617166336, %rcx # imm = 0x24924924A0000000
+; CHECK-NEXT:    mulq %rcx
+; CHECK-NEXT:    movq %rdx, %rax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = udiv i32 %x, %sel
+  ret i32 %r
+}
+
+define i32 @srem_by_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: srem_by_select_const_arm:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %dl
+; CHECK-NEXT:    je .LBB2_2
+; CHECK-NEXT:  # %bb.1: # %select.true
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    cltd
+; CHECK-NEXT:    idivl %esi
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB2_2: # %select.false
+; CHECK-NEXT:    movslq %edi, %rax
+; CHECK-NEXT:    imulq $-1840700269, %rax, %rax # imm = 0x92492493
+; CHECK-NEXT:    shrq $32, %rax
+; CHECK-NEXT:    addl %edi, %eax
+; CHECK-NEXT:    movl %eax, %ecx
+; CHECK-NEXT:    shrl $31, %ecx
+; CHECK-NEXT:    sarl $2, %eax
+; CHECK-NEXT:    addl %ecx, %eax
+; CHECK-NEXT:    leal (,%rax,8), %ecx
+; CHECK-NEXT:    subl %ecx, %eax
+; CHECK-NEXT:    addl %edi, %eax
+; CHECK-NEXT:    # kill: def $eax killed $eax killed $rax
+; CHECK-NEXT:    retq
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = srem i32 %x, %sel
+  ret i32 %r
+}
+
+define i32 @sdiv_by_select_no_const_arm(i32 %x, i32 %y, i32 %z, i1 %k) {
+; CHECK-LABEL: sdiv_by_select_no_const_arm:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    testb $1, %cl
+; CHECK-NEXT:    cmovel %edx, %esi
+; CHECK-NEXT:    cltd
+; CHECK-NEXT:    idivl %esi
+; CHECK-NEXT:    retq
+  %sel = select i1 %k, i32 %y, i32 %z
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/div-rem-by-select.ll b/llvm/test/Transforms/CodeGenPrepare/X86/div-rem-by-select.ll
new file mode 100644
index 0000000000000..799af29e74c46
--- /dev/null
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/div-rem-by-select.ll
@@ -0,0 +1,165 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes='require<profile-summary>,function(codegenprepare)' < %s | FileCheck %s
+
+target triple = "x86_64--linux-gnu"
+
+; https://github.com/llvm/llvm-project/issues/214962
+define i32 @sdiv_by_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_const_arm(
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[K:%.*]]
+; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
+; CHECK:       select.true:
+; CHECK-NEXT:    [[TMP3:%.*]] = sdiv i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br label [[DOTSPLIT:%.*]]
+; CHECK:       select.false:
+; CHECK-NEXT:    [[TMP5:%.*]] = sdiv i32 [[X]], 7
+; CHECK-NEXT:    br label [[DOTSPLIT]]
+; CHECK:       select.end:
+; CHECK-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+define i32 @urem_by_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @urem_by_select_const_arm(
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[K:%.*]]
+; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
+; CHECK:       select.true:
+; CHECK-NEXT:    [[TMP3:%.*]] = urem i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br label [[DOTSPLIT:%.*]]
+; CHECK:       select.false:
+; CHECK-NEXT:    [[TMP5:%.*]] = urem i32 [[X]], 7
+; CHECK-NEXT:    br label [[DOTSPLIT]]
+; CHECK:       select.end:
+; CHECK-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = urem i32 %x, %sel
+  ret i32 %r
+}
+
+define i32 @sdiv_by_select_both_const_arms(i32 %x, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_both_const_arms(
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[K:%.*]]
+; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
+; CHECK:       select.true:
+; CHECK-NEXT:    [[TMP3:%.*]] = sdiv i32 [[X:%.*]], 3
+; CHECK-NEXT:    br label [[DOTSPLIT:%.*]]
+; CHECK:       select.false:
+; CHECK-NEXT:    [[TMP5:%.*]] = sdiv i32 [[X]], 7
+; CHECK-NEXT:    br label [[DOTSPLIT]]
+; CHECK:       select.end:
+; CHECK-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
+; CHECK-NEXT:    ret i32 [[TMP6]]
+;
+  %sel = select i1 %k, i32 3, i32 7
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+; Negative test - select feeds the dividend
+define i32 @sdiv_by_select_dividend_not_divisor(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_dividend_not_divisor(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 7
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[SEL]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %sel, %x
+  ret i32 %r
+}
+
+define i32 @sdiv_by_select_no_const_arm(i32 %x, i32 %y, i32 %z, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_no_const_arm(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %sel = select i1 %k, i32 %y, i32 %z
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+; Negative test - don't want to duplicate the division
+define i32 @sdiv_by_select_const_arm_multiuse(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_const_arm_multiuse(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 7
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    [[R2:%.*]] = add i32 [[R]], [[SEL]]
+; CHECK-NEXT:    ret i32 [[R2]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %x, %sel
+  %r2 = add i32 %r, %sel
+  ret i32 %r2
+}
+
+; Negative test - minsize
+define i32 @sdiv_by_select_const_arm_minsize(i32 %x, i32 %y, i1 %k) minsize {
+; CHECK-LABEL: @sdiv_by_select_const_arm_minsize(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 7
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+; Negative test - optsize
+define i32 @sdiv_by_select_const_arm_optsize(i32 %x, i32 %y, i1 %k) optsize {
+; CHECK-LABEL: @sdiv_by_select_const_arm_optsize(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 7
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+; Negative test - zero divisor is UB
+define i32 @sdiv_by_select_zero_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_zero_const_arm(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 0
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %sel = select i1 %k, i32 %y, i32 0
+  %r = sdiv i32 %x, %sel
+  ret i32 %r
+}
+
+; Negative test - vectors are out of scope
+define <4 x i32> @sdiv_by_select_const_arm_vector(<4 x i32> %x, <4 x i32> %y, i1 %k) {
+; CHECK-LABEL: @sdiv_by_select_const_arm_vector(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], <4 x i32> [[Y:%.*]], <4 x i32> splat (i32 7)
+; CHECK-NEXT:    [[R:%.*]] = sdiv <4 x i32> [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    ret <4 x i32> [[R]]
+;
+  %sel = select i1 %k, <4 x i32> %y, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+  %r = sdiv <4 x i32> %x, %sel
+  ret <4 x i32> %r
+}
+
+; Negative test - don't want to divide twice
+define { i32, i32 } @sdiv_srem_by_same_select_const_arm(i32 %x, i32 %y, i1 %k) {
+; CHECK-LABEL: @sdiv_srem_by_same_select_const_arm(
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[K:%.*]], i32 [[Y:%.*]], i32 7
+; CHECK-NEXT:    [[Q:%.*]] = sdiv i32 [[X:%.*]], [[SEL]]
+; CHECK-NEXT:    [[R:%.*]] = srem i32 [[X]], [[SEL]]
+; CHECK-NEXT:    [[DM0:%.*]] = insertvalue { i32, i32 } poison, i32 [[Q]], 0
+; CHECK-NEXT:    [[DM1:%.*]] = insertvalue { i32, i32 } [[DM0]], i32 [[R]], 1
+; CHECK-NEXT:    ret { i32, i32 } [[DM1]]
+;
+  %sel = select i1 %k, i32 %y, i32 7
+  %q = sdiv i32 %x, %sel
+  %r = srem i32 %x, %sel
+  %dm0 = insertvalue { i32, i32 } poison, i32 %q, 0
+  %dm1 = insertvalue { i32, i32 } %dm0, i32 %r, 1
+  ret { i32, i32 } %dm1
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/215967


More information about the llvm-commits mailing list