; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
;=========================== begin_copyright_notice ============================
;
; Copyright (C) 2024 Intel Corporation
;
; SPDX-License-Identifier: MIT
;
;============================ end_copyright_notice =============================
;
; RUN: igc_opt --igc-scalarize --opaque-pointers -S < %s | FileCheck %s
; REQUIRES: llvm-14-plus
; ------------------------------------------------
; ScalarizeFunction
; ------------------------------------------------
; The pass should break vector operation into many scalar operations
; ------------------------------------------------

define spir_kernel void @basic(<2 x float> %src1) {
; CHECK-LABEL: define spir_kernel void @basic(
; CHECK-SAME: <2 x float> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[SRC1_SCALAR:%.*]] = extractelement <2 x float> [[SRC1]], i32 0
; CHECK-NEXT:    [[SRC1_SCALAR1:%.*]] = extractelement <2 x float> [[SRC1]], i32 1
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <2 x float>, align 8
; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[SRC1_SCALAR]]
; CHECK-NEXT:    [[TMP3:%.*]] = fneg float [[SRC1_SCALAR1]]
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <2 x float> undef, float [[TMP2]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT2:%.*]] = insertelement <2 x float> [[DOTASSEMBLED_VECT]], float [[TMP3]], i32 1
; CHECK-NEXT:    store <2 x float> [[DOTASSEMBLED_VECT2]], ptr [[TMP1]], align 8
; CHECK-NEXT:    ret void
;
  %1 = alloca <2 x float>
  %2 = fneg <2 x float> %src1
  store <2 x float> %2, ptr %1
  ret void
}

define spir_kernel void @should_preserve_metadata(<2 x float> %src1) {
; CHECK-LABEL: define spir_kernel void @should_preserve_metadata(
; CHECK-SAME: <2 x float> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[SRC1_SCALAR:%.*]] = extractelement <2 x float> [[SRC1]], i32 0
; CHECK-NEXT:    [[SRC1_SCALAR1:%.*]] = extractelement <2 x float> [[SRC1]], i32 1
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <2 x float>, align 8
; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[SRC1_SCALAR]], !any_metadata [[META0:![0-9]+]]
; CHECK-NEXT:    [[TMP3:%.*]] = fneg float [[SRC1_SCALAR1]], !any_metadata [[META0]]
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <2 x float> undef, float [[TMP2]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT2:%.*]] = insertelement <2 x float> [[DOTASSEMBLED_VECT]], float [[TMP3]], i32 1
; CHECK-NEXT:    store <2 x float> [[DOTASSEMBLED_VECT2]], ptr [[TMP1]], align 8
; CHECK-NEXT:    ret void
;
  %1 = alloca <2 x float>
  %2 = fneg <2 x float> %src1, !any_metadata !{i32 0}
  store <2 x float> %2, ptr %1
  ret void
}

define spir_kernel void @should_work_with_different_type(<2 x double> %src1) {
; CHECK-LABEL: define spir_kernel void @should_work_with_different_type(
; CHECK-SAME: <2 x double> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[SRC1_SCALAR:%.*]] = extractelement <2 x double> [[SRC1]], i32 0
; CHECK-NEXT:    [[SRC1_SCALAR1:%.*]] = extractelement <2 x double> [[SRC1]], i32 1
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <2 x double>, align 16
; CHECK-NEXT:    [[TMP2:%.*]] = fneg double [[SRC1_SCALAR]]
; CHECK-NEXT:    [[TMP3:%.*]] = fneg double [[SRC1_SCALAR1]]
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <2 x double> undef, double [[TMP2]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT2:%.*]] = insertelement <2 x double> [[DOTASSEMBLED_VECT]], double [[TMP3]], i32 1
; CHECK-NEXT:    store <2 x double> [[DOTASSEMBLED_VECT2]], ptr [[TMP1]], align 16
; CHECK-NEXT:    ret void
;
  %1 = alloca <2 x double>
  %2 = fneg <2 x double> %src1
  store <2 x double> %2, ptr %1
  ret void
}

define spir_kernel void @should_work_with_fast_math_flags(<2 x double> %src1) {
; CHECK-LABEL: define spir_kernel void @should_work_with_fast_math_flags(
; CHECK-SAME: <2 x double> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[SRC1_SCALAR:%.*]] = extractelement <2 x double> [[SRC1]], i32 0
; CHECK-NEXT:    [[SRC1_SCALAR1:%.*]] = extractelement <2 x double> [[SRC1]], i32 1
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <2 x double>, align 16
; CHECK-NEXT:    [[TMP2:%.*]] = fneg fast double [[SRC1_SCALAR]]
; CHECK-NEXT:    [[TMP3:%.*]] = fneg fast double [[SRC1_SCALAR1]]
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <2 x double> undef, double [[TMP2]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT2:%.*]] = insertelement <2 x double> [[DOTASSEMBLED_VECT]], double [[TMP3]], i32 1
; CHECK-NEXT:    store <2 x double> [[DOTASSEMBLED_VECT2]], ptr [[TMP1]], align 16
; CHECK-NEXT:    ret void
;
  %1 = alloca <2 x double>
  %2 = fneg fast <2 x double> %src1
  store <2 x double> %2, ptr %1
  ret void
}

define spir_kernel void @should_work_with_larger_vector_size(<16 x float> %src1) {
; CHECK-LABEL: define spir_kernel void @should_work_with_larger_vector_size(
; CHECK-SAME: <16 x float> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[SRC1_SCALAR:%.*]] = extractelement <16 x float> [[SRC1]], i32 0
; CHECK-NEXT:    [[SRC1_SCALAR1:%.*]] = extractelement <16 x float> [[SRC1]], i32 1
; CHECK-NEXT:    [[SRC1_SCALAR2:%.*]] = extractelement <16 x float> [[SRC1]], i32 2
; CHECK-NEXT:    [[SRC1_SCALAR3:%.*]] = extractelement <16 x float> [[SRC1]], i32 3
; CHECK-NEXT:    [[SRC1_SCALAR4:%.*]] = extractelement <16 x float> [[SRC1]], i32 4
; CHECK-NEXT:    [[SRC1_SCALAR5:%.*]] = extractelement <16 x float> [[SRC1]], i32 5
; CHECK-NEXT:    [[SRC1_SCALAR6:%.*]] = extractelement <16 x float> [[SRC1]], i32 6
; CHECK-NEXT:    [[SRC1_SCALAR7:%.*]] = extractelement <16 x float> [[SRC1]], i32 7
; CHECK-NEXT:    [[SRC1_SCALAR8:%.*]] = extractelement <16 x float> [[SRC1]], i32 8
; CHECK-NEXT:    [[SRC1_SCALAR9:%.*]] = extractelement <16 x float> [[SRC1]], i32 9
; CHECK-NEXT:    [[SRC1_SCALAR10:%.*]] = extractelement <16 x float> [[SRC1]], i32 10
; CHECK-NEXT:    [[SRC1_SCALAR11:%.*]] = extractelement <16 x float> [[SRC1]], i32 11
; CHECK-NEXT:    [[SRC1_SCALAR12:%.*]] = extractelement <16 x float> [[SRC1]], i32 12
; CHECK-NEXT:    [[SRC1_SCALAR13:%.*]] = extractelement <16 x float> [[SRC1]], i32 13
; CHECK-NEXT:    [[SRC1_SCALAR14:%.*]] = extractelement <16 x float> [[SRC1]], i32 14
; CHECK-NEXT:    [[SRC1_SCALAR15:%.*]] = extractelement <16 x float> [[SRC1]], i32 15
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <16 x float>, align 64
; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[SRC1_SCALAR]]
; CHECK-NEXT:    [[TMP3:%.*]] = fneg float [[SRC1_SCALAR1]]
; CHECK-NEXT:    [[TMP4:%.*]] = fneg float [[SRC1_SCALAR2]]
; CHECK-NEXT:    [[TMP5:%.*]] = fneg float [[SRC1_SCALAR3]]
; CHECK-NEXT:    [[TMP6:%.*]] = fneg float [[SRC1_SCALAR4]]
; CHECK-NEXT:    [[TMP7:%.*]] = fneg float [[SRC1_SCALAR5]]
; CHECK-NEXT:    [[TMP8:%.*]] = fneg float [[SRC1_SCALAR6]]
; CHECK-NEXT:    [[TMP9:%.*]] = fneg float [[SRC1_SCALAR7]]
; CHECK-NEXT:    [[TMP10:%.*]] = fneg float [[SRC1_SCALAR8]]
; CHECK-NEXT:    [[TMP11:%.*]] = fneg float [[SRC1_SCALAR9]]
; CHECK-NEXT:    [[TMP12:%.*]] = fneg float [[SRC1_SCALAR10]]
; CHECK-NEXT:    [[TMP13:%.*]] = fneg float [[SRC1_SCALAR11]]
; CHECK-NEXT:    [[TMP14:%.*]] = fneg float [[SRC1_SCALAR12]]
; CHECK-NEXT:    [[TMP15:%.*]] = fneg float [[SRC1_SCALAR13]]
; CHECK-NEXT:    [[TMP16:%.*]] = fneg float [[SRC1_SCALAR14]]
; CHECK-NEXT:    [[TMP17:%.*]] = fneg float [[SRC1_SCALAR15]]
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <16 x float> undef, float [[TMP2]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT16:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT]], float [[TMP3]], i32 1
; CHECK-NEXT:    [[DOTASSEMBLED_VECT17:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT16]], float [[TMP4]], i32 2
; CHECK-NEXT:    [[DOTASSEMBLED_VECT18:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT17]], float [[TMP5]], i32 3
; CHECK-NEXT:    [[DOTASSEMBLED_VECT19:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT18]], float [[TMP6]], i32 4
; CHECK-NEXT:    [[DOTASSEMBLED_VECT20:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT19]], float [[TMP7]], i32 5
; CHECK-NEXT:    [[DOTASSEMBLED_VECT21:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT20]], float [[TMP8]], i32 6
; CHECK-NEXT:    [[DOTASSEMBLED_VECT22:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT21]], float [[TMP9]], i32 7
; CHECK-NEXT:    [[DOTASSEMBLED_VECT23:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT22]], float [[TMP10]], i32 8
; CHECK-NEXT:    [[DOTASSEMBLED_VECT24:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT23]], float [[TMP11]], i32 9
; CHECK-NEXT:    [[DOTASSEMBLED_VECT25:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT24]], float [[TMP12]], i32 10
; CHECK-NEXT:    [[DOTASSEMBLED_VECT26:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT25]], float [[TMP13]], i32 11
; CHECK-NEXT:    [[DOTASSEMBLED_VECT27:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT26]], float [[TMP14]], i32 12
; CHECK-NEXT:    [[DOTASSEMBLED_VECT28:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT27]], float [[TMP15]], i32 13
; CHECK-NEXT:    [[DOTASSEMBLED_VECT29:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT28]], float [[TMP16]], i32 14
; CHECK-NEXT:    [[DOTASSEMBLED_VECT30:%.*]] = insertelement <16 x float> [[DOTASSEMBLED_VECT29]], float [[TMP17]], i32 15
; CHECK-NEXT:    store <16 x float> [[DOTASSEMBLED_VECT30]], ptr [[TMP1]], align 64
; CHECK-NEXT:    ret void
;
  %1 = alloca <16 x float>
  %2 = fneg <16 x float> %src1
  store <16 x float> %2, ptr %1
  ret void
}

define void @should_not_scalarize_optnone(<2 x float> %src1) #0 {
; CHECK-LABEL: define void @should_not_scalarize_optnone(
; CHECK-SAME: <2 x float> [[SRC1:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:    [[TMP1:%.*]] = alloca <2 x float>, align 8
; CHECK-NEXT:    [[TMP2:%.*]] = fneg <2 x float> [[SRC1]]
; CHECK-NEXT:    store <2 x float> [[TMP2]], ptr [[TMP1]], align 8
; CHECK-NEXT:    ret void
;
  %1 = alloca <2 x float>
  %2 = fneg <2 x float> %src1
  store <2 x float> %2, ptr %1
  ret void
}

define <2 x float> @should_not_scalarize_const(<2 x float> %src1) {
; CHECK-LABEL: define <2 x float> @should_not_scalarize_const(
; CHECK-SAME: <2 x float> [[SRC1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = fneg <2 x float> <float 1.000000e+00, float 2.000000e+00>
; CHECK-NEXT:    ret <2 x float> [[TMP1]]
;
  %1 = fneg <2 x float> <float 1.0, float 2.0>
  ret <2 x float> %1
}

define spir_kernel void @should_not_scalarize_scalar(float %src1) {
; CHECK-LABEL: define spir_kernel void @should_not_scalarize_scalar(
; CHECK-SAME: float [[SRC1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = alloca float, align 4
; CHECK-NEXT:    [[TMP2:%.*]] = fneg float [[SRC1]]
; CHECK-NEXT:    store float [[TMP2]], ptr [[TMP1]], align 4
; CHECK-NEXT:    ret void
;
  %1 = alloca float
  %2 = fneg float %src1
  store float %2, ptr %1
  ret void
}

define void @test_fneg_optnone(<4 x float> %src, ptr addrspace(1) %out) #0 {
; CHECK-LABEL: define void @test_fneg_optnone(
; CHECK-SAME: <4 x float> [[SRC:%.*]], ptr addrspace(1) [[OUT:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[SRC_SCALAR:%.*]] = extractelement <4 x float> [[SRC]], i32 0
; CHECK-NEXT:    [[SRC_SCALAR1:%.*]] = extractelement <4 x float> [[SRC]], i32 1
; CHECK-NEXT:    [[SRC_SCALAR2:%.*]] = extractelement <4 x float> [[SRC]], i32 2
; CHECK-NEXT:    [[SRC_SCALAR3:%.*]] = extractelement <4 x float> [[SRC]], i32 3
; CHECK-NEXT:    [[DOTASSEMBLED_VECT:%.*]] = insertelement <3 x float> undef, float [[SRC_SCALAR]], i32 0
; CHECK-NEXT:    [[DOTASSEMBLED_VECT4:%.*]] = insertelement <3 x float> [[DOTASSEMBLED_VECT]], float [[SRC_SCALAR1]], i32 1
; CHECK-NEXT:    [[DOTASSEMBLED_VECT5:%.*]] = insertelement <3 x float> [[DOTASSEMBLED_VECT4]], float [[SRC_SCALAR2]], i32 2
; CHECK-NEXT:    [[TMP1:%.*]] = fneg <3 x float> [[DOTASSEMBLED_VECT5]]
; CHECK-NEXT:    store <3 x float> [[TMP1]], ptr addrspace(1) [[OUT]], align 4
; CHECK-NEXT:    ret void
;
  %1 = shufflevector <4 x float> %src, <4 x float> undef, <3 x i32> <i32 0, i32 1, i32 2>
  %2 = fneg <3 x float> %1
  store <3 x float> %2, ptr addrspace(1) %out, align 4
  ret void
}

attributes #0 = { noinline optnone }

; CHECK: [[META0]] = !{i32 0}