implement runtime operations and add a bunch of logging

This commit is contained in:
Brian Picciano 2016-08-20 12:42:02 -06:00
parent 51367a253a
commit f9aec75bf1
3 changed files with 83 additions and 61 deletions

View File

@ -2,6 +2,7 @@ package expr
import ( import (
"fmt" "fmt"
"log"
"llvm.org/llvm/bindings/go/llvm" "llvm.org/llvm/bindings/go/llvm"
) )
@ -14,10 +15,11 @@ type BuildCtx struct {
func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value { func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value {
var lastVal llvm.Value var lastVal llvm.Value
for _, stmt := range stmts { for _, stmt := range stmts {
fmt.Println(stmt)
if e := bctx.BuildStmt(ctx, stmt); e != nil { if e := bctx.BuildStmt(ctx, stmt); e != nil {
if lv, ok := e.(llvmVal); ok { if lv, ok := e.(llvmVal); ok {
lastVal = llvm.Value(lv) lastVal = llvm.Value(lv)
} else {
log.Printf("BuildStmt returned non llvmVal from %v: %v (%T)", stmt, e, e)
} }
} }
} }
@ -28,8 +30,18 @@ func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value {
} }
func (bctx BuildCtx) BuildStmt(ctx Ctx, s Statement) Expr { func (bctx BuildCtx) BuildStmt(ctx Ctx, s Statement) Expr {
m := s.Op.(Macro) log.Printf("building: %v", s)
return ctx.Macro(m)(bctx, ctx, s.Arg) switch o := s.Op.(type) {
case Macro:
return ctx.Macro(o)(bctx, ctx, s.Arg)
case Identifier:
fn := ctx.Identifier(o).(llvmVal)
arg := bctx.buildExpr(ctx, s.Arg).(llvmVal)
out := bctx.B.CreateCall(llvm.Value(fn), []llvm.Value{llvm.Value(arg)}, "")
return llvmVal(out)
default:
panic(fmt.Sprintf("non op type %v (%T)", s.Op, s.Op))
}
} }
// may return nil if e is a Statement which has no return // may return nil if e is a Statement which has no return
@ -94,7 +106,8 @@ var _ = func() bool {
"bind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr { "bind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple) tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple)
id := bctx.buildExprTill(ctx, tup[0], isIdentifier).(Identifier) id := bctx.buildExprTill(ctx, tup[0], isIdentifier).(Identifier)
ctx.Bind(id, bctx.buildExpr(ctx, tup[1])) val := bctx.buildExpr(ctx, tup[1])
ctx.Bind(id, val)
return NewTuple() return NewTuple()
}, },
@ -129,6 +142,30 @@ var _ = func() bool {
} }
return NewTuple() return NewTuple()
}, },
"op": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
l := bctx.buildExprTill(ctx, e, isList).(List)
stmts := make([]Statement, len(l))
for i := range l {
stmts[i] = l[i].(Statement)
}
// TODO obviously this needs to be fixed
fn := llvm.AddFunction(bctx.M, "", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{llvm.Int64Type()}, false))
fnbl := llvm.AddBasicBlock(fn, "entry")
prevbl := bctx.B.GetInsertBlock()
bctx.B.SetInsertPoint(fnbl, fnbl.FirstInstruction())
out := bctx.Build(NewCtx(), stmts...)
bctx.B.CreateRet(out)
bctx.B.SetInsertPointAtEnd(prevbl)
return llvmVal(fn)
},
"in": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
fn := bctx.B.GetInsertBlock().Parent()
return llvmVal(fn.Param(0))
},
}, },
} }
return false return false

View File

@ -71,6 +71,10 @@ func (i Int) equal(e equaler) bool {
return ok && ii == i return ok && ii == i
} }
func (i Int) String() string {
return fmt.Sprint(int64(i))
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
// String represents a string value // String represents a string value
@ -157,6 +161,11 @@ func (l List) equal(e equaler) bool {
return ok && exprsEqual(l, ll) return ok && exprsEqual(l, ll)
} }
func isList(e Expr) bool {
_, ok := e.(List)
return ok
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Statement represents an actual action which will be taken. The input value is // Statement represents an actual action which will be taken. The input value is

88
main.go
View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
"github.com/mediocregopher/ginger/expr" "github.com/mediocregopher/ginger/expr"
@ -17,93 +18,68 @@ func main() {
// fmt.Println(e) // fmt.Println(e)
//} //}
log.Printf("initializing llvm")
llvm.LinkInMCJIT() llvm.LinkInMCJIT()
llvm.InitializeNativeTarget() llvm.InitializeNativeTarget()
llvm.InitializeNativeAsmPrinter() llvm.InitializeNativeAsmPrinter()
// setup our context, builder, and module log.Printf("initializing build context")
ctx := expr.NewCtx() ctx := expr.NewCtx()
bctx := expr.BuildCtx{ bctx := expr.BuildCtx{
B: llvm.NewBuilder(), B: llvm.NewBuilder(),
M: llvm.NewModule("my_module"), M: llvm.NewModule("my_module"),
} }
// do the work in the function log.Printf("making program")
add := expr.Macro("add") add := expr.Macro("add")
bind := expr.Macro("bind") bind := expr.Macro("bind")
do := expr.Macro("do") op := expr.Macro("op")
ctxnew := expr.Macro("ctxnew") in := expr.Macro("in")
ctxbind := expr.Macro("ctxbind") incr := expr.Identifier("incr")
ctxget := expr.Macro("ctxget")
ctx1 := expr.Identifier("ctx1")
ctx2 := expr.Identifier("ctx2")
idA := expr.Identifier("A")
idB := expr.Identifier("B")
//myAdd := expr.Identifier("myAdd")
out := expr.Identifier("out")
// TODO we couldn't actually use this either, because the builder was
// changing out the internal values of the List the first time it was hit,
// and then just using those the second time around
//myAddStmts := expr.NewList(
// expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
//)
stmts := []expr.Statement{ stmts := []expr.Statement{
// TODO revisit how bind and related macros (maybe all macros?) deal expr.NewStatement(bind, incr,
// with arguments and their evaluation (keeping an identifier vs expr.NewStatement(op,
// eval-ing it) expr.NewList(
//expr.NewStatement(bind, myAdd, myAddStmts), expr.NewStatement(add, expr.NewTuple(
expr.Int(1),
expr.NewStatement(bind, ctx1, expr.NewStatement(ctxnew)), expr.NewStatement(in, expr.NewTuple()),
expr.NewStatement(ctxbind, ctx1, idA, expr.Int(1)),
expr.NewStatement(ctxbind, ctx1, idB, expr.Int(2)),
expr.NewStatement(do, ctx1, expr.NewList(
expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
)),
expr.NewStatement(bind, ctx2, expr.NewStatement(ctxnew)),
expr.NewStatement(ctxbind, ctx2, idA, expr.Int(3)),
expr.NewStatement(ctxbind, ctx2, idB, expr.Int(4)),
expr.NewStatement(do, ctx2, expr.NewList(
expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
)), )),
),
),
),
expr.NewStatement( expr.NewStatement(
add, incr,
expr.NewStatement(ctxget, ctx1, out), expr.Int(5),
expr.NewStatement(ctxget, ctx2, out),
), ),
} }
// create main and call our function log.Printf("creating main function")
mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false)) mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
mainBlock := llvm.AddBasicBlock(mainFn, "entry") mainBlock := llvm.AddBasicBlock(mainFn, "entry")
bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction()) bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
v := bctx.Build(ctx, stmts...) log.Printf("actually processing program")
bctx.B.CreateRet(v) out := bctx.Build(ctx, stmts...)
bctx.B.CreateRet(out)
//bctx.Build(ctx, stmts...)
//bctx.B.CreateRet(llvm.ConstInt(llvm.Int64Type(), uint64(5), false))
// verify it's all good fmt.Println("######## dumping IR")
bctx.M.Dump()
fmt.Println("######## done dumping IR")
log.Printf("verifying")
if err := llvm.VerifyModule(bctx.M, llvm.ReturnStatusAction); err != nil { if err := llvm.VerifyModule(bctx.M, llvm.ReturnStatusAction); err != nil {
panic(err) panic(err)
} }
fmt.Println("# verified")
// Dump the IR log.Printf("creating execution enging")
fmt.Println("# dumping IR")
bctx.M.Dump()
fmt.Println("# done dumping IR")
// create our exe engine
fmt.Println("# creating new execution engine")
engine, err := llvm.NewExecutionEngine(bctx.M) engine, err := llvm.NewExecutionEngine(bctx.M)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// run the function! log.Printf("running main function")
fmt.Println("# running the function main")
funcResult := engine.RunFunction(bctx.M.NamedFunction("main"), []llvm.GenericValue{}) funcResult := engine.RunFunction(bctx.M.NamedFunction("main"), []llvm.GenericValue{})
fmt.Printf("%d\n", funcResult.Int(false)) fmt.Printf("\nOUTPUT:\n%d\n", funcResult.Int(false))
} }