abi.Name; runtime: MakeAnyInt => MakeAnyIntptr; llgo/ssa: AllocU; builtin unsafe.String; MakeInterface; prog.PointerSize
This commit is contained in:
@@ -152,7 +152,7 @@ See [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py) fo
|
|||||||
|
|
||||||
LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports.
|
LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports.
|
||||||
|
|
||||||
The currently imported libraries include:
|
The currently supported libraries include:
|
||||||
|
|
||||||
* [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
|
* [llama2.c](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
|
||||||
* [cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
* [cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module github.com/goplus/llgo
|
module github.com/goplus/llgo
|
||||||
|
|
||||||
go 1.18
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aykevl/go-wasm v0.0.1
|
github.com/aykevl/go-wasm v0.0.1
|
||||||
|
|||||||
Binary file not shown.
@@ -213,36 +213,6 @@ type StructType struct {
|
|||||||
Fields []StructField
|
Fields []StructField
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name is an encoded type Name with optional extra data.
|
|
||||||
//
|
|
||||||
// The first byte is a bit field containing:
|
|
||||||
//
|
|
||||||
// 1<<0 the name is exported
|
|
||||||
// 1<<1 tag data follows the name
|
|
||||||
// 1<<2 pkgPath nameOff follows the name and tag
|
|
||||||
// 1<<3 the name is of an embedded (a.k.a. anonymous) field
|
|
||||||
//
|
|
||||||
// Following that, there is a varint-encoded length of the name,
|
|
||||||
// followed by the name itself.
|
|
||||||
//
|
|
||||||
// If tag data is present, it also has a varint-encoded length
|
|
||||||
// followed by the tag itself.
|
|
||||||
//
|
|
||||||
// If the import path follows, then 4 bytes at the end of
|
|
||||||
// the data form a nameOff. The import path is only set for concrete
|
|
||||||
// methods that are defined in a different package than their type.
|
|
||||||
//
|
|
||||||
// If a name starts with "*", then the exported bit represents
|
|
||||||
// whether the pointed to type is exported.
|
|
||||||
//
|
|
||||||
// Note: this encoding must match here and in:
|
|
||||||
// cmd/compile/internal/reflectdata/reflect.go
|
|
||||||
// cmd/link/internal/ld/decodesym.go
|
|
||||||
|
|
||||||
type Name struct {
|
|
||||||
Bytes *byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type InterfaceType struct {
|
type InterfaceType struct {
|
||||||
Type
|
Type
|
||||||
PkgPath Name // import path
|
PkgPath Name // import path
|
||||||
@@ -330,3 +300,168 @@ func (t *Type) InterfaceType() *InterfaceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// addChecked returns p+x.
|
||||||
|
//
|
||||||
|
// The whySafe string is ignored, so that the function still inlines
|
||||||
|
// as efficiently as p+x, but all call sites should use the string to
|
||||||
|
// record why the addition is safe, which is to say why the addition
|
||||||
|
// does not cause x to advance to the very end of p's allocation
|
||||||
|
// and therefore point incorrectly at the next block in memory.
|
||||||
|
func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
|
||||||
|
_ = whySafe
|
||||||
|
return unsafe.Pointer(uintptr(p) + x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name is an encoded type Name with optional extra data.
|
||||||
|
//
|
||||||
|
// The first byte is a bit field containing:
|
||||||
|
//
|
||||||
|
// 1<<0 the name is exported
|
||||||
|
// 1<<1 tag data follows the name
|
||||||
|
// 1<<2 pkgPath nameOff follows the name and tag
|
||||||
|
// 1<<3 the name is of an embedded (a.k.a. anonymous) field
|
||||||
|
//
|
||||||
|
// Following that, there is a varint-encoded length of the name,
|
||||||
|
// followed by the name itself.
|
||||||
|
//
|
||||||
|
// If tag data is present, it also has a varint-encoded length
|
||||||
|
// followed by the tag itself.
|
||||||
|
//
|
||||||
|
// If the import path follows, then 4 bytes at the end of
|
||||||
|
// the data form a nameOff. The import path is only set for concrete
|
||||||
|
// methods that are defined in a different package than their type.
|
||||||
|
//
|
||||||
|
// If a name starts with "*", then the exported bit represents
|
||||||
|
// whether the pointed to type is exported.
|
||||||
|
//
|
||||||
|
// Note: this encoding must match here and in:
|
||||||
|
// cmd/compile/internal/reflectdata/reflect.go
|
||||||
|
// cmd/link/internal/ld/decodesym.go
|
||||||
|
|
||||||
|
type Name struct {
|
||||||
|
Bytes *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to
|
||||||
|
// be safe for the reason in whySafe (which can appear in a backtrace, etc.)
|
||||||
|
func (n Name) DataChecked(off int, whySafe string) *byte {
|
||||||
|
return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), whySafe))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to
|
||||||
|
// be safe because the runtime made the call (other packages use DataChecked)
|
||||||
|
func (n Name) Data(off int) *byte {
|
||||||
|
return (*byte)(addChecked(unsafe.Pointer(n.Bytes), uintptr(off), "the runtime doesn't need to give you a reason"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExported returns "is n exported?"
|
||||||
|
func (n Name) IsExported() bool {
|
||||||
|
return (*n.Bytes)&(1<<0) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasTag returns true iff there is tag data following this name
|
||||||
|
func (n Name) HasTag() bool {
|
||||||
|
return (*n.Bytes)&(1<<1) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmbedded returns true iff n is embedded (an anonymous field).
|
||||||
|
func (n Name) IsEmbedded() bool {
|
||||||
|
return (*n.Bytes)&(1<<3) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadVarint parses a varint as encoded by encoding/binary.
|
||||||
|
// It returns the number of encoded bytes and the encoded value.
|
||||||
|
func (n Name) ReadVarint(off int) (int, int) {
|
||||||
|
v := 0
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
x := *n.DataChecked(off+i, "read varint")
|
||||||
|
v += int(x&0x7f) << (7 * i)
|
||||||
|
if x&0x80 == 0 {
|
||||||
|
return i + 1, v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlank indicates whether n is "_".
|
||||||
|
func (n Name) IsBlank() bool {
|
||||||
|
if n.Bytes == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, l := n.ReadVarint(1)
|
||||||
|
return l == 1 && *n.Data(2) == '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeVarint writes n to buf in varint form. Returns the
|
||||||
|
// number of bytes written. n must be nonnegative.
|
||||||
|
// Writes at most 10 bytes.
|
||||||
|
func writeVarint(buf []byte, n int) int {
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
b := byte(n & 0x7f)
|
||||||
|
n >>= 7
|
||||||
|
if n == 0 {
|
||||||
|
buf[i] = b
|
||||||
|
return i + 1
|
||||||
|
}
|
||||||
|
buf[i] = b | 0x80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the tag string for n, or empty if there is none.
|
||||||
|
func (n Name) Name() string {
|
||||||
|
if n.Bytes == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
i, l := n.ReadVarint(1)
|
||||||
|
return unsafe.String(n.DataChecked(1+i, "non-empty string"), l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag returns the tag string for n, or empty if there is none.
|
||||||
|
func (n Name) Tag() string {
|
||||||
|
if !n.HasTag() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
i, l := n.ReadVarint(1)
|
||||||
|
i2, l2 := n.ReadVarint(1 + i + l)
|
||||||
|
return unsafe.String(n.DataChecked(1+i+l+i2, "non-empty string"), l2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewName(n, tag string, exported, embedded bool) Name {
|
||||||
|
if len(n) >= 1<<29 {
|
||||||
|
panic("abi.NewName: name too long: " + n[:1024] + "...")
|
||||||
|
}
|
||||||
|
if len(tag) >= 1<<29 {
|
||||||
|
panic("abi.NewName: tag too long: " + tag[:1024] + "...")
|
||||||
|
}
|
||||||
|
var nameLen [10]byte
|
||||||
|
var tagLen [10]byte
|
||||||
|
nameLenLen := writeVarint(nameLen[:], len(n))
|
||||||
|
tagLenLen := writeVarint(tagLen[:], len(tag))
|
||||||
|
|
||||||
|
var bits byte
|
||||||
|
l := 1 + nameLenLen + len(n)
|
||||||
|
if exported {
|
||||||
|
bits |= 1 << 0
|
||||||
|
}
|
||||||
|
if len(tag) > 0 {
|
||||||
|
l += tagLenLen + len(tag)
|
||||||
|
bits |= 1 << 1
|
||||||
|
}
|
||||||
|
if embedded {
|
||||||
|
bits |= 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, l)
|
||||||
|
b[0] = bits
|
||||||
|
copy(b[1:], nameLen[:nameLenLen])
|
||||||
|
copy(b[1+nameLenLen:], n)
|
||||||
|
if len(tag) > 0 {
|
||||||
|
tb := b[1+nameLenLen+len(n):]
|
||||||
|
copy(tb, tagLen[:tagLenLen])
|
||||||
|
copy(tb[tagLenLen:], tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Name{Bytes: &b[0]}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
Binary file not shown.
@@ -34,7 +34,7 @@ var (
|
|||||||
|
|
||||||
type Interface = iface
|
type Interface = iface
|
||||||
|
|
||||||
func MakeAnyInt(typ *Type, data uintptr) Interface {
|
func MakeAnyIntptr(typ *Type, data uintptr) Interface {
|
||||||
tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}
|
tab := &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}
|
||||||
return Interface{
|
return Interface{
|
||||||
tab: tab, data: unsafe.Pointer(data),
|
tab: tab, data: unsafe.Pointer(data),
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ func EmptyString() String {
|
|||||||
return String{nil, 0}
|
return String{nil, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(xsw): unsafe.String
|
||||||
// NewString creates a new string.
|
// NewString creates a new string.
|
||||||
func NewString(data unsafe.Pointer, len int) String {
|
func NewString(data unsafe.Pointer, len int) String {
|
||||||
return String{data, len}
|
return String{data, len}
|
||||||
|
|||||||
73
ssa/_abi/abi.go
Normal file
73
ssa/_abi/abi.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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 abi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder is a helper for constructing ABI types.
|
||||||
|
type Builder struct {
|
||||||
|
h hash.Hash
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new ABI type Builder.
|
||||||
|
func New() *Builder {
|
||||||
|
h := sha256.New()
|
||||||
|
buf := make([]byte, sha256.Size)
|
||||||
|
return &Builder{h, buf}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeName returns the ABI type name for the specified type.
|
||||||
|
func (b *Builder) TypeName(t types.Type) string {
|
||||||
|
switch t := t.(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
return t.Name()
|
||||||
|
case *types.Pointer:
|
||||||
|
return "*" + b.TypeName(t.Elem())
|
||||||
|
case *types.Struct:
|
||||||
|
return b.StructName(t)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructName returns the ABI type name for the specified struct type.
|
||||||
|
func (b *Builder) StructName(t *types.Struct) string {
|
||||||
|
hash := b.structHash(t)
|
||||||
|
return "struct$" + base64.RawURLEncoding.EncodeToString(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) structHash(t *types.Struct) []byte {
|
||||||
|
h := b.h
|
||||||
|
h.Reset()
|
||||||
|
n := t.NumFields()
|
||||||
|
fmt.Fprintln(h, "struct", n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
name := f.Name()
|
||||||
|
if f.Embedded() {
|
||||||
|
name = "-"
|
||||||
|
}
|
||||||
|
fmt.Fprintln(h, name, b.TypeName(f.Type()))
|
||||||
|
}
|
||||||
|
return h.Sum(b.buf[:0])
|
||||||
|
}
|
||||||
@@ -36,6 +36,9 @@ func TestFromTestdata(t *testing.T) {
|
|||||||
|
|
||||||
func TestRuntime(t *testing.T) {
|
func TestRuntime(t *testing.T) {
|
||||||
cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll")
|
cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAbi(t *testing.T) {
|
||||||
cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll")
|
cltest.Pkg(t, "github.com/goplus/llgo/internal/abi", "../internal/abi/llgo_autogen.ll")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
ssa/expr.go
23
ssa/expr.go
@@ -665,7 +665,18 @@ func (b Builder) Alloc(elem Type, heap bool) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alloca allocates space for n bytes.
|
// AllocU allocates uninitialized space for n*sizeof(elem) bytes.
|
||||||
|
func (b Builder) AllocU(elem Type, n ...int64) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("AllocU %v, %v\n", elem.raw.Type, n)
|
||||||
|
}
|
||||||
|
size := b.SizeOf(elem, n...)
|
||||||
|
ret = b.InlineCall(b.Pkg.rtFunc("AllocU"), size)
|
||||||
|
ret.Type = b.Prog.Pointer(elem)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alloca allocates uninitialized space for n bytes.
|
||||||
func (b Builder) Alloca(n Expr) (ret Expr) {
|
func (b Builder) Alloca(n Expr) (ret Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("Alloca %v\n", n.impl)
|
log.Printf("Alloca %v\n", n.impl)
|
||||||
@@ -984,9 +995,10 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
if ln && i > 0 {
|
if ln && i > 0 {
|
||||||
b.InlineCall(b.Pkg.rtFunc("PrintString"), b.Str(" "))
|
b.InlineCall(b.Pkg.rtFunc("PrintString"), b.Str(" "))
|
||||||
|
// TODO(visualfc): maybe use PrintCStr is more efficient
|
||||||
}
|
}
|
||||||
var fn string
|
var fn string
|
||||||
var typ Type
|
var typ Type // TODO(visualfc): typ uninitialized in some cases
|
||||||
switch arg.kind {
|
switch arg.kind {
|
||||||
case vkBool:
|
case vkBool:
|
||||||
fn = "PrintBool"
|
fn = "PrintBool"
|
||||||
@@ -1002,6 +1014,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
case vkSlice:
|
case vkSlice:
|
||||||
fn = "PrintSlice"
|
fn = "PrintSlice"
|
||||||
case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef:
|
case vkPtr, vkFuncPtr, vkFuncDecl, vkClosure, vkPyVarRef, vkPyFuncRef:
|
||||||
|
// TODO(visualfc): vkClosure is not a pointer
|
||||||
|
// TODO(visualfc): vkPyVarRef, vkPyFuncRef is pointer of pointer
|
||||||
fn = "PrintPointer"
|
fn = "PrintPointer"
|
||||||
typ = b.Prog.VoidPtr()
|
typ = b.Prog.VoidPtr()
|
||||||
case vkString:
|
case vkString:
|
||||||
@@ -1037,8 +1051,11 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "String": // unsafe.String
|
||||||
|
// TODO(xsw): make this a builtin
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("NewString"), args[0], args[1])
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo: " + fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -27,19 +27,29 @@ import (
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// AbiBasic returns the abi type of the specified basic kind.
|
// abiBasic returns the abi type of the specified basic kind.
|
||||||
func (b Builder) AbiBasic(kind types.BasicKind) Expr {
|
func (b Builder) abiBasic(kind types.BasicKind) Expr {
|
||||||
return b.InlineCall(b.Pkg.rtFunc("Basic"), b.Prog.Val(int(kind)))
|
return b.InlineCall(b.Pkg.rtFunc("Basic"), b.Prog.Val(int(kind)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// AbiStruct returns the abi type of the specified struct type.
|
// abiStruct returns the abi type of the specified struct type.
|
||||||
func (b Builder) AbiStruct(t *types.Struct) Expr {
|
func (b Builder) abiStruct(t *types.Struct) Expr {
|
||||||
panic("todo")
|
// name := "__llgo_" + b.Prog.abi.StructName(t)
|
||||||
// return b.InlineCall(b.Pkg.rtFunc("Struct"), b.Prog.Val(t.NumFields()))
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// AbiType returns the abi type of the specified type.
|
||||||
|
func (b Builder) AbiType(t Type) Expr {
|
||||||
|
switch tx := t.raw.Type.(type) {
|
||||||
|
case *types.Basic:
|
||||||
|
return b.abiBasic(tx.Kind())
|
||||||
|
//case *types.Struct:
|
||||||
|
// return b.abiStruct(tx)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// MakeInterface constructs an instance of an interface type from a
|
// MakeInterface constructs an instance of an interface type from a
|
||||||
@@ -57,37 +67,66 @@ func (b Builder) AbiStruct(t *types.Struct) Expr {
|
|||||||
// t1 = make interface{} <- int (42:int)
|
// t1 = make interface{} <- int (42:int)
|
||||||
// t2 = make Stringer <- t0
|
// t2 = make Stringer <- t0
|
||||||
func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) {
|
func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) {
|
||||||
raw := tinter.raw.Type
|
rawIntf := tinter.raw.Type.Underlying().(*types.Interface)
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("MakeInterface %v, %v\n", raw, x.impl)
|
log.Printf("MakeInterface %v, %v\n", rawIntf, x.impl)
|
||||||
}
|
}
|
||||||
prog := b.Prog
|
prog := b.Prog
|
||||||
pkg := b.Pkg
|
typ := x.Type
|
||||||
switch tx := x.raw.Type.Underlying().(type) {
|
switch tx := typ.raw.Type.Underlying().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
kind := tx.Kind()
|
kind := tx.Kind()
|
||||||
switch {
|
switch {
|
||||||
case kind >= types.Bool && kind <= types.Uintptr:
|
case kind >= types.Bool && kind <= types.Uintptr:
|
||||||
t := b.AbiBasic(kind)
|
if prog.is32Bits && (kind == types.Int64 || kind == types.Uint64) {
|
||||||
tptr := prog.Uintptr()
|
return b.makeIntfAlloc(tinter, rawIntf, typ, x)
|
||||||
vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr}
|
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
|
|
||||||
case kind == types.Float32:
|
|
||||||
t := b.AbiBasic(kind)
|
|
||||||
tptr := prog.Uintptr()
|
|
||||||
i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32()) // TODO(xsw): more effective
|
|
||||||
vptr := Expr{llvm.CreateIntCast(b.impl, i32, tptr.ll), tptr}
|
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
|
|
||||||
case kind == types.Float64:
|
|
||||||
t := b.AbiBasic(kind)
|
|
||||||
tptr := prog.Uintptr()
|
|
||||||
vptr := Expr{llvm.CreateBitCast(b.impl, x.impl, tptr.ll), tptr}
|
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
|
|
||||||
case kind == types.String:
|
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter}
|
|
||||||
}
|
}
|
||||||
// case *types.Struct:
|
return b.makeIntfByIntptr(tinter, rawIntf, typ, x.impl)
|
||||||
// t := b.AbiStruct(tx)
|
case kind == types.Float32:
|
||||||
|
i32 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt32())
|
||||||
|
return b.makeIntfByIntptr(tinter, rawIntf, typ, i32)
|
||||||
|
case kind == types.Float64:
|
||||||
|
if prog.is32Bits {
|
||||||
|
return b.makeIntfAlloc(tinter, rawIntf, typ, x)
|
||||||
|
}
|
||||||
|
i64 := llvm.CreateBitCast(b.impl, x.impl, prog.tyInt64())
|
||||||
|
return b.makeIntfByIntptr(tinter, rawIntf, typ, i64)
|
||||||
|
case kind == types.String:
|
||||||
|
return Expr{b.InlineCall(b.Pkg.rtFunc("MakeAnyString"), x).impl, tinter}
|
||||||
|
}
|
||||||
|
/* case *types.Struct:
|
||||||
|
size := int(prog.SizeOf(typ))
|
||||||
|
if size > prog.PointerSize() {
|
||||||
|
return b.makeIntfAlloc(tinter, rawIntf, typ, x)
|
||||||
|
}
|
||||||
|
tv := prog.ctx.IntType(size * 8)
|
||||||
|
iv := llvm.CreateBitCast(b.impl, x.impl, tv)
|
||||||
|
return b.makeIntfByIntptr(tinter, rawIntf, typ, iv) */
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) makeIntfAlloc(tinter Type, rawIntf *types.Interface, typ Type, x Expr) (ret Expr) {
|
||||||
|
vptr := b.AllocU(typ)
|
||||||
|
b.Store(vptr, x)
|
||||||
|
return b.makeIntfByPtr(tinter, rawIntf, typ, vptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) makeIntfByPtr(tinter Type, rawIntf *types.Interface, typ Type, vptr Expr) (ret Expr) {
|
||||||
|
if rawIntf.Empty() {
|
||||||
|
ret = b.InlineCall(b.Pkg.rtFunc("MakeAny"), b.AbiType(typ), vptr)
|
||||||
|
ret.Type = tinter
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) makeIntfByIntptr(tinter Type, rawIntf *types.Interface, typ Type, x llvm.Value) (ret Expr) {
|
||||||
|
if rawIntf.Empty() {
|
||||||
|
tptr := b.Prog.Uintptr()
|
||||||
|
x = llvm.CreateIntCast(b.impl, x, tptr.ll)
|
||||||
|
impl := b.InlineCall(b.Pkg.rtFunc("MakeAnyIntptr"), b.AbiType(typ), Expr{x, tptr}).impl
|
||||||
|
return Expr{impl, tinter}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic("todo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ type aProgram struct {
|
|||||||
ctx llvm.Context
|
ctx llvm.Context
|
||||||
typs typeutil.Map // rawType -> Type
|
typs typeutil.Map // rawType -> Type
|
||||||
gocvt goTypes
|
gocvt goTypes
|
||||||
|
//abi *abi.Builder
|
||||||
|
|
||||||
rt *types.Package
|
rt *types.Package
|
||||||
rtget func() *types.Package
|
rtget func() *types.Package
|
||||||
@@ -158,6 +159,7 @@ type aProgram struct {
|
|||||||
|
|
||||||
NeedRuntime bool
|
NeedRuntime bool
|
||||||
NeedPyInit bool
|
NeedPyInit bool
|
||||||
|
is32Bits bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Program presents a program.
|
// A Program presents a program.
|
||||||
@@ -180,7 +182,12 @@ func NewProgram(target *Target) Program {
|
|||||||
// TODO(xsw): Finalize may cause panic, so comment it.
|
// TODO(xsw): Finalize may cause panic, so comment it.
|
||||||
ctx.Finalize()
|
ctx.Finalize()
|
||||||
*/
|
*/
|
||||||
return &aProgram{ctx: ctx, gocvt: newGoTypes(), target: target, td: td, named: make(map[string]llvm.Type)}
|
is32Bits := (td.PointerSize() == 4)
|
||||||
|
return &aProgram{
|
||||||
|
ctx: ctx, gocvt: newGoTypes(), // abi: abi.New(),
|
||||||
|
target: target, td: td, is32Bits: is32Bits,
|
||||||
|
named: make(map[string]llvm.Type),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPython sets the Python package.
|
// SetPython sets the Python package.
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ func (p Program) SizeOf(typ Type, n ...int64) uint64 {
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Program) PointerSize() int {
|
||||||
|
return p.td.PointerSize()
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) Slice(typ Type) Type {
|
func (p Program) Slice(typ Type) Type {
|
||||||
return p.rawType(types.NewSlice(typ.raw.Type))
|
return p.rawType(types.NewSlice(typ.raw.Type))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user