make Block implement LLVMVal
This commit is contained in:
parent
b9a40be6d8
commit
09573cf98b
55
expr/expr.go
55
expr/expr.go
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
14
expr/util.go
Normal 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
34
main.go
@ -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))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user