[dev.regabi] cmd/compile: refactor abiutils from "gc" into new "abi"
Needs to be visible to ssagen, and might as well start clean to avoid
creating a lot of accidental dependencies.
Added some methods for export.
Decided to use a pointer instead of value for ABIConfig uses.
Tests ended up separate from abiutil itself; otherwise there are import cycles.
Change-Id: I5570e1e6a463e303c5e2dc84e8dd4125e7c1adcc
Reviewed-on: https://go-review.googlesource.com/c/go/+/282614
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
diff --git a/src/cmd/compile/internal/test/abiutils_test.go b/src/cmd/compile/internal/test/abiutils_test.go
new file mode 100644
index 0000000..ae7d484
--- /dev/null
+++ b/src/cmd/compile/internal/test/abiutils_test.go
@@ -0,0 +1,269 @@
+// Copyright 2020 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.
+
+package test
+
+import (
+ "bufio"
+ "cmd/compile/internal/abi"
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ssagen"
+ "cmd/compile/internal/typecheck"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/obj/x86"
+ "cmd/internal/src"
+ "os"
+ "testing"
+)
+
+// AMD64 registers available:
+// - integer: RAX, RBX, RCX, RDI, RSI, R8, R9, r10, R11
+// - floating point: X0 - X14
+var configAMD64 = abi.NewABIConfig(9,15)
+
+func TestMain(m *testing.M) {
+ ssagen.Arch.LinkArch = &x86.Linkamd64
+ ssagen.Arch.REGSP = x86.REGSP
+ ssagen.Arch.MAXWIDTH = 1 << 50
+ types.MaxWidth = ssagen.Arch.MAXWIDTH
+ base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
+ base.Ctxt.DiagFunc = base.Errorf
+ base.Ctxt.DiagFlush = base.FlushErrors
+ base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
+ types.PtrSize = ssagen.Arch.LinkArch.PtrSize
+ types.RegSize = ssagen.Arch.LinkArch.RegSize
+ typecheck.InitUniverse()
+ os.Exit(m.Run())
+}
+
+func TestABIUtilsBasic1(t *testing.T) {
+
+ // func(x int32) int32
+ i32 := types.Types[types.TINT32]
+ ft := mkFuncType(nil, []*types.Type{i32}, []*types.Type{i32})
+
+ // expected results
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 } offset: -1 typ: int32
+ OUT 0: R{ I0 } offset: -1 typ: int32
+ intspill: 1 floatspill: 0 offsetToSpillArea: 0
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsBasic2(t *testing.T) {
+ // func(x int32, y float64) (int32, float64, float64)
+ i8 := types.Types[types.TINT8]
+ i16 := types.Types[types.TINT16]
+ i32 := types.Types[types.TINT32]
+ i64 := types.Types[types.TINT64]
+ f32 := types.Types[types.TFLOAT32]
+ f64 := types.Types[types.TFLOAT64]
+ c64 := types.Types[types.TCOMPLEX64]
+ c128 := types.Types[types.TCOMPLEX128]
+ ft := mkFuncType(nil,
+ []*types.Type{
+ i8, i16, i32, i64,
+ f32, f32, f64, f64,
+ i8, i16, i32, i64,
+ f32, f32, f64, f64,
+ c128, c128, c128, c128, c64,
+ i8, i16, i32, i64,
+ i8, i16, i32, i64},
+ []*types.Type{i32, f64, f64})
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 } offset: -1 typ: int8
+ IN 1: R{ I1 } offset: -1 typ: int16
+ IN 2: R{ I2 } offset: -1 typ: int32
+ IN 3: R{ I3 } offset: -1 typ: int64
+ IN 4: R{ F0 } offset: -1 typ: float32
+ IN 5: R{ F1 } offset: -1 typ: float32
+ IN 6: R{ F2 } offset: -1 typ: float64
+ IN 7: R{ F3 } offset: -1 typ: float64
+ IN 8: R{ I4 } offset: -1 typ: int8
+ IN 9: R{ I5 } offset: -1 typ: int16
+ IN 10: R{ I6 } offset: -1 typ: int32
+ IN 11: R{ I7 } offset: -1 typ: int64
+ IN 12: R{ F4 } offset: -1 typ: float32
+ IN 13: R{ F5 } offset: -1 typ: float32
+ IN 14: R{ F6 } offset: -1 typ: float64
+ IN 15: R{ F7 } offset: -1 typ: float64
+ IN 16: R{ F8 F9 } offset: -1 typ: complex128
+ IN 17: R{ F10 F11 } offset: -1 typ: complex128
+ IN 18: R{ F12 F13 } offset: -1 typ: complex128
+ IN 19: R{ } offset: 0 typ: complex128
+ IN 20: R{ F14 } offset: -1 typ: complex64
+ IN 21: R{ I8 } offset: -1 typ: int8
+ IN 22: R{ } offset: 16 typ: int16
+ IN 23: R{ } offset: 20 typ: int32
+ IN 24: R{ } offset: 24 typ: int64
+ IN 25: R{ } offset: 32 typ: int8
+ IN 26: R{ } offset: 34 typ: int16
+ IN 27: R{ } offset: 36 typ: int32
+ IN 28: R{ } offset: 40 typ: int64
+ OUT 0: R{ I0 } offset: -1 typ: int32
+ OUT 1: R{ F0 } offset: -1 typ: float64
+ OUT 2: R{ F1 } offset: -1 typ: float64
+ intspill: 9 floatspill: 15 offsetToSpillArea: 48
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsArrays(t *testing.T) {
+ i32 := types.Types[types.TINT32]
+ ae := types.NewArray(i32, 0)
+ a1 := types.NewArray(i32, 1)
+ a2 := types.NewArray(i32, 2)
+ aa1 := types.NewArray(a1, 1)
+ ft := mkFuncType(nil, []*types.Type{a1, ae, aa1, a2},
+ []*types.Type{a2, a1, ae, aa1})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 } offset: -1 typ: [1]int32
+ IN 1: R{ } offset: 0 typ: [0]int32
+ IN 2: R{ I1 } offset: -1 typ: [1][1]int32
+ IN 3: R{ } offset: 0 typ: [2]int32
+ OUT 0: R{ } offset: 8 typ: [2]int32
+ OUT 1: R{ I0 } offset: -1 typ: [1]int32
+ OUT 2: R{ } offset: 16 typ: [0]int32
+ OUT 3: R{ I1 } offset: -1 typ: [1][1]int32
+ intspill: 2 floatspill: 0 offsetToSpillArea: 16
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsStruct1(t *testing.T) {
+ i8 := types.Types[types.TINT8]
+ i16 := types.Types[types.TINT16]
+ i32 := types.Types[types.TINT32]
+ i64 := types.Types[types.TINT64]
+ s := mkstruct([]*types.Type{i8, i8, mkstruct([]*types.Type{}), i8, i16})
+ ft := mkFuncType(nil, []*types.Type{i8, s, i64},
+ []*types.Type{s, i8, i32})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 } offset: -1 typ: int8
+ IN 1: R{ I1 I2 I3 I4 } offset: -1 typ: struct { int8; int8; struct {}; int8; int16 }
+ IN 2: R{ I5 } offset: -1 typ: int64
+ OUT 0: R{ I0 I1 I2 I3 } offset: -1 typ: struct { int8; int8; struct {}; int8; int16 }
+ OUT 1: R{ I4 } offset: -1 typ: int8
+ OUT 2: R{ I5 } offset: -1 typ: int32
+ intspill: 6 floatspill: 0 offsetToSpillArea: 0
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsStruct2(t *testing.T) {
+ f64 := types.Types[types.TFLOAT64]
+ i64 := types.Types[types.TINT64]
+ s := mkstruct([]*types.Type{i64, mkstruct([]*types.Type{})})
+ fs := mkstruct([]*types.Type{f64, s, mkstruct([]*types.Type{})})
+ ft := mkFuncType(nil, []*types.Type{s, s, fs},
+ []*types.Type{fs, fs})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 } offset: -1 typ: struct { int64; struct {} }
+ IN 1: R{ I1 } offset: -1 typ: struct { int64; struct {} }
+ IN 2: R{ I2 F0 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ OUT 0: R{ I0 F0 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ OUT 1: R{ I1 F1 } offset: -1 typ: struct { float64; struct { int64; struct {} }; struct {} }
+ intspill: 3 floatspill: 1 offsetToSpillArea: 0
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsSliceString(t *testing.T) {
+ i32 := types.Types[types.TINT32]
+ sli32 := types.NewSlice(i32)
+ str := types.New(types.TSTRING)
+ i8 := types.Types[types.TINT8]
+ i64 := types.Types[types.TINT64]
+ ft := mkFuncType(nil, []*types.Type{sli32, i8, sli32, i8, str, i8, i64, sli32},
+ []*types.Type{str, i64, str, sli32})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 I1 I2 } offset: -1 typ: []int32
+ IN 1: R{ I3 } offset: -1 typ: int8
+ IN 2: R{ I4 I5 I6 } offset: -1 typ: []int32
+ IN 3: R{ I7 } offset: -1 typ: int8
+ IN 4: R{ } offset: 0 typ: string
+ IN 5: R{ I8 } offset: -1 typ: int8
+ IN 6: R{ } offset: 16 typ: int64
+ IN 7: R{ } offset: 24 typ: []int32
+ OUT 0: R{ I0 I1 } offset: -1 typ: string
+ OUT 1: R{ I2 } offset: -1 typ: int64
+ OUT 2: R{ I3 I4 } offset: -1 typ: string
+ OUT 3: R{ I5 I6 I7 } offset: -1 typ: []int32
+ intspill: 9 floatspill: 0 offsetToSpillArea: 48
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsMethod(t *testing.T) {
+ i16 := types.Types[types.TINT16]
+ i64 := types.Types[types.TINT64]
+ f64 := types.Types[types.TFLOAT64]
+
+ s1 := mkstruct([]*types.Type{i16, i16, i16})
+ ps1 := types.NewPtr(s1)
+ a7 := types.NewArray(ps1, 7)
+ ft := mkFuncType(s1, []*types.Type{ps1, a7, f64, i16, i16, i16},
+ []*types.Type{a7, f64, i64})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 I1 I2 } offset: -1 typ: struct { int16; int16; int16 }
+ IN 1: R{ I3 } offset: -1 typ: *struct { int16; int16; int16 }
+ IN 2: R{ } offset: 0 typ: [7]*struct { int16; int16; int16 }
+ IN 3: R{ F0 } offset: -1 typ: float64
+ IN 4: R{ I4 } offset: -1 typ: int16
+ IN 5: R{ I5 } offset: -1 typ: int16
+ IN 6: R{ I6 } offset: -1 typ: int16
+ OUT 0: R{ } offset: 56 typ: [7]*struct { int16; int16; int16 }
+ OUT 1: R{ F0 } offset: -1 typ: float64
+ OUT 2: R{ I0 } offset: -1 typ: int64
+ intspill: 7 floatspill: 1 offsetToSpillArea: 112
+`)
+
+ abitest(t, ft, exp)
+}
+
+func TestABIUtilsInterfaces(t *testing.T) {
+ ei := types.Types[types.TINTER] // interface{}
+ pei := types.NewPtr(ei) // *interface{}
+ fldt := mkFuncType(types.FakeRecvType(), []*types.Type{},
+ []*types.Type{types.UntypedString})
+ field := types.NewField(src.NoXPos, nil, fldt)
+ // interface{ ...() string }
+ nei := types.NewInterface(types.LocalPkg, []*types.Field{field})
+
+ i16 := types.Types[types.TINT16]
+ tb := types.Types[types.TBOOL]
+ s1 := mkstruct([]*types.Type{i16, i16, tb})
+
+ ft := mkFuncType(nil, []*types.Type{s1, ei, ei, nei, pei, nei, i16},
+ []*types.Type{ei, nei, pei})
+
+ exp := makeExpectedDump(`
+ IN 0: R{ I0 I1 I2 } offset: -1 typ: struct { int16; int16; bool }
+ IN 1: R{ I3 I4 } offset: -1 typ: interface {}
+ IN 2: R{ I5 I6 } offset: -1 typ: interface {}
+ IN 3: R{ I7 I8 } offset: -1 typ: interface { () untyped string }
+ IN 4: R{ } offset: 0 typ: *interface {}
+ IN 5: R{ } offset: 8 typ: interface { () untyped string }
+ IN 6: R{ } offset: 24 typ: int16
+ OUT 0: R{ I0 I1 } offset: -1 typ: interface {}
+ OUT 1: R{ I2 I3 } offset: -1 typ: interface { () untyped string }
+ OUT 2: R{ I4 } offset: -1 typ: *interface {}
+ intspill: 9 floatspill: 0 offsetToSpillArea: 32
+`)
+
+ abitest(t, ft, exp)
+}