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 }