Merge pull request #62 from xushiwei/q

cl: _testcgo/struct
This commit is contained in:
xushiwei
2024-04-27 08:21:00 +08:00
committed by GitHub
10 changed files with 156 additions and 90 deletions

25
cl/_testcgo/struct/in.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import "C"
import _ "unsafe"
//go:linkname printf C.printf
func printf(format *int8, __llgo_va_list ...any)
type Foo struct {
A C.int
ok bool
}
var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0}
func (p *Foo) Print() {
if p.ok {
printf(&format[0], p.A)
}
}
func main() {
foo := Foo{100, true}
foo.Print()
}

60
cl/_testcgo/struct/out.ll Normal file
View File

@@ -0,0 +1,60 @@
; ModuleID = 'main'
source_filename = "main"
%main.Foo = type { i32, i1 }
@main.format = global ptr null
@"main.init$guard" = global ptr null
define void @"(*main.Foo).Print"(ptr %0) {
_llgo_0:
%1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 1
%2 = load i1, ptr %1, align 1
br i1 %2, label %_llgo_1, label %_llgo_2
_llgo_1: ; preds = %_llgo_0
%3 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0
%4 = load i32, ptr %3, align 4
call void (ptr, ...) @printf(ptr @main.format, i32 %4)
br label %_llgo_2
_llgo_2: ; preds = %_llgo_1, %_llgo_0
ret void
}
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 = alloca %main.Foo, align 8
%1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0
%2 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 1
store i32 100, ptr %1, align 4
store i1 true, ptr %2, align 1
call void @"(*main.Foo).Print"(ptr %0)
ret void
}
declare void @printf(ptr, ...)

View File

@@ -4,16 +4,16 @@ source_filename = "main"
@main.format = global ptr null @main.format = global ptr null
@"main.init$guard" = global ptr null @"main.init$guard" = global ptr null
define i64 @"(T).Add"(i64 %0, i64 %1) { define i64 @"(main.T).Add"(i64 %0, i64 %1) {
_llgo_0: _llgo_0:
%2 = add i64 %0, %1 %2 = add i64 %0, %1
ret i64 %2 ret i64 %2
} }
define i64 @"(*T).Add"(ptr %0, i64 %1) { define i64 @"(*main.T).Add"(ptr %0, i64 %1) {
_llgo_0: _llgo_0:
%2 = load i64, ptr %0, align 4 %2 = load i64, ptr %0, align 4
%3 = call i64 @"(T).Add"(i64 %2, i64 %1) %3 = call i64 @"(main.T).Add"(i64 %2, i64 %1)
ret i64 %3 ret i64 %3
} }
@@ -43,7 +43,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
%0 = call i64 @"(T).Add"(i64 1, i64 2) %0 = call i64 @"(main.T).Add"(i64 1, i64 2)
call void (ptr, ...) @printf(ptr @main.format, i64 %0) call void (ptr, ...) @printf(ptr @main.format, i64 %0)
ret void ret void
} }

View File

@@ -4,7 +4,7 @@ source_filename = "main"
@main.format = global ptr null @main.format = global ptr null
@"main.init$guard" = global ptr null @"main.init$guard" = global ptr null
define void @"(*T).Print"(ptr %0, i64 %1) { define void @"(*main.T).Print"(ptr %0, i64 %1) {
_llgo_0: _llgo_0:
call void (ptr, ...) @printf(ptr %0, i64 %1) call void (ptr, ...) @printf(ptr %0, i64 %1)
ret void ret void
@@ -36,7 +36,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0
define void @main() { define void @main() {
_llgo_0: _llgo_0:
call void @main.init() call void @main.init()
call void @"(*T).Print"(ptr @main.format, i64 100) call void @"(*main.T).Print"(ptr @main.format, i64 100)
ret void ret void
} }

View File

@@ -139,7 +139,7 @@ func (p *context) compileType(pkg llssa.Package, t *ssa.Type) {
tn := t.Object().(*types.TypeName) tn := t.Object().(*types.TypeName)
tnName := tn.Name() tnName := tn.Name()
typ := tn.Type() typ := tn.Type()
name := fullName(tn.Pkg(), tnName) name := llssa.FullName(tn.Pkg(), tnName)
if ignoreName(name) { if ignoreName(name) {
return return
} }
@@ -164,7 +164,7 @@ func (p *context) compileMethods(pkg llssa.Package, typ types.Type) {
// Global variable. // Global variable.
func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) {
typ := gbl.Type() typ := gbl.Type()
name := fullName(gbl.Pkg.Pkg, gbl.Name()) name := llssa.FullName(gbl.Pkg.Pkg, gbl.Name())
if ignoreName(name) || checkCgo(gbl.Name()) { if ignoreName(name) || checkCgo(gbl.Name()) {
return return
} }
@@ -300,6 +300,9 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
t := v.Type() t := v.Type()
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.ChangeType(p.prog.Type(t), x) ret = b.ChangeType(p.prog.Type(t), x)
case *ssa.FieldAddr:
x := p.compileValue(b, v.X)
ret = b.FieldAddr(x, v.Field)
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
@@ -452,7 +455,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
pkgProg := pkg.Prog pkgProg := pkg.Prog
pkgTypes := pkg.Pkg pkgTypes := pkg.Pkg
pkgName, pkgPath := pkgTypes.Name(), pathOf(pkgTypes) pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes)
ret = prog.NewPackage(pkgName, pkgPath) ret = prog.NewPackage(pkgName, pkgPath)
ctx := &context{ ctx := &context{

View File

@@ -51,7 +51,7 @@ func (p *context) importPkg(pkg *types.Package) {
fset := p.fset fset := p.fset
names := scope.Names() names := scope.Names()
contents := make(contentMap) contents := make(contentMap)
pkgPath := pathOf(pkg) pkgPath := llssa.PathOf(pkg)
for _, name := range names { for _, name := range names {
if token.IsExported(name) { if token.IsExported(name) {
obj := scope.Lookup(name) obj := scope.Lookup(name)
@@ -109,17 +109,6 @@ func (p *context) initLinkname(pkgPath, line string) {
} }
} }
func pathOf(pkg *types.Package) string {
if pkg.Name() == "main" {
return "main"
}
return pkg.Path()
}
func fullName(pkg *types.Package, name string) string {
return pathOf(pkg) + "." + name
}
// func: pkg.name // func: pkg.name
// method: (pkg.T).name, (*pkg.T).name // method: (pkg.T).name, (*pkg.T).name
func funcName(pkg *types.Package, fn *ssa.Function) string { func funcName(pkg *types.Package, fn *ssa.Function) string {
@@ -131,10 +120,10 @@ func funcName(pkg *types.Package, fn *ssa.Function) string {
if tp, ok := t.(*types.Pointer); ok { if tp, ok := t.(*types.Pointer); ok {
t, tName = tp.Elem(), "*" t, tName = tp.Elem(), "*"
} }
tName += t.(*types.Named).Obj().Name() tName += llssa.NameOf(t.(*types.Named))
return "(" + tName + ")." + name return "(" + tName + ")." + name
} }
ret := fullName(pkg, name) ret := llssa.FullName(pkg, name)
if ret == "main.main" { if ret == "main.main" {
ret = "main" ret = "main"
} }
@@ -171,7 +160,7 @@ func (p *context) funcOf(fn *ssa.Function) llssa.Function {
func (p *context) varOf(v *ssa.Global) llssa.Global { func (p *context) varOf(v *ssa.Global) llssa.Global {
pkgTypes := p.ensureLoaded(v.Pkg.Pkg) pkgTypes := p.ensureLoaded(v.Pkg.Pkg)
pkg := p.pkg pkg := p.pkg
name := fullName(pkgTypes, v.Name()) name := llssa.FullName(pkgTypes, v.Name())
if ret := pkg.VarOf(name); ret != nil { if ret := pkg.VarOf(name); ret != nil {
return ret return ret
} }

View File

@@ -1,62 +0,0 @@
/*
* Copyright (c) 2023 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 cl
/*
// Define unimplemented intrinsic functions.
//
// Some functions are either normally implemented in Go assembly (like
// sync/atomic functions) or intentionally left undefined to be implemented
// directly in the compiler (like runtime/volatile functions). Either way, look
// for these and implement them if this is the case.
func (b *builder) defineIntrinsicFunction() {
panic("todo")
}
var mathToLLVMMapping = map[string]string{
"math.Ceil": "llvm.ceil.f64",
"math.Exp": "llvm.exp.f64",
"math.Exp2": "llvm.exp2.f64",
"math.Floor": "llvm.floor.f64",
"math.Log": "llvm.log.f64",
"math.Sqrt": "llvm.sqrt.f64",
"math.Trunc": "llvm.trunc.f64",
}
// defineMathOp defines a math function body as a call to a LLVM intrinsic,
// instead of the regular Go implementation. This allows LLVM to reason about
// the math operation and (depending on the architecture) allows it to lower the
// operation to very fast floating point instructions. If this is not possible,
// LLVM will emit a call to a libm function that implements the same operation.
//
// One example of an optimization that LLVM can do is to convert
// float32(math.Sqrt(float64(v))) to a 32-bit floating point operation, which is
// beneficial on architectures where 64-bit floating point operations are (much)
// more expensive than 32-bit ones.
func (b *builder) defineMathOp() {
panic("todo")
}
// Implement most math/bits functions.
//
// This implements all the functions that operate on bits. It does not yet
// implement the arithmetic functions (like bits.Add), which also have LLVM
// intrinsics.
func (b *builder) defineMathBitsIntrinsic() bool {
panic("todo")
}
*/

View File

@@ -280,6 +280,36 @@ func (b Builder) Store(ptr, val Expr) Builder {
return b return b
} }
// The FieldAddr instruction yields the address of Field of *struct X.
//
// The field is identified by its index within the field list of the
// struct type of X.
//
// Dynamically, this instruction panics if X evaluates to a nil
// pointer.
//
// Type() returns a (possibly named) *types.Pointer.
//
// Pos() returns the position of the ast.SelectorExpr.Sel for the
// field, if explicit in the source. For implicit selections, returns
// the position of the inducing explicit selection. If produced for a
// struct literal S{f: e}, it returns the position of the colon; for
// S{e} it returns the start of expression e.
//
// Example printed form:
//
// t1 = &t0.name [#1]
func (b Builder) FieldAddr(x Expr, idx int) Expr {
if debugInstr {
log.Printf("FieldAddr %v, %d\n", x.impl, idx)
}
prog := b.prog
tstruc := prog.Elem(x.Type)
telem := prog.Field(tstruc, idx)
pt := prog.Pointer(telem)
return Expr{llvm.CreateStructGEP(b.impl, tstruc.ll, x.impl, idx), pt}
}
// The IndexAddr instruction yields the address of the element at // The IndexAddr instruction yields the address of the element at
// index `idx` of collection `x`. `idx` is an integer expression. // index `idx` of collection `x`. `idx` is an integer expression.
// //
@@ -324,7 +354,7 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
// t1 = new int // t1 = new int
func (b Builder) Alloc(t Type, heap bool) (ret Expr) { func (b Builder) Alloc(t Type, heap bool) (ret Expr) {
if debugInstr { if debugInstr {
log.Printf("Alloc %v, %v\n", t.ll, heap) log.Printf("Alloc %v, %v\n", t.t, heap)
} }
telem := b.prog.Elem(t) telem := b.prog.Elem(t)
if heap { if heap {

View File

@@ -88,9 +88,9 @@ func TestNamedStruct(t *testing.T) {
assertPkg(t, pkg, `; ModuleID = 'foo/bar' assertPkg(t, pkg, `; ModuleID = 'foo/bar'
source_filename = "foo/bar" source_filename = "foo/bar"
%Empty = type {} %bar.Empty = type {}
@a = external global %Empty @a = external global %bar.Empty
`) `)
} }

View File

@@ -111,6 +111,11 @@ func (p Program) Index(typ Type) Type {
return p.Type(indexType(typ.t)) return p.Type(indexType(typ.t))
} }
func (p Program) Field(typ Type, i int) Type {
tunder := typ.t.Underlying()
return p.Type(tunder.(*types.Struct).Field(i).Type())
}
func (p Program) Type(typ types.Type) Type { func (p Program) Type(typ types.Type) Type {
if v := p.typs.At(typ); v != nil { if v := p.typs.At(typ); v != nil {
return v.(Type) return v.(Type)
@@ -322,11 +327,27 @@ func (p Program) retType(sig *types.Signature) Type {
func (p Program) toLLVMNamed(typ *types.Named) Type { func (p Program) toLLVMNamed(typ *types.Named) Type {
switch t := typ.Underlying().(type) { switch t := typ.Underlying().(type) {
case *types.Struct: case *types.Struct:
name := typ.Obj().Name() name := NameOf(typ)
return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid} return &aType{p.toLLVMNamedStruct(name, t), typ, vkInvalid}
default: default:
return p.Type(t) return p.Type(t)
} }
} }
func NameOf(typ *types.Named) string {
obj := typ.Obj()
return FullName(obj.Pkg(), obj.Name())
}
func FullName(pkg *types.Package, name string) string {
return PathOf(pkg) + "." + name
}
func PathOf(pkg *types.Package) string {
if pkg.Name() == "main" {
return "main"
}
return pkg.Path()
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------