From fd125b3dcdce94143eb2955ca1fa9794d0208e0f Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Sun, 24 Jul 2016 15:57:43 -0600 Subject: [PATCH] actually connect Expr to llvm somewhat, wrote addExpr --- expr/expr.go | 58 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/expr/expr.go b/expr/expr.go index bddb928..d201326 100644 --- a/expr/expr.go +++ b/expr/expr.go @@ -6,12 +6,18 @@ import ( "strconv" "strings" + "llvm.org/llvm/bindings/go/llvm" + "github.com/mediocregopher/ginger/lexer" ) // TODO empty blocks // TODO empty parenthesis +// TODO having Equal as part of the Actual interface is going to be annoying. +// The built in macros which return their own expressions don't really care +// about it, and it's really only needed for tests I think. + // Actual represents the actual expression in question, and has certain // properties. It is wrapped by Expr which also holds onto contextual // information, like the token to which Actual was originally parsed from @@ -19,6 +25,9 @@ type Actual interface { // Equal should return true if the type and value of the other expression // are equal. Equal(Actual) bool + + // Initializes an llvm.Value and returns it + LLVMVal(llvm.Builder) llvm.Value } // Expr contains the actual expression as well as some contextual information @@ -29,6 +38,16 @@ type Expr struct { // Token is a nice-to-have, nothing will break if it's not there Token lexer.Token + + val *llvm.Value +} + +func (e Expr) LLVMVal(builder llvm.Builder) llvm.Value { + if e.val == nil { + v := e.Actual.LLVMVal(builder) + e.val = &v + } + return *e.val } //////////////////////////////////////////////////////////////////////////////// @@ -45,6 +64,10 @@ func (b Bool) Equal(e Actual) bool { return bb == b } +func (b Bool) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Int represents an integer value @@ -59,6 +82,13 @@ func (i Int) Equal(e Actual) bool { return ii == i } +// LLVMVal creates a new llvm value using the builder and returns it +func (i Int) LLVMVal(builder llvm.Builder) llvm.Value { + v := builder.CreateAlloca(llvm.Int64Type(), "") + builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v) + return v +} + //////////////////////////////////////////////////////////////////////////////// // String represents a string value @@ -73,6 +103,10 @@ func (s String) Equal(e Actual) bool { return ss == s } +func (s String) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Identifier represents a binding to some other value which has been given a @@ -88,6 +122,10 @@ func (id Identifier) Equal(e Actual) bool { return idid == id } +func (id Identifier) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Macro is an identifier for a macro which can be used to transform @@ -109,6 +147,10 @@ func (m Macro) Equal(e Actual) bool { return m == mm } +func (m Macro) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Tuple represents a fixed set of expressions which are interacted with as if @@ -137,6 +179,10 @@ func (tup Tuple) Equal(e Actual) bool { return true } +func (tup Tuple) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Pipe represents a set of expressions which operate on values and return new @@ -166,6 +212,10 @@ func (p Pipe) Equal(e Actual) bool { return true } +func (p Pipe) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Statement represents an actual action which will be taken. The input value is @@ -186,6 +236,10 @@ func (s Statement) Equal(e Actual) bool { return ok && s.in.Actual.Equal(ss.in.Actual) && s.pipe.Equal(ss.pipe) } +func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// // Block represents a set of statements which share a scope, i.e. If one @@ -215,6 +269,10 @@ func (b Block) Equal(e Actual) bool { return true } +func (b Block) LLVMVal(builder llvm.Builder) llvm.Value { + return llvm.Value{} +} + //////////////////////////////////////////////////////////////////////////////// type exprErr struct { diff --git a/main.go b/main.go index e001330..1d85739 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,75 @@ package main import ( "fmt" - "os" "github.com/mediocregopher/ginger/expr" + + "llvm.org/llvm/bindings/go/llvm" ) +type addActual []expr.Expr + +func (aa addActual) Equal(expr.Actual) bool { return false } + +func (aa addActual) LLVMVal(builder llvm.Builder) llvm.Value { + a := builder.CreateLoad(aa[0].LLVMVal(builder), "") + for i := range aa[1:] { + b := builder.CreateLoad(aa[i+1].LLVMVal(builder), "") + a = builder.CreateAdd(a, b, "") + } + return a +} + func main() { - ee, err := expr.Parse(os.Stdin) + //ee, err := expr.Parse(os.Stdin) + //if err != nil { + // panic(err) + //} + //for _, e := range ee { + // fmt.Println(e) + //} + + llvm.LinkInMCJIT() + llvm.InitializeNativeTarget() + llvm.InitializeNativeAsmPrinter() + + // setup our builder and module + builder := llvm.NewBuilder() + mod := 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()) + + a := expr.Expr{Actual: expr.Int(1)} + b := expr.Expr{Actual: expr.Int(2)} + c := expr.Expr{Actual: expr.Int(3)} + add := addActual{a, b, c} + result := add.LLVMVal(builder) + builder.CreateRet(result) + + // verify it's all good + if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + panic(err) + } + fmt.Println("# verified") + + // Dump the IR + fmt.Println("# dumping IR") + mod.Dump() + fmt.Println("# done dumping IR") + + // create our exe engine + fmt.Println("# creating new execution engine") + engine, err := llvm.NewExecutionEngine(mod) if err != nil { panic(err) } - for _, e := range ee { - fmt.Println(e) - } + + // run the function! + fmt.Println("# running the function main") + funcResult := engine.RunFunction(mod.NamedFunction("main"), []llvm.GenericValue{}) + fmt.Printf("%d\n", funcResult.Int(false)) }