Bug type: crash
Component: Scalarizer
Bug location: llvm/lib/Transforms/Scalar/Scalarizer.cpp: ScalarizerVisitor::splitCall
ScalarizerVisitor::visitExtractValueInst
Issue title: [Scalarizer] Test *_with_overflow crash with min-bits=32 and min-bits=16
Labels: crash-on-valid
llvm:analysis
Reported by: farzonl

first reported here: https://github.com/llvm/llvm-project/pull/127520
introduced by: https://github.com/llvm/llvm-project/pull/126815

```llvm
; RUN: opt %s -passes='function(scalarizer<load-store;min-bits=16>,dce)' -S | FileCheck %s --check-prefixes=CHECK,MIN16
; RUN: opt %s -passes='function(scalarizer<load-store;min-bits=32>,dce)' -S | FileCheck %s --check-prefixes=CHECK,MIN32

define <3 x i32> @call_v3i32(<3 x i32> %a, <3 x i32> %b) {
; CHECK-LABEL: @call_v3i32(
; CHECK-NEXT:    [[T:%.*]] = call { <3 x i32>, <3 x i1> } @llvm.uadd.with.overflow.v3i32(<3 x i32> [[A:%.*]], <3 x i32> [[B:%.*]])
; CHECK-NEXT:    [[R:%.*]] = extractvalue { <3 x i32>, <3 x i1> } [[T]], 0
; CHECK-NEXT:    ret <3 x i32> [[R]]
;
  %t = call { <3 x i32>, <3 x i1> } @llvm.uadd.with.overflow.v3i32(<3 x i32> %a, <3 x i32> %b)
  %r = extractvalue { <3 x i32>, <3 x i1> } %t, 0
  ret <3 x i32> %r
}

```

```bash
opt: include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From *) [To = llvm::VectorType, From = llvm::Type]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: opt -passes=function(scalarizer<load-store;min-bits=16>,dce) -S
1.	Running pass "function(scalarizer,dce)" on module "<stdin>"
2.	Running pass "scalarizer" on function "call_v3i32"
 #0 0x0000000004028908 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (opt+0x4028908)
 #1 0x000000000402643e llvm::sys::RunSignalHandlers() (opt+0x402643e)
 #2 0x0000000004029131 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x000075c457a45330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
 #4 0x000075c457a9eb2c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x000075c457a9eb2c __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x000075c457a9eb2c pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x000075c457a4527e raise ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x000075c457a288ff abort ./stdlib/abort.c:81:7
 #9 0x000075c457a2881b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x000075c457a3b517 (/lib/x86_64-linux-gnu/libc.so.6+0x3b517)
#11 0x0000000004143bea (opt+0x4143bea)
#12 0x00000000049addf4 (anonymous namespace)::Scatterer::operator[](unsigned int) Scalarizer.cpp:0:0
#13 0x00000000049aa142 (anonymous namespace)::ScalarizerVisitor::visit(llvm::Function&) Scalarizer.cpp:0:0
#14 0x00000000049a5419 llvm::ScalarizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (opt+0x49a5419)
```

No line numbers, Looks like we have some missing debug symbols I suspect the assert is coming from `ScalarizerVisitor::visitExtractValueInst`

There is a use of Scatterer::operator[] as part of creating the ExtractValue IR.

```cpp
for (unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
    Value *ResElem = Builder.CreateExtractValue(
        Op0[OpIdx], Index, EVI.getName() + ".elem" + Twine(Index));
    Res.push_back(ResElem);
  }
```

We likely need to check `VS.NumPacked` before calling `Scatterer::operator[]`

Because that operator is  using `Frag * VS.NumPacked` to create the exrtractElement instruction.

```cpp
 CV[Frag] = Builder.CreateExtractElement(V, Frag * VS.NumPacked,
                                            V->getName() + ".i" + Twine(Frag))
```

  

Comments: author: farzonl
body: @Icohedron can you look into this  issue. I'm also noticing a second potential issue:

`call { <3 x i32>, <3 x i1> }`

The struct return elements are not the same type. one is vec3 of i32 one is and one is vec3 of i1.  you need to add the `*_with_overflow` intrinsics to `isVectorIntrinsicWithStructReturnOverloadAtField` if these types are not the same.
author: Icohedron
body: I'm on it
author: jayfoad
body: As mentioned in #127996, note that you can also provoke this bug by adding `min-bits=64` to `test/Transforms/Scalarizer/frexp.ll`.
author: Icohedron
body: > [@Icohedron](https://github.com/Icohedron) can you look into this issue. I'm also noticing a second potential issue:
> 
> `call { <3 x i32>, <3 x i1> }`
> 
> The struct return elements are not the same type. one is vec3 of i32 one is and one is vec3 of i1. you need to add the `*_with_overflow` intrinsics to `isVectorIntrinsicWithStructReturnOverloadAtField` if these types are not the same.

`isVectorIntrinsicWithStructReturnOverloadAtField` appears to only be for intrinsic name-mangling when there is more than one possible type for the the 2nd element in the struct return type (see [splitCall](https://github.com/llvm/llvm-project/blob/5f8da7e7738f043dbde447e48622e9b2afb5ba92/llvm/lib/Transforms/Scalar/Scalarizer.cpp#L770) and [getOrInsertDeclaration](https://github.com/llvm/llvm-project/blob/5f8da7e7738f043dbde447e48622e9b2afb5ba92/llvm/lib/IR/Intrinsics.cpp#L763)). For the `*_with_overflow` intrinsics, the 2nd element of the return struct is always i1, so it does not need to be added to `isVectorIntrinsicWithStructReturnOverloadAtField`.

Adding the `*_with_overflow` intrinsic to `isVectorIntrinsicWithStructReturnOverloadAtField` results in a broken LLVM module.
```
Intrinsic name not mangled correctly for type arguments! Should be: llvm.uadd.with.overflow.i32
ptr @llvm.uadd.with.overflow.i32.i1
LLVM ERROR: Broken module found, compilation aborted!
```

Fix patch:
commit 1440f02259abf585f0c2965bd4ececf0f3499405
Author: Deric C. <cheung.deric@gmail.com>
Date:   Tue Mar 4 13:10:31 2025 -0800

    [Scalarizer] Ensure valid VectorSplits for each struct element in `visitExtractValueInst` (#128538)
    
    Fixes #127739
    
    The `visitExtractValueInst` is missing a check that was present in
    `splitCall` / `visitCallInst`.
    This check ensures that each struct element has a VectorSplit, and that
    each VectorSplit contains the same number of elements packed per
    fragment.
    
    ---------
    
    Co-authored-by: Jay Foad <jay.foad@amd.com>

diff --git a/llvm/lib/Transforms/Scalar/Scalarizer.cpp b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
index 2b27150112ad..820c8e12d244 100644
--- a/llvm/lib/Transforms/Scalar/Scalarizer.cpp
+++ b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
@@ -719,13 +719,12 @@ bool ScalarizerVisitor::splitCall(CallInst &CI) {
     for (unsigned I = 1; I < CallType->getNumContainedTypes(); I++) {
       std::optional<VectorSplit> CurrVS =
           getVectorSplit(cast<FixedVectorType>(CallType->getContainedType(I)));
-      // This case does not seem to happen, but it is possible for
-      // VectorSplit.NumPacked >= NumElems. If that happens a VectorSplit
-      // is not returned and we will bailout of handling this call.
-      // The secondary bailout case is if NumPacked does not match.
-      // This can happen if ScalarizeMinBits is not set to the default.
-      // This means with certain ScalarizeMinBits intrinsics like frexp
-      // will only scalarize when the struct elements have the same bitness.
+      // It is possible for VectorSplit.NumPacked >= NumElems. If that happens a
+      // VectorSplit is not returned and we will bailout of handling this call.
+      // The secondary bailout case is if NumPacked does not match. This can
+      // happen if ScalarizeMinBits is not set to the default. This means with
+      // certain ScalarizeMinBits intrinsics like frexp will only scalarize when
+      // the struct elements have the same bitness.
       if (!CurrVS || CurrVS->NumPacked != VS->NumPacked)
         return false;
       if (isVectorIntrinsicWithStructReturnOverloadAtField(ID, I, TTI))
@@ -1083,6 +1082,18 @@ bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
   std::optional<VectorSplit> VS = getVectorSplit(VecType);
   if (!VS)
     return false;
+  for (unsigned I = 1; I < OpTy->getNumContainedTypes(); I++) {
+    std::optional<VectorSplit> CurrVS =
+        getVectorSplit(cast<FixedVectorType>(OpTy->getContainedType(I)));
+    // It is possible for VectorSplit.NumPacked >= NumElems. If that happens a
+    // VectorSplit is not returned and we will bailout of handling this call.
+    // The secondary bailout case is if NumPacked does not match. This can
+    // happen if ScalarizeMinBits is not set to the default. This means with
+    // certain ScalarizeMinBits intrinsics like frexp will only scalarize when
+    // the struct elements have the same bitness.
+    if (!CurrVS || CurrVS->NumPacked != VS->NumPacked)
+      return false;
+  }
   IRBuilder<> Builder(&EVI);
   Scatterer Op0 = scatter(&EVI, Op, *VS);
   assert(!EVI.getIndices().empty() && "Make sure an index exists");


Regression tests:
file: llvm/test/Transforms/Scalarizer/min-bits.ll
commands: opt %s -passes='function(scalarizer<load-store;min-bits=16>,dce)' -S
opt %s -passes='function(scalarizer<load-store;min-bits=32>,dce)' -S
opt %s -passes='function(scalarizer<load-store;min-bits=64>,dce)' -S
tests: test_name: load_add_store_v2i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @load_add_store_v2i16(ptr %pa, ptr %pb) {
  %a = load <2 x i16>, ptr %pa, align 8
  %b = load <2 x i16>, ptr %pb, align 8
  %c = add <2 x i16> %a, %b
  store <2 x i16> %c, ptr %pa, align 8
  ret void
}

test_name: select_uniform_condition_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x half> @select_uniform_condition_v3f16(<3 x half> %a, <3 x half> %b, i1 %cc) {
  %r = select i1 %cc, <3 x half> %a, <3 x half> %b
  ret <3 x half> %r
}

test_name: call_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x half> @call_v4f16(<4 x half> %a, <4 x half> %b) {
  %r = call <4 x half> @llvm.minnum.v4f16(<4 x half> %a, <4 x half> %b)
  ret <4 x half> %r
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <4 x half> @llvm.minnum.v4f16(<4 x half>, <4 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: unary_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x half> @unary_v4f16(<4 x half> %a) {
  %r = fneg <4 x half> %a
  ret <4 x half> %r
}

test_name: gep1_v4
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x ptr> @gep1_v4(ptr %base, <4 x i16> %a) {
  %p = getelementptr i32, ptr %base, <4 x i16> %a
  ret <4 x ptr> %p
}

test_name: fptosi_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x i16> @fptosi_v3f16(<3 x half> %a) {
  %r = fptosi <3 x half> %a to <3 x i16>
  ret <3 x i16> %r
}

test_name: binary_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x half> @binary_v2f16(<2 x half> %a, <2 x half> %b) {
  %r = fadd <2 x half> %a, %b
  ret <2 x half> %r
}

test_name: gep3_v4
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x ptr> @gep3_v4(<4 x ptr> %base, <4 x i16> %a) {
  %p = getelementptr i32, <4 x ptr> %base, <4 x i16> %a
  ret <4 x ptr> %p
}

test_name: fptosi_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x i16> @fptosi_v4f16(<4 x half> %a) {
  %r = fptosi <4 x half> %a to <4 x i16>
  ret <4 x i16> %r
}

test_name: binary_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x half> @binary_v3f16(<3 x half> %a, <3 x half> %b) {
  %r = fadd <3 x half> %a, %b
  ret <3 x half> %r
}

test_name: load_add_store_v4i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @load_add_store_v4i16(ptr %pa, ptr %pb) {
  %a = load <4 x i16>, ptr %pa, align 8
  %b = load <4 x i16>, ptr %pb, align 8
  %c = add <4 x i16> %a, %b
  store <4 x i16> %c, ptr %pa, align 8
  ret void
}

test_name: select_uniform_condition_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x half> @select_uniform_condition_v2f16(<2 x half> %a, <2 x half> %b, i1 %cc) {
  %r = select i1 %cc, <2 x half> %a, <2 x half> %b
  ret <2 x half> %r
}

test_name: shufflevector_shrink
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @shufflevector_shrink(ptr %pa) {
  %a = load <4 x i16>, ptr %pa, align 8
  %r = shufflevector <4 x i16> %a, <4 x i16> poison, <2 x i32> <i32 1, i32 2>
  store <2 x i16> %r, ptr %pa, align 4
  ret void
}

test_name: phi_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @phi_v2f16(ptr %base, i64 %bound) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %x = phi <2 x half> [ zeroinitializer, %entry ], [ %x.next, %loop ]
  %idx = phi i64 [ 0, %entry ], [ %idx.next, %loop ]
  %p = getelementptr <2 x half>, ptr %base, i64 %idx
  %a = load <2 x half>, ptr %p, align 2
  %x.next = fadd <2 x half> %x, %a
  %idx.next = add i64 %idx, 1
  %cc = icmp ult i64 %idx.next, %bound
  br i1 %cc, label %loop, label %end

end:                                              ; preds = %loop
  store <2 x half> %x.next, ptr %base, align 4
  ret void
}

test_name: frexp_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define noundef <2 x half> @frexp_v2f16(<2 x half> noundef %h) {
  %r = call { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half> %h)
  %e0 = extractvalue { <2 x half>, <2 x i32> } %r, 0
  ret <2 x half> %e0
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare { <2 x half>, <2 x i32> } @llvm.frexp.v2f16.v2i32(<2 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: load_insertelement_v3i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x i16> @load_insertelement_v3i16(ptr %pa, i16 %b) {
  %a = load <3 x i16>, ptr %pa, align 8
  %r = insertelement <3 x i16> %a, i16 %b, i64 2
  ret <3 x i16> %r
}

test_name: load_add_store_v3i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @load_add_store_v3i16(ptr %pa, ptr %pb) {
  %a = load <3 x i16>, ptr %pa, align 8
  %b = load <3 x i16>, ptr %pb, align 8
  %c = add <3 x i16> %a, %b
  store <3 x i16> %c, ptr %pa, align 8
  ret void
}

test_name: fptosi_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x i16> @fptosi_v2f16(<2 x half> %a) {
  %r = fptosi <2 x half> %a to <2 x i16>
  ret <2 x i16> %r
}

test_name: insertelement_v4i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @insertelement_v4i16(ptr %p, <4 x i16> %a, i16 %b) {
  %r = insertelement <4 x i16> %a, i16 %b, i64 3
  store <4 x i16> %r, ptr %p, align 8
  ret void
}

test_name: load_insertelement_v2i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x i16> @load_insertelement_v2i16(ptr %pa, i16 %b) {
  %a = load <2 x i16>, ptr %pa, align 4
  %r = insertelement <2 x i16> %a, i16 %b, i64 1
  ret <2 x i16> %r
}

test_name: load_insertelement_v4i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x i16> @load_insertelement_v4i16(ptr %pa, i16 %b) {
  %a = load <4 x i16>, ptr %pa, align 8
  %r = insertelement <4 x i16> %a, i16 %b, i64 3
  ret <4 x i16> %r
}

test_name: insertelement_v2i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @insertelement_v2i16(ptr %p, <2 x i16> %a, i16 %b) {
  %r = insertelement <2 x i16> %a, i16 %b, i64 1
  store <2 x i16> %r, ptr %p, align 4
  ret void
}

test_name: shufflevector_grow
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @shufflevector_grow(ptr %pa, ptr %pb) {
  %a = load <2 x i16>, ptr %pa, align 4
  %b = load <2 x i16>, ptr %pb, align 4
  %r = shufflevector <2 x i16> %a, <2 x i16> %b, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  store <4 x i16> %r, ptr %pa, align 8
  ret void
}

test_name: uadd_with_overflow_v3i32
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x i32> @uadd_with_overflow_v3i32(<3 x i32> %a, <3 x i32> %b) {
  %t = call { <3 x i32>, <3 x i1> } @llvm.uadd.with.overflow.v3i32(<3 x i32> %a, <3 x i32> %b)
  %r = extractvalue { <3 x i32>, <3 x i1> } %t, 0
  ret <3 x i32> %r
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare { <3 x i32>, <3 x i1> } @llvm.uadd.with.overflow.v3i32(<3 x i32>, <3 x i32>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: insertelement_v3i16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @insertelement_v3i16(ptr %p, <3 x i16> %a, i16 %b) {
  %r = insertelement <3 x i16> %a, i16 %b, i64 2
  store <3 x i16> %r, ptr %p, align 8
  ret void
}

test_name: call_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x half> @call_v2f16(<2 x half> %a, <2 x half> %b) {
  %r = call <2 x half> @llvm.minnum.v2f16(<2 x half> %a, <2 x half> %b)
  ret <2 x half> %r
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <2 x half> @llvm.minnum.v2f16(<2 x half>, <2 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: phi_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @phi_v3f16(ptr %base, i64 %bound) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %x = phi <3 x half> [ zeroinitializer, %entry ], [ %x.next, %loop ]
  %idx = phi i64 [ 0, %entry ], [ %idx.next, %loop ]
  %p = getelementptr <3 x half>, ptr %base, i64 %idx
  %a = load <3 x half>, ptr %p, align 2
  %x.next = fadd <3 x half> %x, %a
  %idx.next = add i64 %idx, 1
  %cc = icmp ult i64 %idx.next, %bound
  br i1 %cc, label %loop, label %end

end:                                              ; preds = %loop
  store <3 x half> %x.next, ptr %base, align 8
  ret void
}

test_name: phi_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @phi_v4f16(ptr %base, i64 %bound) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %x = phi <4 x half> [ zeroinitializer, %entry ], [ %x.next, %loop ]
  %idx = phi i64 [ 0, %entry ], [ %idx.next, %loop ]
  %p = getelementptr <4 x half>, ptr %base, i64 %idx
  %a = load <4 x half>, ptr %p, align 2
  %x.next = fadd <4 x half> %x, %a
  %idx.next = add i64 %idx, 1
  %cc = icmp ult i64 %idx.next, %bound
  br i1 %cc, label %loop, label %end

end:                                              ; preds = %loop
  store <4 x half> %x.next, ptr %base, align 8
  ret void
}

test_name: call_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x half> @call_v3f16(<3 x half> %a, <3 x half> %b) {
  %r = call <3 x half> @llvm.minnum.v3f16(<3 x half> %a, <3 x half> %b)
  ret <3 x half> %r
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <3 x half> @llvm.minnum.v3f16(<3 x half>, <3 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: binary_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x half> @binary_v4f16(<4 x half> %a, <4 x half> %b) {
  %r = fadd <4 x half> %a, %b
  ret <4 x half> %r
}

test_name: fpext_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x float> @fpext_v4f16(<4 x half> %a) {
  %r = fpext <4 x half> %a to <4 x float>
  ret <4 x float> %r
}

test_name: load_add_store_v4i10
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define void @load_add_store_v4i10(ptr %pa, ptr %pb) {
  %a = load <4 x i10>, ptr %pa, align 8
  %b = load <4 x i10>, ptr %pb, align 8
  %c = add <4 x i10> %a, %b
  store <4 x i10> %c, ptr %pa, align 8
  ret void
}

test_name: unary_v3f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <3 x half> @unary_v3f16(<3 x half> %a) {
  %r = fneg <3 x half> %a
  ret <3 x half> %r
}

test_name: unary_v2f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <2 x half> @unary_v2f16(<2 x half> %a) {
  %r = fneg <2 x half> %a
  ret <2 x half> %r
}

test_name: select_uniform_condition_v4f16
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

define <4 x half> @select_uniform_condition_v4f16(<4 x half> %a, <4 x half> %b, i1 %cc) {
  %r = select i1 %cc, <4 x half> %a, <4 x half> %b
  ret <4 x half> %r
}