Source file src/simd/archsimd/_gen/specgen/loadspec_test.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package specgen
     6  
     7  import (
     8  	"strings"
     9  	"sync"
    10  	"testing"
    11  )
    12  
    13  var (
    14  	specPkg      *specPackage
    15  	specLoadErr  error
    16  	loadSpecOnce sync.Once
    17  )
    18  
    19  func loadSpec(t *testing.T) *specPackage {
    20  	loadSpecOnce.Do(func() {
    21  		var root contextRoot
    22  		ctx := context{root: &root}
    23  
    24  		specPkg = loadSpecPackage(ctx, "../../../internal/spec", &LoadOptions{})
    25  		if err := root.gatherErrors(); err != nil {
    26  			specLoadErr = err
    27  		}
    28  	})
    29  	if specLoadErr != nil {
    30  		t.Fatalf("failed to load spec: %v", specLoadErr)
    31  	}
    32  	return specPkg
    33  }
    34  
    35  func TestLoadSpec(t *testing.T) {
    36  	pkg := loadSpec(t)
    37  
    38  	// Verify we parsed functions
    39  	if len(pkg.Funcs) == 0 {
    40  		t.Errorf("expected parsed functions, got 0")
    41  	}
    42  
    43  	var foundAdd, foundExtend bool
    44  	for _, f := range pkg.Funcs {
    45  		if f.Name == "Add" {
    46  			foundAdd = true
    47  			if len(f.TypeParams) != 2 {
    48  				t.Errorf("Add should have 2 type parameters, got %d", len(f.TypeParams))
    49  			} else {
    50  				if f.TypeParams[0].Obj().Name() != "E" || !strings.Contains(f.TypeParams[0].Constraint().String(), "Nums") {
    51  					t.Errorf("unexpected Add type param 0: %s %s", f.TypeParams[0].Obj().Name(), f.TypeParams[0].Constraint())
    52  				}
    53  				if f.TypeParams[1].Obj().Name() != "W" || !strings.Contains(f.TypeParams[1].Constraint().String(), "Width") {
    54  					t.Errorf("unexpected Add type param 1: %s %s", f.TypeParams[1].Obj().Name(), f.TypeParams[1].Constraint())
    55  				}
    56  			}
    57  			if len(f.Params) != 2 {
    58  				t.Errorf("Add should have 2 params, got %d", len(f.Params))
    59  			} else {
    60  				if f.Params[0].Name() != "x" || !strings.Contains(f.Params[0].Type().String(), "Vec[") {
    61  					t.Errorf("unexpected Add param 0: %s %s", f.Params[0].Name(), f.Params[0].Type())
    62  				}
    63  				if f.Params[1].Name() != "y" || !strings.Contains(f.Params[1].Type().String(), "Vec[") {
    64  					t.Errorf("unexpected Add param 1: %s %s", f.Params[1].Name(), f.Params[1].Type())
    65  				}
    66  			}
    67  			if len(f.Results) != 1 {
    68  				t.Errorf("Add should have 1 result, got %d", len(f.Results))
    69  			} else {
    70  				if !strings.Contains(f.Results[0].Type().String(), "Vec[") {
    71  					t.Errorf("unexpected Add result type: %s", f.Results[0].Type())
    72  				}
    73  			}
    74  		}
    75  
    76  		if f.Name == "ExtendLoLToZ" {
    77  			foundExtend = true
    78  			if len(f.Requirements) != 2 {
    79  				t.Errorf("expected 2 requirements for ExtendLoLToZ, got %d", len(f.Requirements))
    80  			} else {
    81  				if f.Requirements[0] == nil || f.Requirements[1] == nil {
    82  					t.Errorf("expected non-nil parsed requirements")
    83  				}
    84  			}
    85  		}
    86  	}
    87  
    88  	if !foundAdd {
    89  		t.Errorf("failed to find function Add in parsed package")
    90  	}
    91  	if !foundExtend {
    92  		t.Errorf("failed to find function ExtendLoLToZ in parsed package")
    93  	}
    94  }
    95  
    96  func TestLoadSpecNameTmpl(t *testing.T) {
    97  	pkg := loadSpec(t)
    98  	var found bool
    99  	for _, f := range pkg.Funcs {
   100  		if f.Name == "MaskFromBits" {
   101  			found = true
   102  			want := "{z}FromBits"
   103  			if f.NameTmpl.tmpl != want {
   104  				t.Errorf("MaskFromBits: expected NameTmpl.tmpl %q, got %q", want, f.NameTmpl.tmpl)
   105  			}
   106  			break
   107  		}
   108  	}
   109  	if !found {
   110  		t.Errorf("failed to find function MaskFromBits in parsed package")
   111  	}
   112  }
   113  
   114  func TestNewSpecTemplate(t *testing.T) {
   115  	tests := []struct {
   116  		tmpl    string
   117  		want    specTemplate
   118  		wantErr bool
   119  	}{
   120  		{
   121  			tmpl: "",
   122  			want: specTemplate{tmpl: "", fields: nil},
   123  		},
   124  		{
   125  			tmpl: "Convert",
   126  			want: specTemplate{tmpl: "Convert", fields: nil},
   127  		},
   128  		{
   129  			tmpl: "Convert{zL}To{zB}{zN}",
   130  			want: specTemplate{
   131  				tmpl:   "Convert{zL}To{zB}{zN}",
   132  				fields: [][2]int{{7, 11}, {13, 17}, {17, 21}},
   133  			},
   134  		},
   135  		{
   136  			tmpl:    "Convert{zL",
   137  			wantErr: true,
   138  		},
   139  		{
   140  			tmpl:    "Convert}",
   141  			wantErr: true,
   142  		},
   143  		{
   144  			tmpl:    "Convert{a{b}}",
   145  			wantErr: true,
   146  		},
   147  	}
   148  
   149  	for _, tc := range tests {
   150  		got, err := newSpecTemplate(tc.tmpl)
   151  		if (err != nil) != tc.wantErr {
   152  			t.Errorf("newSpecTemplate(%q) returned error: %v, wantErr: %v", tc.tmpl, err, tc.wantErr)
   153  			continue
   154  		}
   155  		if tc.wantErr {
   156  			continue
   157  		}
   158  		if got.tmpl != tc.want.tmpl {
   159  			t.Errorf("newSpecTemplate(%q) tmpl = %q, want %q", tc.tmpl, got.tmpl, tc.want.tmpl)
   160  		}
   161  		if len(got.fields) != len(tc.want.fields) {
   162  			t.Errorf("newSpecTemplate(%q) fields len = %d, want %d", tc.tmpl, len(got.fields), len(tc.want.fields))
   163  		} else {
   164  			for i := range got.fields {
   165  				if got.fields[i] != tc.want.fields[i] {
   166  					t.Errorf("newSpecTemplate(%q) fields[%d] = %v, want %v", tc.tmpl, i, got.fields[i], tc.want.fields[i])
   167  				}
   168  			}
   169  		}
   170  	}
   171  }
   172  
   173  func TestSpecTemplateExpand(t *testing.T) {
   174  	tmpl, err := newSpecTemplate("Convert{zL}To{zB}{zN}")
   175  	if err != nil {
   176  		t.Fatalf("unexpected error parsing template: %v", err)
   177  	}
   178  
   179  	lookup := func(name string) string {
   180  		switch name {
   181  		case "zL":
   182  			return "4"
   183  		case "zB":
   184  			return "Float"
   185  		case "zN":
   186  			return "32"
   187  		}
   188  		return ""
   189  	}
   190  
   191  	got := tmpl.expand(lookup)
   192  	want := "Convert4ToFloat32"
   193  	if got != want {
   194  		t.Errorf("expected expanded string %q, got %q", want, got)
   195  	}
   196  }
   197  

View as plain text