// errorcheck -0 -d=ssa/cpufeatures/debug=1,ssa/rewrite_tern/debug=1

//go:build goexperiment.simd && amd64

// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package foo

import "simd/archsimd"

func f1(x archsimd.Int8x16) {
	return // ERROR "has features avx"
}

func g1() archsimd.Int8x16 {
	var x archsimd.Int8x16
	return x // ERROR "has features avx$"
}

type T1 archsimd.Int8x16

func (x T1) h() {
	return // ERROR "has features avx$"
}

func f2(x archsimd.Int8x64) {
	return // ERROR "has features avx[+]avx2[+]avx512$"
}

func g2() archsimd.Int8x64 {
	var x archsimd.Int8x64
	return x // ERROR "has features avx[+]avx2[+]avx512$"
}

type T2 archsimd.Int8x64

func (x T2) h() {
	return // ERROR "has features avx[+]avx2[+]avx512$"
}

var a int

func f() {
	if a == 0 {
		if !archsimd.X86.AVX512() {
			return
		}
		println("has avx512") // ERROR "has features avx[+]avx2[+]avx512$"
	} else {
		if !archsimd.X86.AVX2() {
			return
		}
		println("has avx2") // ERROR "has features avx[+]avx2$"
	}
	println("has something")
} // ERROR "has features avx[+]avx2$"

func g() {
	if archsimd.X86.AVX2() { // ERROR "has features avx[+]avx2$"
		for range 5 { // ERROR "has features avx[+]avx2$"
			if a < 0 { // ERROR "has features avx[+]avx2$"
				a++ // ERROR "has features avx[+]avx2$"
			}
		}
	}
	println("ahoy!") // ERROR "has features avx[+]avx2$" // this is an artifact of flaky block numbering and why isn't it fused?
	if a > 0 {
		a--
	}
}

//go:noinline
func p() bool {
	return true
}

func hasIrreducibleLoop() {
	if archsimd.X86.AVX2() {
		goto a // ERROR "has features avx[+]avx2$"
	} else {
		goto b
	}
a:
	println("a")
	if p() {
		goto c
	}
b:
	println("b")
	if p() {
		goto a
	}
c:
	println("c")
}

func ternRewrite(m, w, x, y, z archsimd.Int32x16) (t0, t1, t2 archsimd.Int32x16) {
	if !archsimd.X86.AVX512() { // ERROR "has features avx[+]avx2[+]avx512$"
		return // ERROR "has features avx[+]avx2[+]avx512$" // all blocks have it because of the vector size
	}
	t0 = w.Xor(y).Xor(z)                            // ERROR "Rewriting.*ternInt"
	t1 = m.And(w.Xor(y).Xor(z.Not()))               // ERROR "Rewriting.*ternInt"
	t2 = x.Xor(y).Xor(z).And(x.Xor(y).Xor(z.Not())) // ERROR "Rewriting.*ternInt"
	return                                          // ERROR "has features avx[+]avx2[+]avx512$"
}

func ternTricky1(x, y, z archsimd.Int32x8) archsimd.Int32x8 {
	// Int32x8 is a 256-bit vector and does not guarantee AVX-512
	// a is a 3-variable logical expression occurring outside AVX-512 feature check
	a := x.Xor(y).Xor(z)
	var w archsimd.Int32x8
	if !archsimd.X86.AVX512() { // ERROR "has features avx$"
		// do nothing
	} else {
		w = y.AndNot(a) // ERROR "has features avx[+]avx2[+]avx512" "Rewriting.*ternInt"
	}
	// a is a common subexpression
	return a.Or(w) // ERROR "has features avx$"
}

func ternTricky2(x, y, z archsimd.Int32x8) archsimd.Int32x8 {
	// Int32x8 is a 256-bit vector and does not guarantee AVX-512
	var a, w archsimd.Int32x8
	if !archsimd.X86.AVX512() { // ERROR "has features avx$"
		// do nothing
	} else {
		a = x.Xor(y).Xor(z)
		w = y.AndNot(a) // ERROR "has features avx[+]avx2[+]avx512" "Rewriting.*ternInt"
	}
	// a is a common subexpression
	return a.Or(w) // ERROR "has features avx$"
}

func ternTricky3(x, y, z archsimd.Int32x8) archsimd.Int32x8 {
	// Int32x8 is a 256-bit vector and does not guarantee AVX-512
	a := x.Xor(y).Xor(z)
	w := y.AndNot(a)
	if !archsimd.X86.AVX512() { // ERROR "has features avx$"
		return a // ERROR "has features avx$"
	}
	// a is a common subexpression
	return a.Or(w) // ERROR "has features avx[+]avx2[+]avx512"  // This does not rewrite, do we want it to?
}
