Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp: InstCombinerImpl::visitExtractElementInst
Issue title: Wrong swap between `sdiv` and `extractelement` by InstCombine
Labels: miscompilation
llvm:instcombine
Reported by: bongjunj

https://alive2.llvm.org/ce/z/mGNeLx


```ll
----------------------------------------
define i8 @fun0(<4 x i8> %val0, i32 %val1) {
#0:
  %val2 = sdiv <4 x i8> { 42, 42, 42, 42 }, %val0
  %val3 = extractelement <4 x i8> %val2, i32 %val1
  ret i8 %val3
}
=>
define i8 @fun0(<4 x i8> %val0, i32 %val1) {
#0:
  %#1 = extractelement <4 x i8> %val0, i32 %val1
  %val3 = sdiv i8 42, %#1
  ret i8 %val3
}
Transformation doesn't verify!

ERROR: Source is more defined than target

Example:
<4 x i8> %val0 = < #x01 (1), #x08 (8), #x02 (2), #x04 (4) >
i32 %val1 = #x20000000 (536870912)

Source:
<4 x i8> %val2 = < #x2a (42), #x05 (5), #x15 (21), #x0a (10) >
i8 %val3 = poison

Target:
i8 %#1 = poison
i8 %val3 = UB triggered!


Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


`sdiv` and `extractelement` cannot be swapped for vector operands as it can trigger UB, diving an integer by `poison`.


Fix patch:
commit 4d2ae88d1617a910ec3a1436ce53579523ac2f97
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Jul 3 10:58:38 2024 +0200

    [InstCombine] Fix invalid scalarization of div
    
    If the binop is not speculatable, and the extract index is out of
    range, then scalarizing will perform the operation on a poison
    operand, resulting in immediate UB, instead of the previous
    poison result.
    
    Fixes https://github.com/llvm/llvm-project/issues/97053.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
index 3de56a403803..753ed55523c8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
@@ -419,6 +419,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) {
   // If extracting a specified index from the vector, see if we can recursively
   // find a previously computed scalar that was inserted into the vector.
   auto *IndexC = dyn_cast<ConstantInt>(Index);
+  bool HasKnownValidIndex = false;
   if (IndexC) {
     // Canonicalize type of constant indices to i64 to simplify CSE
     if (auto *NewIdx = getPreferredVectorIndex(IndexC))
@@ -426,6 +427,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) {
 
     ElementCount EC = EI.getVectorOperandType()->getElementCount();
     unsigned NumElts = EC.getKnownMinValue();
+    HasKnownValidIndex = IndexC->getValue().ult(NumElts);
 
     if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(SrcVec)) {
       Intrinsic::ID IID = II->getIntrinsicID();
@@ -471,8 +473,11 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) {
     return UnaryOperator::CreateWithCopiedFlags(UO->getOpcode(), E, UO);
   }
 
+  // If the binop is not speculatable, we cannot hoist the extractelement if
+  // it may make the operand poison.
   BinaryOperator *BO;
-  if (match(SrcVec, m_BinOp(BO)) && cheapToScalarize(SrcVec, Index)) {
+  if (match(SrcVec, m_BinOp(BO)) && cheapToScalarize(SrcVec, Index) &&
+      (HasKnownValidIndex || isSafeToSpeculativelyExecute(BO))) {
     // extelt (binop X, Y), Index --> binop (extelt X, Index), (extelt Y, Index)
     Value *X = BO->getOperand(0), *Y = BO->getOperand(1);
     Value *E0 = Builder.CreateExtractElement(X, Index);


Regression tests:
file: llvm/test/Transforms/InstCombine/scalarization.ll
commands: opt -passes=instcombine -S < %s
tests: test_name: extract_element_binop_splat_variable_index_may_trap
test_body: define i8 @extract_element_binop_splat_variable_index_may_trap(<4 x i8> %x, <4 x i8> %y, i32 %z) {
  %b = sdiv <4 x i8> splat (i8 42), %y
  %r = extractelement <4 x i8> %b, i32 %z
  ret i8 %r
}

test_name: extract_element_binop_splat_variable_index
test_body: define i8 @extract_element_binop_splat_variable_index(<4 x i8> %x, i32 %y) {
  %b = sdiv <4 x i8> %x, splat (i8 42)
  %r = extractelement <4 x i8> %b, i32 %y
  ret i8 %r
}