cl: _testdata/ptrmthd
This commit is contained in:
@@ -33,6 +33,13 @@ _llgo_0:
|
|||||||
ret i64 %2
|
ret i64 %2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i64 @"(*main.T).Add"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
%2 = load i64, ptr %0, align 4
|
||||||
|
%3 = call i64 @"(main.T).Add"(i64 %2, i64 %1)
|
||||||
|
ret i64 %3
|
||||||
|
}
|
||||||
|
|
||||||
declare void @printf(ptr, ...)
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
define void @main() {
|
define void @main() {
|
||||||
|
|||||||
19
cl/_testdata/ptrmthd/in.go
Normal file
19
cl/_testdata/ptrmthd/in.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname printf printf
|
||||||
|
func printf(format *int8, __llgo_va_list ...any)
|
||||||
|
|
||||||
|
type T int8
|
||||||
|
|
||||||
|
func (f *T) Print(v int) {
|
||||||
|
printf((*int8)(f), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = [...]T{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f := &format[0]
|
||||||
|
f.Print(100)
|
||||||
|
}
|
||||||
43
cl/_testdata/ptrmthd/out.ll
Normal file
43
cl/_testdata/ptrmthd/out.ll
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
@main.format = global ptr null
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @printf(ptr, ...)
|
||||||
|
|
||||||
|
define void @"(*main.T).Print"(ptr %0, i64 %1) {
|
||||||
|
_llgo_0:
|
||||||
|
call void (ptr, ...) @printf(ptr %0, i64 %1)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
call void @"(*main.T).Print"(ptr @main.format, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
@@ -109,12 +109,17 @@ func (p *context) compileType(pkg llssa.Package, t *ssa.Type) {
|
|||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewType", name, typ)
|
log.Println("==> NewType", name, typ)
|
||||||
}
|
}
|
||||||
|
p.compileMethods(pkg, typ)
|
||||||
|
p.compileMethods(pkg, types.NewPointer(typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
|
||||||
prog := p.goProg
|
prog := p.goProg
|
||||||
mthds := prog.MethodSets.MethodSet(typ)
|
mthds := prog.MethodSets.MethodSet(typ)
|
||||||
for i, n := 0, mthds.Len(); i < n; i++ {
|
for i, n := 0, mthds.Len(); i < n; i++ {
|
||||||
mthd := mthds.At(i)
|
mthd := mthds.At(i)
|
||||||
ssaMthd := prog.MethodValue(mthd)
|
ssaMthd := prog.MethodValue(mthd)
|
||||||
p.compileFunc(pkg, ssaMthd)
|
p.compileFunc(pkg, mthd.Obj().Pkg(), ssaMthd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +134,18 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
|
|||||||
g.Init(p.prog.Null(g.Type))
|
g.Init(p.prog.Null(g.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) {
|
func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa.Function) {
|
||||||
name := p.funcName(f.Pkg.Pkg, f)
|
sig := f.Signature
|
||||||
|
name := p.funcName(pkgTypes, f)
|
||||||
/* TODO(xsw): confirm this is not needed more
|
/* TODO(xsw): confirm this is not needed more
|
||||||
if name == "unsafe.init" {
|
if name == "unsafe.init" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("==> NewFunc", name, f.Signature)
|
log.Println("==> NewFunc", name, "type:", sig.Recv(), sig)
|
||||||
}
|
}
|
||||||
fn := pkg.NewFunc(name, f.Signature)
|
fn := pkg.NewFunc(name, sig)
|
||||||
p.inits = append(p.inits, func() {
|
p.inits = append(p.inits, func() {
|
||||||
p.fn = fn
|
p.fn = fn
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -221,16 +227,29 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
call := v.Call
|
call := v.Call
|
||||||
kind := funcKind(call.Value)
|
cv := call.Value
|
||||||
|
kind := funcKind(cv)
|
||||||
if kind == fnUnsafeInit {
|
if kind == fnUnsafeInit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if debugGoSSA {
|
if debugGoSSA {
|
||||||
log.Println(">>> Call", call.Value, call.Args)
|
log.Println(">>> Call", cv, call.Args)
|
||||||
}
|
}
|
||||||
fn := p.compileValue(b, call.Value)
|
if builtin, ok := cv.(*ssa.Builtin); ok {
|
||||||
|
fn := builtin.Name()
|
||||||
|
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
||||||
|
arg := call.Args[0]
|
||||||
|
ret = p.compileValue(b, arg)
|
||||||
|
// log.Println("wrapnilchk:", ret.TypeOf())
|
||||||
|
} else {
|
||||||
|
args := p.compileValues(b, call.Args, kind)
|
||||||
|
ret = b.BuiltinCall(fn, args...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn := p.compileValue(b, cv)
|
||||||
args := p.compileValues(b, call.Args, kind)
|
args := p.compileValues(b, call.Args, kind)
|
||||||
ret = b.Call(fn, args...)
|
ret = b.Call(fn, args...)
|
||||||
|
}
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
y := p.compileValue(b, v.Y)
|
y := p.compileValue(b, v.Y)
|
||||||
@@ -238,6 +257,10 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
case *ssa.UnOp:
|
case *ssa.UnOp:
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.UnOp(v.Op, x)
|
ret = b.UnOp(v.Op, x)
|
||||||
|
case *ssa.ChangeType:
|
||||||
|
t := v.Type()
|
||||||
|
x := p.compileValue(b, v.X)
|
||||||
|
ret = b.ChangeType(p.prog.Type(t), x)
|
||||||
case *ssa.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
vx := v.X
|
vx := v.X
|
||||||
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
|
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
|
||||||
@@ -418,7 +441,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
// Do not try to build generic (non-instantiated) functions.
|
// Do not try to build generic (non-instantiated) functions.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ctx.compileFunc(ret, member)
|
ctx.compileFunc(ret, member.Pkg.Pkg, member)
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ctx.compileType(ret, member)
|
ctx.compileType(ret, member)
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
|
|||||||
57
ssa/expr.go
57
ssa/expr.go
@@ -34,6 +34,13 @@ type Expr struct {
|
|||||||
Type
|
Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TypeOf returns the type of the expression.
|
||||||
|
func (v Expr) TypeOf() types.Type {
|
||||||
|
return v.t
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
func llvmValues(vals []Expr) []llvm.Value {
|
func llvmValues(vals []Expr) []llvm.Value {
|
||||||
@@ -330,6 +337,46 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The ChangeType instruction applies to X a value-preserving type
|
||||||
|
// change to Type().
|
||||||
|
//
|
||||||
|
// Type changes are permitted:
|
||||||
|
// - between a named type and its underlying type.
|
||||||
|
// - between two named types of the same underlying type.
|
||||||
|
// - between (possibly named) pointers to identical base types.
|
||||||
|
// - from a bidirectional channel to a read- or write-channel,
|
||||||
|
// optionally adding/removing a name.
|
||||||
|
// - between a type (t) and an instance of the type (tσ), i.e.
|
||||||
|
// Type() == σ(X.Type()) (or X.Type()== σ(Type())) where
|
||||||
|
// σ is the type substitution of Parent().TypeParams by
|
||||||
|
// Parent().TypeArgs.
|
||||||
|
//
|
||||||
|
// This operation cannot fail dynamically.
|
||||||
|
//
|
||||||
|
// Type changes may to be to or from a type parameter (or both). All
|
||||||
|
// types in the type set of X.Type() have a value-preserving type
|
||||||
|
// change to all types in the type set of Type().
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
|
||||||
|
// from an explicit conversion in the source.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = changetype *int <- IntPtr (t0)
|
||||||
|
func (b Builder) ChangeType(t Type, x Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("ChangeType %v, %v\n", t.t, x.impl)
|
||||||
|
}
|
||||||
|
typ := t.t
|
||||||
|
switch typ.(type) {
|
||||||
|
case *types.Pointer:
|
||||||
|
ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr")
|
||||||
|
ret.Type = b.prog.Type(typ)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// The Call instruction represents a function or method call.
|
// The Call instruction represents a function or method call.
|
||||||
@@ -362,4 +409,14 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Builtin represents a specific use of a built-in function, e.g. len.
|
||||||
|
//
|
||||||
|
// Builtins are immutable values. Builtins do not have addresses.
|
||||||
|
//
|
||||||
|
// `fn` indicates the function: one of the built-in functions from the
|
||||||
|
// Go spec (excluding "make" and "new").
|
||||||
|
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
32
ssa/type.go
32
ssa/type.go
@@ -72,6 +72,22 @@ func indexType(t types.Type) types.Type {
|
|||||||
panic("index: type doesn't support index - " + t.String())
|
panic("index: type doesn't support index - " + t.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert method to func
|
||||||
|
func methodToFunc(sig *types.Signature) *types.Signature {
|
||||||
|
if recv := sig.Recv(); recv != nil {
|
||||||
|
tParams := sig.Params()
|
||||||
|
nParams := tParams.Len()
|
||||||
|
params := make([]*types.Var, nParams+1)
|
||||||
|
params[0] = recv
|
||||||
|
for i := 0; i < nParams; i++ {
|
||||||
|
params[i+1] = tParams.At(i)
|
||||||
|
}
|
||||||
|
return types.NewSignatureType(
|
||||||
|
nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
|
||||||
|
}
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type aType struct {
|
type aType struct {
|
||||||
@@ -105,24 +121,12 @@ func (p Program) Type(typ types.Type) Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p Program) llvmSignature(sig *types.Signature) Type {
|
func (p Program) llvmSignature(sig *types.Signature) Type {
|
||||||
|
sig = methodToFunc(sig)
|
||||||
if v := p.typs.At(sig); v != nil {
|
if v := p.typs.At(sig); v != nil {
|
||||||
return v.(Type)
|
return v.(Type)
|
||||||
}
|
}
|
||||||
sigOrg := sig
|
|
||||||
if recv := sig.Recv(); recv != nil {
|
|
||||||
// convert method to func
|
|
||||||
tParams := sig.Params()
|
|
||||||
nParams := tParams.Len()
|
|
||||||
params := make([]*types.Var, nParams+1)
|
|
||||||
params[0] = recv
|
|
||||||
for i := 0; i < nParams; i++ {
|
|
||||||
params[i+1] = tParams.At(i)
|
|
||||||
}
|
|
||||||
sig = types.NewSignatureType(
|
|
||||||
nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
|
|
||||||
}
|
|
||||||
ret := p.toLLVMFunc(sig)
|
ret := p.toLLVMFunc(sig)
|
||||||
p.typs.Set(sigOrg, ret)
|
p.typs.Set(sig, ret)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user