cl: _testdata/printval
This commit is contained in:
12
cl/_testdata/printval/in.go
Normal file
12
cl/_testdata/printval/in.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//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() {
|
||||||
|
printf(&format[0], 100)
|
||||||
|
}
|
||||||
37
cl/_testdata/printval/out.ll
Normal file
37
cl/_testdata/printval/out.ll
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
; 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() {
|
||||||
|
_llgo_0:
|
||||||
|
call void @main.init()
|
||||||
|
call void (ptr, ...) @printf(ptr @main.format, i64 100)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package cl
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/constant"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"log"
|
"log"
|
||||||
@@ -96,6 +97,7 @@ type context struct {
|
|||||||
link map[string]string // pkgPath.nameInPkg => linkname
|
link map[string]string // pkgPath.nameInPkg => linkname
|
||||||
loaded map[*types.Package]none // loaded packages
|
loaded map[*types.Package]none // loaded packages
|
||||||
bvals map[ssa.Value]llssa.Expr // block values
|
bvals map[ssa.Value]llssa.Expr // block values
|
||||||
|
vargs map[*ssa.Alloc][]llssa.Expr // varargs
|
||||||
inits []func()
|
inits []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +162,43 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAny(t types.Type) bool {
|
||||||
|
if t, ok := t.(*types.Interface); ok {
|
||||||
|
return t.Empty()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func intVal(v ssa.Value) int64 {
|
||||||
|
if c, ok := v.(*ssa.Const); ok {
|
||||||
|
if iv, exact := constant.Int64Val(c.Value); exact {
|
||||||
|
return iv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("intVal: ssa.Value is not a const int")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) isVArgs(vx ssa.Value) (ret []llssa.Expr, ok bool) {
|
||||||
|
if va, vok := vx.(*ssa.Alloc); vok {
|
||||||
|
ret, ok = p.vargs[va] // varargs: this is a varargs index
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *context) checkVArgs(v *ssa.Alloc, t types.Type) bool {
|
||||||
|
if v.Comment == "varargs" { // this is a varargs allocation
|
||||||
|
if t, ok := t.(*types.Pointer); ok {
|
||||||
|
if arr, ok := t.Elem().(*types.Array); ok {
|
||||||
|
if isAny(arr.Elem()) {
|
||||||
|
p.vargs[v] = make([]llssa.Expr, arr.Len())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret llssa.Expr) {
|
func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret llssa.Expr) {
|
||||||
if v, ok := p.bvals[iv]; ok {
|
if v, ok := p.bvals[iv]; ok {
|
||||||
return v
|
return v
|
||||||
@@ -185,12 +224,31 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l
|
|||||||
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.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
x := p.compileValue(b, v.X)
|
vx := v.X
|
||||||
|
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x := p.compileValue(b, vx)
|
||||||
idx := p.compileValue(b, v.Index)
|
idx := p.compileValue(b, v.Index)
|
||||||
ret = b.IndexAddr(x, idx)
|
ret = b.IndexAddr(x, idx)
|
||||||
|
case *ssa.Slice:
|
||||||
|
vx := v.X
|
||||||
|
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
|
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
|
||||||
|
return
|
||||||
|
}
|
||||||
ret = b.Alloc(p.prog.Type(t), v.Heap)
|
ret = b.Alloc(p.prog.Type(t), v.Heap)
|
||||||
|
case *ssa.MakeInterface:
|
||||||
|
t := v.Type()
|
||||||
|
if isAny(t) { // varargs: don't need to convert an expr to any
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv))
|
||||||
}
|
}
|
||||||
@@ -205,7 +263,19 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
|
|||||||
}
|
}
|
||||||
switch v := instr.(type) {
|
switch v := instr.(type) {
|
||||||
case *ssa.Store:
|
case *ssa.Store:
|
||||||
ptr := p.compileValue(b, v.Addr)
|
va := v.Addr
|
||||||
|
if va, ok := va.(*ssa.IndexAddr); ok {
|
||||||
|
if args, ok := p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
||||||
|
idx := intVal(va.Index)
|
||||||
|
val := v.Val
|
||||||
|
if vi, ok := val.(*ssa.MakeInterface); ok {
|
||||||
|
val = vi.X
|
||||||
|
}
|
||||||
|
args[idx] = p.compileValue(b, val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr := p.compileValue(b, va)
|
||||||
val := p.compileValue(b, v.Val)
|
val := p.compileValue(b, v.Val)
|
||||||
b.Store(ptr, val)
|
b.Store(ptr, val)
|
||||||
case *ssa.Jump:
|
case *ssa.Jump:
|
||||||
@@ -262,12 +332,16 @@ func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr {
|
|||||||
func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr {
|
func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr {
|
||||||
_ = b
|
_ = b
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
|
case *ssa.Slice: // varargs: this is a varargs slice
|
||||||
|
if args, ok := p.isVArgs(v.X); ok {
|
||||||
|
return append(ret, args...)
|
||||||
|
}
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
if v.Value == nil {
|
if v.Value == nil {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("todo")
|
panic(fmt.Sprintf("compileVArg: unknown value - %T\n", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr {
|
func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr {
|
||||||
@@ -316,6 +390,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll
|
|||||||
goPkg: pkg,
|
goPkg: pkg,
|
||||||
link: make(map[string]string),
|
link: make(map[string]string),
|
||||||
loaded: make(map[*types.Package]none),
|
loaded: make(map[*types.Package]none),
|
||||||
|
vargs: make(map[*ssa.Alloc][]llssa.Expr),
|
||||||
}
|
}
|
||||||
ctx.initFiles(pkgPath, files)
|
ctx.initFiles(pkgPath, files)
|
||||||
for _, m := range members {
|
for _, m := range members {
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ import (
|
|||||||
"github.com/goplus/llgo/cl/cltest"
|
"github.com/goplus/llgo/cl/cltest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromTestdata(t *testing.T) {
|
|
||||||
cltest.FromDir(t, "", "./_testdata")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCompile(t *testing.T, src, expected string) {
|
func testCompile(t *testing.T, src, expected string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
cltest.TestCompileEx(t, src, "foo.go", expected)
|
cltest.TestCompileEx(t, src, "foo.go", expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFromTestdata(t *testing.T) {
|
||||||
|
cltest.FromDir(t, "", "./_testdata")
|
||||||
|
}
|
||||||
|
|
||||||
func TestVar(t *testing.T) {
|
func TestVar(t *testing.T) {
|
||||||
testCompile(t, `package foo
|
testCompile(t, `package foo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user