github.com/goplus/llgo@v0.8.3/ssa/type.go (about)

     1  /*
     2   * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ssa
    18  
    19  import (
    20  	"fmt"
    21  	"go/types"
    22  
    23  	"github.com/goplus/llvm"
    24  )
    25  
    26  var (
    27  	tyAny = types.NewInterfaceType(nil, nil)
    28  )
    29  
    30  // -----------------------------------------------------------------------------
    31  
    32  type valueKind = int
    33  
    34  const (
    35  	vkInvalid valueKind = iota
    36  	vkSigned
    37  	vkUnsigned
    38  	vkFloat
    39  	vkComplex
    40  	vkString
    41  	vkBool
    42  	vkPtr
    43  	vkFuncDecl
    44  	vkFuncPtr
    45  	vkClosure
    46  	vkPyFuncRef
    47  	vkPyVarRef
    48  	vkTuple
    49  	vkSlice
    50  	vkArray
    51  	vkMap
    52  	vkInterface
    53  	vkPhisExpr = -1
    54  )
    55  
    56  // -----------------------------------------------------------------------------
    57  
    58  func indexType(t types.Type) types.Type {
    59  	switch t := t.(type) {
    60  	case *types.Slice:
    61  		return t.Elem()
    62  	case *types.Pointer:
    63  		switch t := t.Elem().(type) {
    64  		case *types.Array:
    65  			return t.Elem()
    66  		}
    67  	case *types.Array:
    68  		return t.Elem()
    69  	}
    70  	panic("index: type doesn't support index - " + t.String())
    71  }
    72  
    73  // -----------------------------------------------------------------------------
    74  
    75  type rawType struct {
    76  	types.Type
    77  }
    78  
    79  type aType struct {
    80  	ll   llvm.Type
    81  	raw  rawType
    82  	kind valueKind // value kind of llvm.Type
    83  }
    84  
    85  type Type = *aType
    86  
    87  // RawType returns the raw type.
    88  func (t Type) RawType() types.Type {
    89  	return t.raw.Type
    90  }
    91  
    92  // TODO(xsw):
    93  // how to generate platform independent code?
    94  func (p Program) SizeOf(typ Type, n ...int64) uint64 {
    95  	size := p.td.TypeAllocSize(typ.ll)
    96  	if len(n) != 0 {
    97  		size *= uint64(n[0])
    98  	}
    99  	return size
   100  }
   101  
   102  func (p Program) Slice(typ Type) Type {
   103  	return p.rawType(types.NewSlice(typ.raw.Type))
   104  }
   105  
   106  func (p Program) Pointer(typ Type) Type {
   107  	return p.rawType(types.NewPointer(typ.raw.Type))
   108  }
   109  
   110  func (p Program) Elem(typ Type) Type {
   111  	elem := typ.raw.Type.(interface {
   112  		types.Type
   113  		Elem() types.Type
   114  	}).Elem()
   115  	return p.rawType(elem)
   116  }
   117  
   118  func (p Program) Index(typ Type) Type {
   119  	return p.rawType(indexType(typ.raw.Type))
   120  }
   121  
   122  func (p Program) Field(typ Type, i int) Type {
   123  	tunder := typ.raw.Type.Underlying()
   124  	tfld := tunder.(*types.Struct).Field(i).Type()
   125  	return p.rawType(tfld)
   126  }
   127  
   128  func (p Program) rawType(raw types.Type) Type {
   129  	if v := p.typs.At(raw); v != nil {
   130  		return v.(Type)
   131  	}
   132  	ret := p.toType(raw)
   133  	p.typs.Set(raw, ret)
   134  	return ret
   135  }
   136  
   137  func (p Program) tyVoidPtr() llvm.Type {
   138  	if p.voidPtrTy.IsNil() {
   139  		p.voidPtrTy = llvm.PointerType(p.tyVoid(), 0)
   140  	}
   141  	return p.voidPtrTy
   142  }
   143  
   144  func (p Program) tyVoid() llvm.Type {
   145  	if p.voidType.IsNil() {
   146  		p.voidType = p.ctx.VoidType()
   147  	}
   148  	return p.voidType
   149  }
   150  
   151  func (p Program) tyInt1() llvm.Type {
   152  	if p.int1Type.IsNil() {
   153  		p.int1Type = p.ctx.Int1Type()
   154  	}
   155  	return p.int1Type
   156  }
   157  
   158  func (p Program) tyInt() llvm.Type {
   159  	if p.intType.IsNil() {
   160  		p.intType = llvmIntType(p.ctx, p.td.PointerSize())
   161  	}
   162  	return p.intType
   163  }
   164  
   165  func llvmIntType(ctx llvm.Context, size int) llvm.Type {
   166  	if size <= 4 {
   167  		return ctx.Int32Type()
   168  	}
   169  	return ctx.Int64Type()
   170  }
   171  
   172  func (p Program) tyInt8() llvm.Type {
   173  	if p.int8Type.IsNil() {
   174  		p.int8Type = p.ctx.Int8Type()
   175  	}
   176  	return p.int8Type
   177  }
   178  
   179  func (p Program) tyInt16() llvm.Type {
   180  	if p.int16Type.IsNil() {
   181  		p.int16Type = p.ctx.Int16Type()
   182  	}
   183  	return p.int16Type
   184  }
   185  
   186  func (p Program) tyInt32() llvm.Type {
   187  	if p.int32Type.IsNil() {
   188  		p.int32Type = p.ctx.Int32Type()
   189  	}
   190  	return p.int32Type
   191  }
   192  
   193  func (p Program) tyInt64() llvm.Type {
   194  	if p.int64Type.IsNil() {
   195  		p.int64Type = p.ctx.Int64Type()
   196  	}
   197  	return p.int64Type
   198  }
   199  
   200  func (p Program) toTuple(typ *types.Tuple) Type {
   201  	return &aType{p.toLLVMTuple(typ), rawType{typ}, vkTuple}
   202  }
   203  
   204  func (p Program) toType(raw types.Type) Type {
   205  	typ := rawType{raw}
   206  	switch t := raw.(type) {
   207  	case *types.Basic:
   208  		switch t.Kind() {
   209  		case types.Int:
   210  			return &aType{p.tyInt(), typ, vkSigned}
   211  		case types.Uint, types.Uintptr:
   212  			return &aType{p.tyInt(), typ, vkUnsigned}
   213  		case types.Bool:
   214  			return &aType{p.tyInt1(), typ, vkBool}
   215  		case types.Uint8:
   216  			return &aType{p.tyInt8(), typ, vkUnsigned}
   217  		case types.Int8:
   218  			return &aType{p.tyInt8(), typ, vkSigned}
   219  		case types.Int16:
   220  			return &aType{p.tyInt16(), typ, vkSigned}
   221  		case types.Uint16:
   222  			return &aType{p.tyInt16(), typ, vkUnsigned}
   223  		case types.Int32:
   224  			return &aType{p.tyInt32(), typ, vkSigned}
   225  		case types.Uint32:
   226  			return &aType{p.tyInt32(), typ, vkUnsigned}
   227  		case types.Int64:
   228  			return &aType{p.tyInt64(), typ, vkSigned}
   229  		case types.Uint64:
   230  			return &aType{p.tyInt64(), typ, vkUnsigned}
   231  		case types.Float32:
   232  			return &aType{p.ctx.FloatType(), typ, vkFloat}
   233  		case types.Float64:
   234  			return &aType{p.ctx.DoubleType(), typ, vkFloat}
   235  		case types.Complex64:
   236  		case types.Complex128:
   237  		case types.String:
   238  			return &aType{p.rtString(), typ, vkString}
   239  		case types.UnsafePointer:
   240  			return &aType{p.tyVoidPtr(), typ, vkPtr}
   241  		}
   242  	case *types.Pointer:
   243  		elem := p.rawType(t.Elem())
   244  		return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr}
   245  	case *types.Interface:
   246  		return &aType{p.rtIface(), typ, vkInterface}
   247  	case *types.Slice:
   248  		return &aType{p.rtSlice(), typ, vkSlice}
   249  	case *types.Map:
   250  		return &aType{p.rtMap(), typ, vkMap}
   251  	case *types.Struct:
   252  		ll, kind := p.toLLVMStruct(t)
   253  		return &aType{ll, typ, kind}
   254  	case *types.Named:
   255  		return p.toNamed(t)
   256  	case *types.Signature: // represents a C function pointer in raw type
   257  		return &aType{p.toLLVMFuncPtr(t), typ, vkFuncPtr}
   258  	case *types.Array:
   259  		elem := p.rawType(t.Elem())
   260  		return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkArray}
   261  	case *types.Chan:
   262  	}
   263  	panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ))
   264  }
   265  
   266  func (p Program) toLLVMNamedStruct(name string, raw *types.Struct) llvm.Type {
   267  	if typ, ok := p.named[name]; ok {
   268  		return typ
   269  	}
   270  	t := p.ctx.StructCreateNamed(name)
   271  	p.named[name] = t
   272  	fields := p.toLLVMFields(raw)
   273  	t.StructSetBody(fields, false)
   274  	return t
   275  }
   276  
   277  func (p Program) toLLVMStruct(raw *types.Struct) (ret llvm.Type, kind valueKind) {
   278  	fields := p.toLLVMFields(raw)
   279  	ret = p.ctx.StructType(fields, false)
   280  	if isClosure(raw) {
   281  		kind = vkClosure
   282  	}
   283  	return
   284  }
   285  
   286  func isClosure(raw *types.Struct) bool {
   287  	n := raw.NumFields()
   288  	if n == 2 {
   289  		if _, ok := raw.Field(0).Type().(*types.Signature); ok {
   290  			return raw.Field(1).Type() == types.Typ[types.UnsafePointer]
   291  		}
   292  	}
   293  	return false
   294  }
   295  
   296  func (p Program) toLLVMFields(raw *types.Struct) (fields []llvm.Type) {
   297  	n := raw.NumFields()
   298  	if n > 0 {
   299  		fields = make([]llvm.Type, n)
   300  		for i := 0; i < n; i++ {
   301  			fields[i] = p.rawType(raw.Field(i).Type()).ll
   302  		}
   303  	}
   304  	return
   305  }
   306  
   307  func (p Program) toLLVMTuple(t *types.Tuple) llvm.Type {
   308  	return p.ctx.StructType(p.toLLVMTypes(t, t.Len()), false)
   309  }
   310  
   311  func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) {
   312  	if n > 0 {
   313  		ret = make([]llvm.Type, n)
   314  		for i := 0; i < n; i++ {
   315  			ret[i] = p.rawType(t.At(i).Type()).ll
   316  		}
   317  	}
   318  	return
   319  }
   320  
   321  func (p Program) toLLVMFunc(sig *types.Signature) llvm.Type {
   322  	tParams := sig.Params()
   323  	n := tParams.Len()
   324  	hasVArg := sig.Variadic()
   325  	if hasVArg {
   326  		n--
   327  	}
   328  	params := p.toLLVMTypes(tParams, n)
   329  	out := sig.Results()
   330  	var ret llvm.Type
   331  	switch nret := out.Len(); nret {
   332  	case 0:
   333  		ret = p.tyVoid()
   334  	case 1:
   335  		ret = p.rawType(out.At(0).Type()).ll
   336  	default:
   337  		ret = p.toLLVMTuple(out)
   338  	}
   339  	return llvm.FunctionType(ret, params, hasVArg)
   340  }
   341  
   342  func (p Program) toLLVMFuncPtr(sig *types.Signature) llvm.Type {
   343  	ft := p.toLLVMFunc(sig)
   344  	return llvm.PointerType(ft, 0)
   345  }
   346  
   347  func (p Program) retType(raw *types.Signature) Type {
   348  	out := raw.Results()
   349  	switch n := out.Len(); n {
   350  	case 0:
   351  		return p.Void()
   352  	case 1:
   353  		return p.rawType(out.At(0).Type())
   354  	default:
   355  		return &aType{p.toLLVMTuple(out), rawType{out}, vkTuple}
   356  	}
   357  }
   358  
   359  func (p Program) toNamed(raw *types.Named) Type {
   360  	switch t := raw.Underlying().(type) {
   361  	case *types.Struct:
   362  		name := NameOf(raw)
   363  		return &aType{p.toLLVMNamedStruct(name, t), rawType{raw}, vkInvalid}
   364  	default:
   365  		return p.rawType(t)
   366  	}
   367  }
   368  
   369  func NameOf(typ *types.Named) string {
   370  	obj := typ.Obj()
   371  	return FullName(obj.Pkg(), obj.Name())
   372  }
   373  
   374  func FullName(pkg *types.Package, name string) string {
   375  	return PathOf(pkg) + "." + name
   376  }
   377  
   378  func PathOf(pkg *types.Package) string {
   379  	if pkg.Name() == "main" {
   380  		return "main"
   381  	}
   382  	return pkg.Path()
   383  }
   384  
   385  // -----------------------------------------------------------------------------