ssa: TestIf

This commit is contained in:
xushiwei
2024-04-20 19:53:00 +08:00
parent 905c05e099
commit 55a757b9f8
4 changed files with 120 additions and 42 deletions

View File

@@ -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]
}
// -----------------------------------------------------------------------------

View File

@@ -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'

View File

@@ -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)
}
// -----------------------------------------------------------------------------