Skip to content

Commit

Permalink
cmd/compile/internal/noder: handle unsafe.Sizeof, etc in unified IR
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mdempsky authored and gopherbot committed Sep 11, 2023
1 parent f72693d commit 2e457b3
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/cmd/compile/internal/ir/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/cmd/compile/internal/noder/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ const (
exprConvert
exprNew
exprMake
exprSizeof
exprAlignof
exprOffsetof
exprNil
exprFuncInst
exprRecv
Expand Down
20 changes: 20 additions & 0 deletions src/cmd/compile/internal/noder/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
33 changes: 33 additions & 0 deletions src/cmd/compile/internal/noder/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down
27 changes: 27 additions & 0 deletions test/fixedbugs/issue62515.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 2e457b3

Please sign in to comment.