]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssagen/abi.go
f65fe497ec3787acec33e7c0e5802fbc09a244f0
[gostls13.git] / src / cmd / compile / internal / ssagen / abi.go
1 // Copyright 2009 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 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 // SymABIs records information provided by the assembler about symbol
25 // definition ABIs and reference ABIs.
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 // canonicalize returns the canonical name used for a linker symbol in
39 // s's maps. Symbols in this package may be written either as "".X or
40 // with the package's import path already in the symbol. This rewrites
41 // both to use the full path, which matches compiler-generated linker
42 // symbol names.
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 // ReadSymABIs reads a symabis file that specifies definitions and
51 // references of text symbols by ABI.
52 //
53 // The symabis format is a set of lines, where each line is a sequence
54 // of whitespace-separated fields. The first field is a verb and is
55 // either "def" for defining a symbol ABI or "ref" for referencing a
56 // symbol using an ABI. For both "def" and "ref", the second field is
57 // the symbol name and the third field is the ABI name, as one of the
58 // named cmd/internal/obj.ABI constants.
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++ // 1-based
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                         // Parse line.
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                         // Record for later.
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 // GenABIWrappers applies ABI information to Funcs and generates ABI
100 // wrapper functions where necessary.
101 func (s *SymABIs) GenABIWrappers() {
102         // For cgo exported symbols, we tell the linker to export the
103         // definition ABI to C. That also means that we don't want to
104         // create ABI wrappers even if there's a linkname.
105         //
106         // TODO(austin): Maybe we want to create the ABI wrappers, but
107         // ensure the linker exports the right ABI definition under
108         // the unmangled name?
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         // Apply ABI defs and refs to Funcs and generate wrappers.
120         //
121         // This may generate new decls for the wrappers, but we
122         // specifically *don't* want to visit those, lest we create
123         // wrappers for wrappers.
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                 // Apply definitions.
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                         // CgoUnsafeArgs indicates the function (or its callee) uses
148                         // offsets to dispatch arguments, which currently using ABI0
149                         // frame layout. Pin it to ABI0.
150                         fn.ABI = obj.ABI0
151                 }
152
153                 // If cgo-exported, add the definition ABI to the cgo
154                 // pragmas.
155                 cgoExport := cgoExports[symName]
156                 for _, pprag := range cgoExport {
157                         // The export pragmas have the form:
158                         //
159                         //   cgo_export_* <local> [<remote>]
160                         //
161                         // If <remote> is omitted, it's the same as
162                         // <local>.
163                         //
164                         // Expand to
165                         //
166                         //   cgo_export_* <local> <remote> <ABI>
167                         if len(*pprag) == 2 {
168                                 *pprag = append(*pprag, (*pprag)[1])
169                         }
170                         // Add the ABI argument.
171                         *pprag = append(*pprag, fn.ABI.String())
172                 }
173
174                 // Apply references.
175                 if abis, ok := s.refs[symName]; ok {
176                         fn.ABIRefs |= abis
177                 }
178                 // Assume all functions are referenced at least as
179                 // ABIInternal, since they may be referenced from
180                 // other packages.
181                 fn.ABIRefs.Set(obj.ABIInternal, true)
182
183                 // If a symbol is defined in this package (either in
184                 // Go or assembly) and given a linkname, it may be
185                 // referenced from another package, so make it
186                 // callable via any ABI. It's important that we know
187                 // it's defined in this package since other packages
188                 // may "pull" symbols using linkname and we don't want
189                 // to create duplicate ABI wrappers.
190                 //
191                 // However, if it's given a linkname for exporting to
192                 // C, then we don't make ABI wrappers because the cgo
193                 // tool wants the original definition.
194                 hasBody := len(fn.Body) != 0
195                 if sym.Linkname != "" && (hasBody || hasDefABI) && len(cgoExport) == 0 {
196                         fn.ABIRefs |= obj.ABISetCallable
197                 }
198
199                 // Double check that cgo-exported symbols don't get
200                 // any wrappers.
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 // makeABIWrapper creates a new function that will be called with
228 // wrapperABI and calls "f" using f.ABI.
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         // Q: is this needed?
235         savepos := base.Pos
236         savedcurfn := ir.CurFunc
237
238         pos := base.AutogeneratedPos
239         base.Pos = pos
240
241         // At the moment we don't support wrapping a method, we'd need machinery
242         // below to handle the receiver. Panic if we see this scenario.
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         // Reuse f's types.Sym to create a new ODCLFUNC/function.
250         // TODO(mdempsky): Means we can't set sym.Def in Declfunc, ugh.
251         fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
252                 typecheck.NewFuncParams(ft.Params(), true),
253                 typecheck.NewFuncParams(ft.Results(), false)))
254         fn.ABI = wrapperABI
255         typecheck.DeclFunc(fn)
256
257         fn.SetABIWrapper(true)
258         fn.SetDupok(true)
259
260         // ABI0-to-ABIInternal wrappers will be mainly loading params from
261         // stack into registers (and/or storing stack locations back to
262         // registers after the wrapped call); in most cases they won't
263         // need to allocate stack space, so it should be OK to mark them
264         // as NOSPLIT in these cases. In addition, my assumption is that
265         // functions written in assembly are NOSPLIT in most (but not all)
266         // cases. In the case of an ABIInternal target that has too many
267         // parameters to fit into registers, the wrapper would need to
268         // allocate stack space, but this seems like an unlikely scenario.
269         // Hence: mark these wrappers NOSPLIT.
270         //
271         // ABIInternal-to-ABI0 wrappers on the other hand will be taking
272         // things in registers and pushing them onto the stack prior to
273         // the ABI0 call, meaning that they will always need to allocate
274         // stack space. If the compiler marks them as NOSPLIT this seems
275         // as though it could lead to situations where the linker's
276         // nosplit-overflow analysis would trigger a link failure. On the
277         // other hand if they not tagged NOSPLIT then this could cause
278         // problems when building the runtime (since there may be calls to
279         // asm routine in cases where it's not safe to grow the stack). In
280         // most cases the wrapper would be (in effect) inlined, but are
281         // there (perhaps) indirect calls from the runtime that could run
282         // into trouble here.
283         // FIXME: at the moment all.bash does not pass when I leave out
284         // NOSPLIT for these wrappers, so all are currently tagged with NOSPLIT.
285         fn.Pragma |= ir.Nosplit
286
287         // Generate call. Use tail call if no params and no returns,
288         // but a regular call otherwise.
289         //
290         // Note: ideally we would be using a tail call in cases where
291         // there are params but no returns for ABI0->ABIInternal wrappers,
292         // provided that all params fit into registers (e.g. we don't have
293         // to allocate any stack space). Doing this will require some
294         // extra work in typecheck/walk/ssa, might want to add a new node
295         // OTAILCALL or something to this effect.
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                 // cannot tailcall on PPC64 with dynamic linking, as we need
299                 // to restore R2 after call.
300                 tailcall = false
301         }
302         if base.Ctxt.Arch.Name == "amd64" && wrapperABI == obj.ABIInternal {
303                 // cannot tailcall from ABIInternal to ABI0 on AMD64, as we need
304                 // to special registers (X15) when returning to ABIInternal.
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         // Restore previous context.
328         base.Pos = savepos
329         ir.CurFunc = savedcurfn
330 }
331
332 // CreateWasmImportWrapper creates a wrapper for imported WASM functions to
333 // adapt them to the Go calling convention. The body for this function is
334 // generated in cmd/internal/obj/wasm/wasmobj.go
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         // Wrapper functions never need their own stack frame
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 // setupTextLSym initializes the LSym for a with-body text symbol.
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                 // Functions that are imported from the "gojs" module use a special
414                 // ABI that just accepts the stack pointer.
415                 // Example:
416                 //
417                 //      //go:wasmimport gojs add
418                 //      func importedAdd(a, b uint) uint
419                 //
420                 // will roughly become
421                 //
422                 //      (import "gojs" "add" (func (param i32)))
423                 wi.Params = []obj.WasmField{{Type: obj.WasmI32}}
424         } else {
425                 // All other imported functions use the normal WASM ABI.
426                 // Example:
427                 //
428                 //      //go:wasmimport a_module add
429                 //      func importedAdd(a, b uint) uint
430                 //
431                 // will roughly become
432                 //
433                 //      (import "a_module" "add" (func (param i32 i32) (result i32)))
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 }