1
2
3
4
5 package ssagen
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "log"
11 "os"
12 "strings"
13
14 "cmd/compile/internal/abi"
15 "cmd/compile/internal/base"
16 "cmd/compile/internal/ir"
17 "cmd/compile/internal/objw"
18 "cmd/compile/internal/typecheck"
19 "cmd/compile/internal/types"
20 "cmd/internal/obj"
21 "cmd/internal/obj/wasm"
22 )
23
24
25
26 type SymABIs struct {
27 defs map[string]obj.ABI
28 refs map[string]obj.ABISet
29 }
30
31 func NewSymABIs() *SymABIs {
32 return &SymABIs{
33 defs: make(map[string]obj.ABI),
34 refs: make(map[string]obj.ABISet),
35 }
36 }
37
38
39
40
41
42
43 func (s *SymABIs) canonicalize(linksym string) string {
44 if strings.HasPrefix(linksym, `"".`) {
45 panic("non-canonical symbol name: " + linksym)
46 }
47 return linksym
48 }
49
50
51
52
53
54
55
56
57
58
59 func (s *SymABIs) ReadSymABIs(file string) {
60 data, err := os.ReadFile(file)
61 if err != nil {
62 log.Fatalf("-symabis: %v", err)
63 }
64
65 for lineNum, line := range strings.Split(string(data), "\n") {
66 lineNum++
67 line = strings.TrimSpace(line)
68 if line == "" || strings.HasPrefix(line, "#") {
69 continue
70 }
71
72 parts := strings.Fields(line)
73 switch parts[0] {
74 case "def", "ref":
75
76 if len(parts) != 3 {
77 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
78 }
79 sym, abistr := parts[1], parts[2]
80 abi, valid := obj.ParseABI(abistr)
81 if !valid {
82 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
83 }
84
85 sym = s.canonicalize(sym)
86
87
88 if parts[0] == "def" {
89 s.defs[sym] = abi
90 } else {
91 s.refs[sym] |= obj.ABISetOf(abi)
92 }
93 default:
94 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
95 }
96 }
97 }
98
99
100
101 func (s *SymABIs) GenABIWrappers() {
102
103
104
105
106
107
108
109 cgoExports := make(map[string][]*[]string)
110 for i, prag := range typecheck.Target.CgoPragmas {
111 switch prag[0] {
112 case "cgo_export_static", "cgo_export_dynamic":
113 symName := s.canonicalize(prag[1])
114 pprag := &typecheck.Target.CgoPragmas[i]
115 cgoExports[symName] = append(cgoExports[symName], pprag)
116 }
117 }
118
119
120
121
122
123
124 for _, fn := range typecheck.Target.Funcs {
125 nam := fn.Nname
126 if ir.IsBlank(nam) {
127 continue
128 }
129 sym := nam.Sym()
130
131 symName := sym.Linkname
132 if symName == "" {
133 symName = sym.Pkg.Prefix + "." + sym.Name
134 }
135 symName = s.canonicalize(symName)
136
137
138 defABI, hasDefABI := s.defs[symName]
139 if hasDefABI {
140 if len(fn.Body) != 0 {
141 base.ErrorfAt(fn.Pos(), 0, "%v defined in both Go and assembly", fn)
142 }
143 fn.ABI = defABI
144 }
145
146 if fn.Pragma&ir.CgoUnsafeArgs != 0 {
147
148
149
150 fn.ABI = obj.ABI0
151 }
152
153
154
155 cgoExport := cgoExports[symName]
156 for _, pprag := range cgoExport {
157
158
159
160
161
162
163
164
165
166
167 if len(*pprag) == 2 {
168 *pprag = append(*pprag, (*pprag)[1])
169 }
170
171 *pprag = append(*pprag, fn.ABI.String())
172 }
173
174
175 if abis, ok := s.refs[symName]; ok {
176 fn.ABIRefs |= abis
177 }
178
179
180
181 fn.ABIRefs.Set(obj.ABIInternal, true)
182
183
184
185
186
187
188
189
190
191
192
193
194 hasBody := len(fn.Body) != 0
195 if sym.Linkname != "" && (hasBody || hasDefABI) && len(cgoExport) == 0 {
196 fn.ABIRefs |= obj.ABISetCallable
197 }
198
199
200
201 if len(cgoExport) > 0 && fn.ABIRefs&^obj.ABISetOf(fn.ABI) != 0 {
202 base.Fatalf("cgo exported function %v cannot have ABI wrappers", fn)
203 }
204
205 if !buildcfg.Experiment.RegabiWrappers {
206 continue
207 }
208
209 forEachWrapperABI(fn, makeABIWrapper)
210 }
211 }
212
213 func forEachWrapperABI(fn *ir.Func, cb func(fn *ir.Func, wrapperABI obj.ABI)) {
214 need := fn.ABIRefs &^ obj.ABISetOf(fn.ABI)
215 if need == 0 {
216 return
217 }
218
219 for wrapperABI := obj.ABI(0); wrapperABI < obj.ABICount; wrapperABI++ {
220 if !need.Get(wrapperABI) {
221 continue
222 }
223 cb(fn, wrapperABI)
224 }
225 }
226
227
228
229 func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
230 if base.Debug.ABIWrap != 0 {
231 fmt.Fprintf(os.Stderr, "=-= %v to %v wrapper for %v\n", wrapperABI, f.ABI, f)
232 }
233
234
235 savepos := base.Pos
236 savedcurfn := ir.CurFunc
237
238 pos := base.AutogeneratedPos
239 base.Pos = pos
240
241
242
243 ft := f.Nname.Type()
244 if ft.NumRecvs() != 0 {
245 base.ErrorfAt(f.Pos(), 0, "makeABIWrapper support for wrapping methods not implemented")
246 return
247 }
248
249
250
251 fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
252 typecheck.NewFuncParams(ft.Params()),
253 typecheck.NewFuncParams(ft.Results())))
254 fn.ABI = wrapperABI
255 typecheck.DeclFunc(fn)
256
257 fn.SetABIWrapper(true)
258 fn.SetDupok(true)
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 fn.Pragma |= ir.Nosplit
286
287
288
289
290
291
292
293
294
295
296 tailcall := fn.Type().NumResults() == 0 && fn.Type().NumParams() == 0 && fn.Type().NumRecvs() == 0
297 if base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink {
298
299
300 tailcall = false
301 }
302 if base.Ctxt.Arch.Name == "amd64" && wrapperABI == obj.ABIInternal {
303
304
305 tailcall = false
306 }
307
308 var tail ir.Node
309 call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
310 call.Args = ir.ParamNames(fn.Type())
311 call.IsDDD = fn.Type().IsVariadic()
312 tail = call
313 if tailcall {
314 tail = ir.NewTailCallStmt(base.Pos, call)
315 } else if fn.Type().NumResults() > 0 {
316 n := ir.NewReturnStmt(base.Pos, nil)
317 n.Results = []ir.Node{call}
318 tail = n
319 }
320 fn.Body.Append(tail)
321
322 typecheck.FinishFuncBody()
323
324 ir.CurFunc = fn
325 typecheck.Stmts(fn.Body)
326
327
328 base.Pos = savepos
329 ir.CurFunc = savedcurfn
330 }
331
332
333
334
335 func CreateWasmImportWrapper(fn *ir.Func) bool {
336 if fn.WasmImport == nil {
337 return false
338 }
339 if buildcfg.GOARCH != "wasm" {
340 base.FatalfAt(fn.Pos(), "CreateWasmImportWrapper call not supported on %s: func was %v", buildcfg.GOARCH, fn)
341 }
342
343 ir.InitLSym(fn, true)
344
345 setupWasmABI(fn)
346
347 pp := objw.NewProgs(fn, 0)
348 defer pp.Free()
349 pp.Text.To.Type = obj.TYPE_TEXTSIZE
350 pp.Text.To.Val = int32(types.RoundUp(fn.Type().ArgWidth(), int64(types.RegSize)))
351
352 pp.Text.To.Offset = 0
353 pp.Flush()
354
355 return true
356 }
357
358 func paramsToWasmFields(f *ir.Func, result *abi.ABIParamResultInfo, abiParams []abi.ABIParamAssignment) []obj.WasmField {
359 wfs := make([]obj.WasmField, len(abiParams))
360 for i, p := range abiParams {
361 t := p.Type
362 switch t.Kind() {
363 case types.TINT32, types.TUINT32:
364 wfs[i].Type = obj.WasmI32
365 case types.TINT64, types.TUINT64:
366 wfs[i].Type = obj.WasmI64
367 case types.TFLOAT32:
368 wfs[i].Type = obj.WasmF32
369 case types.TFLOAT64:
370 wfs[i].Type = obj.WasmF64
371 case types.TUNSAFEPTR:
372 wfs[i].Type = obj.WasmPtr
373 default:
374 base.ErrorfAt(f.Pos(), 0, "go:wasmimport %s %s: unsupported parameter type %s", f.WasmImport.Module, f.WasmImport.Name, t.String())
375 }
376 wfs[i].Offset = p.FrameOffset(result)
377 }
378 return wfs
379 }
380
381 func resultsToWasmFields(f *ir.Func, result *abi.ABIParamResultInfo, abiParams []abi.ABIParamAssignment) []obj.WasmField {
382 if len(abiParams) > 1 {
383 base.ErrorfAt(f.Pos(), 0, "go:wasmimport %s %s: too many return values", f.WasmImport.Module, f.WasmImport.Name)
384 return nil
385 }
386 wfs := make([]obj.WasmField, len(abiParams))
387 for i, p := range abiParams {
388 t := p.Type
389 switch t.Kind() {
390 case types.TINT32, types.TUINT32:
391 wfs[i].Type = obj.WasmI32
392 case types.TINT64, types.TUINT64:
393 wfs[i].Type = obj.WasmI64
394 case types.TFLOAT32:
395 wfs[i].Type = obj.WasmF32
396 case types.TFLOAT64:
397 wfs[i].Type = obj.WasmF64
398 default:
399 base.ErrorfAt(f.Pos(), 0, "go:wasmimport %s %s: unsupported result type %s", f.WasmImport.Module, f.WasmImport.Name, t.String())
400 }
401 wfs[i].Offset = p.FrameOffset(result)
402 }
403 return wfs
404 }
405
406
407 func setupWasmABI(f *ir.Func) {
408 wi := obj.WasmImport{
409 Module: f.WasmImport.Module,
410 Name: f.WasmImport.Name,
411 }
412 if wi.Module == wasm.GojsModule {
413
414
415
416
417
418
419
420
421
422
423 wi.Params = []obj.WasmField{{Type: obj.WasmI32}}
424 } else {
425
426
427
428
429
430
431
432
433
434 abiConfig := AbiForBodylessFuncStackMap(f)
435 abiInfo := abiConfig.ABIAnalyzeFuncType(f.Type())
436 wi.Params = paramsToWasmFields(f, abiInfo, abiInfo.InParams())
437 wi.Results = resultsToWasmFields(f, abiInfo, abiInfo.OutParams())
438 }
439 f.LSym.Func().WasmImport = &wi
440 }
441
View as plain text