| // 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. |
| |
| package xmlspec |
| |
| import ( |
| "flag" |
| "regexp" |
| "strings" |
| "testing" |
| ) |
| |
| var remoteData = flag.Bool("remote", false, "use remote data") |
| |
| func getData(t *testing.T) []*InstructionParsed { |
| if *remoteData { |
| xmlDir, err := GetArm64XMLSpec(t.TempDir(), ExpectedURL, ExpectedVersion) |
| if err != nil { |
| t.Fatalf("GetArm64XMLSpec failed: %v", err) |
| } |
| return ParseXMLFiles(xmlDir) |
| } |
| return ParseXMLFiles("testdata") |
| } |
| |
| func TestParseXMLFiles(t *testing.T) { |
| insts := getData(t) |
| // Merely check the parser runs. |
| t.Logf("Number of instructions: %d\n", len(insts)) |
| } |
| |
| func TestProcessXMLFiles(t *testing.T) { |
| insts := getData(t) |
| ProcessXMLFiles(insts) |
| specialInsts := map[string]bool{ |
| "HISTSEG -- A64": true, |
| "REVB, REVH, REVW -- A64": true, |
| "SXTB, SXTH, SXTW -- A64": true, |
| "URECPE -- A64": true, |
| "URSQRTE -- A64": true, |
| "UXTB, UXTH, UXTW -- A64": true, |
| } |
| outer: |
| for _, inst := range insts { |
| if inst == nil { |
| continue |
| } |
| if specialInsts[inst.Title] { |
| // These instructions's size is not encoded in the assembler symbols, |
| // but specified in the mnemonic and decoding ASL. |
| // The parser should have special logic to handle them, skip them for now here. |
| continue |
| } |
| isAlias := false |
| for _, doc := range inst.DocVars { |
| if doc.Key == "alias_mnemonic" { |
| isAlias = true |
| break |
| } |
| } |
| if isAlias { |
| // Alias instructions are not fully specified in their own XML files, |
| // skip them. |
| continue |
| } |
| // Check RegDiagram and Encodings all parsed |
| for _, iclass := range inst.Classes.Iclass { |
| if !iclass.RegDiagram.Parsed { |
| continue |
| } |
| for _, encoding := range iclass.Encodings { |
| if !encoding.Parsed { |
| continue outer |
| } |
| } |
| // Check for all encodings, every named box should be encoded |
| // by some encoding elements |
| encodedBoxes := make(map[string]bool) |
| for _, encoding := range iclass.Encodings { |
| if encoding.Alias { |
| // Alias encodings are not fully specified in their own section, |
| // skip them. |
| continue |
| } |
| for _, operand := range encoding.Operands { |
| for _, elem := range operand.Elems { |
| encodedIn := elem.encodedIn |
| encodedBoxes[encodedIn] = true |
| if strings.Contains(encodedIn, ":") { |
| // Some weird instructions like smlalb_z_zzzi |
| // encodes an immediate in 2 or 3 disjoin fields |
| // appended together. We need to record all of them. |
| // They are represented as "(name1 :: name2)" or |
| // "(name1 :: name2 :: name3)". |
| // We need to extract these names. |
| re := regexp.MustCompile(`\((.*?) :: (.*?)( :: (.*?))?\)`) |
| matches := re.FindStringSubmatch(encodedIn) |
| if len(matches) == 3 { |
| encodedBoxes[matches[1]] = true |
| encodedBoxes[matches[2]] = true |
| } else if len(matches) == 5 { |
| encodedBoxes[matches[1]] = true |
| encodedBoxes[matches[2]] = true |
| encodedBoxes[matches[4]] = true |
| } |
| } |
| if strings.Contains(encodedIn, "[") { |
| // Some weird instructions like histcnt_z_p_zz |
| // encodes only part of a field: |
| // size[0] (meanwhile size is of size 2). |
| // We need to record the full field name. |
| re := regexp.MustCompile(`(.*)\[.*?\]`) |
| matches := re.FindStringSubmatch(encodedIn) |
| if len(matches) == 2 { |
| encodedBoxes[matches[1]] = true |
| } |
| } |
| } |
| } |
| } |
| for name := range iclass.RegDiagram.varBin { |
| if !encodedBoxes[name] { |
| t.Errorf("Box %s not encoded in %s", name, inst.file) |
| } |
| } |
| } |
| } |
| } |