1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package test 6 7// This file contains utility routines and harness infrastructure used 8// by the ABI tests in "abiutils_test.go". 9 10import ( 11 "cmd/compile/internal/abi" 12 "cmd/compile/internal/ir" 13 "cmd/compile/internal/typecheck" 14 "cmd/compile/internal/types" 15 "cmd/internal/src" 16 "fmt" 17 "strings" 18 "testing" 19 "text/scanner" 20) 21 22func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field { 23 field := types.NewField(src.NoXPos, s, t) 24 n := ir.NewNameAt(src.NoXPos, s, t) 25 n.Class = which 26 field.Nname = n 27 return field 28} 29 30// mkstruct is a helper routine to create a struct type with fields 31// of the types specified in 'fieldtypes'. 32func mkstruct(fieldtypes ...*types.Type) *types.Type { 33 fields := make([]*types.Field, len(fieldtypes)) 34 for k, t := range fieldtypes { 35 if t == nil { 36 panic("bad -- field has no type") 37 } 38 f := types.NewField(src.NoXPos, nil, t) 39 fields[k] = f 40 } 41 s := types.NewStruct(fields) 42 return s 43} 44 45func mkFuncType(rcvr *types.Type, ins []*types.Type, outs []*types.Type) *types.Type { 46 q := typecheck.Lookup("?") 47 inf := []*types.Field{} 48 for _, it := range ins { 49 inf = append(inf, mkParamResultField(it, q, ir.PPARAM)) 50 } 51 outf := []*types.Field{} 52 for _, ot := range outs { 53 outf = append(outf, mkParamResultField(ot, q, ir.PPARAMOUT)) 54 } 55 var rf *types.Field 56 if rcvr != nil { 57 rf = mkParamResultField(rcvr, q, ir.PPARAM) 58 } 59 return types.NewSignature(rf, inf, outf) 60} 61 62type expectedDump struct { 63 dump string 64 file string 65 line int 66} 67 68func tokenize(src string) []string { 69 var s scanner.Scanner 70 s.Init(strings.NewReader(src)) 71 res := []string{} 72 for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() { 73 res = append(res, s.TokenText()) 74 } 75 return res 76} 77 78func verifyParamResultOffset(t *testing.T, f *types.Field, r abi.ABIParamAssignment, which string, idx int) int { 79 n := f.Nname.(*ir.Name) 80 if n.FrameOffset() != int64(r.Offset()) { 81 t.Errorf("%s %d: got offset %d wanted %d t=%v", 82 which, idx, r.Offset(), n.Offset_, f.Type) 83 return 1 84 } 85 return 0 86} 87 88func makeExpectedDump(e string) expectedDump { 89 return expectedDump{dump: e} 90} 91 92func difftokens(atoks []string, etoks []string) string { 93 if len(atoks) != len(etoks) { 94 return fmt.Sprintf("expected %d tokens got %d", 95 len(etoks), len(atoks)) 96 } 97 for i := 0; i < len(etoks); i++ { 98 if etoks[i] == atoks[i] { 99 continue 100 } 101 102 return fmt.Sprintf("diff at token %d: expected %q got %q", 103 i, etoks[i], atoks[i]) 104 } 105 return "" 106} 107 108func nrtest(t *testing.T, ft *types.Type, expected int) { 109 types.CalcSize(ft) 110 got := configAMD64.NumParamRegs(ft) 111 if got != expected { 112 t.Errorf("]\nexpected num regs = %d, got %d, type %v", expected, got, ft) 113 } 114} 115 116func abitest(t *testing.T, ft *types.Type, exp expectedDump) { 117 118 types.CalcSize(ft) 119 120 // Analyze with full set of registers. 121 regRes := configAMD64.ABIAnalyze(ft, false) 122 regResString := strings.TrimSpace(regRes.String()) 123 124 // Check results. 125 reason := difftokens(tokenize(regResString), tokenize(exp.dump)) 126 if reason != "" { 127 t.Errorf("\nexpected:\n%s\ngot:\n%s\nreason: %s", 128 strings.TrimSpace(exp.dump), regResString, reason) 129 } 130 131} 132