Source file src/cmd/internal/obj/arm64/inst.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  	"cmd/internal/obj"
     9  	"fmt"
    10  	"iter"
    11  )
    12  
    13  // instEncoder represents an instruction encoder.
    14  type instEncoder struct {
    15  	goOp      obj.As    // Go opcode mnemonic
    16  	fixedBits uint32    // Known bits
    17  	args      []operand // Operands, in Go order
    18  }
    19  
    20  type varBits struct {
    21  	// The low and high bit index in the binary encoding, exclusive on hi
    22  	lo, hi  int
    23  	encoded bool // If true then its value is already encoded
    24  	bits    uint32
    25  }
    26  
    27  // component is the component of an binary encoding.
    28  // e.g. for operand <Zda>.<T>, <T>'s encoding function might be described as:
    29  //
    30  //	For the "Byte and halfword" variant: is the size specifier,
    31  //	sz	<T>
    32  //	0	B
    33  //	1	H
    34  //	bit range mappings:
    35  //	sz: [22:23)
    36  //
    37  // Then sz is the component of the binary encoding.
    38  type component uint16
    39  
    40  type elemEncoder struct {
    41  	fn func(uint32) (uint32, bool)
    42  	// comp is the component of the binary encoding.
    43  	comp component
    44  }
    45  
    46  // operand is the operand type of an instruction.
    47  type operand struct {
    48  	class AClass // Operand class, register, constant, memory operation etc.
    49  	// The elements that this operand includes, this only includes the encoding-related parts
    50  	// They are represented as a list of pointers to the encoding functions.
    51  	// The first returned value is the encoded binary, the second is the ok signal.
    52  	// The encoding functions return the ok signal for deduplication purposes:
    53  	// For example:
    54  	//	SDOT  <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>
    55  	//	SDOT  <Zda>.H, <Zn>.B, <Zm>.B
    56  	//	SDOT  <Zda>.S, <Zn>.H, <Zm>.H
    57  	//
    58  	// <T> and <Tb> are specified in the encoding text, that there is a constraint "T = 4*Tb".
    59  	// We don't know this fact by looking at the encoding format solely, without this information
    60  	// the first encoding domain entails the other 2. And at instruction matching phase we simply
    61  	// cannot deduplicate them. So we defer this deduplication to the encoding phase.
    62  	// We need the ok signal with [elemEncoder.comp] field to deduplicate them.
    63  	elemEncoders []elemEncoder
    64  }
    65  
    66  // opsInProg returns an iterator over the operands ([Addr]) of p
    67  func opsInProg(p *obj.Prog) iter.Seq[*obj.Addr] {
    68  	return func(yield func(*obj.Addr) bool) {
    69  		// Go order: From, Reg, RestArgs..., To
    70  		// For SVE, Reg is unused as it's so common that registers have arrangements.
    71  		if p.From.Type != obj.TYPE_NONE {
    72  			if !yield(&p.From) {
    73  				return
    74  			}
    75  		}
    76  		for j := range p.RestArgs {
    77  			if !yield(&p.RestArgs[j].Addr) {
    78  				return
    79  			}
    80  		}
    81  		if p.To.Type != obj.TYPE_NONE {
    82  			if !yield(&p.To) {
    83  				return
    84  			}
    85  		}
    86  	}
    87  }
    88  
    89  // aclass returns the AClass of an Addr.
    90  func aclass(a *obj.Addr) AClass {
    91  	if a.Type == obj.TYPE_REG {
    92  		if a.Reg >= REG_Z0 && a.Reg <= REG_Z31 {
    93  			return AC_ZREG
    94  		}
    95  		if a.Reg >= REG_P0 && a.Reg <= REG_P15 {
    96  			return AC_PREG
    97  		}
    98  		if a.Reg >= REG_ARNG && a.Reg < REG_ELEM {
    99  			return AC_ARNG
   100  		}
   101  		if a.Reg >= REG_ZARNG && a.Reg < REG_PARNGZM {
   102  			return AC_ARNG
   103  		}
   104  		if a.Reg >= REG_PARNGZM && a.Reg < REG_PARNGZM_END {
   105  			switch (a.Reg >> 5) & 15 {
   106  			case PRED_M, PRED_Z:
   107  				return AC_PREGZM
   108  			default:
   109  				return AC_ARNG
   110  			}
   111  		}
   112  	}
   113  	panic("unknown AClass")
   114  }
   115  
   116  // addrComponent returns the binary (component) of the stored element in a at index, for operand
   117  // of type aclass.
   118  //
   119  // For example, for operand of type AC_ARNG, it has 2 permissible components (identified by index)
   120  //  0. register: <reg>
   121  //  1. arrangement: <T>
   122  //
   123  // They are stored in a.Reg as:
   124  //
   125  //	reg | (arrangement << 5)
   126  //
   127  // More details are in the comments in the switch cases of this function.
   128  func addrComponent(a *obj.Addr, acl AClass, index int) uint32 {
   129  	switch acl {
   130  	//	AClass: AC_ARNG, AC_PREG, AC_PREGZ, AC_PREGM, AC_ZREG
   131  	//	GNU mnemonic: <reg>.<T> Or <reg>/<T> (T is M or Z)
   132  	//	Go mnemonic:
   133  	//		reg.<T>
   134  	//	Encoding:
   135  	//		Type = TYPE_REG
   136  	// 		Reg = reg | (arrangement or predication << 5)
   137  	case AC_ARNG, AC_PREG, AC_PREGZM, AC_ZREG:
   138  		switch index {
   139  		case 0:
   140  			return uint32(a.Reg & 31)
   141  		case 1:
   142  			return uint32((a.Reg >> 5) & 15)
   143  		default:
   144  			panic(fmt.Errorf("unknown elm index at %d in AClass %d", index, acl))
   145  		}
   146  	}
   147  	// TODO: handle more AClasses.
   148  	panic(fmt.Errorf("unknown AClass %d", acl))
   149  }
   150  
   151  // tryEncode tries to encode p with i, it returns the encoded binary and ok signal.
   152  func (i *instEncoder) tryEncode(p *obj.Prog) (uint32, bool) {
   153  	bin := i.fixedBits
   154  	// Some elements are encoded in the same component, they need to be equal.
   155  	// For example { <Zn1>.<Tb>-<Zn2>.<Tb> }.
   156  	// The 2 instances of <Tb> must encode to the same value.
   157  	encoded := map[component]uint32{}
   158  	opIdx := 0
   159  	for addr := range opsInProg(p) {
   160  		if opIdx >= len(i.args) {
   161  			return 0, false
   162  		}
   163  		op := i.args[opIdx]
   164  		opIdx++
   165  		acl := aclass(addr)
   166  		if acl != op.class {
   167  			return 0, false
   168  		}
   169  		for i, enc := range op.elemEncoders {
   170  			val := addrComponent(addr, acl, i)
   171  			if b, ok := enc.fn(val); ok {
   172  				bin |= b
   173  				if _, ok := encoded[enc.comp]; ok && b != encoded[enc.comp] {
   174  					return 0, false
   175  				}
   176  				if enc.comp != enc_NIL {
   177  					encoded[enc.comp] = b
   178  				}
   179  			} else {
   180  				return 0, false
   181  			}
   182  		}
   183  	}
   184  	if opIdx != len(i.args) {
   185  		return 0, false
   186  	}
   187  	return bin, true
   188  }
   189  

View as plain text