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  

View as plain text