simd/archsimd: correct ARM64 IfElse semantics

ARM64's IfElse behavior is reversed from other platforms. Reverse
it. Internally, its bitSelect is also the reverse of Wasm's
BitSelect. Reverse the ARM64 one to match.

Make Masked and IfElse tests portable.

Change-Id: Icd2dbcb3383b2be642fd6fc7115ef1cbef0f9b78
Reviewed-on: https://go-review.googlesource.com/c/go/+/793361
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/src/cmd/compile/internal/arm64/simdssa.go b/src/cmd/compile/internal/arm64/simdssa.go
index dd89daf..41ae292 100644
--- a/src/cmd/compile/internal/arm64/simdssa.go
+++ b/src/cmd/compile/internal/arm64/simdssa.go
@@ -272,8 +272,8 @@
 		p = simdV21Imm(s, v, arm64.ARNG_16B)
 
 	case ssa.OpARM64VMLA16B,
-		ssa.OpARM64VBIT16B,
-		ssa.OpARM64VBIF16B:
+		ssa.OpARM64VBIF16B,
+		ssa.OpARM64VBIT16B:
 		p = simdV31ResultInArg0(s, v, arm64.ARNG_16B)
 
 	case ssa.OpARM64VFMLA2D:
diff --git a/src/cmd/compile/internal/ssa/_gen/simdARM64.rules b/src/cmd/compile/internal/ssa/_gen/simdARM64.rules
index fb85f66..131ab8e 100644
--- a/src/cmd/compile/internal/ssa/_gen/simdARM64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/simdARM64.rules
@@ -376,10 +376,10 @@
 (XorUint16x8 ...) => (VEOR16B ...) // pureVreg
 (XorUint32x4 ...) => (VEOR16B ...) // pureVreg
 (XorUint64x2 ...) => (VEOR16B ...) // pureVreg
-(bitSelectInt8x16 ...) => (VBIT16B ...) // pureVreg
-(VBIT16B x y (VNOT16B mask)) => (VBIF16B x y mask) // specialLower
-(bitSelectNotInt8x16 ...) => (VBIF16B ...) // pureVreg
+(bitSelectInt8x16 ...) => (VBIF16B ...) // pureVreg
 (VBIF16B x y (VNOT16B mask)) => (VBIT16B x y mask) // specialLower
+(bitSelectNotInt8x16 ...) => (VBIT16B ...) // pureVreg
+(VBIT16B x y (VNOT16B mask)) => (VBIF16B x y mask) // specialLower
 (broadcast1To2Float64x2 x) => (VDUPDbcast [0] x) // pureVreg
 (broadcast1To2Int64x2 x) => (VDUPDbcast [0] x) // pureVreg
 (broadcast1To2Uint64x2 x) => (VDUPDbcast [0] x) // pureVreg
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index d93a204..26d94b9 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -2276,10 +2276,10 @@
 	case OpZeroSIMD:
 		return rewriteValueARM64_OpZeroSIMD(v)
 	case OpbitSelectInt8x16:
-		v.Op = OpARM64VBIT16B
+		v.Op = OpARM64VBIF16B
 		return true
 	case OpbitSelectNotInt8x16:
-		v.Op = OpARM64VBIF16B
+		v.Op = OpARM64VBIT16B
 		return true
 	case Opbroadcast1To16Int8x16:
 		return rewriteValueARM64_Opbroadcast1To16Int8x16(v)
diff --git a/src/simd/archsimd/_gen/simdgen/ops/Moves/categories.yaml b/src/simd/archsimd/_gen/simdgen/ops/Moves/categories.yaml
index 68dc1ab..872628e 100644
--- a/src/simd/archsimd/_gen/simdgen/ops/Moves/categories.yaml
+++ b/src/simd/archsimd/_gen/simdgen/ops/Moves/categories.yaml
@@ -85,11 +85,11 @@
 - go: bitSelect
   commutative: false
   documentation: !string |-
-    // NAME selects bits from y where mask is 1, keeps bits from x where mask is 0.
+    // NAME returns the bitwise selection if mask[i] then x[i] else y[i].
 - go: bitSelectNot
   commutative: false
   documentation: !string |-
-    // NAME selects bits from y where mask is 0, keeps bits from x where mask is 1.
+    // NAME returns the bitwise selection if mask[i] then y[i] else x[i].
 - go: move
   commutative: false
   noTypes: "true"
diff --git a/src/simd/archsimd/_gen/simdgen/ops/Moves/go_arm64.yaml b/src/simd/archsimd/_gen/simdgen/ops/Moves/go_arm64.yaml
index e81879a..1f6ed73 100644
--- a/src/simd/archsimd/_gen/simdgen/ops/Moves/go_arm64.yaml
+++ b/src/simd/archsimd/_gen/simdgen/ops/Moves/go_arm64.yaml
@@ -122,12 +122,12 @@
   out:
   - *bcast64
 
-# bitSelect — VBIT (bit insert if true, internal)
-# Only Int8x16 is needed since VBIT operates on the full 128-bit register.
+# bitSelect — VBIF (bit insert if false, internal)
+# Only Int8x16 is needed since VBIF operates on the full 128-bit register.
 # Other types cast to Int8x16 before calling bitSelect.
 - go: bitSelect
-  asm: "VBIT"
-  specialLower: !string "match (%h x y (VNOT16B mask)) => (VBIF16B x y mask)"
+  asm: "VBIF"
+  specialLower: !string "match (%h x y (VNOT16B mask)) => (VBIT16B x y mask)"
   in:
   - &v8
     go: $t
@@ -142,10 +142,10 @@
   out:
   - *v8
 
-# bitSelectNot — VBIF (bit insert if false, internal)
+# bitSelectNot — VBIT (bit insert if true, internal)
 - go: bitSelectNot
-  asm: "VBIF"
-  specialLower: !string "match (%h x y (VNOT16B mask)) => (VBIT16B x y mask)"
+  asm: "VBIT"
+  specialLower: !string "match (%h x y (VNOT16B mask)) => (VBIF16B x y mask)"
   in:
   - *v8
   - *v8
diff --git a/src/simd/archsimd/internal/simd_test/arm64_compare_test.go b/src/simd/archsimd/internal/simd_test/arm64_compare_test.go
deleted file mode 100644
index ad1c55b..0000000
--- a/src/simd/archsimd/internal/simd_test/arm64_compare_test.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2026 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.
-
-//go:build goexperiment.simd && arm64
-
-package simd_test
-
-import (
-	"simd/archsimd"
-	"testing"
-)
-
-// --- Masked: zero elements where mask is false ---
-
-func TestMasked(t *testing.T) {
-	// Test Masked for Int8x16
-	forSlicePair(t, int8s, 16, func(x, y []int8) bool {
-		t.Helper()
-		a := archsimd.LoadInt8x16(x)
-		mask := archsimd.LoadInt8x16(y).Greater(archsimd.Int8x16{}) // mask: y > 0
-		g := make([]int8, 16)
-		a.Masked(mask).Store(g)
-		w := make([]int8, 16)
-		for i := range w {
-			if y[i] > 0 {
-				w[i] = x[i]
-			}
-		}
-		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v", x, y) })
-	})
-
-	// Test Masked for Float64x2
-	forSlicePair(t, float64s, 2, func(x, y []float64) bool {
-		t.Helper()
-		a := archsimd.LoadFloat64x2(x)
-		mask := archsimd.LoadFloat64x2(y).Greater(archsimd.Float64x2{}) // mask: y > 0
-		g := make([]float64, 2)
-		a.Masked(mask).Store(g)
-		w := make([]float64, 2)
-		for i := range w {
-			if y[i] > 0 {
-				w[i] = x[i]
-			}
-		}
-		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v", x, y) })
-	})
-}
-
-// --- IfElse: set elements to y where mask is true, keep x where true ---
-
-func TestIfElse(t *testing.T) {
-	// Test Merge for Int8x16
-	forSliceTriple(t, int8s, 16, func(x, y, m []int8) bool {
-		t.Helper()
-		a := archsimd.LoadInt8x16(x)
-		b := archsimd.LoadInt8x16(y)
-		mask := archsimd.LoadInt8x16(m).Greater(archsimd.Int8x16{}) // mask: m > 0
-		g := make([]int8, 16)
-		a.IfElse(mask, b).Store(g)
-		w := make([]int8, 16)
-		for i := range w {
-			if m[i] > 0 {
-				w[i] = y[i]
-			} else {
-				w[i] = x[i]
-			}
-		}
-		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v, m=%v", x, y, m) })
-	})
-
-	// Test Merge for Float32x4
-	forSliceTriple(t, float32s, 4, func(x, y, m []float32) bool {
-		t.Helper()
-		a := archsimd.LoadFloat32x4(x)
-		b := archsimd.LoadFloat32x4(y)
-		mask := archsimd.LoadFloat32x4(m).Greater(archsimd.Float32x4{}) // mask: m > 0
-		g := make([]float32, 4)
-		a.IfElse(mask, b).Store(g)
-		w := make([]float32, 4)
-		for i := range w {
-			if m[i] > 0 {
-				w[i] = y[i]
-			} else {
-				w[i] = x[i]
-			}
-		}
-		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v, m=%v", x, y, m) })
-	})
-}
diff --git a/src/simd/archsimd/internal/simd_test/compare_128_test.go b/src/simd/archsimd/internal/simd_test/compare_128_test.go
index 98ade49..2d1b05a 100644
--- a/src/simd/archsimd/internal/simd_test/compare_128_test.go
+++ b/src/simd/archsimd/internal/simd_test/compare_128_test.go
@@ -118,3 +118,77 @@
 // 			return x.IsNaN().Or(y.IsNaN())
 // 		}, want64)
 // }
+
+func TestMasked(t *testing.T) {
+	// Test Masked for Int8x16
+	forSlicePair(t, int8s, 16, func(x, y []int8) bool {
+		t.Helper()
+		a := archsimd.LoadInt8x16(x)
+		mask := archsimd.LoadInt8x16(y).Greater(archsimd.Int8x16{}) // mask: y > 0
+		g := make([]int8, 16)
+		a.Masked(mask).Store(g)
+		w := make([]int8, 16)
+		for i := range w {
+			if y[i] > 0 {
+				w[i] = x[i]
+			}
+		}
+		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v", x, y) })
+	})
+
+	// Test Masked for Float64x2
+	forSlicePair(t, float64s, 2, func(x, y []float64) bool {
+		t.Helper()
+		a := archsimd.LoadFloat64x2(x)
+		mask := archsimd.LoadFloat64x2(y).Greater(archsimd.Float64x2{}) // mask: y > 0
+		g := make([]float64, 2)
+		a.Masked(mask).Store(g)
+		w := make([]float64, 2)
+		for i := range w {
+			if y[i] > 0 {
+				w[i] = x[i]
+			}
+		}
+		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v", x, y) })
+	})
+}
+
+func TestIfElse(t *testing.T) {
+	// Test Merge for Int8x16
+	forSliceTriple(t, int8s, 16, func(x, y, m []int8) bool {
+		t.Helper()
+		a := archsimd.LoadInt8x16(x)
+		b := archsimd.LoadInt8x16(y)
+		mask := archsimd.LoadInt8x16(m).Greater(archsimd.Int8x16{}) // mask: m > 0
+		g := make([]int8, 16)
+		a.IfElse(mask, b).Store(g)
+		w := make([]int8, 16)
+		for i := range w {
+			if m[i] > 0 {
+				w[i] = x[i]
+			} else {
+				w[i] = y[i]
+			}
+		}
+		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v, m=%v", x, y, m) })
+	})
+
+	// Test Merge for Float32x4
+	forSliceTriple(t, float32s, 4, func(x, y, m []float32) bool {
+		t.Helper()
+		a := archsimd.LoadFloat32x4(x)
+		b := archsimd.LoadFloat32x4(y)
+		mask := archsimd.LoadFloat32x4(m).Greater(archsimd.Float32x4{}) // mask: m > 0
+		g := make([]float32, 4)
+		a.IfElse(mask, b).Store(g)
+		w := make([]float32, 4)
+		for i := range w {
+			if m[i] > 0 {
+				w[i] = x[i]
+			} else {
+				w[i] = y[i]
+			}
+		}
+		return checkSlicesLogInput(t, g, w, 0.0, func() { t.Helper(); t.Logf("x=%v, y=%v, m=%v", x, y, m) })
+	})
+}
diff --git a/src/simd/archsimd/ops_internal_arm64.go b/src/simd/archsimd/ops_internal_arm64.go
index 8a47bfe..49f92db 100644
--- a/src/simd/archsimd/ops_internal_arm64.go
+++ b/src/simd/archsimd/ops_internal_arm64.go
@@ -6,16 +6,16 @@
 
 /* bitSelect */
 
-// bitSelect selects bits from y where mask is 1, keeps bits from x where mask is 0.
+// bitSelect returns the bitwise selection if mask[i] then x[i] else y[i].
 //
-// Asm: VBIT, CPU Feature: NEON
+// Asm: VBIF, CPU Feature: NEON
 func (x Int8x16) bitSelect(y Int8x16, mask Int8x16) Int8x16
 
 /* bitSelectNot */
 
-// bitSelectNot selects bits from y where mask is 0, keeps bits from x where mask is 1.
+// bitSelectNot returns the bitwise selection if mask[i] then y[i] else x[i].
 //
-// Asm: VBIF, CPU Feature: NEON
+// Asm: VBIT, CPU Feature: NEON
 func (x Int8x16) bitSelectNot(y Int8x16, mask Int8x16) Int8x16
 
 /* broadcast1To2 */
diff --git a/test/codegen/simd_arm64.go b/test/codegen/simd_arm64.go
index 5be078b..209e1fe 100644
--- a/test/codegen/simd_arm64.go
+++ b/test/codegen/simd_arm64.go
@@ -110,14 +110,14 @@
 }
 
 func mergeWithNotMask(x, y archsimd.Int8x16, mask archsimd.Mask8x16, f1, f2 archsimd.Float32x4) {
-	// arm64:`VBIF` -`VBIT` -`VNOT`
+	// arm64:`VBIT` -`VBIF` -`VNOT`
 	sinkI8 = x.IfElse(mask.Not(), y)
 	// arm64: `VFCMEQ`
 	eq := f1.Equal(f2)
 	// The next line `ne` should be CSEd with `eq` above
 	ne := f1.NotEqual(f2)    // arm64: -`.*`
-	fne := f1.IfElse(eq, f2) // arm64:`VBIT`
-	feq := f1.IfElse(ne, f2) // arm64:`VBIF`
+	feq := f1.IfElse(eq, f2) // arm64:`VBIF`
+	fne := f1.IfElse(ne, f2) // arm64:`VBIT`
 	sinkF32 = fne.Add(feq)
 }