cl: _testcgo/any
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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])
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
74
ssa/expr.go
74
ssa/expr.go
@@ -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 {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const (
|
|||||||
vkBool
|
vkBool
|
||||||
vkFunc
|
vkFunc
|
||||||
vkTuple
|
vkTuple
|
||||||
|
vkDelayExpr = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user