Source file src/simd/archsimd/_gen/simdgen/arm64/operands_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 arm64
     6  
     7  import (
     8  	"testing"
     9  )
    10  
    11  // TestOperandParsing tests operand parsing phases: tokenizeTemplate, classifyTokens, and buildOperandList.
    12  func TestOperandParsing(t *testing.T) {
    13  	tests := []struct {
    14  		name         string // test case name
    15  		template     string // assembly template string to parse
    16  		resultInArg0 bool   // whether destination register is also an input
    17  
    18  		// Expected after tokenizeTemplate
    19  		wantTokenText []string // raw token strings from template
    20  
    21  		// Expected after classifyTokens
    22  		wantTypes  []OperandType // operand type per token
    23  		wantIsDest []bool        // is-destination flag per token
    24  
    25  		// Expected after buildOperandList
    26  		wantCount    int      // number of final operands
    27  		wantClasses  []string // operand class (vreg, greg, immediate)
    28  		wantRoles    []string // operand role
    29  		wantListNums []int    // ListNumber (-1 for non-list)
    30  	}{
    31  		{
    32  			name:          "ADD simple binary - from add_advsimd.xml",
    33  			template:      "ADD  <Vd>.<T>, <Vn>.<T>, <Vm>.<T>",
    34  			resultInArg0:  false,
    35  			wantTokenText: []string{"<Vd>.<T>", "<Vn>.<T>", "<Vm>.<T>"},
    36  			wantTypes:     []OperandType{OperandVReg, OperandVReg, OperandVReg},
    37  			wantIsDest:    []bool{true, false, false},
    38  			wantCount:     3,
    39  			wantClasses:   []string{"vreg", "vreg", "vreg"},
    40  			wantRoles:     []string{"destination", "op0", "op1"},
    41  			wantListNums:  []int{-1, -1, -1},
    42  		},
    43  		{
    44  			name:          "TBL with list operand - from tbl_advsimd.xml",
    45  			template:      "TBL  <Vd>.8B, { <Vn>.16B, <Vn+1>.16B }, <Vm>.8B",
    46  			resultInArg0:  false,
    47  			wantTokenText: []string{"<Vd>.8B", "{ <Vn>.16B, <Vn+1>.16B }", "<Vm>.8B"},
    48  			wantTypes:     []OperandType{OperandVReg, OperandList, OperandVReg},
    49  			wantIsDest:    []bool{true, false, false},
    50  			wantCount:     3,
    51  			wantClasses:   []string{"vreg", "vreg", "vreg"},
    52  			wantRoles:     []string{"destination", "op0", "op1"},
    53  			wantListNums:  []int{-1, 0, -1},
    54  		},
    55  		{
    56  			name:          "MOVI with optional LSL modifier - from movi_advsimd.xml",
    57  			template:      "MOVI  <Vd>.4S, #<imm8>{, LSL #<amount>}",
    58  			resultInArg0:  false,
    59  			wantTokenText: []string{"<Vd>.4S", "#<imm8>{, LSL #<amount>}"},
    60  			wantTypes:     []OperandType{OperandVReg, OperandImm},
    61  			wantIsDest:    []bool{true, false},
    62  			wantCount:     2,
    63  			wantClasses:   []string{"vreg", "immediate"},
    64  			wantRoles:     []string{"destination", "imm8"},
    65  			wantListNums:  []int{-1, -1},
    66  		},
    67  		{
    68  			name:          "BIC with optional LSL modifier - from bic_advsimd_imm.xml",
    69  			template:      "BIC  <Vd>.2S, #<imm8>{, LSL #<amount>}",
    70  			resultInArg0:  false,
    71  			wantTokenText: []string{"<Vd>.2S", "#<imm8>{, LSL #<amount>}"},
    72  			wantTypes:     []OperandType{OperandVReg, OperandImm},
    73  			wantIsDest:    []bool{true, false},
    74  			wantCount:     2,
    75  			wantClasses:   []string{"vreg", "immediate"},
    76  			wantRoles:     []string{"destination", "imm8"},
    77  			wantListNums:  []int{-1, -1},
    78  		},
    79  		{
    80  			name:          "INS element to element - from ins_advsimd_elt.xml",
    81  			template:      "INS  <Vd>.4S[<index1>], <Vn>.4S[<index2>]",
    82  			resultInArg0:  true,
    83  			wantTokenText: []string{"<Vd>.4S[<index1>]", "<Vn>.4S[<index2>]"},
    84  			wantTypes:     []OperandType{OperandVElem, OperandVElem},
    85  			wantIsDest:    []bool{true, false},
    86  			wantCount:     5,
    87  			wantClasses:   []string{"vreg", "immediate", "immediate", "vreg", "vreg"},
    88  			wantRoles:     []string{"destination", "destination_i", "op0_i", "original", "op0"},
    89  			wantListNums:  []int{-1, -1, -1, -1, -1},
    90  		},
    91  		{
    92  			name:          "INS general register to element - from ins_advsimd_gen.xml",
    93  			template:      "INS  <Vd>.4S[<index1>], <Wn>",
    94  			resultInArg0:  false, // VElem dest automatically sets resultInArg0
    95  			wantTokenText: []string{"<Vd>.4S[<index1>]", "<Wn>"},
    96  			wantTypes:     []OperandType{OperandVElem, OperandGReg},
    97  			wantIsDest:    []bool{true, false},
    98  			wantCount:     4,
    99  			wantClasses:   []string{"vreg", "immediate", "vreg", "greg"},
   100  			wantRoles:     []string{"destination", "destination_i", "original", "op0"},
   101  			wantListNums:  []int{-1, -1, -1, -1},
   102  		},
   103  		{
   104  			name:          "UMOV to general register - from umov_advsimd.xml",
   105  			template:      "UMOV  <Wd>, <Vn>.4S[<index>]",
   106  			resultInArg0:  false,
   107  			wantTokenText: []string{"<Wd>", "<Vn>.4S[<index>]"},
   108  			wantTypes:     []OperandType{OperandGReg, OperandVElem},
   109  			wantIsDest:    []bool{true, false},
   110  			wantCount:     3,
   111  			wantClasses:   []string{"greg", "immediate", "vreg"},
   112  			wantRoles:     []string{"destination", "op0_i", "op0"},
   113  			wantListNums:  []int{-1, -1, -1},
   114  		},
   115  		{
   116  			name:          "SHL immediate - from shl_advsimd.xml",
   117  			template:      "SHL  <Vd>.<T>, <Vn>.<T>, #<shift>",
   118  			resultInArg0:  false,
   119  			wantTokenText: []string{"<Vd>.<T>", "<Vn>.<T>", "#<shift>"},
   120  			wantTypes:     []OperandType{OperandVReg, OperandVReg, OperandImm},
   121  			wantIsDest:    []bool{true, false, false},
   122  			wantCount:     3,
   123  			wantClasses:   []string{"vreg", "immediate", "vreg"},
   124  			wantRoles:     []string{"destination", "shift", "op0"},
   125  			wantListNums:  []int{-1, -1, -1},
   126  		},
   127  		{
   128  			name:          "TBX with list (with resultInArg0) - from tbx_advsimd.xml",
   129  			template:      "TBX  <Vd>.8B, { <Vn>.16B, <Vn+1>.16B }, <Vm>.8B",
   130  			resultInArg0:  true,
   131  			wantTokenText: []string{"<Vd>.8B", "{ <Vn>.16B, <Vn+1>.16B }", "<Vm>.8B"},
   132  			wantTypes:     []OperandType{OperandVReg, OperandList, OperandVReg},
   133  			wantIsDest:    []bool{true, false, false},
   134  			wantCount:     4,
   135  			wantClasses:   []string{"vreg", "vreg", "vreg", "vreg"},
   136  			wantRoles:     []string{"destination", "original", "op0", "op1"},
   137  			wantListNums:  []int{-1, -1, 0, -1}, // List operand is at position 2 (after "original" is inserted)
   138  		},
   139  	}
   140  
   141  	for _, tt := range tests {
   142  		t.Run(tt.name, func(t *testing.T) {
   143  			// Split template string into individual operand tokens.
   144  			tokens := tokenizeTemplate(tt.template)
   145  
   146  			if !requireEqual(t, len(tt.wantTokenText), len(tokens)) {
   147  				return
   148  			}
   149  
   150  			for i := range tokens {
   151  				requireEqual(t, tt.wantTokenText[i], tokens[i].text)
   152  				requireEqual(t, i, tokens[i].asmPos)
   153  			}
   154  
   155  			// Determine type and direction of each token.
   156  			parsed := classifyTokens(tokens)
   157  
   158  			if !requireEqual(t, len(tt.wantTypes), len(parsed)) {
   159  				return
   160  			}
   161  
   162  			for i := range parsed {
   163  				requireEqual(t, tt.wantTypes[i], parsed[i].operandType)
   164  				requireEqual(t, tt.wantIsDest[i], parsed[i].isDestination)
   165  			}
   166  
   167  			// Build final operand list, inserting "original" if result is in arg0.
   168  			operands := buildOperandList(parsed, tt.resultInArg0)
   169  
   170  			if !requireEqual(t, tt.wantCount, len(operands)) {
   171  				return
   172  			}
   173  
   174  			for i := range operands {
   175  				requireEqual(t, tt.wantClasses[i], operands[i].Class)
   176  				requireEqual(t, tt.wantRoles[i], operands[i].Role)
   177  				requireEqual(t, tt.wantListNums[i], operands[i].ListNumber)
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  // TestOperandInstantiateBits tests that Instantiate sets Bits correctly for INS greg operands.
   184  func TestOperandInstantiateBits(t *testing.T) {
   185  	tests := []struct {
   186  		name        string
   187  		mnemonic    string
   188  		arrangement Arrangement
   189  		wantBits    int
   190  	}{
   191  		{
   192  			name:     "INS 16B element - 8-bit greg",
   193  			mnemonic: "INS",
   194  			arrangement: Arrangement{
   195  				arrangement: "16B",
   196  				bits:        128,
   197  				elemBits:    8,
   198  				lanes:       16,
   199  				baseType:    "uint",
   200  			},
   201  			wantBits: 8,
   202  		},
   203  		{
   204  			name:     "INS 8H element - 16-bit greg",
   205  			mnemonic: "INS",
   206  			arrangement: Arrangement{
   207  				arrangement: "8H",
   208  				bits:        128,
   209  				elemBits:    16,
   210  				lanes:       8,
   211  				baseType:    "uint",
   212  			},
   213  			wantBits: 16,
   214  		},
   215  		{
   216  			name:     "INS 4S element - 32-bit greg",
   217  			mnemonic: "INS",
   218  			arrangement: Arrangement{
   219  				arrangement: "4S",
   220  				bits:        128,
   221  				elemBits:    32,
   222  				lanes:       4,
   223  				baseType:    "uint",
   224  			},
   225  			wantBits: 32,
   226  		},
   227  		{
   228  			name:     "INS 2D element - 64-bit greg",
   229  			mnemonic: "INS",
   230  			arrangement: Arrangement{
   231  				arrangement: "2D",
   232  				bits:        128,
   233  				elemBits:    64,
   234  				lanes:       2,
   235  				baseType:    "uint",
   236  			},
   237  			wantBits: 64,
   238  		},
   239  	}
   240  
   241  	for _, tt := range tests {
   242  		t.Run(tt.name, func(t *testing.T) {
   243  			op := &Operand{
   244  				Type:       OperandGReg,
   245  				Class:      "greg",
   246  				Role:       "op0",
   247  				ListNumber: -1,
   248  			}
   249  			op.instantiate(tt.arrangement, DefaultArngs, 1, tt.mnemonic)
   250  			requireEqual(t, tt.wantBits, op.Bits)
   251  		})
   252  	}
   253  }
   254  

View as plain text