; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --remove_checks
; RUN: llc < %s -mtriple=colossus -colossus-coissue=false -mattr=+ipu1 | FileCheck %s
; RUN: llc < %s -mtriple=colossus -colossus-coissue=false -mattr=+ipu2 | FileCheck %s


; The insert/extract N cases produce branchier code than would be hand written.
; The insert/extract at known N are optimal. On the basis that indices into
; vector will usually be deduced at compile time this is acceptable.
; The applicable test cases for N are specific and fragile, partly to detect
; when the codegen changes (for better or for worse);

;===------------------------------------------------------------------------===;
; Build vector.
;===------------------------------------------------------------------------===;

; This could be implemented by writing to a0 then copying to a1
; or vice versa. Assuming the reg allocator picks $a0 first
; because I can't specify this condition in filecheck
define <4 x float> @test_build_v4f32_splat(<4 x float> %a) {
; CHECK-LABEL: test_build_v4f32_splat:
; CHECK:       # %bb.0:
; CHECK-NEXT:    or $a0, $a15, 1073741824
; CHECK-NEXT:    mov $a1, $a0
; CHECK-NEXT:    mov $a2:3, $a0:1
; CHECK-NEXT:    br $m10
  ret <4 x float> <float 2.0, float 2.0, float 2.0, float 2.0>
}

; %a1 and %a2 are in $a0 and $a1 already, so it's a no-op
define <4 x float> @test_build_v4f32_nop(float %a1, float %a2) {
; CHECK-LABEL: test_build_v4f32_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %res1 = insertelement <4 x float> undef, float %a1, i32 0
  %res2 = insertelement <4 x float> %res1, float %a2, i32 1
  ret <4 x float> %res2
}

define <4 x float> @test_build_v4f32(float %a3, float %a4,
; CHECK-LABEL: test_build_v4f32:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a5, $a1
; CHECK-NEXT:    mov $a4, $a0
; CHECK-NEXT:    mov $a0:1, $a2:3
; CHECK-NEXT:    mov $a2:3, $a4:5
; CHECK-NEXT:    br $m10
                                     float %a1, float %a2) {
  %res1 = insertelement <4 x float> undef, float %a1, i32 0
  %res2 = insertelement <4 x float> %res1, float %a2, i32 1
  %res3 = insertelement <4 x float> %res2, float %a3, i32 2
  %res4 = insertelement <4 x float> %res3, float %a4, i32 3
  ret <4 x float> %res4
}

define <4 x float> @build_from_constants() {
; CHECK-LABEL: build_from_constants:
; CHECK:       # %bb.0:
; CHECK-NEXT:    or $a0, $a15, 1073741824
; CHECK-NEXT:    or $a1, $a15, 1077936128
; CHECK-NEXT:    or $a2, $a15, 1082130432
; CHECK-NEXT:    or $a3, $a15, 1084227584
; CHECK-NEXT:    br $m10
  ret <4 x float> <float 2.0, float 3.0, float 4.0, float 5.0>
}

define <4 x float> @build_from_zeros() {
; CHECK-LABEL: build_from_zeros:
; CHECK:       # %bb.0:
; CHECK-NEXT:    zero $a0:1
; CHECK-NEXT:    zero $a2:3
; CHECK-NEXT:    br $m10
  ret <4 x float> <float 0.0, float 0.0, float 0.0, float 0.0>
}

define <4 x float> @build_from_all_ones() {
; CHECK-LABEL: build_from_all_ones:
; CHECK:       # %bb.0:
; CHECK-NEXT:    not64 $a0:1, $a14:15
; CHECK-NEXT:    mov $a2:3, $a0:1
; CHECK-NEXT:    br $m10
  %c = bitcast i32 -1 to float
  %1 = insertelement <4 x float> undef, float %c, i32 0
  %2 = insertelement <4 x float> %1, float %c, i32 1
  %3 = insertelement <4 x float> %1, float %c, i32 2
  %4 = insertelement <4 x float> %1, float %c, i32 3
  ret <4 x float> %4
}

;===------------------------------------------------------------------------===;
; Insert element.
;===------------------------------------------------------------------------===;

define <4 x float> @insert_float_0_undef(float %ignore, float %x) {
; CHECK-LABEL: insert_float_0_undef:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0, $a1
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 0
  ret <4 x float> %1
}

define <4 x float> @insert_float_1_undef(float %x) {
; CHECK-LABEL: insert_float_1_undef:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a1, $a0
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 1
  ret <4 x float> %1
}

define <4 x float> @insert_float_2_undef(float %x) {
; CHECK-LABEL: insert_float_2_undef:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a2:3, $a0:1
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 2
  ret <4 x float> %1
}

define <4 x float> @insert_float_3_undef(float %x) {
; CHECK-LABEL: insert_float_3_undef:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a3, $a0
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 3
  ret <4 x float> %1
}

define <4 x float> @insert_float_0_undef_nop(float %x) {
; CHECK-LABEL: insert_float_0_undef_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 0
  ret <4 x float> %1
}

define <4 x float> @insert_float_1_undef_nop(float %ignore, float %x) {
; CHECK-LABEL: insert_float_1_undef_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 1
  ret <4 x float> %1
}

define <4 x float> @insert_float_2_undef_nop(float %ignore,
; CHECK-LABEL: insert_float_2_undef_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
                                             float %ignore2, float %x) {
  %1 = insertelement <4 x float> undef, float %x, i32 2
  ret <4 x float> %1
}

define <4 x float> @insert_float_3_undef_nop(float %ignore, float %ignore2,
; CHECK-LABEL: insert_float_3_undef_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
                                             float %ignore3,  float %x) {
  %1 = insertelement <4 x float> undef, float %x, i32 3
  ret <4 x float> %1
}

define <4 x float> @insert_float_N_undef(float %ignore0, float %ignore1,
; CHECK-LABEL: insert_float_N_undef:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    st32 $a2, $m1, $m15, $m0
; CHECK-NEXT:    ld64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    ld64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
                                         float %x, i32 %y) {
  %1 = insertelement <4 x float> undef, float %x, i32 %y
  ret <4 x float> %1
}

define <4 x float> @insert_float_N_undef_nop0(float %x, i32 %y) {
; CHECK-LABEL: insert_float_N_undef_nop0:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    st32 $a0, $m1, $m15, $m0
; CHECK-NEXT:    ld64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    ld64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 %y
  ret <4 x float> %1
}

define <4 x float> @insert_float_N_undef_nop1(float %ignore, float %x, i32 %y) {
; CHECK-LABEL: insert_float_N_undef_nop1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    st32 $a1, $m1, $m15, $m0
; CHECK-NEXT:    ld64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    ld64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> undef, float %x, i32 %y
  ret <4 x float> %1
}

define <4 x float> @insert_float_0(<4 x float> %x, float %y) {
; CHECK-LABEL: insert_float_0:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0, $a4
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> %x, float %y, i32 0
  ret <4 x float> %1
}

define <4 x float> @insert_float_1(<4 x float> %x, float %y) {
; CHECK-LABEL: insert_float_1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a1, $a4
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> %x, float %y, i32 1
  ret <4 x float> %1
}

define <4 x float> @insert_float_N(<4 x float> %x, i32 %y, float %z) {
; CHECK-LABEL: insert_float_N:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    st64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    st64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    st32 $a4, $m1, $m15, $m0
; CHECK-NEXT:    ld64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    ld64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> %x, float %z, i32 %y
  ret <4 x float> %1
}

; This is UB. Any output is fine, provided not a crash.
define <4 x float> @insert_float_4(<4 x float> %x, float %y) {
; CHECK-LABEL: insert_float_4:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %1 = insertelement <4 x float> %x, float %y, i32 4
  ret <4 x float> %1
}

;===------------------------------------------------------------------------===;
; Extract element.
;===------------------------------------------------------------------------===;

define float @extract_float_0(float %ignore, <4 x float> %x) {
; CHECK-LABEL: extract_float_0:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0:1, $a2:3
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 0
  ret float %1
}

define float @extract_float_0_nop(<4 x float> %x) {
; CHECK-LABEL: extract_float_0_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 0
  ret float %1
}

define float @extract_float_1(<4 x float> %x)  {
; CHECK-LABEL: extract_float_1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0, $a1
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 1
  ret float %1
}

define float @extract_float_N(float %ignore, <4 x float> %x, i32 %idx) {
; CHECK-LABEL: extract_float_N:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    st64 $a4:5, $m11, $m15, 1
; CHECK-NEXT:    st64 $a2:3, $m11, $m15, 0
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    ld32 $a0, $m1, $m15, $m0
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 %idx
  ret float %1
}

define float @extract_float_N_nop(<4 x float> %x, i32 %idx) {
; CHECK-LABEL: extract_float_N_nop:
; CHECK:       # %bb.0:
; CHECK-NEXT:    add $m11, $m11, -16
; CHECK-NEXT:    .cfi_def_cfa_offset 16
; CHECK-NEXT:    and $m0, $m0, 3
; CHECK-NEXT:    st64 $a2:3, $m11, $m15, 1
; CHECK-NEXT:    st64 $a0:1, $m11, $m15, 0
; CHECK-NEXT:    add $m1, $m11, 0
; CHECK-NEXT:    ld32 $a0, $m1, $m15, $m0
; CHECK-NEXT:    add $m11, $m11, 16
; CHECK-NEXT:    .cfi_def_cfa_offset 0
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 %idx
  ret float %1
}

; This is UB. Any output is fine, provided not a crash.
define float @extract_float_2(<4 x float> %x)  {
; CHECK-LABEL: extract_float_2:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0:1, $a2:3
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 2
  ret float %1
}

define float @extract_float_3(<4 x float> %x)  {
; CHECK-LABEL: extract_float_3:
; CHECK:       # %bb.0:
; CHECK-NEXT:    mov $a0, $a3
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 3
  ret float %1
}

; This is UB. Any output is fine, provided not a crash.
define float @extract_float_4(<4 x float> %x)  {
; CHECK-LABEL: extract_float_4:
; CHECK:       # %bb.0:
; CHECK-NEXT:    br $m10
  %1 = extractelement <4 x float> %x, i32 4
  ret float %1
}

