// 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.

package noder

import (
	"fmt"

	"cmd/compile/internal/types"
	"cmd/compile/internal/types2"
)

// Code below based on go/types.StdSizes.
// Intentional differences are marked with "gc:".

type gcSizes struct{}

func (s *gcSizes) Alignof(T types2.Type) int64 {
	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := T.Underlying().(type) {
	case *types2.Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return s.Alignof(t.Elem())
	case *types2.Struct:
		if t.NumFields() == 0 && types2.IsSyncAtomicAlign64(T) {
			// Special case: sync/atomic.align64 is an
			// empty struct we recognize as a signal that
			// the struct it contains must be
			// 64-bit-aligned.
			//
			// This logic is equivalent to the logic in
			// cmd/compile/internal/types/size.go:calcStructOffset
			return 8
		}

		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		max := int64(1)
		for i, nf := 0, t.NumFields(); i < nf; i++ {
			if a := s.Alignof(t.Field(i).Type()); a > max {
				max = a
			}
		}
		return max
	case *types2.Slice, *types2.Interface:
		// Multiword data structures are effectively structs
		// in which each element has size PtrSize.
		return int64(types.PtrSize)
	case *types2.Basic:
		// Strings are like slices and interfaces.
		if t.Info()&types2.IsString != 0 {
			return int64(types.PtrSize)
		}
	}
	a := s.Sizeof(T) // may be 0
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if a < 1 {
		return 1
	}
	// complex{64,128} are aligned like [2]float{32,64}.
	if isComplex(T) {
		a /= 2
	}
	if a > int64(types.RegSize) {
		return int64(types.RegSize)
	}
	return a
}

func isComplex(T types2.Type) bool {
	basic, ok := T.Underlying().(*types2.Basic)
	return ok && basic.Info()&types2.IsComplex != 0
}

func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
	offsets := make([]int64, len(fields))
	var offs int64
	for i, f := range fields {
		if offs < 0 {
			// all remaining offsets are too large
			offsets[i] = -1
			continue
		}
		// offs >= 0
		typ := f.Type()
		a := s.Alignof(typ)
		offs = types.RoundUp(offs, a) // possibly < 0 if align overflows
		offsets[i] = offs
		if d := s.Sizeof(typ); d >= 0 && offs >= 0 {
			offs += d // ok to overflow to < 0
		} else {
			offs = -1
		}
	}
	return offsets
}

func (s *gcSizes) Sizeof(T types2.Type) int64 {
	switch t := T.Underlying().(type) {
	case *types2.Basic:
		k := t.Kind()
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		switch k {
		case types2.String:
			return int64(types.PtrSize) * 2
		case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer:
			return int64(types.PtrSize)
		}
		panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k))
	case *types2.Array:
		n := t.Len()
		if n <= 0 {
			return 0
		}
		// n > 0
		// gc: Size includes alignment padding.
		esize := s.Sizeof(t.Elem())
		if esize < 0 {
			return -1 // array element too large
		}
		if esize == 0 {
			return 0 // 0-size element
		}
		// esize > 0
		// Final size is esize * n; and size must be <= maxInt64.
		const maxInt64 = 1<<63 - 1
		if esize > maxInt64/n {
			return -1 // esize * n overflows
		}
		return esize * n
	case *types2.Slice:
		return int64(types.PtrSize) * 3
	case *types2.Struct:
		n := t.NumFields()
		if n == 0 {
			return 0
		}
		fields := make([]*types2.Var, n)
		for i := range fields {
			fields[i] = t.Field(i)
		}
		offsets := s.Offsetsof(fields)

		// gc: The last field of a non-zero-sized struct is not allowed to
		// have size 0.
		last := s.Sizeof(fields[n-1].Type())
		if last == 0 && offsets[n-1] > 0 {
			last = 1
		}

		// gc: Size includes alignment padding.
		return types.RoundUp(offsets[n-1]+last, s.Alignof(t)) // may overflow to < 0 which is ok
	case *types2.Interface:
		return int64(types.PtrSize) * 2
	case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
		return int64(types.PtrSize)
	default:
		panic(fmt.Sprintf("unimplemented type: %T", t))
	}
}

var basicSizes = [...]byte{
	types2.Invalid:    1,
	types2.Bool:       1,
	types2.Int8:       1,
	types2.Int16:      2,
	types2.Int32:      4,
	types2.Int64:      8,
	types2.Uint8:      1,
	types2.Uint16:     2,
	types2.Uint32:     4,
	types2.Uint64:     8,
	types2.Float32:    4,
	types2.Float64:    8,
	types2.Complex64:  8,
	types2.Complex128: 16,
}
