Skip to content

Commit

Permalink
compiler,runtime: pass only ptr and len to some runtime calls
Browse files Browse the repository at this point in the history
This ports https://golang.org/cl/227163 to the Go frontend.
This is a step toward moving up to the go1.15rc1 release.

Original CL description:

    cmd/compile,runtime: pass only ptr and len to some runtime calls

    Some runtime calls accept a slice, but only use ptr and len.
    This change modifies most such routines to accept only ptr and len.

    After this change, the only runtime calls that accept an unnecessary
    cap arg are concatstrings and slicerunetostring.
    Neither is particularly common, and both are complicated to modify.

    Negligible compiler performance impact. Shrinks binaries a little.
    There are only a few regressions; the one I investigated was
    due to register allocation fluctuation.

    Passes 'go test -race std cmd', modulo golang/go#38265 and golang/go#38266.
    Wow, does that take a long time to run.

    file      before    after     Δ       %
    compile   19655024  19655152  +128    +0.001%
    cover     5244840   5236648   -8192   -0.156%
    dist      3662376   3658280   -4096   -0.112%
    link      6680056   6675960   -4096   -0.061%
    pprof     14789844  14777556  -12288  -0.083%
    test2json 2824744   2820648   -4096   -0.145%
    trace     11647876  11639684  -8192   -0.070%
    vet       8260472   8256376   -4096   -0.050%
    total     115163736 115118808 -44928  -0.039%

For golang/go#36890

Change-Id: I1dc1424ccb092a9ad70472e560a743c35dd27bfc
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/245099
Reviewed-by: Cherry Zhang <cherryyz@google.com>
  • Loading branch information
ianlancetaylor committed Jul 28, 2020
1 parent 8b9c7fb commit 63bc243
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 97 deletions.
60 changes: 33 additions & 27 deletions go/expressions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4157,45 +4157,43 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
go_assert(e->integer_type() != NULL);
go_assert(this->expr_->is_variable());

Runtime::Function code;
Expression* buf;
if (this->no_escape_ && !this->no_copy_)
{
Type* byte_type = Type::lookup_integer_type("uint8");
Expression* buflen =
Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
Type* array_type = Type::make_array_type(byte_type, buflen);
buf = Expression::make_allocation(array_type, loc);
buf->allocation_expression()->set_allocate_on_stack();
buf->allocation_expression()->set_no_zero();
}
else
buf = Expression::make_nil(loc);

if (e->integer_type()->is_byte())
{
Expression* ptr =
Expression::make_slice_info(this->expr_, SLICE_INFO_VALUE_POINTER,
loc);
Expression* len =
Expression::make_slice_info(this->expr_, SLICE_INFO_LENGTH, loc);
if (this->no_copy_)
{
if (gogo->debug_optimization())
go_debug(loc, "no copy string([]byte)");
Expression* ptr = Expression::make_slice_info(this->expr_,
SLICE_INFO_VALUE_POINTER,
loc);
Expression* len = Expression::make_slice_info(this->expr_,
SLICE_INFO_LENGTH,
loc);
Expression* str = Expression::make_string_value(ptr, len, loc);
return str->get_backend(context);
}
code = Runtime::SLICEBYTETOSTRING;
return Runtime::make_call(Runtime::SLICEBYTETOSTRING, loc, 3, buf,
ptr, len)->get_backend(context);
}
else
{
go_assert(e->integer_type()->is_rune());
code = Runtime::SLICERUNETOSTRING;
}

Expression* buf;
if (this->no_escape_)
{
Type* byte_type = Type::lookup_integer_type("uint8");
Expression* buflen =
Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
Type* array_type = Type::make_array_type(byte_type, buflen);
buf = Expression::make_allocation(array_type, loc);
buf->allocation_expression()->set_allocate_on_stack();
buf->allocation_expression()->set_no_zero();
}
else
buf = Expression::make_nil(loc);
return Runtime::make_call(code, loc, 2, buf,
this->expr_)->get_backend(context);
return Runtime::make_call(Runtime::SLICERUNETOSTRING, loc, 2, buf,
this->expr_)->get_backend(context);
}
}
else if (type->is_slice_type() && expr_type->is_string_type())
{
Expand Down Expand Up @@ -8397,8 +8395,16 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
if (et->has_pointer())
{
Expression* td = Expression::make_type_descriptor(et, loc);
Expression* pd =
Expression::make_slice_info(arg1, SLICE_INFO_VALUE_POINTER, loc);
Expression* ld =
Expression::make_slice_info(arg1, SLICE_INFO_LENGTH, loc);
Expression* ps =
Expression::make_slice_info(arg2, SLICE_INFO_VALUE_POINTER, loc);
Expression* ls =
Expression::make_slice_info(arg2, SLICE_INFO_LENGTH, loc);
ret = Runtime::make_call(Runtime::TYPEDSLICECOPY, loc,
3, td, arg1, arg2);
5, td, pd, ld, ps, ls);
}
else
{
Expand Down
13 changes: 6 additions & 7 deletions go/runtime.def
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING))

// Convert a []byte to a string.
DEF_GO_RUNTIME(SLICEBYTETOSTRING, "runtime.slicebytetostring",
P2(POINTER, SLICE), R1(STRING))
P3(POINTER, POINTER, INT), R1(STRING))

// Convert a []rune to a string.
DEF_GO_RUNTIME(SLICERUNETOSTRING, "runtime.slicerunetostring",
Expand Down Expand Up @@ -249,17 +249,16 @@ DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0())


// Copy.
DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy", P3(SLICE, SLICE, UINTPTR),
R1(INT))
DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy",
P5(POINTER, INT, POINTER, INT, UINTPTR), R1(INT))

// Copy from string.
DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy", P2(SLICE, STRING),
R1(INT))
DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy",
P3(POINTER, INT, STRING), R1(INT))

// Copy of value containing pointers.
DEF_GO_RUNTIME(TYPEDSLICECOPY, "runtime.typedslicecopy",
P3(TYPE, SLICE, SLICE), R1(INT))

P5(TYPE, POINTER, INT, POINTER, INT), R1(INT))

// Grow a slice for append.
DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice",
Expand Down
13 changes: 7 additions & 6 deletions libgo/go/runtime/cgocheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,24 @@ func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
cgoCheckTypedBlock(typ, src, off, size)
}

// cgoCheckSliceCopy is called when copying n elements of a slice from
// src to dst. typ is the element type of the slice.
// cgoCheckSliceCopy is called when copying n elements of a slice.
// src and dst are pointers to the first element of the slice.
// typ is the element type of the slice.
// It throws if the program is copying slice elements that contain Go pointers
// into non-Go memory.
//go:nosplit
//go:nowritebarrier
func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
func cgoCheckSliceCopy(typ *_type, dst, src unsafe.Pointer, n int) {
if typ.ptrdata == 0 {
return
}
if !cgoIsGoPointer(src.array) {
if !cgoIsGoPointer(src) {
return
}
if cgoIsGoPointer(dst.array) {
if cgoIsGoPointer(dst) {
return
}
p := src.array
p := src
for i := 0; i < n; i++ {
cgoCheckTypedBlock(typ, p, 0, typ.size)
p = add(p, typ.size)
Expand Down
28 changes: 13 additions & 15 deletions libgo/go/runtime/mbarrier.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,16 +219,14 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size
}

//go:nosplit
func typedslicecopy(typ *_type, dst, src slice) int {
n := dst.len
if n > src.len {
n = src.len
func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe.Pointer, srcLen int) int {
n := dstLen
if n > srcLen {
n = srcLen
}
if n == 0 {
return 0
}
dstp := dst.array
srcp := src.array

// The compiler emits calls to typedslicecopy before
// instrumentation runs, so unlike the other copying and
Expand All @@ -237,19 +235,19 @@ func typedslicecopy(typ *_type, dst, src slice) int {
if raceenabled {
callerpc := getcallerpc()
pc := funcPC(slicecopy)
racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
racewriterangepc(dstPtr, uintptr(n)*typ.size, callerpc, pc)
racereadrangepc(srcPtr, uintptr(n)*typ.size, callerpc, pc)
}
if msanenabled {
msanwrite(dstp, uintptr(n)*typ.size)
msanread(srcp, uintptr(n)*typ.size)
msanwrite(dstPtr, uintptr(n)*typ.size)
msanread(srcPtr, uintptr(n)*typ.size)
}

if writeBarrier.cgo {
cgoCheckSliceCopy(typ, dst, src, n)
cgoCheckSliceCopy(typ, dstPtr, srcPtr, n)
}

if dstp == srcp {
if dstPtr == srcPtr {
return n
}

Expand All @@ -259,11 +257,11 @@ func typedslicecopy(typ *_type, dst, src slice) int {
// before calling typedslicecopy.
size := uintptr(n) * typ.size
if writeBarrier.needed {
bulkBarrierPreWrite(uintptr(dstp), uintptr(srcp), size)
bulkBarrierPreWrite(uintptr(dstPtr), uintptr(srcPtr), size)
}
// See typedmemmove for a discussion of the race between the
// barrier and memmove.
memmove(dstp, srcp, size)
memmove(dstPtr, srcPtr, size)
return n
}

Expand Down Expand Up @@ -293,7 +291,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
memmove(dst.array, src.array, size)
return n
}
return typedslicecopy(elemType, dst, src)
return typedslicecopy(elemType, dst.array, dst.len, src.array, src.len)
}

// typedmemclr clears the typed memory at ptr with type typ. The
Expand Down
7 changes: 4 additions & 3 deletions libgo/go/runtime/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,14 @@ func getHugePageSize() uintptr {
if fd < 0 {
return 0
}
n := read(fd, noescape(unsafe.Pointer(&numbuf[0])), int32(len(numbuf)))
ptr := noescape(unsafe.Pointer(&numbuf[0]))
n := read(fd, ptr, int32(len(numbuf)))
closefd(fd)
if n <= 0 {
return 0
}
l := n - 1 // remove trailing newline
v, ok := atoi(slicebytetostringtmp(numbuf[:l]))
n-- // remove trailing newline
v, ok := atoi(slicebytetostringtmp((*byte)(ptr), int(n)))
if !ok || v < 0 {
v = 0
}
Expand Down
36 changes: 18 additions & 18 deletions libgo/go/runtime/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,14 @@ func isPowerOfTwo(x uintptr) bool {
return x&(x-1) == 0
}

func slicecopy(to, fm slice, width uintptr) int {
if fm.len == 0 || to.len == 0 {
func slicecopy(toPtr unsafe.Pointer, toLen int, fmPtr unsafe.Pointer, fmLen int, width uintptr) int {
if fmLen == 0 || toLen == 0 {
return 0
}

n := fm.len
if to.len < n {
n = to.len
n := fmLen
if toLen < n {
n = toLen
}

if width == 0 {
Expand All @@ -216,43 +216,43 @@ func slicecopy(to, fm slice, width uintptr) int {
if raceenabled {
callerpc := getcallerpc()
pc := funcPC(slicecopy)
racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
racewriterangepc(toPtr, uintptr(n*int(width)), callerpc, pc)
racereadrangepc(fmPtr, uintptr(n*int(width)), callerpc, pc)
}
if msanenabled {
msanwrite(to.array, uintptr(n*int(width)))
msanread(fm.array, uintptr(n*int(width)))
msanwrite(toPtr, uintptr(n*int(width)))
msanread(fmPtr, uintptr(n*int(width)))
}

size := uintptr(n) * width
if size == 1 { // common case worth about 2x to do here
// TODO: is this still worth it with new memmove impl?
*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
*(*byte)(toPtr) = *(*byte)(fmPtr) // known to be a byte pointer
} else {
memmove(to.array, fm.array, size)
memmove(toPtr, fmPtr, size)
}
return n
}

func slicestringcopy(to []byte, fm string) int {
if len(fm) == 0 || len(to) == 0 {
func slicestringcopy(toPtr *byte, toLen int, fm string) int {
if len(fm) == 0 || toLen == 0 {
return 0
}

n := len(fm)
if len(to) < n {
n = len(to)
if toLen < n {
n = toLen
}

if raceenabled {
callerpc := getcallerpc()
pc := funcPC(slicestringcopy)
racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
racewriterangepc(unsafe.Pointer(toPtr), uintptr(n), callerpc, pc)
}
if msanenabled {
msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
msanwrite(unsafe.Pointer(toPtr), uintptr(n))
}

memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
memmove(unsafe.Pointer(toPtr), stringStructOf(&fm).str, uintptr(n))
return n
}
Loading

0 comments on commit 63bc243

Please sign in to comment.