From 133d41d7484ad627924b636463aececefeea4575 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 3 May 2024 16:51:01 +0800 Subject: [PATCH] llgo/ssa: CType, CFuncDecl --- ssa/type.go | 49 +++---------------- ssa/type_c.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 42 deletions(-) create mode 100644 ssa/type_c.go diff --git a/ssa/type.go b/ssa/type.go index c87618e0..93feee6b 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -48,27 +48,8 @@ const ( vkPhisExpr = -2 ) -// CFuncPtr represents a C function pointer. -type CFuncPtr types.Signature - // ----------------------------------------------------------------------------- -const ( - NameValist = "__llgo_va_list" -) - -func VArg() *types.Var { - return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) -} - -func IsVArg(arg *types.Var) bool { - return arg.Name() == NameValist -} - -func HasVArg(t *types.Tuple, n int) bool { - return n > 0 && IsVArg(t.At(n-1)) -} - func indexType(t types.Type) types.Type { switch t := t.(type) { case *types.Slice: @@ -102,18 +83,6 @@ func methodToFunc(sig *types.Signature) *types.Signature { // ----------------------------------------------------------------------------- -// CType convert a C type into Go. -func CType(typ types.Type) types.Type { - panic("todo") -} - -// CFuncDecl convert a C function decl into Go signature. -func CFuncDecl(sig *types.Signature) *types.Signature { - panic("todo") -} - -// ----------------------------------------------------------------------------- - type aType struct { ll llvm.Type t types.Type @@ -278,6 +247,8 @@ func (p Program) toLLVMType(typ types.Type) Type { return p.toLLVMNamed(t) case *types.Signature: return p.toLLVMFunc(t, false, false) + case *CFuncPtr: + return p.toLLVMFunc((*types.Signature)(t), true, false) case *types.Array: elem := p.Type(t.Elem()) return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} @@ -327,14 +298,11 @@ func (p Program) toLLVMFunc(sig *types.Signature, inC, isDecl bool) Type { var kind valueKind var ft llvm.Type if isDecl || inC { - var tParams = sig.Params() - var n = tParams.Len() - var hasVArg bool - if inC { - hasVArg = HasVArg(tParams, n) - if hasVArg { - n-- - } + tParams := sig.Params() + n := tParams.Len() + hasVArg := HasVArg(tParams, n) + if hasVArg { + n-- } params := p.toLLVMTypes(tParams, n) out := sig.Results() @@ -378,9 +346,6 @@ func (p Program) toLLVMNamed(typ *types.Named) Type { case *types.Struct: name := NameOf(typ) return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} - case *types.Signature: - inC := true // TODO(xsw): how to check in C - return p.toLLVMFunc(t, inC, false) default: return p.Type(t) } diff --git a/ssa/type_c.go b/ssa/type_c.go new file mode 100644 index 00000000..e4d982f5 --- /dev/null +++ b/ssa/type_c.go @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package ssa + +import "go/types" + +// ----------------------------------------------------------------------------- + +const ( + NameValist = "__llgo_va_list" +) + +func VArg() *types.Var { + return types.NewParam(0, nil, NameValist, types.Typ[types.Invalid]) +} + +func IsVArg(arg *types.Var) bool { + return arg.Name() == NameValist +} + +func HasVArg(t *types.Tuple, n int) bool { + return n > 0 && IsVArg(t.At(n-1)) +} + +// ----------------------------------------------------------------------------- + +// CFuncPtr represents a C function pointer. +type CFuncPtr types.Signature + +func (t *CFuncPtr) String() string { return (*types.Signature)(t).String() } +func (t *CFuncPtr) Underlying() types.Type { return (*types.Signature)(t) } + +// ----------------------------------------------------------------------------- + +// CType convert a C type into Go. +func CType(typ types.Type) types.Type { + t, _ := cvtCType(typ) + return t +} + +// CFuncDecl convert a C function decl into Go signature. +func CFuncDecl(sig *types.Signature) *types.Signature { + hasVArg := sig.Variadic() + params, cvt1 := cvtTuple(sig.Params(), hasVArg) + results, cvt2 := cvtTuple(sig.Results(), false) + if cvt1 || cvt2 { + return types.NewSignatureType(nil, nil, nil, params, results, hasVArg) + } + return sig +} + +func cvtCType(typ types.Type) (types.Type, bool) { + switch t := typ.(type) { + case *types.Basic: + case *types.Pointer: + if elem, cvt := cvtCType(t.Elem()); cvt { + return types.NewPointer(elem), true + } + case *types.Struct: + return cvtCStruct(t) + case *types.Signature: + t = CFuncDecl(t) + return (*CFuncPtr)(t), true + case *types.Array: + if elem, cvt := cvtCType(t.Elem()); cvt { + return types.NewArray(elem, t.Len()), true + } + default: + panic("unreachable") + } + return typ, false +} + +func cvtTuple(t *types.Tuple, hasVArg bool) (*types.Tuple, bool) { + n := t.Len() + vars := make([]*types.Var, n) + needcvt := false + if hasVArg { + n-- + vars[n] = t.At(n) + } + for i := 0; i < n; i++ { + v := t.At(i) + if t, cvt := cvtCType(v.Type()); cvt { + v = types.NewParam(v.Pos(), v.Pkg(), v.Name(), t) + needcvt = true + } + vars[i] = v + } + if needcvt { + return types.NewTuple(vars...), true + } + return t, false +} + +func cvtCStruct(typ *types.Struct) (*types.Struct, bool) { + n := typ.NumFields() + flds := make([]*types.Var, n) + needcvt := false + for i := 0; i < n; i++ { + f := typ.Field(i) + if t, cvt := cvtCType(f.Type()); cvt { + f = types.NewField(f.Pos(), f.Pkg(), f.Name(), t, f.Anonymous()) + needcvt = true + } + flds[i] = f + } + if needcvt { + return types.NewStruct(flds, nil), true + } + return typ, false +} + +// -----------------------------------------------------------------------------