Source file test/simd_critical.go
1 // errorcheck -0 -d=ssa/critical/debug=1 2 3 //go:build goexperiment.simd && amd64 4 5 // Copyright 2026 The Go Authors. All rights reserved. 6 // Use of this source code is governed by a BSD-style 7 // license that can be found in the LICENSE file. 8 9 // Test that blocks created by the critical pass to split critical 10 // edges inherit the CPU features of the edge they sit on, so that 11 // later consumers (e.g. regalloc-inserted shuffle copies) can use 12 // feature-dependent instruction encodings there. There are three 13 // paths through the pass, each exercised below: 14 // 15 // 1. a fresh split block for an edge into a block with a single phi 16 // 2. a fresh split block for an edge into a block with several phis 17 // (or none) 18 // 3. a split block reused for several predecessor edges carrying the 19 // same phi argument, which keeps only the features all of its 20 // predecessors guarantee 21 22 package foo 23 24 import "simd/archsimd" 25 26 var cond bool 27 28 // Case 1: the merge block has a single phi (x), so the split block for 29 // the critical edge is created on the single-phi path. It inherits 30 // avx from its predecessor and successor. 31 func singlePhi(a, b archsimd.Int64x4) archsimd.Int64x4 { 32 x := a.Add(b) 33 if cond { // ERROR "split critical edge" "split-edge block b[0-9]+ has features avx$" 34 x = x.Add(a) 35 } 36 return x 37 } 38 39 // Case 2: the merge block has two phis (x and y), so the split block 40 // for the critical edge is created on the no-single-phi path. 41 func multiPhi(a, b archsimd.Int64x4) (archsimd.Int64x4, archsimd.Int64x4) { 42 x := a.Add(b) 43 y := b.Sub(a) 44 if cond { // ERROR "split critical edge" "split-edge block b[0-9]+ has features avx$" 45 x = x.Add(a) 46 y = y.Sub(b) 47 } 48 return x, y 49 } 50 51 // Case 3: the short-circuit && evaluates each operand in its own 52 // block, and both false edges jump to the single-phi merge block with 53 // the same phi argument (the zero value of x). The split block is 54 // created for the edge from the second operand's block, whose features 55 // are avx+avx2+avx512 (it is dominated by the first operand's block 56 // and holds the 512-bit ops); when it is reused for the edge from the 57 // first operand's block, which only guarantees avx, its features must 58 // drop to the common subset rather than keep avx512. 59 func reuseIntersect(s []int64, s8 []int64) { 60 var x archsimd.Int64x4 61 if archsimd.LoadInt64x4(s).IsZero() && // ERROR "split critical edge" "reused split-edge block b[0-9]+ has features avx$" "split-edge block b[0-9]+ has features avx$" 62 archsimd.LoadInt64x8(s8).Equal(archsimd.LoadInt64x8(s8)).ToBits() != 0 { // ERROR "split critical edge" "split-edge block b[0-9]+ has features avx[+]avx2[+]avx512$" 63 x = archsimd.LoadInt64x4(s) 64 } 65 x.Store(s) 66 } 67