Skip to content
This repository has been archived by the owner on Jun 1, 2020. It is now read-only.

use llir/llvm@v0.3.0-pre2 for code generation #113

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions codegen/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package codegen

import (
"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/constant"
"github.com/llir/llvm/ir/enum"
"github.com/llir/llvm/ir/types"
"github.com/llir/llvm/ir/value"
)

type Builder interface {
NewAShr(x, y value.Value) *ir.InstAShr
NewAdd(x, y value.Value) *ir.InstAdd
NewAddrSpaceCast(from value.Value, to types.Type) *ir.InstAddrSpaceCast
NewAlloca(elemType types.Type) *ir.InstAlloca
NewAnd(x, y value.Value) *ir.InstAnd
NewAtomicRMW(op enum.AtomicOp, dst, x value.Value, ordering enum.AtomicOrdering) *ir.InstAtomicRMW
NewBitCast(from value.Value, to types.Type) *ir.InstBitCast
NewBr(target *ir.BasicBlock) *ir.TermBr
NewCall(callee value.Value, args ...value.Value) *ir.InstCall
NewCatchPad(scope *ir.TermCatchSwitch, args ...value.Value) *ir.InstCatchPad
NewCatchRet(from *ir.InstCatchPad, to *ir.BasicBlock) *ir.TermCatchRet
NewCatchSwitch(scope ir.ExceptionScope, handlers []*ir.BasicBlock, unwindTarget ir.UnwindTarget) *ir.TermCatchSwitch
NewCleanupPad(scope ir.ExceptionScope, args ...value.Value) *ir.InstCleanupPad
NewCleanupRet(from *ir.InstCleanupPad, to ir.UnwindTarget) *ir.TermCleanupRet
NewCmpXchg(ptr, cmp, new value.Value, successOrdering, failureOrdering enum.AtomicOrdering) *ir.InstCmpXchg
NewCondBr(cond value.Value, targetTrue, targetFalse *ir.BasicBlock) *ir.TermCondBr
NewExtractElement(x, index value.Value) *ir.InstExtractElement
NewExtractValue(x value.Value, indices ...int64) *ir.InstExtractValue
NewFAdd(x, y value.Value) *ir.InstFAdd
NewFCmp(pred enum.FPred, x, y value.Value) *ir.InstFCmp
NewFDiv(x, y value.Value) *ir.InstFDiv
NewFMul(x, y value.Value) *ir.InstFMul
NewFPExt(from value.Value, to types.Type) *ir.InstFPExt
NewFPToSI(from value.Value, to types.Type) *ir.InstFPToSI
NewFPToUI(from value.Value, to types.Type) *ir.InstFPToUI
NewFPTrunc(from value.Value, to types.Type) *ir.InstFPTrunc
NewFRem(x, y value.Value) *ir.InstFRem
NewFSub(x, y value.Value) *ir.InstFSub
NewFence(ordering enum.AtomicOrdering) *ir.InstFence
NewGetElementPtr(src value.Value, indices ...value.Value) *ir.InstGetElementPtr
NewICmp(pred enum.IPred, x, y value.Value) *ir.InstICmp
NewIndirectBr(addr constant.Constant, validTargets ...*ir.BasicBlock) *ir.TermIndirectBr
NewInsertElement(x, elem, index value.Value) *ir.InstInsertElement
NewInsertValue(x, elem value.Value, indices ...int64) *ir.InstInsertValue
NewIntToPtr(from value.Value, to types.Type) *ir.InstIntToPtr
NewInvoke(invokee value.Value, args []value.Value, normal, exception *ir.BasicBlock) *ir.TermInvoke
NewLShr(x, y value.Value) *ir.InstLShr
NewLandingPad(resultType types.Type, clauses ...*ir.Clause) *ir.InstLandingPad
NewLoad(src value.Value) *ir.InstLoad
NewMul(x, y value.Value) *ir.InstMul
NewOr(x, y value.Value) *ir.InstOr
NewPhi(incs ...*ir.Incoming) *ir.InstPhi
NewPtrToInt(from value.Value, to types.Type) *ir.InstPtrToInt
NewResume(x value.Value) *ir.TermResume
NewRet(x value.Value) *ir.TermRet
NewSDiv(x, y value.Value) *ir.InstSDiv
NewSExt(from value.Value, to types.Type) *ir.InstSExt
NewSIToFP(from value.Value, to types.Type) *ir.InstSIToFP
NewSRem(x, y value.Value) *ir.InstSRem
NewSelect(cond, x, y value.Value) *ir.InstSelect
NewShl(x, y value.Value) *ir.InstShl
NewShuffleVector(x, y, mask value.Value) *ir.InstShuffleVector
NewStore(src, dst value.Value) *ir.InstStore
NewSub(x, y value.Value) *ir.InstSub
NewSwitch(x value.Value, targetDefault *ir.BasicBlock, cases ...*ir.Case) *ir.TermSwitch
NewTrunc(from value.Value, to types.Type) *ir.InstTrunc
NewUDiv(x, y value.Value) *ir.InstUDiv
NewUIToFP(from value.Value, to types.Type) *ir.InstUIToFP
NewURem(x, y value.Value) *ir.InstURem
NewUnreachable() *ir.TermUnreachable
NewVAArg(vaList value.Value, argType types.Type) *ir.InstVAArg
NewXor(x, y value.Value) *ir.InstXor
NewZExt(from value.Value, to types.Type) *ir.InstZExt
}
90 changes: 48 additions & 42 deletions codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ import (
"fmt"

"github.com/elz-lang/elz/ast"
"github.com/elz-lang/elz/lib/llvm"

"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/constant"
"github.com/llir/llvm/ir/types"
"github.com/llir/llvm/ir/value"
)

type CodeGenerator struct {
// For LLVM
mod llvm.Module
mod *ir.Module
// Internal
bindings map[string]*ast.Binding
}

func NewGenerator() *CodeGenerator {
return &CodeGenerator{
mod: llvm.NewModule(""),
mod: ir.NewModule(),
bindings: make(map[string]*ast.Binding),
}
}
Expand All @@ -30,31 +34,29 @@ func (c *CodeGenerator) GenBinding(binding *ast.Binding) {
// TODO: generate function template
}

func (c *CodeGenerator) CallBindingWith(builder llvm.Builder, binding *ast.Binding, vs []llvm.Value) llvm.Value {
func (c *CodeGenerator) CallBindingWith(builder Builder, binding *ast.Binding, vs []value.Value) value.Value {
if len(vs) == len(binding.ParamList) {
typeList := make([]llvm.Type, len(vs))
scope := map[string]llvm.Type{}
valueScope := map[string]llvm.Value{}
params := make([]*ir.Param, len(vs))
scope := map[string]types.Type{}
valueScope := map[string]value.Value{}
for i, v := range vs {
paramName := binding.ParamList[i]
scope[paramName] = v.Type()
valueScope[paramName] = v
typeList[i] = v.Type()
params[i] = ir.NewParam(paramName, v.Type())
}
retT := c.GetExprType(scope, binding.Expr)
ft := llvm.FunctionType(retT, typeList, false)
newFn := llvm.AddFunction(c.mod, binding.Name, ft)
newFunctionBuilder := llvm.NewBuilder()
block := llvm.AddBasicBlock(newFn, "")
newFunctionBuilder.SetInsertPointAtEnd(block)
newFn := c.mod.NewFunc(binding.Name, retT, params...)
block := newFn.NewBlock("")
newFunctionBuilder := block
fnExpr := c.NewExpr(valueScope, newFunctionBuilder, binding.Expr)
newFunctionBuilder.CreateRet(fnExpr)
return builder.CreateCall(newFn, vs, "")
newFunctionBuilder.NewRet(fnExpr)
return builder.NewCall(newFn, vs...)
}
panic("not implement lambda yet")
}

func (c *CodeGenerator) NewExpr(scope map[string]llvm.Value, builder llvm.Builder, expr ast.Expr) llvm.Value {
func (c *CodeGenerator) NewExpr(scope map[string]value.Value, builder Builder, expr ast.Expr) value.Value {
if expr.IsConst() {
return c.NewConstExpr(expr)
}
Expand All @@ -65,7 +67,7 @@ func (c *CodeGenerator) NewExpr(scope map[string]llvm.Value, builder llvm.Builde
return c.SearchOperation(builder, expr.Operator, left, right)
case *ast.FuncCall:
binding := c.bindings[expr.Identifier]
args := make([]llvm.Value, 0)
args := make([]value.Value, 0)
for _, expr := range expr.ExprList {
args = append(args, c.NewExpr(scope, builder, expr))
}
Expand All @@ -77,80 +79,84 @@ func (c *CodeGenerator) NewExpr(scope map[string]llvm.Value, builder llvm.Builde
}

type Operator struct {
RetType llvm.Type
Operation func(builder llvm.Builder, l, r llvm.Value) llvm.Value
RetType types.Type
Operation func(builder Builder, l, r value.Value) value.Value
}

var (
binaryOpFormat = "%s(%s,%s)"
i32 = llvm.Int32Type()
i32 = types.I32
opMap = map[string]*Operator{
fmt.Sprintf(binaryOpFormat, "+", i32, i32): {
RetType: i32,
Operation: func(builder llvm.Builder, l, r llvm.Value) llvm.Value {
return builder.CreateAdd(l, r, "")
Operation: func(builder Builder, l, r value.Value) value.Value {
return builder.NewAdd(l, r)
},
},
fmt.Sprintf(binaryOpFormat, "-", i32, i32): {
RetType: i32,
Operation: func(builder llvm.Builder, l, r llvm.Value) llvm.Value {
return builder.CreateSub(l, r, "")
Operation: func(builder Builder, l, r value.Value) value.Value {
return builder.NewSub(l, r)
},
},
fmt.Sprintf(binaryOpFormat, "*", i32, i32): {
RetType: i32,
Operation: func(builder llvm.Builder, l, r llvm.Value) llvm.Value {
return builder.CreateMul(l, r, "")
Operation: func(builder Builder, l, r value.Value) value.Value {
return builder.NewMul(l, r)
},
},
fmt.Sprintf(binaryOpFormat, "/", i32, i32): {
RetType: i32,
Operation: func(builder llvm.Builder, l, r llvm.Value) llvm.Value {
return builder.CreateSDiv(l, r, "")
Operation: func(builder Builder, l, r value.Value) value.Value {
return builder.NewSDiv(l, r)
},
},
}
)

func (c *CodeGenerator) SearchOperation(builder llvm.Builder, operator string, left, right llvm.Value) llvm.Value {
func (c *CodeGenerator) SearchOperation(builder Builder, operator string, left, right value.Value) value.Value {
generator := opMap[fmt.Sprintf(binaryOpFormat, operator, left.Type(), right.Type())]
return generator.Operation(builder, left, right)
}

func (c *CodeGenerator) GetExprType(scope map[string]llvm.Type, expr ast.Expr) llvm.Type {
func (c *CodeGenerator) GetExprType(scope map[string]types.Type, expr ast.Expr) types.Type {
switch expr := expr.(type) {
case *ast.Int:
return llvm.Int32Type()
return types.I32
case *ast.Float:
return llvm.DoubleType()
return types.Double
case *ast.Bool:
return llvm.Int1Type()
return types.I1
case *ast.BinaryExpr:
operator := opMap[fmt.Sprintf(binaryOpFormat, expr.Operator, c.GetExprType(scope, expr.LExpr), c.GetExprType(scope, expr.RExpr))]
return operator.RetType
case *ast.FuncCall:
return llvm.Int32Type()
return types.I32
case *ast.Ident:
return scope[expr.Value]
default:
panic("unsupported type refer")
}
}

func (c *CodeGenerator) NewConstExpr(expr ast.Expr) llvm.Value {
func (c *CodeGenerator) NewConstExpr(expr ast.Expr) value.Value {
switch expr := expr.(type) {
case *ast.Int:
// default is i32
return llvm.ConstIntFromString(llvm.Int32Type(), expr.Literal, 10)
v, err := constant.NewIntFromString(types.I32, expr.Literal)
if err != nil {
panic(fmt.Errorf("unable to parse integer literal %q; %v", expr.Literal, err))
}
return v
case *ast.Float:
// default is f64(double)
return llvm.ConstFloatFromString(llvm.DoubleType(), expr.Literal)
case *ast.Bool:
if expr.IsTrue {
return llvm.ConstInt(llvm.Int1Type(), 1, false)
} else {
return llvm.ConstInt(llvm.Int1Type(), 0, false)
v, err := constant.NewFloatFromString(types.Double, expr.Literal)
if err != nil {
panic(fmt.Errorf("unable to parse floating-point literal %q; %v", expr.Literal, err))
}
return v
case *ast.Bool:
return constant.NewBool(expr.IsTrue)
case *ast.String:
panic("unsupported string right now")
case *ast.Ident:
Expand Down
17 changes: 9 additions & 8 deletions codegen/codegen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"testing"

"github.com/elz-lang/elz/ast"
"github.com/elz-lang/elz/lib/llvm"

"github.com/llir/llvm/ir/types"
"github.com/llir/llvm/ir/value"
)

func TestBinaryFunction(t *testing.T) {
Expand All @@ -20,13 +22,11 @@ func TestBinaryFunction(t *testing.T) {
Operator: "+",
},
})
ft := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{}, false)
mainFn := llvm.AddFunction(c.mod, "main", ft)
bb := llvm.AddBasicBlock(mainFn, "")
builder := llvm.NewBuilder()
builder.SetInsertPointAtEnd(bb)
c.NewExpr(
map[string]llvm.Value{},
mainFn := c.mod.NewFunc("main", types.I32)
bb := mainFn.NewBlock("")
builder := bb
v := c.NewExpr(
map[string]value.Value{},
builder,
&ast.FuncCall{
Identifier: "add",
Expand All @@ -36,5 +36,6 @@ func TestBinaryFunction(t *testing.T) {
},
},
)
builder.NewRet(v)
fmt.Printf("%s", c.mod)
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module github.com/elz-lang/elz

require (
github.com/antlr/antlr4 v0.0.0-20181121174635-180f1af9689e
github.com/antlr/antlr4 v0.0.0-20181125170845-8268fdd957c4
github.com/dannypsnl/assert v0.0.12
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/llir/llvm v0.3.0-pre2.0.20181125202625-a4f2487113c4
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 // indirect
golang.org/x/sys v0.0.0-20181121002834-0cf1ed9e522b // indirect
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect
)
33 changes: 29 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
github.com/antlr/antlr4 v0.0.0-20181121174635-180f1af9689e h1:qPCShZA5q7qZ1ACk9VeCGpxev2lZS2X+HPPMNlV6wDE=
github.com/antlr/antlr4 v0.0.0-20181121174635-180f1af9689e/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
github.com/antlr/antlr4 v0.0.0-20181125170845-8268fdd957c4 h1:aAzE99h/mAdAba6P97roJ3+MLiIx6da4y21tvD9i84c=
github.com/antlr/antlr4 v0.0.0-20181125170845-8268fdd957c4/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
github.com/dannypsnl/assert v0.0.12 h1:b2j1egq4/uBREMj3JWmQSJEHcUNTdWRQ58M57SMUUMQ=
github.com/dannypsnl/assert v0.0.12/go.mod h1:+jfk+ZXLhZdRte6a88J2upwTCxXeahqNbJsgBoJD6wI=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inspirer/textmapper v0.0.0-20181104204410-4bdb1fb0392a/go.mod h1:SpoIwXu07A3gguovN379QUCTHpUk1lhX2KIjVxpQOas=
github.com/inspirer/textmapper v0.0.0-20181111212404-973a0cda8bfa h1:h4DKmR668ZzPWziVPrpyE7bAHAMCSPSC9Q4+rrsz6p8=
github.com/inspirer/textmapper v0.0.0-20181111212404-973a0cda8bfa/go.mod h1:SpoIwXu07A3gguovN379QUCTHpUk1lhX2KIjVxpQOas=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/llir/ll v0.0.0-20181124143609-405448b26944 h1:0Ie0H7XbvWS+NCEelOaPU0QTpbUXjn+hVxzWQ2RRVQY=
github.com/llir/ll v0.0.0-20181124143609-405448b26944/go.mod h1:a4JSuI2i1XkjU15LV11UxD243X6zJFuVeCHc63E/kGA=
github.com/llir/llvm v0.3.0-pre2.0.20181125202625-a4f2487113c4 h1:BC1t6cf7J/8Dm1h1cdQfk/KU2rYurjvu6AsgNypUpbk=
github.com/llir/llvm v0.3.0-pre2.0.20181125202625-a4f2487113c4/go.mod h1:GjmZh4l6Kcz7/Q1G25oyiZuD2VqOWfHwnudPDaeArAE=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mewkiz/pkg v0.0.0-20181119122551-9729f4f4ff2b h1:XHFBx9ZEVHnSCRiTz7w1a/NRBk9x7iyFiqnoN6R+vu8=
github.com/mewkiz/pkg v0.0.0-20181119122551-9729f4f4ff2b/go.mod h1:bhmdGJSMX5WCIBFmk27tBnUvBJm5WxXmarBV41qvbNI=
github.com/mewmew/float v0.0.0-20181121163145-c0f786d7da73 h1:bTqCgPsW3TFb9MFtvaOmGFWVhCmN3EmRw02zkchdOHo=
github.com/mewmew/float v0.0.0-20181121163145-c0f786d7da73/go.mod h1:obQBs6O+vjhgOZLkGdALxItKw4xrI49lSBEnAMO6lWI=
github.com/mewspring/tools v0.0.0-20181107085742-4dbfa080ff87 h1:F2Al+vk1BRMOIx0Sp7qIp4PfzgLlD8ItGsCx7O+b+nw=
github.com/mewspring/tools v0.0.0-20181107085742-4dbfa080ff87/go.mod h1:UAdVbSksr+7Bg+z4mga16OaBg3qAcgdaF3x3AeqJHEs=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181121002834-0cf1ed9e522b h1:fpg9kqwtLzitbbnpLJATV5Ty8sDv8sJ2ii9+e6fG89A=
golang.org/x/sys v0.0.0-20181121002834-0cf1ed9e522b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1 h1:bsEj/LXbv3BCtkp/rBj9Wi/0Nde4OMaraIZpndHAhdI=
golang.org/x/tools v0.0.0-20181122213734-04b5d21e00f1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=