cl: _testcgo/any

This commit is contained in:
xushiwei
2024-04-27 20:45:55 +08:00
parent 6a3eb2f2f9
commit 08da38a609
8 changed files with 167 additions and 58 deletions

View File

@@ -0,0 +1,55 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
@main.format = global ptr null
@"main.init$guard" = global ptr null
define i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0) {
_llgo_0:
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
%2 = call i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1)
%3 = add i64 %2, 1
ret i64 %3
}
define void @main.init() {
_llgo_0:
%0 = load i1, ptr @"main.init$guard", align 1
br i1 %0, label %_llgo_2, label %_llgo_1
_llgo_1: ; preds = %_llgo_0
store i1 true, ptr @"main.init$guard", align 1
store i8 72, ptr @main.format, align 1
store i8 101, ptr getelementptr inbounds (i8, ptr @main.format, i64 1), align 1
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 2), align 1
store i8 108, ptr getelementptr inbounds (i8, ptr @main.format, i64 3), align 1
store i8 111, ptr getelementptr inbounds (i8, ptr @main.format, i64 4), align 1
store i8 32, ptr getelementptr inbounds (i8, ptr @main.format, i64 5), align 1
store i8 37, ptr getelementptr inbounds (i8, ptr @main.format, i64 6), align 1
store i8 100, ptr getelementptr inbounds (i8, ptr @main.format, i64 7), align 1
store i8 10, ptr getelementptr inbounds (i8, ptr @main.format, i64 8), align 1
store i8 0, ptr getelementptr inbounds (i8, ptr @main.format, i64 9), align 1
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
define void @main() {
_llgo_0:
call void @main.init()
%0 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(i64 100)
%1 = call i64 @main.incVal(%"github.com/goplus/llgo/internal/runtime.iface" %0)
call void (ptr, ...) @printf(ptr @main.format, i64 %1)
ret void
}
declare void @printf(ptr, ...)
declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64)

View File

@@ -324,11 +324,12 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
} }
ret = b.Alloc(p.prog.Type(t), v.Heap) ret = b.Alloc(p.prog.Type(t), v.Heap)
case *ssa.MakeInterface: case *ssa.MakeInterface:
const (
delayExpr = true // varargs: don't need to convert an expr to any
)
t := v.Type() t := v.Type()
if isAny(t) { // varargs: don't need to convert an expr to any x := p.compileValue(b, v.X)
return ret = b.MakeInterface(t, x, delayExpr)
}
panic("todo")
case *ssa.TypeAssert: case *ssa.TypeAssert:
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.TypeAssert(x, p.prog.Type(v.AssertedType), v.CommaOk) ret = b.TypeAssert(x, p.prog.Type(v.AssertedType), v.CommaOk)
@@ -417,6 +418,9 @@ func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []
switch v := v.(type) { switch v := v.(type) {
case *ssa.Slice: // varargs: this is a varargs slice case *ssa.Slice: // varargs: this is a varargs slice
if args, ok := p.isVArgs(v.X); ok { if args, ok := p.isVArgs(v.X); ok {
for i, arg := range args {
args[i] = arg.Do(true)
}
return append(ret, args...) return append(ret, args...)
} }
case *ssa.Const: case *ssa.Const:
@@ -431,7 +435,7 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int)
n := len(vals) - hasVArg n := len(vals) - hasVArg
ret := make([]llssa.Expr, n) ret := make([]llssa.Expr, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
ret[i] = p.compileValue(b, vals[i]) ret[i] = p.compileValue(b, vals[i]).Do(false)
} }
if hasVArg > 0 { if hasVArg > 0 {
ret = p.compileVArg(ret, b, vals[n]) ret = p.compileVArg(ret, b, vals[n])

View File

@@ -28,7 +28,7 @@ func testCompile(t *testing.T, src, expected string) {
} }
func TestFromTestcgo(t *testing.T) { func TestFromTestcgo(t *testing.T) {
cltest.FromDir(t, "any", "./_testcgo", true) cltest.FromDir(t, "", "./_testcgo", true)
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {

View File

@@ -30,9 +30,37 @@ var (
TyAny = &InterfaceType{} TyAny = &InterfaceType{}
) )
func MakeAnyInt(typ *Type, data uintptr) Interface {
return Interface{
tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}},
data: unsafe.Pointer(data),
}
}
func MakeAny(typ *Type, data unsafe.Pointer) Interface { func MakeAny(typ *Type, data unsafe.Pointer) Interface {
return Interface{ return 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}},
data: data, data: data,
} }
} }
func MakeInterface(inter *InterfaceType, typ *Type, data unsafe.Pointer) Interface {
return Interface{
tab: &itab{inter: inter, _type: typ, hash: 0, fun: [1]uintptr{0}},
data: data,
}
}
func I2Int(v Interface, t *Type) uintptr {
if v.tab._type == t {
return uintptr(v.data)
}
panic("I2Int: type mismatch")
}
func CheckI2Int(v Interface, t *Type) (uintptr, bool) {
if v.tab._type == t {
return uintptr(v.data), true
}
return 0, false
}

View File

@@ -25,20 +25,6 @@ import (
type Type = abi.Type type Type = abi.Type
func I2Int(v Interface, t *Type) int64 {
if v.tab._type == t {
return int64(uintptr(v.data))
}
panic("I2Int: type mismatch")
}
func CheckI2Int(v Interface, t *Type) (int64, bool) {
if v.tab._type == t {
return int64(uintptr(v.data)), true
}
return 0, false
}
func Basic(kind types.BasicKind) *Type { func Basic(kind types.BasicKind) *Type {
return basicTypes[kind] return basicTypes[kind]
} }

View File

@@ -1,37 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeheader contains header declarations for the Go runtime's slice
// and string implementations.
//
// This package allows packages that cannot import "reflect" to use types that
// are tested to be equivalent to reflect.SliceHeader and reflect.StringHeader.
package unsafeheader
import (
"unsafe"
)
// Slice is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
//
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
// data it references will not be garbage collected.
type Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// String is the runtime representation of a string.
// It cannot be used safely or portably and its representation may
// change in a later release.
//
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
// data it references will not be garbage collected.
type String struct {
Data unsafe.Pointer
Len int
}

View File

@@ -41,6 +41,37 @@ func (v Expr) TypeOf() types.Type {
} }
*/ */
// Do evaluates the delay expression and returns the result.
func (v Expr) Do(isVArg bool) Expr {
if vt := v.Type; vt.kind == vkDelayExpr {
delay := vt.t.(*delayExprTy)
if f := delay.f; f != nil {
delay.f = nil
delay.val = f(isVArg)
}
return delay.val
}
return v
}
// DelayExpr returns a delay expression.
func DelayExpr(f func(isVArg bool) Expr) Expr {
return Expr{Type: &aType{t: &delayExprTy{f: f}, kind: vkDelayExpr}}
}
type delayExprTy struct {
f func(isVArg bool) Expr
val Expr
}
func (p *delayExprTy) Underlying() types.Type {
panic("don't call")
}
func (p *delayExprTy) String() string {
return "delayExpr"
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
func llvmValues(vals []Expr) []llvm.Value { func llvmValues(vals []Expr) []llvm.Value {
@@ -407,6 +438,47 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
panic("todo") panic("todo")
} }
// MakeInterface constructs an instance of an interface type from a
// value of a concrete type.
//
// Use Program.MethodSets.MethodSet(X.Type()) to find the method-set
// of X, and Program.MethodValue(m) to find the implementation of a method.
//
// To construct the zero value of an interface type T, use:
//
// NewConst(constant.MakeNil(), T, pos)
//
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
// from an explicit conversion in the source.
//
// Example printed form:
//
// t1 = make interface{} <- int (42:int)
// t2 = make Stringer <- t0
func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Expr) {
if debugInstr {
log.Printf("MakeInterface %v, %v\n", inter, x.impl)
}
t := inter.Underlying().(*types.Interface)
isAny := t.Empty()
fnDo := func(isVArg bool) Expr {
if isVArg { // don't need make interface
return x
}
pkg := b.fn.pkg
switch x.kind {
case vkSigned, vkUnsigned, vkFloat:
fn := pkg.rtFunc("MakeAnyInt")
return b.InlineCall(fn, x)
}
panic("todo")
}
if mayDelay && isAny {
return DelayExpr(fnDo)
}
return fnDo(false)
}
// The TypeAssert instruction tests whether interface value X has type // The TypeAssert instruction tests whether interface value X has type
// AssertedType. // AssertedType.
// //
@@ -451,7 +523,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) {
log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.t, commaOk) log.Printf("TypeAssert %v, %v, %v\n", x.impl, assertedTyp.t, commaOk)
} }
switch assertedTyp.kind { switch assertedTyp.kind {
case vkSigned, vkUnsigned: case vkSigned, vkUnsigned, vkFloat:
pkg := b.fn.pkg pkg := b.fn.pkg
fnName := "I2Int" fnName := "I2Int"
if commaOk { if commaOk {

View File

@@ -41,6 +41,7 @@ const (
vkBool vkBool
vkFunc vkFunc
vkTuple vkTuple
vkDelayExpr = -1
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------