make Block implement LLVMVal

This commit is contained in:
Brian Picciano 2016-08-01 18:08:51 -06:00
parent b9a40be6d8
commit 09573cf98b
6 changed files with 80 additions and 42 deletions

View File

@ -13,13 +13,19 @@ import (
// TODO empty parenthesis // TODO empty parenthesis
// TODO need to figure out how to test LLVMVal stuff // TODO need to figure out how to test LLVMVal stuff
// TODO once we're a bit more confident, make ActualFunc // TODO once we're a bit more confident, make ActualFunc
// TODO LLVMVal -> LLVMBuild?
type LLVMCtx struct {
B llvm.Builder
M llvm.Module
}
// Actual represents the actual expression in question, and has certain // Actual represents the actual expression in question, and has certain
// properties. It is wrapped by Expr which also holds onto contextual // properties. It is wrapped by Expr which also holds onto contextual
// information, like the token to which Actual was originally parsed from // information, like the token to which Actual was originally parsed from
type Actual interface { type Actual interface {
// Initializes an llvm.Value and returns it. // Initializes an llvm.Value and returns it.
LLVMVal(*Ctx, llvm.Builder) llvm.Value LLVMVal(*Ctx, LLVMCtx) llvm.Value
} }
// equaler is used to compare two expressions. The comparison should not take // equaler is used to compare two expressions. The comparison should not take
@ -43,9 +49,9 @@ type Expr struct {
// LLVMVal passes its arguments to the underlying Actual instance. It caches the // LLVMVal passes its arguments to the underlying Actual instance. It caches the
// result, so if this is called multiple times the underlying one is only called // result, so if this is called multiple times the underlying one is only called
// the first time. // the first time.
func (e Expr) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (e Expr) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
if e.val == nil { if e.val == nil {
v := e.Actual.LLVMVal(ctx, builder) v := e.Actual.LLVMVal(ctx, lctx)
e.val = &v e.val = &v
} }
return *e.val return *e.val
@ -67,7 +73,7 @@ func (e Expr) equal(e2 Expr) bool {
type Bool bool type Bool bool
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (b Bool) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (b Bool) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -85,9 +91,9 @@ func (b Bool) equal(e equaler) bool {
type Int int64 type Int int64
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (i Int) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (i Int) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
v := builder.CreateAlloca(llvm.Int64Type(), "") v := lctx.B.CreateAlloca(llvm.Int64Type(), "")
builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v) lctx.B.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
return v return v
} }
@ -105,7 +111,7 @@ func (i Int) equal(e equaler) bool {
type String string type String string
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (s String) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (s String) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -124,7 +130,7 @@ func (s String) equal(e equaler) bool {
type Identifier string type Identifier string
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (id Identifier) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (id Identifier) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -149,7 +155,7 @@ func (m Macro) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (m Macro) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (m Macro) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
panic("Macros have no inherent LLVMVal") panic("Macros have no inherent LLVMVal")
} }
@ -176,7 +182,7 @@ func (tup Tuple) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (tup Tuple) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (tup Tuple) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -208,7 +214,7 @@ func (s Statement) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (s Statement) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
m, ok := s.To.Actual.(Macro) m, ok := s.To.Actual.(Macro)
if !ok { if !ok {
// TODO proper error // TODO proper error
@ -225,7 +231,7 @@ func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
// TODO proper error // TODO proper error
panic(err) panic(err)
} }
return newe.LLVMVal(ctx, builder) return newe.LLVMVal(ctx, lctx)
} }
func (s Statement) equal(e equaler) bool { func (s Statement) equal(e equaler) bool {
@ -238,19 +244,34 @@ func (s Statement) equal(e equaler) bool {
// Block represents a set of statements which share a scope, i.e. If one // Block represents a set of statements which share a scope, i.e. If one
// statement binds a variable the rest of the statements in the block can use // statement binds a variable the rest of the statements in the block can use
// that variable, including sub-blocks within this one. // that variable, including sub-blocks within this one.
type Block []Statement type Block []Expr
func (b Block) String() string { func (b Block) String() string {
strs := make([]string, len(b)) strs := make([]string, len(b))
for i := range b { for i := range b {
strs[i] = b[i].String() strs[i] = b[i].Actual.(Statement).String()
} }
return fmt.Sprintf("{ %s }", strings.Join(strs, " ")) return fmt.Sprintf("{ %s }", strings.Join(strs, " "))
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (b Block) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (b Block) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
return llvm.Value{} name := randStr() // TODO make this based on token
// TODO make these based on actual statements
out := llvm.Int64Type()
in := []llvm.Type{}
fn := llvm.AddFunction(lctx.M, name, llvm.FunctionType(out, in, false))
block := llvm.AddBasicBlock(fn, "entry")
lctx.B.SetInsertPoint(block, block.FirstInstruction())
var v llvm.Value
for _, se := range b {
v = se.Actual.LLVMVal(ctx, lctx)
}
// last v is used as return
// TODO empty return
lctx.B.CreateRet(v)
return fn
} }
func (b Block) equal(e equaler) bool { func (b Block) equal(e equaler) bool {

View File

@ -8,11 +8,11 @@ import (
type addActual []Expr type addActual []Expr
func (aa addActual) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { func (aa addActual) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
a := builder.CreateLoad(aa[0].LLVMVal(ctx, builder), "") a := lctx.B.CreateLoad(aa[0].LLVMVal(ctx, lctx), "")
for i := range aa[1:] { for i := range aa[1:] {
b := builder.CreateLoad(aa[i+1].LLVMVal(ctx, builder), "") b := lctx.B.CreateLoad(aa[i+1].LLVMVal(ctx, lctx), "")
a = builder.CreateAdd(a, b, "") a = lctx.B.CreateAdd(a, b, "")
} }
return a return a
} }

View File

@ -291,14 +291,13 @@ func parseBlock(toks []lexer.Token) (Expr, error) {
if expr, toks, err = parse(toks); err != nil { if expr, toks, err = parse(toks); err != nil {
return Expr{}, err return Expr{}, err
} }
stmt, ok := expr.Actual.(Statement) if _, ok := expr.Actual.(Statement); !ok {
if !ok {
return Expr{}, exprErr{ return Expr{}, exprErr{
reason: "blocks may only contain full statements", reason: "blocks may only contain full statements",
tok: expr.Token, tok: expr.Token,
tokCtx: "non-statement here", tokCtx: "non-statement here",
} }
} }
b = append(b, stmt) b = append(b, expr)
} }
} }

View File

@ -131,10 +131,10 @@ func TestParseStatement(t *T) {
} }
func TestParseBlock(t *T) { func TestParseBlock(t *T) {
stmt := func(in, to Expr) Statement { stmt := func(in, to Expr) Expr {
return Statement{In: in, To: to} return Expr{Actual: Statement{In: in, To: to}}
} }
block := func(stmts ...Statement) Expr { block := func(stmts ...Expr) Expr {
return Expr{Actual: Block(stmts)} return Expr{Actual: Block(stmts)}
} }

14
expr/util.go Normal file
View File

@ -0,0 +1,14 @@
package expr
import (
"encoding/hex"
"math/rand"
)
func randStr() string {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
panic(err)
}
return hex.EncodeToString(b)
}

34
main.go
View File

@ -22,45 +22,49 @@ func main() {
llvm.InitializeNativeAsmPrinter() llvm.InitializeNativeAsmPrinter()
// setup our builder and module // setup our builder and module
builder := llvm.NewBuilder() lctx := expr.LLVMCtx{
mod := llvm.NewModule("my_module") B: llvm.NewBuilder(),
M: llvm.NewModule("my_module"),
// create our function prologue }
main := llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false)
llvm.AddFunction(mod, "main", main)
block := llvm.AddBasicBlock(mod.NamedFunction("main"), "entry")
builder.SetInsertPoint(block, block.FirstInstruction())
// do the work in the function
a := expr.Expr{Actual: expr.Int(1)} a := expr.Expr{Actual: expr.Int(1)}
b := expr.Expr{Actual: expr.Int(2)} b := expr.Expr{Actual: expr.Int(2)}
c := expr.Expr{Actual: expr.Int(3)} c := expr.Expr{Actual: expr.Int(3)}
tup := expr.Expr{Actual: expr.Tuple{a, b, c}} tup := expr.Expr{Actual: expr.Tuple([]expr.Expr{a, b, c})}
addMacro := expr.Expr{Actual: expr.Macro("add")} addMacro := expr.Expr{Actual: expr.Macro("add")}
stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}} stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}}
block := expr.Block([]expr.Expr{stmt})
fn := block.LLVMVal(expr.RootCtx, lctx)
result := stmt.LLVMVal(expr.RootCtx, builder) // create main and call our function
builder.CreateRet(result) mainFn := llvm.AddFunction(lctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
lctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
ret := lctx.B.CreateCall(fn, []llvm.Value{}, "")
lctx.B.CreateRet(ret)
// verify it's all good // verify it's all good
if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { if err := llvm.VerifyModule(lctx.M, llvm.ReturnStatusAction); err != nil {
panic(err) panic(err)
} }
fmt.Println("# verified") fmt.Println("# verified")
// Dump the IR // Dump the IR
fmt.Println("# dumping IR") fmt.Println("# dumping IR")
mod.Dump() lctx.M.Dump()
fmt.Println("# done dumping IR") fmt.Println("# done dumping IR")
// create our exe engine // create our exe engine
fmt.Println("# creating new execution engine") fmt.Println("# creating new execution engine")
engine, err := llvm.NewExecutionEngine(mod) engine, err := llvm.NewExecutionEngine(lctx.M)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// run the function! // run the function!
fmt.Println("# running the function main") fmt.Println("# running the function main")
funcResult := engine.RunFunction(mod.NamedFunction("main"), []llvm.GenericValue{}) funcResult := engine.RunFunction(lctx.M.NamedFunction("main"), []llvm.GenericValue{})
fmt.Printf("%d\n", funcResult.Int(false)) fmt.Printf("%d\n", funcResult.Int(false))
} }