Udiv *obj.LSym
WriteBarrier *obj.LSym
Zerobase *obj.LSym
+ ZeroVal *obj.LSym
ARM64HasATOMICS *obj.LSym
ARMHasVFPv4 *obj.LSym
Loong64HasLAMCAS *obj.LSym
ir.Syms.Udiv = typecheck.LookupRuntimeVar("udiv") // asm func with special ABI
ir.Syms.WriteBarrier = typecheck.LookupRuntimeVar("writeBarrier") // struct { bool; ... }
ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
+ ir.Syms.ZeroVal = typecheck.LookupRuntimeVar("zeroVal")
if Arch.LinkArch.Family == sys.Wasm {
BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("goPanicIndex")
xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
xe.SetBounded(true)
value = xe
+ case n.Op() == ir.OLINKSYMOFFSET && n.(*ir.LinksymOffsetExpr).Linksym == ir.Syms.ZeroVal && n.(*ir.LinksymOffsetExpr).Offset_ == 0:
+ // n is using zeroVal, so we can use n directly.
+ // (Note that n does not have a proper pos in this case, so using conv for the diagnostic instead.)
+ diagnose("using global for zero value interface value", conv)
+ value = n
case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
// n is a readonly global; use it directly.
diagnose("using global for interface value", n)
import (
"fmt"
"go/constant"
+ "internal/abi"
"internal/buildcfg"
"cmd/compile/internal/base"
return vstat
}
- // Check now for a composite literal to possibly store
- // in the read-only data section.
+ // Check now for a composite literal to possibly store in the read-only data section.
v := staticValue(n)
if v == nil {
v = n
}
- if (v.Op() == ir.OSTRUCTLIT || v.Op() == ir.OARRAYLIT) && isStaticCompositeLiteral(v) && !base.Ctxt.IsFIPS() {
- // v can be directly represented in the read-only data section.
- lit := v.(*ir.CompLitExpr)
- vstat := readonlystaticname(lit.Type())
- fixedlit(inInitFunction, initKindStatic, lit, vstat, nil) // nil init
- vstat = typecheck.Expr(vstat).(*ir.Name)
- return vstat
+ if (v.Op() == ir.OSTRUCTLIT || v.Op() == ir.OARRAYLIT) && !base.Ctxt.IsFIPS() {
+ if ir.IsZero(v) && 0 < v.Type().Size() && v.Type().Size() <= abi.ZeroValSize {
+ // This zero value can be represented by the read-only zeroVal.
+ zeroVal := ir.NewLinksymExpr(v.Pos(), ir.Syms.ZeroVal, v.Type())
+ vstat := typecheck.Expr(zeroVal).(*ir.LinksymOffsetExpr)
+ return vstat
+ }
+ if isStaticCompositeLiteral(v) {
+ // v can be directly represented in the read-only data section.
+ lit := v.(*ir.CompLitExpr)
+ vstat := readonlystaticname(lit.Type())
+ fixedlit(inInitFunction, initKindStatic, lit, vstat, nil) // nil init
+ vstat = typecheck.Expr(vstat).(*ir.Name)
+ return vstat
+ }
}
// Prevent taking the address of an SSA-able local variable (#63332).
. "reflect"
"strconv"
"testing"
+ "time"
)
var sourceAll = struct {
}
}
+// BenchmarkZero overlaps some with BenchmarkSetZero,
+// but the inputs are set up differently to exercise
+// different optimizations.
+func BenchmarkZero(b *testing.B) {
+ type bm struct {
+ name string
+ zero Value
+ nonZero Value
+ size int
+ }
+ type Small struct {
+ A int64
+ B, C bool
+ }
+ type Big struct {
+ A int64
+ B, C bool
+ D [1008]byte
+ }
+ entry := func(name string, zero any, nonZero any) bm {
+ return bm{name, ValueOf(zero), ValueOf(nonZero).Elem(), int(TypeOf(zero).Size())}
+ }
+ nonZeroTime := func() *time.Time { t := time.Now(); return &t }
+
+ bms := []bm{
+ entry("ByteArray", [16]byte{}, &[16]byte{1}),
+ entry("ByteArray", [64]byte{}, &[64]byte{1}),
+ entry("ByteArray", [1024]byte{}, &[1024]byte{1}),
+ entry("BigStruct", Big{}, &Big{A: 1}),
+ entry("SmallStruct", Small{}, &Small{A: 1}),
+ entry("SmallStructArray", [4]Small{}, &[4]Small{0: {A: 1}}),
+ entry("SmallStructArray", [64]Small{}, &[64]Small{0: {A: 1}}),
+ entry("Time", time.Time{}, nonZeroTime()),
+ }
+
+ for _, bm := range bms {
+ b.Run(fmt.Sprintf("IsZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ bm.zero.IsZero()
+ }
+ })
+ }
+ for _, bm := range bms {
+ b.Run(fmt.Sprintf("SetZero/%s/size=%d", bm.name, bm.size), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ bm.nonZero.Set(bm.zero)
+ }
+ })
+ }
+}
+
func BenchmarkSelect(b *testing.B) {
channel := make(chan int)
close(channel)
}
func struct3() {
- sink = S{} // ERROR "using global for interface value"
+ sink = S{} // ERROR "using global for zero value interface value"
}
func struct4() {
v := S{}
- sink = v // ERROR "using global for interface value"
+ sink = v // ERROR "using global for zero value interface value"
}
func struct5() {