[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