Files
llgo/ssa/type.go

421 lines
9.2 KiB
Go
Raw Normal View History

2024-04-15 04:00:38 +08:00
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2024-04-15 17:12:30 +08:00
package ssa
2024-04-15 04:00:38 +08:00
import (
2024-04-25 21:44:23 +08:00
"fmt"
2024-04-15 04:00:38 +08:00
"go/types"
2024-04-15 05:48:48 +08:00
"github.com/goplus/llvm"
2024-04-15 04:00:38 +08:00
)
2024-04-27 13:57:21 +08:00
var (
tyAny = types.NewInterfaceType(nil, nil)
)
2024-04-18 15:03:10 +08:00
// -----------------------------------------------------------------------------
2024-04-19 00:05:57 +08:00
type valueKind = int
const (
vkInvalid valueKind = iota
vkSigned
vkUnsigned
vkFloat
vkComplex
vkString
vkBool
2024-04-28 07:08:01 +08:00
vkPtr
vkFuncDecl
vkFuncPtr
2024-05-05 12:11:51 +08:00
vkClosure
2024-05-12 23:08:44 +08:00
vkPyFuncRef
2024-05-15 18:32:50 +08:00
vkPyVarRef
2024-04-19 00:05:57 +08:00
vkTuple
2024-05-15 10:29:06 +08:00
vkSlice
2024-05-15 21:26:53 +08:00
vkArray
vkMap
vkEface
vkIface
vkStruct
2024-05-09 06:48:16 +08:00
vkPhisExpr = -1
2024-04-19 00:05:57 +08:00
)
// -----------------------------------------------------------------------------
2024-04-21 15:12:57 +08:00
func indexType(t types.Type) types.Type {
switch t := t.(type) {
case *types.Slice:
return t.Elem()
case *types.Pointer:
switch t := t.Elem().(type) {
case *types.Array:
return t.Elem()
}
case *types.Array:
return t.Elem()
}
panic("index: type doesn't support index - " + t.String())
}
2024-04-20 13:50:48 +08:00
// -----------------------------------------------------------------------------
2024-05-05 12:11:51 +08:00
type rawType struct {
2024-05-23 01:34:48 +08:00
Type types.Type
2024-05-05 12:11:51 +08:00
}
2024-04-18 15:03:10 +08:00
type aType struct {
ll llvm.Type
2024-05-05 12:11:51 +08:00
raw rawType
kind valueKind // value kind of llvm.Type
2024-04-15 04:00:38 +08:00
}
2024-04-18 15:03:10 +08:00
type Type = *aType
2024-05-05 12:11:51 +08:00
// RawType returns the raw type.
func (t Type) RawType() types.Type {
return t.raw.Type
}
2024-05-03 23:10:02 +08:00
// TODO(xsw):
// how to generate platform independent code?
func (p Program) SizeOf(typ Type, n ...int64) uint64 {
2024-05-04 07:21:07 +08:00
size := p.td.TypeAllocSize(typ.ll)
2024-05-03 23:10:02 +08:00
if len(n) != 0 {
size *= uint64(n[0])
}
return size
}
// OffsetOf returns the offset of a field in a struct.
func (p Program) OffsetOf(typ Type, i int) uint64 {
return p.td.ElementOffset(typ.ll, i)
}
// SizeOf returns the size of a type.
func SizeOf(prog Program, t Type, n ...int64) Expr {
size := prog.SizeOf(t, n...)
return prog.IntVal(size, prog.Uintptr())
}
func OffsetOf(prog Program, t Type, i int) Expr {
offset := prog.OffsetOf(t, i)
return prog.IntVal(offset, prog.Uintptr())
}
func (p Program) PointerSize() int {
return p.td.PointerSize()
}
2024-04-30 08:23:55 +08:00
func (p Program) Slice(typ Type) Type {
2024-05-05 12:11:51 +08:00
return p.rawType(types.NewSlice(typ.raw.Type))
2024-04-30 08:23:55 +08:00
}
2024-04-21 15:12:57 +08:00
func (p Program) Pointer(typ Type) Type {
2024-05-05 12:11:51 +08:00
return p.rawType(types.NewPointer(typ.raw.Type))
2024-04-21 15:12:57 +08:00
}
func (p Program) Elem(typ Type) Type {
2024-05-15 10:29:06 +08:00
elem := typ.raw.Type.(interface {
Elem() types.Type
}).Elem()
2024-05-05 12:11:51 +08:00
return p.rawType(elem)
2024-04-21 15:12:57 +08:00
}
func (p Program) Index(typ Type) Type {
2024-05-05 12:11:51 +08:00
return p.rawType(indexType(typ.raw.Type))
2024-04-21 15:12:57 +08:00
}
2024-04-27 07:47:10 +08:00
func (p Program) Field(typ Type, i int) Type {
var fld *types.Var
switch t := typ.raw.Type.(type) {
case *types.Tuple:
fld = t.At(i)
default:
fld = t.Underlying().(*types.Struct).Field(i)
}
return p.rawType(fld.Type())
2024-04-27 07:47:10 +08:00
}
2024-05-05 12:11:51 +08:00
func (p Program) rawType(raw types.Type) Type {
if v := p.typs.At(raw); v != nil {
2024-04-18 15:03:10 +08:00
return v.(Type)
2024-04-15 04:00:38 +08:00
}
2024-05-05 12:11:51 +08:00
ret := p.toType(raw)
p.typs.Set(raw, ret)
2024-04-15 04:00:38 +08:00
return ret
}
2024-04-18 15:03:10 +08:00
func (p Program) tyVoidPtr() llvm.Type {
2024-04-16 03:05:20 +08:00
if p.voidPtrTy.IsNil() {
p.voidPtrTy = llvm.PointerType(p.tyVoid(), 0)
}
return p.voidPtrTy
}
2024-04-18 15:03:10 +08:00
func (p Program) tyVoid() llvm.Type {
2024-04-16 03:05:20 +08:00
if p.voidType.IsNil() {
p.voidType = p.ctx.VoidType()
}
return p.voidType
}
2024-04-18 15:03:10 +08:00
func (p Program) tyInt1() llvm.Type {
if p.int1Type.IsNil() {
p.int1Type = p.ctx.Int1Type()
}
return p.int1Type
}
func (p Program) tyInt() llvm.Type {
2024-04-15 04:00:38 +08:00
if p.intType.IsNil() {
p.intType = llvmIntType(p.ctx, p.td.PointerSize())
}
return p.intType
}
2024-04-18 15:03:10 +08:00
func llvmIntType(ctx llvm.Context, size int) llvm.Type {
if size <= 4 {
return ctx.Int32Type()
}
return ctx.Int64Type()
}
func (p Program) tyInt8() llvm.Type {
2024-04-15 04:00:38 +08:00
if p.int8Type.IsNil() {
p.int8Type = p.ctx.Int8Type()
}
return p.int8Type
}
2024-04-18 15:03:10 +08:00
func (p Program) tyInt16() llvm.Type {
2024-04-15 04:00:38 +08:00
if p.int16Type.IsNil() {
p.int16Type = p.ctx.Int16Type()
}
return p.int16Type
}
2024-04-18 15:03:10 +08:00
func (p Program) tyInt32() llvm.Type {
2024-04-15 04:00:38 +08:00
if p.int32Type.IsNil() {
p.int32Type = p.ctx.Int32Type()
}
return p.int32Type
}
2024-04-18 15:03:10 +08:00
func (p Program) tyInt64() llvm.Type {
2024-04-15 04:00:38 +08:00
if p.int64Type.IsNil() {
p.int64Type = p.ctx.Int64Type()
}
return p.int64Type
}
/*
2024-05-10 13:25:36 +08:00
func (p Program) toTuple(typ *types.Tuple) Type {
return &aType{p.toLLVMTuple(typ), rawType{typ}, vkTuple}
}
*/
2024-05-10 13:25:36 +08:00
2024-05-05 12:11:51 +08:00
func (p Program) toType(raw types.Type) Type {
typ := rawType{raw}
switch t := raw.(type) {
2024-04-15 04:00:38 +08:00
case *types.Basic:
switch t.Kind() {
2024-04-18 15:03:10 +08:00
case types.Int:
return &aType{p.tyInt(), typ, vkSigned}
case types.Uint, types.Uintptr:
return &aType{p.tyInt(), typ, vkUnsigned}
case types.Bool:
return &aType{p.tyInt1(), typ, vkBool}
case types.Uint8:
return &aType{p.tyInt8(), typ, vkUnsigned}
case types.Int8:
return &aType{p.tyInt8(), typ, vkSigned}
case types.Int16:
return &aType{p.tyInt16(), typ, vkSigned}
case types.Uint16:
return &aType{p.tyInt16(), typ, vkUnsigned}
case types.Int32:
return &aType{p.tyInt32(), typ, vkSigned}
case types.Uint32:
return &aType{p.tyInt32(), typ, vkUnsigned}
case types.Int64:
return &aType{p.tyInt64(), typ, vkSigned}
case types.Uint64:
return &aType{p.tyInt64(), typ, vkUnsigned}
2024-04-15 04:00:38 +08:00
case types.Float32:
2024-04-18 15:03:10 +08:00
return &aType{p.ctx.FloatType(), typ, vkFloat}
2024-04-15 04:00:38 +08:00
case types.Float64:
2024-04-18 15:03:10 +08:00
return &aType{p.ctx.DoubleType(), typ, vkFloat}
2024-04-15 04:00:38 +08:00
case types.Complex64:
case types.Complex128:
case types.String:
return &aType{p.rtString(), typ, vkString}
2024-04-15 04:00:38 +08:00
case types.UnsafePointer:
2024-04-28 07:08:01 +08:00
return &aType{p.tyVoidPtr(), typ, vkPtr}
2024-04-15 04:00:38 +08:00
}
2024-04-16 03:05:20 +08:00
case *types.Pointer:
2024-05-05 12:11:51 +08:00
elem := p.rawType(t.Elem())
2024-04-28 07:08:01 +08:00
return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr}
2024-04-27 13:57:21 +08:00
case *types.Interface:
if t.Empty() {
return &aType{p.rtEface(), typ, vkEface}
}
2024-04-16 03:05:20 +08:00
case *types.Slice:
2024-05-15 10:29:06 +08:00
return &aType{p.rtSlice(), typ, vkSlice}
2024-04-16 03:05:20 +08:00
case *types.Map:
2024-05-15 21:26:53 +08:00
return &aType{p.rtMap(), typ, vkMap}
2024-04-16 03:05:20 +08:00
case *types.Struct:
2024-05-05 13:29:20 +08:00
ll, kind := p.toLLVMStruct(t)
return &aType{ll, typ, kind}
2024-04-16 03:05:20 +08:00
case *types.Named:
2024-05-05 12:11:51 +08:00
return p.toNamed(t)
case *types.Signature: // represents a C function pointer in raw type
return &aType{p.toLLVMFuncPtr(t), typ, vkFuncPtr}
2024-05-23 01:34:48 +08:00
case *types.Tuple:
return &aType{p.toLLVMTuple(t), typ, vkTuple}
2024-04-16 03:05:20 +08:00
case *types.Array:
2024-05-05 12:11:51 +08:00
elem := p.rawType(t.Elem())
2024-05-15 21:26:53 +08:00
return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkArray}
2024-04-16 03:05:20 +08:00
case *types.Chan:
2024-04-15 04:00:38 +08:00
}
2024-05-23 01:34:48 +08:00
panic(fmt.Sprintf("toLLVMType: todo - %T\n", raw))
2024-04-15 04:00:38 +08:00
}
2024-05-05 12:11:51 +08:00
func (p Program) toLLVMNamedStruct(name string, raw *types.Struct) llvm.Type {
2024-05-11 12:03:02 +08:00
if typ, ok := p.named[name]; ok {
return typ
}
2024-04-16 03:05:20 +08:00
t := p.ctx.StructCreateNamed(name)
2024-05-11 12:03:02 +08:00
p.named[name] = t
2024-05-05 12:11:51 +08:00
fields := p.toLLVMFields(raw)
2024-04-16 03:05:20 +08:00
t.StructSetBody(fields, false)
return t
}
2024-05-05 13:29:20 +08:00
func (p Program) toLLVMStruct(raw *types.Struct) (ret llvm.Type, kind valueKind) {
2024-05-05 12:11:51 +08:00
fields := p.toLLVMFields(raw)
2024-05-05 13:29:20 +08:00
ret = p.ctx.StructType(fields, false)
if isClosure(raw) {
kind = vkClosure
} else {
kind = vkStruct
2024-05-05 13:29:20 +08:00
}
return
}
func isClosure(raw *types.Struct) bool {
n := raw.NumFields()
if n == 2 {
if _, ok := raw.Field(0).Type().(*types.Signature); ok {
return raw.Field(1).Type() == types.Typ[types.UnsafePointer]
}
}
return false
2024-04-16 03:05:20 +08:00
}
2024-05-05 12:11:51 +08:00
func (p Program) toLLVMFields(raw *types.Struct) (fields []llvm.Type) {
n := raw.NumFields()
2024-04-20 13:50:48 +08:00
if n > 0 {
fields = make([]llvm.Type, n)
for i := 0; i < n; i++ {
2024-05-05 12:11:51 +08:00
fields[i] = p.rawType(raw.Field(i).Type()).ll
2024-04-20 13:50:48 +08:00
}
2024-04-16 03:05:20 +08:00
}
2024-04-20 13:50:48 +08:00
return
2024-04-16 03:05:20 +08:00
}
2024-04-18 15:03:10 +08:00
func (p Program) toLLVMTuple(t *types.Tuple) llvm.Type {
2024-04-20 13:50:48 +08:00
return p.ctx.StructType(p.toLLVMTypes(t, t.Len()), false)
2024-04-16 03:05:20 +08:00
}
2024-04-20 13:50:48 +08:00
func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
if n > 0 {
ret = make([]llvm.Type, n)
for i := 0; i < n; i++ {
2024-05-05 12:11:51 +08:00
ret[i] = p.rawType(t.At(i).Type()).ll
2024-04-20 13:50:48 +08:00
}
2024-04-16 03:05:20 +08:00
}
2024-04-20 13:50:48 +08:00
return
2024-04-16 03:05:20 +08:00
}
2024-05-05 12:11:51 +08:00
func (p Program) toLLVMFunc(sig *types.Signature) llvm.Type {
tParams := sig.Params()
n := tParams.Len()
2024-05-15 13:09:43 +08:00
hasVArg := sig.Variadic()
2024-05-05 12:11:51 +08:00
if hasVArg {
n--
}
2024-05-05 12:11:51 +08:00
params := p.toLLVMTypes(tParams, n)
out := sig.Results()
var ret llvm.Type
switch nret := out.Len(); nret {
case 0:
ret = p.tyVoid()
case 1:
ret = p.rawType(out.At(0).Type()).ll
default:
ret = p.toLLVMTuple(out)
2024-05-04 07:21:07 +08:00
}
2024-05-05 12:11:51 +08:00
return llvm.FunctionType(ret, params, hasVArg)
2024-04-16 03:05:20 +08:00
}
2024-05-05 12:11:51 +08:00
func (p Program) toLLVMFuncPtr(sig *types.Signature) llvm.Type {
ft := p.toLLVMFunc(sig)
return llvm.PointerType(ft, 0)
}
func (p Program) retType(raw *types.Signature) Type {
out := raw.Results()
2024-04-19 00:05:57 +08:00
switch n := out.Len(); n {
case 0:
return p.Void()
case 1:
2024-05-05 12:11:51 +08:00
return p.rawType(out.At(0).Type())
2024-04-19 00:05:57 +08:00
default:
2024-05-05 12:11:51 +08:00
return &aType{p.toLLVMTuple(out), rawType{out}, vkTuple}
2024-04-19 00:05:57 +08:00
}
}
2024-05-05 12:11:51 +08:00
func (p Program) toNamed(raw *types.Named) Type {
switch t := raw.Underlying().(type) {
2024-04-16 03:05:20 +08:00
case *types.Struct:
2024-05-05 12:11:51 +08:00
name := NameOf(raw)
return &aType{p.toLLVMNamedStruct(name, t), rawType{raw}, vkStruct}
2024-04-25 21:44:23 +08:00
default:
2024-05-24 07:38:06 +08:00
typ := p.rawType(t)
return &aType{typ.ll, rawType{raw}, typ.kind}
2024-04-16 03:05:20 +08:00
}
}
2024-04-18 15:03:10 +08:00
2024-04-27 07:47:10 +08:00
func NameOf(typ *types.Named) string {
obj := typ.Obj()
return FullName(obj.Pkg(), obj.Name())
}
func FullName(pkg *types.Package, name string) string {
return PathOf(pkg) + "." + name
}
func PathOf(pkg *types.Package) string {
if pkg.Name() == "main" {
return "main"
}
return pkg.Path()
}
2024-04-18 15:03:10 +08:00
// -----------------------------------------------------------------------------