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 (
"fmt"
"log"
"llvm.org/llvm/bindings/go/llvm"
)
@ -14,10 +15,11 @@ type BuildCtx struct {
func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value {
var lastVal llvm.Value
for _, stmt := range stmts {
fmt.Println(stmt)
if e := bctx.BuildStmt(ctx, stmt); e != nil {
if lv, ok := e.(llvmVal); ok {
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 {
m := s.Op.(Macro)
return ctx.Macro(m)(bctx, ctx, s.Arg)
log.Printf("building: %v", s)
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
@ -94,7 +106,8 @@ var _ = func() bool {
"bind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple)
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()
},
@ -129,6 +142,30 @@ var _ = func() bool {
}
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

View File

@ -71,6 +71,10 @@ func (i Int) equal(e equaler) bool {
return ok && ii == i
}
func (i Int) String() string {
return fmt.Sprint(int64(i))
}
////////////////////////////////////////////////////////////////////////////////
/*
// String represents a string value
@ -157,6 +161,11 @@ func (l List) equal(e equaler) bool {
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

90
main.go
View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"log"
"github.com/mediocregopher/ginger/expr"
@ -17,93 +18,68 @@ func main() {
// fmt.Println(e)
//}
log.Printf("initializing llvm")
llvm.LinkInMCJIT()
llvm.InitializeNativeTarget()
llvm.InitializeNativeAsmPrinter()
// setup our context, builder, and module
log.Printf("initializing build context")
ctx := expr.NewCtx()
bctx := expr.BuildCtx{
B: llvm.NewBuilder(),
M: llvm.NewModule("my_module"),
}
// do the work in the function
log.Printf("making program")
add := expr.Macro("add")
bind := expr.Macro("bind")
do := expr.Macro("do")
ctxnew := expr.Macro("ctxnew")
ctxbind := expr.Macro("ctxbind")
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)),
//)
op := expr.Macro("op")
in := expr.Macro("in")
incr := expr.Identifier("incr")
stmts := []expr.Statement{
// TODO revisit how bind and related macros (maybe all macros?) deal
// with arguments and their evaluation (keeping an identifier vs
// eval-ing it)
//expr.NewStatement(bind, myAdd, myAddStmts),
expr.NewStatement(bind, ctx1, expr.NewStatement(ctxnew)),
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(bind, incr,
expr.NewStatement(op,
expr.NewList(
expr.NewStatement(add, expr.NewTuple(
expr.Int(1),
expr.NewStatement(in, expr.NewTuple()),
)),
),
),
),
expr.NewStatement(
add,
expr.NewStatement(ctxget, ctx1, out),
expr.NewStatement(ctxget, ctx2, out),
incr,
expr.Int(5),
),
}
// create main and call our function
log.Printf("creating main function")
mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
v := bctx.Build(ctx, stmts...)
bctx.B.CreateRet(v)
log.Printf("actually processing program")
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 {
panic(err)
}
fmt.Println("# verified")
// Dump the IR
fmt.Println("# dumping IR")
bctx.M.Dump()
fmt.Println("# done dumping IR")
// create our exe engine
fmt.Println("# creating new execution engine")
log.Printf("creating execution enging")
engine, err := llvm.NewExecutionEngine(bctx.M)
if err != nil {
panic(err)
}
// run the function!
fmt.Println("# running the function main")
log.Printf("running main function")
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))
}