actually connect Expr to llvm somewhat, wrote addExpr

This commit is contained in:
Brian Picciano 2016-07-24 15:57:43 -06:00
parent b53da9531c
commit fd125b3dcd
2 changed files with 121 additions and 5 deletions

View File

@ -6,12 +6,18 @@ import (
"strconv" "strconv"
"strings" "strings"
"llvm.org/llvm/bindings/go/llvm"
"github.com/mediocregopher/ginger/lexer" "github.com/mediocregopher/ginger/lexer"
) )
// TODO empty blocks // TODO empty blocks
// TODO empty parenthesis // 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 // 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
@ -19,6 +25,9 @@ type Actual interface {
// Equal should return true if the type and value of the other expression // Equal should return true if the type and value of the other expression
// are equal. // are equal.
Equal(Actual) bool 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 // 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 is a nice-to-have, nothing will break if it's not there
Token lexer.Token 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 return bb == b
} }
func (b Bool) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Int represents an integer value // Int represents an integer value
@ -59,6 +82,13 @@ func (i Int) Equal(e Actual) bool {
return ii == i 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 // String represents a string value
@ -73,6 +103,10 @@ func (s String) Equal(e Actual) bool {
return ss == s 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 // 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 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 // 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 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 // 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 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 // 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 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 // 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) 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 // 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 return true
} }
func (b Block) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
type exprErr struct { type exprErr struct {

68
main.go
View File

@ -2,17 +2,75 @@ package main
import ( import (
"fmt" "fmt"
"os"
"github.com/mediocregopher/ginger/expr" "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() { 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 { if err != nil {
panic(err) 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))
} }