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