github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ssa/_gen/allocators.go (about)

     1  package main
     2  
     3  // TODO: should we share backing storage for similarly-shaped types?
     4  // e.g. []*Value and []*Block, or even []int32 and []bool.
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"github.com/bir3/gocompiler/src/go/format"
    10  	"io"
    11  	"log"
    12  	"os"
    13  )
    14  
    15  type allocator struct {
    16  	name     string // name for alloc/free functions
    17  	typ      string // the type they return/accept
    18  	mak      string // code to make a new object (takes power-of-2 size as fmt arg)
    19  	capacity string // code to calculate the capacity of an object. Should always report a power of 2.
    20  	resize   string // code to shrink to sub-power-of-two size (takes size as fmt arg)
    21  	clear    string // code for clearing object before putting it on the free list
    22  	minLog   int    // log_2 of minimum allocation size
    23  	maxLog   int    // log_2 of maximum allocation size
    24  }
    25  
    26  func genAllocators() {
    27  	allocators := []allocator{
    28  		{
    29  			name:     "ValueSlice",
    30  			typ:      "[]*Value",
    31  			capacity: "cap(%s)",
    32  			mak:      "make([]*Value, %s)",
    33  			resize:   "%s[:%s]",
    34  			clear:    "for i := range %[1]s {\n%[1]s[i] = nil\n}",
    35  			minLog:   5,
    36  			maxLog:   32,
    37  		},
    38  		{
    39  			name:     "BlockSlice",
    40  			typ:      "[]*Block",
    41  			capacity: "cap(%s)",
    42  			mak:      "make([]*Block, %s)",
    43  			resize:   "%s[:%s]",
    44  			clear:    "for i := range %[1]s {\n%[1]s[i] = nil\n}",
    45  			minLog:   5,
    46  			maxLog:   32,
    47  		},
    48  		{
    49  			name:     "BoolSlice",
    50  			typ:      "[]bool",
    51  			capacity: "cap(%s)",
    52  			mak:      "make([]bool, %s)",
    53  			resize:   "%s[:%s]",
    54  			clear:    "for i := range %[1]s {\n%[1]s[i] = false\n}",
    55  			minLog:   8,
    56  			maxLog:   32,
    57  		},
    58  		{
    59  			name:     "IntSlice",
    60  			typ:      "[]int",
    61  			capacity: "cap(%s)",
    62  			mak:      "make([]int, %s)",
    63  			resize:   "%s[:%s]",
    64  			clear:    "for i := range %[1]s {\n%[1]s[i] = 0\n}",
    65  			minLog:   5,
    66  			maxLog:   32,
    67  		},
    68  		{
    69  			name:     "Int32Slice",
    70  			typ:      "[]int32",
    71  			capacity: "cap(%s)",
    72  			mak:      "make([]int32, %s)",
    73  			resize:   "%s[:%s]",
    74  			clear:    "for i := range %[1]s {\n%[1]s[i] = 0\n}",
    75  			minLog:   6,
    76  			maxLog:   32,
    77  		},
    78  		{
    79  			name:     "Int8Slice",
    80  			typ:      "[]int8",
    81  			capacity: "cap(%s)",
    82  			mak:      "make([]int8, %s)",
    83  			resize:   "%s[:%s]",
    84  			clear:    "for i := range %[1]s {\n%[1]s[i] = 0\n}",
    85  			minLog:   8,
    86  			maxLog:   32,
    87  		},
    88  		{
    89  			name:     "IDSlice",
    90  			typ:      "[]ID",
    91  			capacity: "cap(%s)",
    92  			mak:      "make([]ID, %s)",
    93  			resize:   "%s[:%s]",
    94  			clear:    "for i := range %[1]s {\n%[1]s[i] = 0\n}",
    95  			minLog:   6,
    96  			maxLog:   32,
    97  		},
    98  		{
    99  			name:     "SparseSet",
   100  			typ:      "*sparseSet",
   101  			capacity: "%s.cap()",
   102  			mak:      "newSparseSet(%s)",
   103  			resize:   "", // larger-sized sparse sets are ok
   104  			clear:    "%s.clear()",
   105  			minLog:   5,
   106  			maxLog:   32,
   107  		},
   108  		{
   109  			name:     "SparseMap",
   110  			typ:      "*sparseMap",
   111  			capacity: "%s.cap()",
   112  			mak:      "newSparseMap(%s)",
   113  			resize:   "", // larger-sized sparse maps are ok
   114  			clear:    "%s.clear()",
   115  			minLog:   5,
   116  			maxLog:   32,
   117  		},
   118  		{
   119  			name:     "SparseMapPos",
   120  			typ:      "*sparseMapPos",
   121  			capacity: "%s.cap()",
   122  			mak:      "newSparseMapPos(%s)",
   123  			resize:   "", // larger-sized sparse maps are ok
   124  			clear:    "%s.clear()",
   125  			minLog:   5,
   126  			maxLog:   32,
   127  		},
   128  	}
   129  
   130  	w := new(bytes.Buffer)
   131  	fmt.Fprintf(w, "// Code generated from _gen/allocators.go; DO NOT EDIT.\n")
   132  	fmt.Fprintln(w)
   133  	fmt.Fprintln(w, "package ssa")
   134  
   135  	fmt.Fprintln(w, "import (")
   136  	fmt.Fprintln(w, "\"math/bits\"")
   137  	fmt.Fprintln(w, "\"sync\"")
   138  	fmt.Fprintln(w, ")")
   139  	for _, a := range allocators {
   140  		genAllocator(w, a)
   141  	}
   142  	// gofmt result
   143  	b := w.Bytes()
   144  	var err error
   145  	b, err = format.Source(b)
   146  	if err != nil {
   147  		fmt.Printf("%s\n", w.Bytes())
   148  		panic(err)
   149  	}
   150  
   151  	if err := os.WriteFile("../allocators.go", b, 0666); err != nil {
   152  		log.Fatalf("can't write output: %v\n", err)
   153  	}
   154  }
   155  func genAllocator(w io.Writer, a allocator) {
   156  	fmt.Fprintf(w, "var poolFree%s [%d]sync.Pool\n", a.name, a.maxLog-a.minLog)
   157  	fmt.Fprintf(w, "func (c *Cache) alloc%s(n int) %s {\n", a.name, a.typ)
   158  	fmt.Fprintf(w, "var s %s\n", a.typ)
   159  	fmt.Fprintf(w, "n2 := n\n")
   160  	fmt.Fprintf(w, "if n2 < %d { n2 = %d }\n", 1<<a.minLog, 1<<a.minLog)
   161  	fmt.Fprintf(w, "b := bits.Len(uint(n2-1))\n")
   162  	fmt.Fprintf(w, "v := poolFree%s[b-%d].Get()\n", a.name, a.minLog)
   163  	fmt.Fprintf(w, "if v == nil {\n")
   164  	fmt.Fprintf(w, "  s = %s\n", fmt.Sprintf(a.mak, "1<<b"))
   165  	fmt.Fprintf(w, "} else {\n")
   166  	if a.typ[0] == '*' {
   167  		fmt.Fprintf(w, "s = v.(%s)\n", a.typ)
   168  	} else {
   169  		fmt.Fprintf(w, "sp := v.(*%s)\n", a.typ)
   170  		fmt.Fprintf(w, "s = *sp\n")
   171  		fmt.Fprintf(w, "*sp = nil\n")
   172  		fmt.Fprintf(w, "c.hdr%s = append(c.hdr%s, sp)\n", a.name, a.name)
   173  	}
   174  	fmt.Fprintf(w, "}\n")
   175  	if a.resize != "" {
   176  		fmt.Fprintf(w, "s = %s\n", fmt.Sprintf(a.resize, "s", "n"))
   177  	}
   178  	fmt.Fprintf(w, "return s\n")
   179  	fmt.Fprintf(w, "}\n")
   180  	fmt.Fprintf(w, "func (c *Cache) free%s(s %s) {\n", a.name, a.typ)
   181  	fmt.Fprintf(w, "%s\n", fmt.Sprintf(a.clear, "s"))
   182  	fmt.Fprintf(w, "b := bits.Len(uint(%s) - 1)\n", fmt.Sprintf(a.capacity, "s"))
   183  	if a.typ[0] == '*' {
   184  		fmt.Fprintf(w, "poolFree%s[b-%d].Put(s)\n", a.name, a.minLog)
   185  	} else {
   186  		fmt.Fprintf(w, "var sp *%s\n", a.typ)
   187  		fmt.Fprintf(w, "if len(c.hdr%s) == 0 {\n", a.name)
   188  		fmt.Fprintf(w, "  sp = new(%s)\n", a.typ)
   189  		fmt.Fprintf(w, "} else {\n")
   190  		fmt.Fprintf(w, "  sp = c.hdr%s[len(c.hdr%s)-1]\n", a.name, a.name)
   191  		fmt.Fprintf(w, "  c.hdr%s[len(c.hdr%s)-1] = nil\n", a.name, a.name)
   192  		fmt.Fprintf(w, "  c.hdr%s = c.hdr%s[:len(c.hdr%s)-1]\n", a.name, a.name, a.name)
   193  		fmt.Fprintf(w, "}\n")
   194  		fmt.Fprintf(w, "*sp = s\n")
   195  		fmt.Fprintf(w, "poolFree%s[b-%d].Put(sp)\n", a.name, a.minLog)
   196  	}
   197  	fmt.Fprintf(w, "}\n")
   198  }