2021-11-12 18:35:36 -08:00
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"text/tabwriter"
|
|
|
|
|
|
2026-03-06 20:14:02 +00:00
|
|
|
"sources.truenas.cloud/code/avo/internal/inst"
|
2021-11-12 18:35:36 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Function represents a function that constructs some collection of
|
|
|
|
|
// instruction forms.
|
|
|
|
|
type Function struct {
|
|
|
|
|
Instruction inst.Instruction
|
|
|
|
|
Suffixes inst.Suffixes
|
|
|
|
|
inst.Forms
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Name returns the function name.
|
|
|
|
|
func (f *Function) Name() string {
|
|
|
|
|
return f.opcodesuffix("_")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Opcode returns the full Go opcode of the instruction built by this function. Includes any suffixes.
|
|
|
|
|
func (f *Function) Opcode() string {
|
|
|
|
|
return f.opcodesuffix(".")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Function) opcodesuffix(sep string) string {
|
|
|
|
|
n := f.Instruction.Opcode
|
|
|
|
|
for _, suffix := range f.Suffixes {
|
|
|
|
|
n += sep
|
|
|
|
|
n += suffix.String()
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HasSuffix reports whether the function has the provided suffix.
|
|
|
|
|
func (f *Function) HasSuffix(suffix inst.Suffix) bool {
|
|
|
|
|
for _, s := range f.Suffixes {
|
|
|
|
|
if s == suffix {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Summary returns a summary of the instruction this function constructs.
|
|
|
|
|
func (f *Function) Summary() string {
|
|
|
|
|
summary := f.Instruction.Summary
|
|
|
|
|
if len(f.Suffixes) > 0 {
|
|
|
|
|
summary += " (" + strings.Join(f.Suffixes.Summaries(), ", ") + ")"
|
|
|
|
|
}
|
|
|
|
|
return summary
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Doc returns the function document comment as a list of lines.
|
|
|
|
|
func (f *Function) Doc() []string {
|
|
|
|
|
lines := []string{
|
|
|
|
|
fmt.Sprintf("%s: %s.", f.Name(), f.Summary()),
|
|
|
|
|
"",
|
|
|
|
|
"Forms:",
|
|
|
|
|
"",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write a table of instruction forms.
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
|
w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
|
|
|
|
|
for _, form := range f.Forms {
|
|
|
|
|
row := f.Opcode() + "\t" + strings.Join(form.Signature(), "\t") + "\n"
|
|
|
|
|
fmt.Fprint(w, row)
|
|
|
|
|
}
|
|
|
|
|
w.Flush()
|
|
|
|
|
|
|
|
|
|
tbl := strings.TrimSpace(buf.String())
|
|
|
|
|
for _, line := range strings.Split(tbl, "\n") {
|
|
|
|
|
lines = append(lines, "\t"+line)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lines
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Signature of the function. Derived from the instruction forms generated by this function.
|
|
|
|
|
func (f *Function) Signature() Signature {
|
|
|
|
|
// Handle the case of forms with multiple arities.
|
|
|
|
|
switch {
|
|
|
|
|
case f.IsVariadic():
|
|
|
|
|
return variadic{name: "ops"}
|
|
|
|
|
case f.IsNiladic():
|
|
|
|
|
return niladic{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate nice-looking variable names.
|
|
|
|
|
n := f.Arity()
|
|
|
|
|
ops := make([]string, n)
|
|
|
|
|
count := map[string]int{}
|
2024-12-22 19:01:48 -05:00
|
|
|
for j := range n {
|
2021-11-12 18:35:36 -08:00
|
|
|
// Collect unique lowercase bytes from first characters of operand types.
|
|
|
|
|
s := map[byte]bool{}
|
|
|
|
|
for _, form := range f.Forms {
|
|
|
|
|
c := form.Operands[j].Type[0]
|
|
|
|
|
if 'a' <= c && c <= 'z' {
|
|
|
|
|
s[c] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Operand name is the sorted bytes.
|
|
|
|
|
var b []byte
|
|
|
|
|
for c := range s {
|
|
|
|
|
b = append(b, c)
|
|
|
|
|
}
|
|
|
|
|
sort.Slice(b, func(i, j int) bool { return b[i] < b[j] })
|
|
|
|
|
name := string(b)
|
|
|
|
|
|
|
|
|
|
// Append a counter if we've seen it already.
|
|
|
|
|
m := count[name]
|
|
|
|
|
count[name]++
|
|
|
|
|
if m > 0 {
|
|
|
|
|
name += strconv.Itoa(m)
|
|
|
|
|
}
|
|
|
|
|
ops[j] = name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return argslist(ops)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// InstructionFunctions builds the list of all functions for a given
|
|
|
|
|
// instruction.
|
|
|
|
|
func InstructionFunctions(i inst.Instruction) []*Function {
|
|
|
|
|
// One function for each possible suffix combination.
|
|
|
|
|
bysuffix := map[string]*Function{}
|
|
|
|
|
for _, f := range i.Forms {
|
|
|
|
|
for _, suffixes := range f.SupportedSuffixes() {
|
|
|
|
|
k := suffixes.String()
|
|
|
|
|
if _, ok := bysuffix[k]; !ok {
|
|
|
|
|
bysuffix[k] = &Function{
|
|
|
|
|
Instruction: i,
|
|
|
|
|
Suffixes: suffixes,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bysuffix[k].Forms = append(bysuffix[k].Forms, f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert to a sorted slice.
|
|
|
|
|
var fns []*Function
|
|
|
|
|
for _, fn := range bysuffix {
|
|
|
|
|
fns = append(fns, fn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SortFunctions(fns)
|
|
|
|
|
|
|
|
|
|
return fns
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// InstructionsFunctions builds all functions for a list of instructions.
|
|
|
|
|
func InstructionsFunctions(is []inst.Instruction) []*Function {
|
|
|
|
|
var all []*Function
|
|
|
|
|
for _, i := range is {
|
|
|
|
|
fns := InstructionFunctions(i)
|
|
|
|
|
all = append(all, fns...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SortFunctions(all)
|
|
|
|
|
|
|
|
|
|
return all
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SortFunctions sorts a list of functions by name.
|
|
|
|
|
func SortFunctions(fns []*Function) {
|
|
|
|
|
sort.Slice(fns, func(i, j int) bool {
|
|
|
|
|
return fns[i].Name() < fns[j].Name()
|
|
|
|
|
})
|
|
|
|
|
}
|