From ee40bb666bed55e7232c50a980e238aed7a32e0c Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 5 Apr 2021 09:47:22 -0400 Subject: [PATCH] cmd/compile: add "surprised by IData of Arg" case for register args This fixes a compile crash for GOEXPERIMENT=regabi,regabiargs go test -c go/constant Updates #40724. Change-Id: I238cef436e045647815326fc8fdb025c30ba1f5c Reviewed-on: https://go-review.googlesource.com/c/go/+/307309 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 9 ++ test/abi/idata.go | 97 ++++++++++++++++++++ test/abi/idata.out | 1 + 3 files changed, 107 insertions(+) create mode 100644 test/abi/idata.go create mode 100644 test/abi/idata.out diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index b6683d076d..6a6517deb8 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -317,6 +317,15 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, } } switch selector.Op { + case OpArgIntReg, OpArgFloatReg: + if leafType == selector.Type { // OpIData leads us here, sometimes. + leaf.copyOf(selector) + } else { + x.f.Fatalf("Unexpected %s type, selector=%s, leaf=%s\n", selector.Op.String(), selector.LongString(), leaf.LongString()) + } + if x.debug { + x.Printf("---%s, break\n", selector.Op.String()) + } case OpArg: if !x.isAlreadyExpandedAggregateType(selector.Type) { if leafType == selector.Type { // OpIData leads us here, sometimes. diff --git a/test/abi/idata.go b/test/abi/idata.go new file mode 100644 index 0000000000..af2b87b9d6 --- /dev/null +++ b/test/abi/idata.go @@ -0,0 +1,97 @@ +// run + +// Copyright 2021 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. + +// Excerpted from go/constant/value.go to capture a bug from there. + +package main + +import ( + "fmt" + "math" + "math/big" +) + +type ( + unknownVal struct{} + intVal struct{ val *big.Int } // Int values not representable as an int64 + ratVal struct{ val *big.Rat } // Float values representable as a fraction + floatVal struct{ val *big.Float } // Float values not representable as a fraction + complexVal struct{ re, im Value } +) + +const prec = 512 + +func (unknownVal) String() string { return "unknown" } + +func (x intVal) String() string { return x.val.String() } +func (x ratVal) String() string { return rtof(x).String() } + +func (x floatVal) String() string { + f := x.val + + // Use exact fmt formatting if in float64 range (common case): + // proceed if f doesn't underflow to 0 or overflow to inf. + if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) { + return fmt.Sprintf("%.6g", x) + } + + return "OOPS" +} + +func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) } + +func newFloat() *big.Float { return new(big.Float).SetPrec(prec) } + +//go:noinline +//go:registerparams +func itor(x intVal) ratVal { return ratVal{nil} } + +//go:noinline +//go:registerparams +func itof(x intVal) floatVal { return floatVal{nil} } +func rtof(x ratVal) floatVal { return floatVal{newFloat().SetRat(x.val)} } + +type Value interface { + String() string +} + +//go:noinline +//go:registerparams +func ToFloat(x Value) Value { + switch x := x.(type) { + case intVal: + if smallInt(x.val) { + return itor(x) + } + return itof(x) + case ratVal, floatVal: + return x + case complexVal: + if Sign(x.im) == 0 { + return ToFloat(x.re) + } + } + return unknownVal{} +} + +//go:noinline +//go:registerparams +func smallInt(x *big.Int) bool { + return false +} + +//go:noinline +//go:registerparams +func Sign(x Value) int { + return 0 +} + + +func main() { + v := ratVal{big.NewRat(22,7)} + s := ToFloat(v).String() + fmt.Printf("s=%s\n", s) +} diff --git a/test/abi/idata.out b/test/abi/idata.out new file mode 100644 index 0000000000..98190c2755 --- /dev/null +++ b/test/abi/idata.out @@ -0,0 +1 @@ +s=3.14286