ssa: TestIf
This commit is contained in:
49
ssa/decl.go
49
ssa/decl.go
@@ -24,6 +24,9 @@ import (
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type aNamedConst struct {
|
||||
}
|
||||
|
||||
// A NamedConst is a Member of a Package representing a package-level
|
||||
// named constant.
|
||||
//
|
||||
@@ -32,22 +35,19 @@ import (
|
||||
//
|
||||
// NB: a NamedConst is not a Value; it contains a constant Value, which
|
||||
// it augments with the name and position of its 'const' declaration.
|
||||
type aNamedConst struct {
|
||||
}
|
||||
|
||||
type NamedConst = *aNamedConst
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type aGlobal struct {
|
||||
Expr
|
||||
}
|
||||
|
||||
// A Global is a named Value holding the address of a package-level
|
||||
// variable.
|
||||
//
|
||||
// Pos() returns the position of the ast.ValueSpec.Names[*]
|
||||
// identifier.
|
||||
type aGlobal struct {
|
||||
Expr
|
||||
}
|
||||
|
||||
type Global = *aGlobal
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -104,16 +104,18 @@ type Global = *aGlobal
|
||||
type aFunction struct {
|
||||
Expr
|
||||
prog Program
|
||||
blks []BasicBlock
|
||||
|
||||
params []Type
|
||||
hasVArg bool
|
||||
}
|
||||
|
||||
// Function represents a function or method.
|
||||
type Function = *aFunction
|
||||
|
||||
func newFunction(fn llvm.Value, t Type, prog Program) Function {
|
||||
params, hasVArg := newParams(t, prog)
|
||||
return &aFunction{Expr{fn, t}, prog, params, hasVArg}
|
||||
return &aFunction{Expr{fn, t}, prog, nil, params, hasVArg}
|
||||
}
|
||||
|
||||
func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
|
||||
@@ -131,17 +133,40 @@ func newParams(fn Type, prog Program) (params []Type, hasVArg bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// Params returns the function's ith parameter.
|
||||
func (p Function) Param(i int) Expr {
|
||||
return Expr{p.impl.Param(i), p.params[i]}
|
||||
}
|
||||
|
||||
func (p Function) MakeBody(label string) Builder {
|
||||
body := llvm.AddBasicBlock(p.impl, label)
|
||||
// MakeBody creates nblk basic blocks for the function, and creates
|
||||
// a new Builder associated to #0 block.
|
||||
func (p Function) MakeBody(nblk int) Builder {
|
||||
p.MakeBlocks(nblk)
|
||||
prog := p.prog
|
||||
b := prog.ctx.NewBuilder()
|
||||
b.Finalize()
|
||||
b.SetInsertPointAtEnd(body)
|
||||
return &aBuilder{b, prog}
|
||||
b.SetInsertPointAtEnd(p.blks[0].impl)
|
||||
return &aBuilder{b, p, prog}
|
||||
}
|
||||
|
||||
// MakeBlocks creates nblk basic blocks for the function.
|
||||
func (p Function) MakeBlocks(nblk int) []BasicBlock {
|
||||
if p.blks == nil {
|
||||
p.blks = make([]BasicBlock, 0, nblk)
|
||||
}
|
||||
n := len(p.blks)
|
||||
f := p.impl
|
||||
for i := 0; i < nblk; i++ {
|
||||
label := ""
|
||||
blk := llvm.AddBasicBlock(f, label)
|
||||
p.blks = append(p.blks, &aBasicBlock{blk, p, n + i})
|
||||
}
|
||||
return p.blks[n:]
|
||||
}
|
||||
|
||||
// Block returns the ith basic block of the function.
|
||||
func (p Function) Block(idx int) BasicBlock {
|
||||
return p.blks[idx]
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -26,18 +26,6 @@ func init() {
|
||||
Initialize(InitAll)
|
||||
}
|
||||
|
||||
/*
|
||||
func asmPkg(t *testing.T, p *Package) {
|
||||
b, err := p.CodeGen(AssemblyFile)
|
||||
if err != nil {
|
||||
t.Fatal("ctx.ParseIR:", err)
|
||||
}
|
||||
if v := string(b); v != "" {
|
||||
t.Log(v)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func assertPkg(t *testing.T, p Package, expected string) {
|
||||
if v := p.String(); v != expected {
|
||||
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
|
||||
@@ -105,7 +93,7 @@ func TestBasicFunc(t *testing.T) {
|
||||
types.NewVar(0, nil, "b", types.Typ[types.Float64]))
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
pkg.NewFunc("fn", sig).MakeBody("").
|
||||
pkg.NewFunc("fn", sig).MakeBody(1).
|
||||
Return(prog.Val(1))
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
@@ -125,7 +113,7 @@ func TestFuncParam(t *testing.T) {
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
fn.MakeBody("").Return(fn.Param(0))
|
||||
fn.MakeBody(1).Return(fn.Param(0))
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
|
||||
@@ -145,11 +133,11 @@ func TestFuncCall(t *testing.T) {
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
fn.MakeBody("").
|
||||
fn.MakeBody(1).
|
||||
Return(prog.Val(1))
|
||||
|
||||
sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false)
|
||||
b := pkg.NewFunc("main", sigMain).MakeBody("")
|
||||
b := pkg.NewFunc("main", sigMain).MakeBody(1)
|
||||
b.Call(fn.Expr, prog.Val(1), prog.Val(1.2))
|
||||
b.Return()
|
||||
|
||||
@@ -178,7 +166,7 @@ func TestFuncMultiRet(t *testing.T) {
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
a := pkg.NewVar("a", types.Typ[types.Int])
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
b := fn.MakeBody("")
|
||||
b := fn.MakeBody(1)
|
||||
b.Return(a.Expr, fn.Param(0))
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
@@ -192,6 +180,39 @@ define { i64, double } @fn(double %0) {
|
||||
`)
|
||||
}
|
||||
|
||||
func TestIf(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
b := fn.MakeBody(3)
|
||||
iftrue := fn.Block(1)
|
||||
iffalse := fn.Block(2)
|
||||
if iftrue.Index() != 1 || iftrue.Parent() != fn {
|
||||
t.Fatal("iftrue")
|
||||
}
|
||||
cond := b.BinOp(token.GTR, fn.Param(0), prog.Val(0))
|
||||
b.If(cond, iftrue, iffalse)
|
||||
b.SetBlock(iftrue).Return(prog.Val(1))
|
||||
b.SetBlock(iffalse).Return(prog.Val(0))
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
source_filename = "foo/bar"
|
||||
|
||||
define i64 @fn(i64 %0) {
|
||||
%2 = icmp sgt i64 %0, 0
|
||||
br i1 %2, label %3, label %4
|
||||
|
||||
3: ; preds = %1
|
||||
ret i64 1
|
||||
|
||||
4: ; preds = %1
|
||||
ret i64 0
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
func TestPrintf(t *testing.T) {
|
||||
prog := NewProgram(nil)
|
||||
pkg := prog.NewPackage("bar", "foo/bar")
|
||||
@@ -216,7 +237,7 @@ func TestBinOp(t *testing.T) {
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
b := fn.MakeBody("")
|
||||
b := fn.MakeBody(1)
|
||||
ret := b.BinOp(token.ADD, fn.Param(0), prog.Val(1))
|
||||
b.Return(ret)
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
@@ -238,7 +259,7 @@ func TestUnOp(t *testing.T) {
|
||||
rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
|
||||
sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
|
||||
fn := pkg.NewFunc("fn", sig)
|
||||
b := fn.MakeBody("")
|
||||
b := fn.MakeBody(1)
|
||||
ret := b.UnOp(token.MUL, fn.Param(0))
|
||||
b.Return(ret)
|
||||
assertPkg(t, pkg, `; ModuleID = 'foo/bar'
|
||||
|
||||
@@ -21,21 +21,48 @@ import (
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/*
|
||||
type BasicBlock struct {
|
||||
|
||||
type aBasicBlock struct {
|
||||
impl llvm.BasicBlock
|
||||
fn Function
|
||||
idx int
|
||||
}
|
||||
*/
|
||||
|
||||
// BasicBlock represents a basic block in a function.
|
||||
type BasicBlock = *aBasicBlock
|
||||
|
||||
// Parent returns the function to which the basic block belongs.
|
||||
func (p BasicBlock) Parent() Function {
|
||||
return p.fn
|
||||
}
|
||||
|
||||
// Index returns the index of the basic block in the parent function.
|
||||
func (p BasicBlock) Index() int {
|
||||
return p.idx
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type aBuilder struct {
|
||||
impl llvm.Builder
|
||||
fn Function
|
||||
prog Program
|
||||
}
|
||||
|
||||
// Builder represents a builder for creating instructions in a function.
|
||||
type Builder = *aBuilder
|
||||
|
||||
func (b Builder) Return(results ...Expr) Builder {
|
||||
// SetBlock sets the current block to the specified basic block.
|
||||
func (b Builder) SetBlock(blk BasicBlock) Builder {
|
||||
if b.fn != blk.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
b.impl.SetInsertPointAtEnd(blk.impl)
|
||||
return b
|
||||
}
|
||||
|
||||
// Return emits a return instruction.
|
||||
func (b Builder) Return(results ...Expr) {
|
||||
switch n := len(results); n {
|
||||
case 0:
|
||||
b.impl.CreateRetVoid()
|
||||
@@ -44,7 +71,14 @@ func (b Builder) Return(results ...Expr) Builder {
|
||||
default:
|
||||
b.impl.CreateAggregateRet(llvmValues(results))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// If emits an if instruction.
|
||||
func (b Builder) If(cond Expr, thenb, elseb BasicBlock) {
|
||||
if b.fn != thenb.fn || b.fn != elseb.fn {
|
||||
panic("mismatched function")
|
||||
}
|
||||
b.impl.CreateCondBr(cond.impl, thenb.impl, elseb.impl)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user