Source file src/simd/archsimd/_gen/simdgen/arm64/emit.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  	"fmt"
     9  	"strings"
    10  
    11  	"_gen/unify"
    12  )
    13  
    14  // asComment formats text as a comment
    15  func asComment(text string, width int) string {
    16  	text = strings.TrimSpace(text)
    17  	text = strings.ReplaceAll(text, "&", "&")
    18  	text = strings.ReplaceAll(text, "\n", " ")
    19  	words := strings.Fields(text)
    20  	var lines []string
    21  	line := ""
    22  	for _, w := range words {
    23  		if line != "" {
    24  			line = line + " "
    25  		}
    26  		line = line + w
    27  		if len(line) >= width {
    28  			lines = append(lines, "// "+line)
    29  			line = ""
    30  		}
    31  	}
    32  	if len(line) > 0 {
    33  		lines = append(lines, "// "+line)
    34  	}
    35  	return strings.Join(lines, "\n")
    36  }
    37  
    38  // Emit generates the unify.Value representation of this operand
    39  func (op *Operand) Emit() *unify.Value {
    40  	var opDb unify.DefBuilder
    41  	opDb.Add("class", unify.NewValue(unify.NewStringExact(op.Class)))
    42  
    43  	if op.BaseType != "" {
    44  		opDb.Add("base", unify.NewValue(unify.NewStringExact(op.BaseType)))
    45  	}
    46  
    47  	if op.Bits > 0 {
    48  		opDb.Add("bits", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.Bits))))
    49  	}
    50  
    51  	if op.ElemBits > 0 {
    52  		opDb.Add("elemBits", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.ElemBits))))
    53  	}
    54  
    55  	if op.Lanes > 0 {
    56  		opDb.Add("lanes", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.Lanes))))
    57  	}
    58  
    59  	if op.Type == OperandImm {
    60  		opDb.Add("bits", unify.NewValue(unify.NewStringExact("8")))
    61  		if op.ImmMax == 0 {
    62  			opDb.Add("const", unify.NewValue(unify.NewStringExact("0")))
    63  		} else {
    64  			opDb.Add("immOffset", unify.NewValue(unify.NewStringExact("0")))
    65  		}
    66  		if op.ImmMax > 0 {
    67  			opDb.Add("immMax", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.ImmMax))))
    68  		}
    69  	}
    70  
    71  	if op.Role != "" {
    72  		opDb.Add("role", unify.NewValue(unify.NewStringExact(op.Role)))
    73  	}
    74  
    75  	if op.ListNumber >= 0 {
    76  		opDb.Add("listNumber", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.ListNumber))))
    77  	}
    78  
    79  	opDb.Add("asmPos", unify.NewValue(unify.NewStringExact(fmt.Sprint(op.AsmPos))))
    80  
    81  	return unify.NewValue(opDb.Build())
    82  }
    83  
    84  // Emit generates a single instruction Definition for the given arrangement.
    85  func (template *template) Emit(arrangement string) *unify.Value {
    86  	var db unify.DefBuilder
    87  
    88  	// Map mnemonic to Go assembly
    89  	mnemonic := template.instruction.Mnemonic()
    90  	switch mnemonic {
    91  	case "INS", "UMOV":
    92  		arrangement = arrangement[len(arrangement)-1:]
    93  		mnemonic = "VMOV"
    94  	case "DUP":
    95  		arrangement = arrangement[len(arrangement)-1:]
    96  		mnemonic = "V" + mnemonic
    97  	default:
    98  		// AES and SHA instructions do not use "V" prefix (assembler compatibility)
    99  		// Match SHA followed by digit (SHA1, SHA256, SHA512) but not SHADD
   100  		isAESOrSHA := strings.HasPrefix(mnemonic, "AES") ||
   101  			(len(mnemonic) > 3 && mnemonic[:3] == "SHA" && mnemonic[3] >= '0' && mnemonic[3] <= '9')
   102  		if !isAESOrSHA {
   103  			mnemonic = "V" + mnemonic
   104  		}
   105  	}
   106  
   107  	db.Add("asm", unify.NewValue(unify.NewStringExact(mnemonic)))
   108  	db.Add("arrangement", unify.NewValue(unify.NewStringExact(arrangement)))
   109  	db.Add("goarch", unify.NewValue(unify.NewStringExact("arm64")))
   110  	db.Add("cpuFeature", unify.NewValue(unify.NewStringExact("NEON"))) // TODO: features
   111  	db.Add("inVariant", unify.NewValue(unify.NewTuple()))
   112  
   113  	if doc := template.instruction.Documentation(); doc != "" {
   114  		db.Add("details", unify.NewValue(unify.NewStringExact(asComment(doc, 80))))
   115  	}
   116  
   117  	var inVals, outVals []*unify.Value
   118  	for _, op := range template.operands {
   119  		if op.Role == "destination" {
   120  			outVals = append(outVals, op.Emit())
   121  		} else {
   122  			inVals = append(inVals, op.Emit())
   123  		}
   124  	}
   125  
   126  	db.Add("in", unify.NewValue(unify.NewTuple(inVals...)))
   127  	db.Add("out", unify.NewValue(unify.NewTuple(outVals...)))
   128  
   129  	return unify.NewValue(db.Build())
   130  }
   131  
   132  // EmitAll generates instruction definitions for all arrangements of this instruction.
   133  // Returns nil for instructions with UnsupportedArngs.
   134  func (instruction *Instruction) EmitAll() []*unify.Value {
   135  	var defs []*unify.Value
   136  
   137  	mnemonic := instruction.Mnemonic()
   138  	templates := instruction.templates()
   139  	arrangements, ashape := instruction.Arrangements()
   140  	if ashape == UnsupportedArngs {
   141  		return nil
   142  	}
   143  	for _, template := range templates {
   144  		for _, arr := range arrangements {
   145  			// Clone template so each arrangement gets its own operand slice.
   146  			updatedTemplate := template
   147  			updatedTemplate.operands = make([]Operand, len(template.operands))
   148  			copy(updatedTemplate.operands, template.operands)
   149  
   150  			// Instantiate operands for this arrangement.
   151  			// Most instructions (DefaultArngs) stamp the same arrangement into all vreg operands.
   152  			// Special shapes (NarrowArngs, LongArngs, WideArngs) adjust only certain operands
   153  			// (e.g. only the result, or only the second input) to half or double width.
   154  			vregPos := 0
   155  			for i := range updatedTemplate.operands {
   156  				updatedTemplate.operands[i].instantiate(arr, ashape, vregPos, mnemonic)
   157  				if updatedTemplate.operands[i].Type == OperandVReg {
   158  					vregPos++
   159  				}
   160  			}
   161  			defs = append(defs, updatedTemplate.Emit(arr.arrangement))
   162  		}
   163  	}
   164  
   165  	return defs
   166  }
   167  

View as plain text