diff --git a/cl/_testdata/method/in.go b/cl/_testdata/method/in.go new file mode 100644 index 00000000..991b92b0 --- /dev/null +++ b/cl/_testdata/method/in.go @@ -0,0 +1,19 @@ +package main + +import _ "unsafe" + +type T int + +func (a T) Add(b T) T { + return a + b +} + +//go:linkname printf printf +func printf(format *int8, __llgo_va_list ...any) + +var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0} + +func main() { + a := T(1) + printf(&format[0], a.Add(2)) +} diff --git a/cl/_testdata/method/out.ll b/cl/_testdata/method/out.ll new file mode 100644 index 00000000..8416147c --- /dev/null +++ b/cl/_testdata/method/out.ll @@ -0,0 +1,44 @@ +; 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 +} + +define i64 @"(main.T).Add"(i64 %0, i64 %1) { +_llgo_0: + %2 = add i64 %0, %1 + ret i64 %2 +} + +declare void @printf(ptr, ...) + +define void @main() { +_llgo_0: + call void @main.init() + %0 = call i64 @"(main.T).Add"(i64 1, i64 2) + call void (ptr, ...) @printf(ptr @main.format, i64 %0) + ret void +} diff --git a/cl/compile.go b/cl/compile.go index 0c72c90a..964906ed 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -92,6 +92,7 @@ type context struct { pkg llssa.Package fn llssa.Function fset *token.FileSet + goProg *ssa.Program goTyps *types.Package goPkg *ssa.Package link map[string]string // pkgPath.nameInPkg => linkname @@ -101,8 +102,20 @@ type context struct { inits []func() } -func (p *context) compileType(pkg llssa.Package, member *ssa.Type) { - panic("todo") +func (p *context) compileType(pkg llssa.Package, t *ssa.Type) { + tn := t.Object().(*types.TypeName) + typ := tn.Type() + name := fullName(tn.Pkg(), tn.Name()) + if debugInstr { + log.Println("==> NewType", name, typ) + } + prog := p.goProg + mthds := prog.MethodSets.MethodSet(typ) + for i, n := 0, mthds.Len(); i < n; i++ { + mthd := mthds.At(i) + ssaMthd := prog.MethodValue(mthd) + p.compileFunc(pkg, ssaMthd) + } } // Global variable. @@ -118,11 +131,13 @@ func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { func (p *context) compileFunc(pkg llssa.Package, f *ssa.Function) { name := p.funcName(f.Pkg.Pkg, f) + /* TODO(xsw): confirm this is not needed more if name == "unsafe.init" { return } + */ if debugInstr { - log.Println("==> NewFunc", name) + log.Println("==> NewFunc", name, f.Signature) } fn := pkg.NewFunc(name, f.Signature) p.inits = append(p.inits, func() { @@ -378,6 +393,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll return iPos < jPos }) + pkgProg := pkg.Prog pkgTypes := pkg.Pkg pkgName, pkgPath := pkgTypes.Name(), pathOf(pkgTypes) ret = prog.NewPackage(pkgName, pkgPath) @@ -385,7 +401,8 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll ctx := &context{ prog: prog, pkg: ret, - fset: pkg.Prog.Fset, + fset: pkgProg.Fset, + goProg: pkgProg, goTyps: pkgTypes, goPkg: pkg, link: make(map[string]string), diff --git a/cl/import.go b/cl/import.go index 0509f648..5f2faf45 100644 --- a/cl/import.go +++ b/cl/import.go @@ -116,7 +116,13 @@ func fullName(pkg *types.Package, name string) string { return pathOf(pkg) + "." + name } +// func: pkg.name +// method: (pkg.T).name func funcName(pkg *types.Package, fn *ssa.Function) string { + sig := fn.Signature + if recv := sig.Recv(); recv != nil { + return "(" + recv.Type().String() + ")." + fn.Name() + } ret := fullName(pkg, fn.Name()) if ret == "main.main" { ret = "main" diff --git a/ssa/expr.go b/ssa/expr.go index 970abbc6..45bcdcf2 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -258,7 +258,7 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr { // Load returns the value at the pointer ptr. func (b Builder) Load(ptr Expr) Expr { if debugInstr { - log.Printf("Load %v\n", ptr.impl.Name()) + log.Printf("Load %v\n", ptr.impl) } telem := b.prog.Elem(ptr.Type) return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem} @@ -267,7 +267,7 @@ func (b Builder) Load(ptr Expr) Expr { // Store stores val at the pointer ptr. func (b Builder) Store(ptr, val Expr) Builder { if debugInstr { - log.Printf("Store %v, %v\n", ptr.impl.Name(), val.impl) + log.Printf("Store %v, %v\n", ptr.impl, val.impl) } b.impl.CreateStore(val.impl, ptr.impl) return b @@ -346,7 +346,7 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) { func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { if debugInstr { var b bytes.Buffer - fmt.Fprint(&b, "Call @", fn.impl.Name()) + fmt.Fprint(&b, "Call ", fn.impl.Name()) for _, arg := range args { fmt.Fprint(&b, ", ", arg.impl) } diff --git a/ssa/package.go b/ssa/package.go index 7d040420..bf0cc726 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -187,6 +187,7 @@ type aPackage struct { type Package = *aPackage +// NewConst creates a new named constant. func (p Package) NewConst(name string, val constant.Value) NamedConst { return &aNamedConst{} } diff --git a/ssa/type.go b/ssa/type.go index cb35a885..832846b8 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -17,8 +17,8 @@ package ssa import ( + "fmt" "go/types" - "log" "github.com/goplus/llvm" ) @@ -108,8 +108,21 @@ func (p Program) llvmSignature(sig *types.Signature) Type { if v := p.typs.At(sig); v != nil { 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) - p.typs.Set(sig, ret) + p.typs.Set(sigOrg, ret) return ret } @@ -228,8 +241,7 @@ func (p Program) toLLVMType(typ types.Type) Type { return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} case *types.Chan: } - log.Println("toLLVMType: todo -", typ) - panic("todo") + panic(fmt.Sprintf("toLLVMType: todo - %T\n", typ)) } func (p Program) toLLVMNamedStruct(name string, typ *types.Struct) llvm.Type { @@ -304,12 +316,13 @@ func (p Program) retType(sig *types.Signature) Type { } func (p Program) toLLVMNamed(typ *types.Named) Type { - name := typ.Obj().Name() - switch typ := typ.Underlying().(type) { + switch t := typ.Underlying().(type) { case *types.Struct: - return &aType{p.toLLVMNamedStruct(name, typ), typ, vkInvalid} + name := typ.Obj().Name() + return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} + default: + return p.Type(t) } - panic("todo") } // -----------------------------------------------------------------------------