Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: switch to a register-based calling convention for Go functions #40724

Open
aclements opened this issue Aug 12, 2020 · 195 comments
Open

cmd/compile: switch to a register-based calling convention for Go functions #40724

aclements opened this issue Aug 12, 2020 · 195 comments

Comments

@aclements
Copy link
Member

@aclements aclements commented Aug 12, 2020

I propose that we switch the Go internal ABI (used between Go functions) from stack-based to register-based argument and result passing for Go 1.16 1.17.

I lay out the details of our proposal and the work required in this document.

The ABI specification can be found here.

This was previously proposed in #18597, where @dr2chase did some excellent prototyping work that our new proposal builds on. With multiple ABI support, we’re now in a much better position to execute on this without breaking compatibility with the existing body of Go assembly code. I’ve opened this new issue to focus on discussion of our new proposal.

/cc @dr2chase @danscales @thanm @cherrymui @mknyszek @prattmic @randall77

An incomplete and evolving list of tasks:

  • Define ABI specification (CL, @aclements)
  • Add GOEXPERIMENT=regabi and asm macro (CL)
  • cmd/compile: late call lowering (CLs)
  • cmd/compile: implement register arguments (@dr2chase)
    • spill around morestack call (CL)
    • add temporary ABI pragma for testing (CL)
    • add abstract argument registers (WIP CL)
    • implement ABI rules (CL)
    • use abstract argument registers
  • cmd/compile: implement register returns
  • cmd/compile: ABI wrappers (CL, old CL)
    • cmd/link: mangle wrapper names for ELF (CL)
    • cmd/link: mangle wrapper names for PE (CL)
    • implement zeroing of X15 in ABI0->ABIInternal wrappers (CL)
  • cmd/asm: add syntax for runtime packages to reference ABIInternal symbols (CL)
    • Mark runtime.{goexit,asyncPreempt}, reflect.{makeFuncStub,methodValueCall} definitions ABIInternal (CL)
    • Mark reference to runtime.callbackWrap in sys_windows_amd64.s as ABIInternal (CL)
  • runtime: fix assembly closure calls (mcall) (@aclements, CL)
  • reflect: support calling ABIInternal (CL)
  • reflect: support MakeFunc and method value calls (CL)
  • go and defer statements
    • cmd/compile: desugar go/defer to zero-argument (@thanm, CL)
    • cmd/compile: fix defer recover() (@cherrymui, CL)
    • cmd/compile: desugar go/defer with results (@cherrymui, CL)
  • cmd/cgo: decouple cgo callbacks from ABI (CL)
  • runtime: finalizer support (CL)
  • runtime: Windows callback support (CL)
  • cmd/internal/obj: introduce and use RegEntryTmp registers in prologue (@mknyszek, CL)
  • cmd/compile: generate correct ABI0 argument maps for body-less functions (see WriteFuncMap) (@dr2chase, CL)
  • cmd/compile: make cgo_unsafe_args generate an ABI0 function (or an ABIInternal-with-no-registers function) (@cherrymui, CL)
  • runtime: update debug call protocol (CL)
  • Fix ABI0/ABIInternal confusion in cgo (CL)
  • Run signature fuzzer and fix bugs (everyone)
  • Get all.bash to pass on Linux, Windows, and Darwin (everyone)

High-priority non-critical path

  • Export ABI information across package boundaries to eliminate more wrappers (@aclements, CL)
  • Make funcPC always return the "native" PC of a function (maybe also introduce ABIOther) (@cherrymui, CL)
  • Strip unnecessary ABIInternal annotations once funcPC is in
  • Tracebacks
    • Define extended argument metadata format (in progress, @cherrymui)
    • cmd/compile: produce extended argument metadata (@cherrymui, CL)
    • runtime: consume extended argument metadata (@cherrymui, CL)
    • cmd/compile,runtime: traceback metadata for spill slot liveness
  • DWARF
    • cmd/compile: ensure arguments have appropriate DWARF locations
    • Ensure GDB and Delve can find register arguments
    • cmd/compile: add a DWARF vendor attribute with function argument frame size (context)
  • Wrapper mangling for non-critical arches
    • cmd/link: mangle wrapper names for Mach-O (CL)
    • cmd/link: mangle wrapper names for xcoff
    • cmd/link: mangle wrapper names for Plan 9
  • runtime: simplify go/defer call paths
    • assert that go/defer frames are zero sized (CL)
    • replace defer reflectcall with a direct closure call (CL)
  • cmd/internal/obj: reject splittable ABIInternal functions without morestack spill info (e.g., asm functions) because we can't generate a correct morestack path (CL)
  • cmd/asm: don't reference args_stackmap in ABIInternal functions (because it's for ABI0) (CL)
  • Port performance-critical assembly to ABIInternal (see CL 296372 for valuable functions) (CL 308931, CL 310184)
  • math: fix overhead of assembly->Go calls CL 310331
  • Release notes
    • Mention undocumented behavior we've observed applications depending on that may have changed.
      • Using reflect.ValueOf(fn).Pointer() to get the PC of an assembly function will now return the PC of the ABI wrapper
    • Performance surprise: calling from assembly to Go is slightly more expensive.
    • Performance surprise: calling an assembly function via a closure is slightly more expensive.
    • Traceback format is much improved

Enabling steps

  • Enable regabiwrappers by default on amd64 (Linux, Windows, and Darwin)
  • Enable regabidefer
  • Enable regabireflect
  • Enable regabig
  • Enable regabiargs

Testing

  • Function signature fuzzer (ongoing)
    • Static call, closure call, method call, interface call, reflect.{ValueOf(target),MakeFunc(x, target),Method(x)}.{Call,Interface}, called from defer, called from go, called as a finalizer
    • {Big,Small} {argument,result} in {memory,registers} and {not addressed,addressed and not leaked to heap,addressed and leaked to heap}
    • Use defer in a test function (check arguments, modify results)
    • Pass pointers-to-stack and pointers-to-heap
    • Cause result to move to heap
    • runtime: add MoveStackOnNextCall, assertions for pointer-to-stack/pointer-to-heap, assertions for live/dead (@aclements, CL)
    • Integrate runtime testing hook
  • cmd/compile: revive clobberdead (CL)
  • cmd/compile: add clobberdeadreg (CL)

Post-MVP

  • Move g from TLS to register (CL)
    • Use g register on non-Linux OSes (see CL)
  • Reserve and use X15 as zero register (CL)
    • Should this be X0 for more compact instruction encoding?
  • Port to other platforms
  • Eliminate legacy ABI paths for all platforms, even if they're using ABIInternal with 0 registers
  • Eliminate spill slots?
  • Pass pointer-shaped method receiver in context register (#44827)
  • runtime: simplify go/defer call paths
    • simplify go/defer paths to assume zero args/results
    • simplify special _defer allocator and remove special _defer cases from mallocgc (because _defer records will be fixed size).
  • cmd/vet: add syntax and checks for register arguments and results in assembly like x+0(FP)
  • cmd/vet: check argument size for ABIInternal functions and fix runtime asm declarations

Cleanup (can be done later)

  • runtime: port all assembly -> Go calls to ABIInternal?
  • Eliminate ABIAlias support from cmd/compile, cmd/link, and object format
  • remove now-redundant fields from ssa.AuxCall
  • rationalize use of LocalsOffset/FrameOffset (for registers that use a link register, e.g. arm64, powerppc).
  • cmd/compile: revisit abiutils.go and clean up the API (also reduce ABIConfig copying)
  • cmd/internal/obj: generate stack maps in obj so we can better compact the morestack/body maps and reduce subtlety?
  • cmd/compile,runtime: re-enable passing arguments to go in runtime (context)
  • cmd/compile: always attach ir.Func to function ir.Names (context)
  • cmd/compile: support ABIInternal for tail calls (context)
  • cmd/compile: once wrapping of defers is on for all arch/OS combinations, it should be possible to simplify or remove some of the openDefer processing in ssagen (notablly we could get rid of openDeferSave()
  • runtime: think about an ABI-insensitive debugCall
@aclements aclements added this to the Go1.16 milestone Aug 12, 2020
@seebs
Copy link
Contributor

@seebs seebs commented Aug 12, 2020

Once upon a time, I was one of several people whose primary work activity for I think two days was tracking down a weird kernel crash, which was ultimately caused by callee-saved registers. Well, the crash was caused by a [FOO_MAX] array being overrun. But the thing where the result of that overrun was to overwrite a single automatic variable, which never had its address taken, five call frames away? That was caused by callee-saved registers.

Which is to say:

Platform ABIs typically define callee-save registers, which place substantial additional requirements on a garbage collector. There are alternatives to callee-save registers that share many of their benefits, while being much better suited to Go.

+1 +1 +1 +1 +1 +1 [...]

@ncw
Copy link
Contributor

@ncw ncw commented Aug 13, 2020

If I'm understanding the proposal correctly, assembler code will continue to be written with the current stack based calling conventions.

I understand the excellent reasoning behind doing this, I'll just note that this is surely going to frustrate assembly code writers not being able to pass and receive args in registers as often assembly code fragments are tiny and the overhead of calling them is massive.

@mknyszek
Copy link
Contributor

@mknyszek mknyszek commented Aug 13, 2020

@ncw This restriction to ABI0 for assembly writers isn't necessarily permanent. See https://go.googlesource.com/proposal/+/master/design/27539-internal-abi.md#proposal.

@laboger
Copy link
Contributor

@laboger laboger commented Aug 13, 2020

Right now writeBarrier is a special builtin that allows arguments to be passed in registers. Couldn't that same concept be extended to others like memmove and memcpy to avoid call overhead even though they are asm?

@aclements
Copy link
Member Author

@aclements aclements commented Aug 13, 2020

@laboger , yes, we're considering special-casing just a few assembly functions. The hottest ones by far are memmove, memclrNoHeapPointers, and possibly syscall.Syscall. The write barrier calling convention is very specialized because its context is so unusual and performance-sensitive. We'll probably just switch the others to use the register ABI rather than anything more specialized (and teach the toolchain that those are special even though they're assembly).

@mknyszek
Copy link
Contributor

@mknyszek mknyszek commented Aug 14, 2020

A comment on the "stack growth" section of the doc, specifically about spilling register state for morestack into the guard space for a goroutine (copied from Gerrit):

I worry a little bit about cases where functions marked nosplit eventually call into a non-nosplit function. If the nosplit frames are large (but don't exceed the guard space) we might find out that we don't have any space left. What should we do in this case? Throwing doesn't seem quite right since this works just fine today (though, you have to be careful). Should we have "guard space" and a subset of that as "no, really, this is very guarded" space? That would require extending the guard space a bit further which isn't great...

One alternative is to manage per-goroutine space for this, but that's not great either, since its more memory used per goroutine.

@cherrymui
Copy link
Contributor

@cherrymui cherrymui commented Aug 14, 2020

Good point. This is especially true for architectures that have a lot registers. Maybe we could decide that some registers are never live across a call?

@aclements
Copy link
Member Author

@aclements aclements commented Aug 14, 2020

That's an excellent point. A few possible solutions come to mind:

  1. It would be really sad if we had to make more per-goroutine space for this since you almost always have space on the stack. One possibility is to spill to the stack if there's room, and otherwise we keep a pool of allocated "spill space" objects. For that, we could keep just one pre-allocated per P and if the goroutine needs it, it can pull it off the P, spill into it, and then once it's entered the runtime it can allocate a new one (probably getting it from a global allocation pool) and attach it to the P. On return, it can return it to the allocation pool.

  2. A similar option would be to have just one spill space per P. Again, use the stack if you can, otherwise spill into the P, enter the runtime, grow the stack even if it's just a preemption, and then dump the spilled registers back onto the stack in the right place.

  3. We could revisit the nosplit rules. It's often (though not always) a mistake to call from a nosplit function to a non-nosplit function. I'm not sure exactly what this would look like. Maybe a non-nosplit function called from a nosplit function has to have a special prologue? Related: #21314 (comment). I think the only cases I enumerated in that comment that intentionally call from a nosplit to a non-nosplit function aren't running on a user G stack and thus can't grow it anyway.

@gopherbot
Copy link

@gopherbot gopherbot commented Sep 1, 2020

Change https://golang.org/cl/252258 mentions this issue: cmd/asm: define a macro for GOEXPERIMENT=regabi

@gopherbot
Copy link

@gopherbot gopherbot commented Sep 1, 2020

Change https://golang.org/cl/252257 mentions this issue: cmd/internal/objabi: add regabi GOEXPERIMENT

gopherbot pushed a commit that referenced this issue Sep 3, 2020
This is the "feature flag" for the register calling convention work
(though since this work is expected to extend over a few releases,
it's not version-prefixed). This will let us develop the register
calling convention on the main branch while maintaining an easy toggle
between the old and new ABIs.

Updates #40724.

Change-Id: I129c8d87d34e6fa0910b6fa43efb35b706021637
Reviewed-on: https://go-review.googlesource.com/c/go/+/252257
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
gopherbot pushed a commit that referenced this issue Sep 3, 2020
This defines a macro for the regabi GOEXPERIMENT when assembling
runtime assembly code.

In general, assembly code will be shielded from the calling convention
change, but there is a small amount of runtime assembly that is going
to have to change. By defining a macro, we can easily make the small
necessary changes. The other option is to use build tags, but that
would require duplicating nontrivial amounts of unaffected code,
leading to potential divergence issues. (And unlike Go code, assembly
code can't depend on the compiler optimizing away branches on a
feature constant.) We consider the macro preferable, especially since
this is expected to be temporary as we transition to the new calling
convention.

Updates #40724.

Change-Id: I73984065123968337ec10b47bb12c4a1cbc07dc5
Reviewed-on: https://go-review.googlesource.com/c/go/+/252258
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
@gopherbot
Copy link

@gopherbot gopherbot commented Oct 1, 2020

Change https://golang.org/cl/258938 mentions this issue: runtime,cmd/cgo: simplify C -> Go call path

@aclements
Copy link
Member Author

@aclements aclements commented Oct 2, 2020

@alexbrainman , I just ran into a bit of a snag on Windows that maybe you can better inform me on. It looks like syscall.NewCallback is going to also need an implementation of the Go internal ABI rules and I'm trying to figure out exactly what that needs to look like. (I pinged you because it looks like you last substantially touched that code, but feel free to pass the ping.)

The documentation says "The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr." Does this actually mean the arguments (and result) must be an integral, floating-point, or pointer type? Or does it mean, say, struct { x, y uint16 } or struct { x [4]byte } is allowed, since those are technically no larger than the size of a uintptr? The current implementation permits the latter, though I don't know if it actually works.

If they must be int/float/pointer, then mapping from the Windows ABI to the Go register ABI is relatively straightforward. If compounds are allowed, then this gets much harder.

@networkimprov
Copy link

@networkimprov networkimprov commented Oct 2, 2020

cc @jstarks re the ABI question.

@alexbrainman
Copy link
Member

@alexbrainman alexbrainman commented Oct 3, 2020

@aclements I reckon there are very few instances of syscall.NewCallback usage. But they are used a lot.

If you want to build Windows GUI, you have to use syscall.NewCallback, because Windows GUI API requires syscall.NewCallback.

Similarly, if you want to build Windows service, you have to use syscall.NewCallback.

These two pretty much cover syscall.NewCallback usage.

For Windows service, you can look in golang.org/x/sys/windows/svc. It uses this RegisterServiceCtrlHandlerEx WIndows API

https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-registerservicectrlhandlerexw

which requires LPHANDLER_FUNCTION_EX

https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nc-winsvc-lphandler_function_ex

so LPHANDLER_FUNCTION_EX returns DWORD (uint32).

For GUI grep in golang.org/x/exp/shiny - it uses RegisterClass

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclassw

which uses WNDCLASSW.lpfnWndProc

https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassw

which is WNDPROC

https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms633573(v=vs.85)

which returns LRESULT which is LONG_PTR or uintptr (in Go)

https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

Also I recommend you look at github.com/lxn/walk for their syscall.NewCallback usage. This is an ultimate package to create GUI apps. But, I doubt, you will find different usage than golang.org/x/exp/shine. (I did not look myself)

I reckon, that is about it. For Microsoft APIs (maybe google code for syscall.NewCallback or windows.NewCallback).

But some people might use it in their custom / proprietary interface. I am not sure how these are supported by Go. You will be the judge.

Alex

@CAFxX
Copy link
Contributor

@CAFxX CAFxX commented Oct 3, 2020

IIUC this example in the microsoft docs shows that compounds are allowed:

struct Struct2 {
   int j, k;    // Struct2 fits in 64 bits, and meets requirements for return by value.
};
Struct2 func4(int a, double b, int c, float d);
// Caller passes a in RCX, b in XMM1, c in R8, and d in XMM3;
// callee returns Struct2 result by value in RAX.
@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/262197 mentions this issue: go/analysis/passes/asmdecl: add support for ABI selector clauses

gopherbot pushed a commit to golang/tools that referenced this issue Oct 14, 2020
Accept ABI selector clauses for function definitions. The assembler
allows these clauses when compiling the runtime, so the checker needs
to be able to digest them as well.

Updates golang/go#40724

Change-Id: I49ea4d87450c498bdfe10a8c441b48fcf70bea7c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/262197
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/262319 mentions this issue: reflect,runtime: use internal ABI for selected ASM routines

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/262317 mentions this issue: cmd/dist,cmd/go: broaden use of asm macro GOEXPERIMENT_REGABI

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/259445 mentions this issue: cmd/compile,cmd/link: initial support for ABI wrappers

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/260477 mentions this issue: cmd/asm: allow def/ref of func ABI when compiling runtime

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2020

Change https://golang.org/cl/262318 mentions this issue: cmd: go get golang.org/x/tools@d1624618 && go mod vendor

@ianlancetaylor ianlancetaylor added this to Incoming in Proposals Oct 14, 2020
@gopherbot
Copy link

@gopherbot gopherbot commented Oct 17, 2020

Change https://golang.org/cl/262117 mentions this issue: cmd/compile: delay expansion of OpArg until expand_calls

@aclements
Copy link
Member Author

@aclements aclements commented Apr 19, 2021

@andig, @mknyszek put together the benchmark suite. He's been working on open-sourcing it, but I'm not sure what the current status is.

Are there any plans for adding the register ABI to darwin/arm64?

Yes. ARM64 is the next architecture we plan to work on, and Darwin will definitely be included in that.

gopherbot pushed a commit that referenced this issue Apr 19, 2021
For #40724.

Change-Id: Ibf4ff8b24b501813839657ac195b909682ac7d0b
Reviewed-on: https://go-review.googlesource.com/c/go/+/310173
Trust: Austin Clements <austin@google.com>
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopherbot pushed a commit that referenced this issue Apr 19, 2021
For #40724.

Change-Id: Ib3e4a67c3826176f0d51619754270022344ee194
Reviewed-on: https://go-review.googlesource.com/c/go/+/310174
Trust: Austin Clements <austin@google.com>
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 20, 2021

Change https://golang.org/cl/311689 mentions this issue: cmd/compile: preserve/translate names for parameters

gopherbot pushed a commit that referenced this issue Apr 20, 2021
For #40724.

Change-Id: If3a66c0e29cb20dd29ac13c8d00aa46ee279ab97
Reviewed-on: https://go-review.googlesource.com/c/go/+/310175
Trust: Austin Clements <austin@google.com>
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopherbot pushed a commit that referenced this issue Apr 20, 2021
For #40724.

Change-Id: I7509668478d20dd625f210e5a33f5d896a76d6b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/310176
Trust: Austin Clements <austin@google.com>
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 21, 2021

Change https://golang.org/cl/312429 mentions this issue: runtime: fix runtimeQPC ABIInternal call

gopherbot pushed a commit that referenced this issue Apr 21, 2021
Currently we call runtimeQPC as ABIInternal because it shaves off 24
bytes by not having an extra wrapper, and at the time we were exceeding
the nosplit stack limit in some cases.

However, this code was written before we had the regabiargs GOEXPERIMENT
flag, and wasn't properly flagged. Naturally, with regabiargs enabled,
it leads to garbage being returned, because it needs to store
runtimeQPC's result to the stack.

We didn't notice this because today runtimeQPC is only used in Wine, not
on any native Windows platform.

Back when I wrote this code, it appeared to be necessary on even native
Windows, but it turns out that's not true anymore. Turn it back into a
native call through a wrapper.

For #40724.

Change-Id: Ia2e5901965ef46c5f299daccef49952026854fe6
Reviewed-on: https://go-review.googlesource.com/c/go/+/312429
Trust: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 22, 2021

Change https://golang.org/cl/312650 mentions this issue: runtime: make nanotime1 ABIInternal on Windows

gopherbot pushed a commit that referenced this issue Apr 22, 2021
Currently, when the runtime printing a stack track (at panic, or
when runtime.Stack is called), it prints the function arguments
as words in memory. With a register-based calling convention,
the layout of argument area of the memory changes, so the
printing also needs to change. In particular, the memory order
and the syntax order of the arguments may differ. To address
that, this CL lets the compiler to emit some metadata about the
memory layout of the arguments, and the runtime will use this
information to print arguments in syntax order.

Previously we print the memory contents of the results along with
the arguments. The results are likely uninitialized when the
traceback is taken, so that information is rarely useful. Also,
with a register-based calling convention the results may not
have corresponding locations in memory. This CL changes it to not
print results.

Previously the runtime simply prints the memory contents as
pointer-sized words. With a register-based calling convention,
as the layout changes, arguments that were packed in one word
may no longer be in one word. Also, as the spill slots are not
always initialized, it is possible that some part of a word
contains useful informationwhile the rest contains garbage.
Instead of letting the runtime recreating the ABI0 layout and
print them as words, we now print each component separately.
Aggregate-typed argument/component is surrounded by "{}".

For example, for a function

F(int, [3]byte, byte) int

when called as F(1, [3]byte{2, 3, 4}, 5), it used to print

F(0x1, 0x5040302, 0xXXXXXXXX) // assuming little endian, 0xXXXXXXXX is uninitilized result

Now prints

F(0x1, {0x2, 0x3, 0x4}, 0x5).

Note: the liveness tracking of the spill splots has not been
implemented in this CL. Currently the runtime just assumes all
the slots are live and print them all.

Increase binary sizes by ~1.5%.

                     old          new
hello (println)    1171328      1187712 (+1.4%)
hello (fmt)        1877024      1901600 (+1.3%)
cmd/compile       22326928     22662800 (+1.5%)
cmd/go            13505024     13726208 (+1.6%)

Updates #40724.

Change-Id: I351e0bf497f99bdbb3f91df2fb17e3c2c5c316dc
Reviewed-on: https://go-review.googlesource.com/c/go/+/304470
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 22, 2021

Change https://golang.org/cl/312869 mentions this issue: cmd/compile: fix bug in defer wrapping

gopherbot pushed a commit that referenced this issue Apr 23, 2021
The defer wrapping feature added to the compiler's "order" phase
creates temporaries into which it copies defer arguments. If one of
these temps is large enough that we place it into the defer closure by
address (as opposed to by value), then the temp in question can't be
reused later on in the order phase, nor do we want a VARKILL
annotation for it at the end of the current block scope.

Test written by Cherry.

Updates #40724.

Change-Id: Iec7efd87ec5a3e3d7de41cdcc7f39c093ed1e815
Reviewed-on: https://go-review.googlesource.com/c/go/+/312869
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
@mvdan
Copy link
Member

@mvdan mvdan commented Apr 23, 2021

Do we have any numbers or guesses as to how this will end up affecting binary sizes? I originally imagined it wouldn't be a significant change either way, but I just noticed https://golang.org/cl/304470 talking about a 1.5% size increase for the sake of stack traces, and it got me thinking.

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 23, 2021

Change https://golang.org/cl/312989 mentions this issue: cmd/compile: spos handling fixes to improve prolog debuggability

@cherrymui
Copy link
Contributor

@cherrymui cherrymui commented Apr 23, 2021

Binary sizes are decreasing, even with that CL. @dr2chase may have better numbers.

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 23, 2021

Change https://golang.org/cl/313071 mentions this issue: dashboard: convert regabi builders to noregabi

gopherbot pushed a commit to golang/build that referenced this issue Apr 23, 2021
Now that GOEXPERIMENT includes regabi by default, there is a need to
make sure that the non-regabi paths for the compiler and runtime
continue to function correctly (in case for some reason we need to
turn regabi off). Switch the *-regabi builders to "noregabi" builders,
so that we have test coverage for this scenario.

Updates golang/go#40724.

Change-Id: Id5c0d4fda2f56393992c90ace463674e86b941ee
Reviewed-on: https://go-review.googlesource.com/c/build/+/313071
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 24, 2021

Change https://golang.org/cl/313212 mentions this issue: cmd/compile: make the stack allocator more careful about register args.

gopherbot pushed a commit that referenced this issue Apr 26, 2021
With the new register ABI, the compiler sometimes introduces spills of
argument registers in function prologs; depending on the positions
assigned to these spills and whether they have the IsStmt flag set,
this can degrade the debugging experience. For example, in this
function from one of the Delve regression tests:

L13:  func foo((eface interface{}) {
L14:	if eface != nil {
L15:		n++
L16:	}
L17   }

we wind up with a prolog containing two spill instructions, the first
with line 14, the second with line 13.  The end result for the user
is that if you set a breakpoint in foo and run to it, then do "step",
execution will initially stop at L14, then jump "backwards" to L13.

The root of the problem in this case is that an ArgIntReg pseudo-op is
introduced during expand calls, then promoted (due to lowering) to a
first-class statement (IsStmt flag set), which in turn causes
downstream handling to propagate its position to the first of the register
spills in the prolog.

To help improve things, this patch changes the rewriter to avoid
moving an "IsStmt" flag from a deleted/replaced instruction to an
Arg{Int,Float}Reg value, and adds Arg{Int,Float}Reg to the list of
opcodes not suitable for selection as statement boundaries, and
suppresses generation of additional register spills in defframe() when
optimization is disabled (since in that case things will get spilled
in any case).

This is not a comprehensive/complete fix; there are still cases where
we get less-than-ideal source position markers (ex: issue 45680).

Updates #40724.

Change-Id: Ica8bba4940b2291bef6b5d95ff0cfd84412a2d40
Reviewed-on: https://go-review.googlesource.com/c/go/+/312989
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 27, 2021

Change https://golang.org/cl/314431 mentions this issue: cmd/compile: regabi support for DWARF location expressions

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 29, 2021

Change https://golang.org/cl/315071 mentions this issue: cmd/compile: handle field padding for register-passed structs

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 30, 2021

Change https://golang.org/cl/315390 mentions this issue: internal/buildcfg: enable regabi for Android

@gopherbot
Copy link

@gopherbot gopherbot commented Apr 30, 2021

Change https://golang.org/cl/315610 mentions this issue: cmd/compile: fix abbrev selection for output params

gopherbot pushed a commit that referenced this issue Apr 30, 2021
This will permit us to write ABIInternal assembler code for linux-amd64.

For #40724

Change-Id: I681866651554eda4229d6faa7f0c1ba42d07e57d
Reviewed-on: https://go-review.googlesource.com/c/go/+/315390
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopherbot pushed a commit that referenced this issue Apr 30, 2021
Revise the code that generates DWARF location expressions for input
parameters to get it to work properly with the new register ABI when
optimization is turned off.

The previously implementation assumed stack locations for all
input+output parameters when -N (disable optimization) was in effect.
In the new implementation, a register-resident input parameter is
given a 2-element location list, the first list element pointing to
the ABI register(s) containing the param, and the second element
pointing to the stack home once it has been spilled.

NB, this change fixes a bunch of the Delve pkg/proc unit tests (maybe
about half of the outstanding failures). Still a good number that need
to be investigated, however.

Updates #40724.
Updates #45720.

Change-Id: I743bbb9af187bcdebeb8e690fdd6db58094ca415
Reviewed-on: https://go-review.googlesource.com/c/go/+/314431
Trust: Than McIntosh <thanm@google.com>
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
gopherbot pushed a commit that referenced this issue Apr 30, 2021
When constructing multi-piece DWARF location expressions for
struct-typed parameters using the register ABI, make sure that the
location expressions generated properly reflect padding between
elements (this is required by debuggers). Example:

   type small struct { x uint16 ; y uint8 ; z int32 }
   func ABC(p1 int, p2 small, f1 float32) {
     ...

In the DWARF location expression for "p2" on entry to the routine, we
need pieces for each field, but for debuggers (such as GDB) to work
properly, we also need to describe the padding between elements. Thus
instead of

  <rbx> DW_OP_piece 2 <rcx> DW_OP_piece 1 <rdi> DW_OP_piece 4

we need to emit

  <rbx> DW_OP_piece 2 <rcx> DW_OP_piece 1 DW_OP_piece 1 <rdi> DW_OP_piece 4

This patch adds a new helper routine in abiutils to compute the
correct padding amounts for a struct type, a unit test for the helper,
and updates the debug generation code to call the helper and insert
apadding "piece" ops in the right spots.

Updates #40724.
Updates #45720.

Change-Id: Ie208bee25776b9eb70642041869e65e4fa65a005
Reviewed-on: https://go-review.googlesource.com/c/go/+/315071
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
gopherbot pushed a commit that referenced this issue Apr 30, 2021
In Cl 302071 we changed the compiler to use a different recipe for
selecting the DWARF frame offset for output parameters, to reflect the
fact that registerized output params don't have a stack memory
location on entry to the function. In the process, however, we
switched from using an abbrev pf DW_ABRV_PARAM to an abbrev of
DW_ABRV_AUTO, which means that Delve can't recognize them correctly.
To fix the problem, switch back to picking the correct abbrev entry,
while leaving the new offset recipe intact.

Updates #40724.
Updates #45720.

Change-Id: If721c9255bcd030177806576cde3450563f7a235
Reviewed-on: https://go-review.googlesource.com/c/go/+/315610
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopherbot pushed a commit that referenced this issue May 3, 2021
Assignment between input parameters causes them to have more than
one "Name", and running this backwards from names to values can end
up confusing (conflating) parameter spill slots.

Around 105a6e9, this cases a stack overflow running
go test -race encoding/pem
because two slice parameters spill (incorrectly) into the same
stack slots (in the AB?I-defined parameter spill area).

This also tickles a failure in cue, which turned out to be
easier to isolate.

Fixes #45851.
Updates #40724.

Change-Id: I39c56815bd6abb652f1ccbe83c47f4f373a125c3
Reviewed-on: https://go-review.googlesource.com/c/go/+/313212
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
gopherbot pushed a commit that referenced this issue May 4, 2021
This is part of getting debugging into good shape
with the register ABI.  (This may generate a backport
for 1.16, there was some regression there as well.)

This is not necessarily fully-baked yet; my goal is to
make it work "well enough" for actual debugging, then
revisit the metrics, which are currently ignorant
of registers used for passing parameters (currently,
rejects them as a valid option).

Updates #40724.

Change-Id: Ib649adf39f947b7b54895c5bf181cf48ca4d38a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/311689
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Proposals
Accepted
Linked pull requests

Successfully merging a pull request may close this issue.

None yet