]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/noder: handle unsafe.Sizeof, etc in unified IR
authorMatthew Dempsky <mdempsky@google.com>
Fri, 8 Sep 2023 23:21:17 +0000 (16:21 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 11 Sep 2023 20:48:07 +0000 (20:48 +0000)
Previously, the unified frontend implemented unsafe.Sizeof, etc that
involved derived types by constructing a normal OSIZEOF, etc
expression, including fully instantiating their argument. (When
unsafe.Sizeof is applied to a non-generic type, types2 handles
constant folding it.)

This worked, but involves unnecessary work, since all we really need
to track is the argument type (and the field selections, for
unsafe.Offsetof).

Further, the argument expression could generate temporary variables,
which would then go unused after typecheck replaced the OSIZEOF
expression with an OLITERAL. This results in compiler failures after
CL 523315, which made later passes stricter about expecting the
frontend to not construct unused temporaries.

Fixes #62515.

Change-Id: I37baed048fd2e35648c59243f66c97c24413aa94
Reviewed-on: https://go-review.googlesource.com/c/go/+/527097
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>

src/cmd/compile/internal/ir/const.go
src/cmd/compile/internal/noder/codes.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/writer.go
test/fixedbugs/issue62515.go [new file with mode: 0644]

index 74e55511e48511c934ee23c8b5e4b0dfc353cbd5..e2976714490edd149bb3116306cfc5398affad77 100644 (file)
@@ -29,6 +29,11 @@ func NewString(pos src.XPos, s string) Node {
        return NewBasicLit(pos, types.UntypedString, constant.MakeString(s))
 }
 
+// NewUintptr returns an OLITERAL representing v as a uintptr.
+func NewUintptr(pos src.XPos, v int64) Node {
+       return NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(v))
+}
+
 // NewOne returns an OLITERAL representing 1 with the given type.
 func NewOne(pos src.XPos, typ *types.Type) Node {
        var val constant.Value
index c1ee8d15c5d15b0b55310d0e28a17550cf8ac6ab..764d53e9c5849bcf3fd38a75d5bf57dfb425283b 100644 (file)
@@ -55,6 +55,9 @@ const (
        exprConvert
        exprNew
        exprMake
+       exprSizeof
+       exprAlignof
+       exprOffsetof
        exprNil
        exprFuncInst
        exprRecv
index 4b26eb466880216007ff041ab264d2c6db3f7279..4c7b2e3e51a399a4b592615f63666d96940177f2 100644 (file)
@@ -2459,6 +2459,26 @@ func (r *reader) expr() (res ir.Node) {
                typ := r.exprType()
                return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
 
+       case exprSizeof:
+               return ir.NewUintptr(r.pos(), r.typ().Size())
+
+       case exprAlignof:
+               return ir.NewUintptr(r.pos(), r.typ().Alignment())
+
+       case exprOffsetof:
+               pos := r.pos()
+               typ := r.typ()
+               types.CalcSize(typ)
+
+               var offset int64
+               for i := r.Len(); i >= 0; i-- {
+                       field := typ.Field(r.Len())
+                       offset += field.Offset
+                       typ = field.Type
+               }
+
+               return ir.NewUintptr(pos, offset)
+
        case exprReshape:
                typ := r.typ()
                x := r.expr()
index 044771609d49bc0824ecd9c72faf992aacf82387..c9162e880aa6cb0e9836fc625115c3c430987373 100644 (file)
@@ -1965,6 +1965,39 @@ func (w *writer) expr(expr syntax.Expr) {
                                w.exprType(nil, expr.ArgList[0])
                                return
 
+                       case "Sizeof":
+                               assert(len(expr.ArgList) == 1)
+                               assert(!expr.HasDots)
+
+                               w.Code(exprSizeof)
+                               w.pos(expr)
+                               w.typ(w.p.typeOf(expr.ArgList[0]))
+                               return
+
+                       case "Alignof":
+                               assert(len(expr.ArgList) == 1)
+                               assert(!expr.HasDots)
+
+                               w.Code(exprAlignof)
+                               w.pos(expr)
+                               w.typ(w.p.typeOf(expr.ArgList[0]))
+                               return
+
+                       case "Offsetof":
+                               assert(len(expr.ArgList) == 1)
+                               assert(!expr.HasDots)
+                               selector := syntax.Unparen(expr.ArgList[0]).(*syntax.SelectorExpr)
+                               index := w.p.info.Selections[selector].Index()
+
+                               w.Code(exprOffsetof)
+                               w.pos(expr)
+                               w.typ(deref2(w.p.typeOf(selector.X)))
+                               w.Len(len(index) - 1)
+                               for _, idx := range index {
+                                       w.Len(idx)
+                               }
+                               return
+
                        case "append":
                                rtype = sliceElem(w.p.typeOf(expr))
                        case "copy":
diff --git a/test/fixedbugs/issue62515.go b/test/fixedbugs/issue62515.go
new file mode 100644 (file)
index 0000000..8d9a580
--- /dev/null
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unified frontend generated unnecessary temporaries for expressions
+// within unsafe.Sizeof, etc functions.
+
+package main
+
+import "unsafe"
+
+func F[G int](g G) (uintptr, uintptr, uintptr) {
+       var c chan func() int
+       type s struct {
+               g G
+               x []int
+       }
+       return unsafe.Sizeof(s{g, make([]int, (<-c)())}),
+               unsafe.Alignof(s{g, make([]int, (<-c)())}),
+               unsafe.Offsetof(s{g, make([]int, (<-c)())}.x)
+}
+
+func main() {
+       F(0)
+}