fspl/llvm/terminator.go

385 lines
8.8 KiB
Go

package llvm
import "fmt"
import "strings"
type Terminator interface {
IsTerminator ()
Instruction
}
type TerminatorBr struct {
Target Value
}
func (*TerminatorBr) IsTerminator () { }
func (this *TerminatorBr) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "br %s", this.Target)
return buf.String()
}
func (this *Block) NewBr (target Value) *TerminatorBr {
terminator := &TerminatorBr { Target: target }
this.AddInstruction(terminator)
return terminator
}
type TerminatorCallBr struct {
InstructionCall
NormalTarget Value
OtherTargets []Value
}
func (*TerminatorCallBr) IsTerminator () { }
func (this *TerminatorCallBr) LLString () string {
buf := &strings.Builder{}
if _, ok := this.Type().(*TypeVoid); !ok {
fmt.Fprintf(buf, "%s = ", this.Name())
}
buf.WriteString("callbr")
// (optional) Address space.
if this.AddressSpace != 0 {
fmt.Fprintf(buf, " %s", this.AddressSpace)
}
// Use function signature instead of return type for variadic functions.
calleeType := this.Type()
if sig := this.Signature; sig.Variadic {
calleeType = sig
}
fmt.Fprintf(buf, " %s %s(", calleeType, this.Callee)
for index, arg := range this.Arguments {
if index > 0 {
buf.WriteString(", ")
}
buf.WriteString(arg.String())
}
buf.WriteString(")")
fmt.Fprintf(buf, "\n\t\tto %s [", this.NormalTarget)
for i, otherRetTarget := range this.OtherTargets {
if i != 0 {
buf.WriteString(", ")
}
buf.WriteString(otherRetTarget.String())
}
buf.WriteString("]")
return buf.String()
}
func (this *Block) NewCallBr (
callee Value,
signature *TypeFunction,
args []Value,
normalTarget Value,
otherTargets ...Value,
) *TerminatorCallBr {
terminator := &TerminatorCallBr { }
terminator.Callee = callee
terminator.Arguments = args
terminator.NormalTarget = normalTarget
terminator.OtherTargets = otherTargets
terminator.Signature = signature
terminator.Ty = signature.Return
this.AddInstruction(terminator)
return terminator
}
type TerminatorCatchRet struct {
CatchPad Value
Target Value
}
func (*TerminatorCatchRet) IsTerminator () { }
func (this *TerminatorCatchRet) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "catchret from %s to %s", this.CatchPad.Name(), this.Target)
return buf.String()
}
func (this *Block) NewCatchRet (catchPad Value, target Value) *TerminatorCatchRet {
terminator := &TerminatorCatchRet {
CatchPad: catchPad,
Target: target,
}
this.AddInstruction(terminator)
return terminator
}
type TerminatorCatchSwitch struct {
Register
ParentPad Value
Handlers []Value
DefaultUnwindTarget Value
}
func (*TerminatorCatchSwitch) IsTerminator () { }
func (this *TerminatorCatchSwitch) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "%s = ", this.Name())
fmt.Fprintf(buf, "catchswitch within %s [", this.ParentPad.Name())
for i, handler := range this.Handlers {
if i != 0 {
buf.WriteString(", ")
}
buf.WriteString(handler.String())
}
buf.WriteString("] unwind ")
if this.DefaultUnwindTarget != nil {
buf.WriteString(this.DefaultUnwindTarget.String())
} else {
buf.WriteString("to caller")
}
return buf.String()
}
func (this *Block) NewCatchSwitch (parentPad Value, handlers []Value, defaultUnwindTarget Value) *TerminatorCatchSwitch {
terminator := &TerminatorCatchSwitch {
ParentPad: parentPad,
Handlers: handlers,
DefaultUnwindTarget: defaultUnwindTarget,
}
terminator.Ty = &TypeToken { }
this.AddInstruction(terminator)
return terminator
}
type TerminatorCleanupRet struct {
CleanupPad Value
UnwindTarget Value
}
func (*TerminatorCleanupRet) IsTerminator () { }
func (this *TerminatorCleanupRet) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "cleanupret from %s unwind ", this.CleanupPad.Name())
if this.UnwindTarget != nil {
buf.WriteString(this.UnwindTarget.String())
} else {
buf.WriteString("to caller")
}
return buf.String()
}
func (this *Block) NewCleanupRet (cleanupPad, unwindTarget Value) *TerminatorCleanupRet {
terminator := &TerminatorCleanupRet {
CleanupPad: cleanupPad,
UnwindTarget: unwindTarget,
}
this.AddInstruction(terminator)
return terminator
}
type TerminatorCondBr struct {
Condition Value
True Value
False Value
}
func (*TerminatorCondBr) IsTerminator () { }
func (this *TerminatorCondBr) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "br %s, %s, %s", this.Condition, this.True, this.False)
return buf.String()
}
func (this *Block) NewCondBr (condition Value, tru, fals Value) *TerminatorCondBr {
terminator := &TerminatorCondBr {
Condition: condition,
True: tru,
False: fals,
}
this.AddInstruction(terminator)
return terminator
}
type TerminatorIndirectBr struct {
Address Value
ValidTargets []Value
}
func (*TerminatorIndirectBr) IsTerminator () { }
func (this *TerminatorIndirectBr) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "indirectbr %s, [", this.Address)
for i, target := range this.ValidTargets {
if i != 0 {
buf.WriteString(", ")
}
buf.WriteString(target.String())
}
buf.WriteString("]")
return buf.String()
}
func (this *Block) NewIndirectBr (address Value, validTargets ...Value) *TerminatorIndirectBr {
terminator := &TerminatorIndirectBr {
Address: address,
ValidTargets: validTargets,
}
this.AddInstruction(terminator)
return terminator
}
type TerminatorInvoke struct {
Register
Invokee Value
Signature *TypeFunction
Arguments []Value
NormalTarget Value
ExceptionTarget Value
AddressSpace AddressSpace
// TODO complete this
}
func (*TerminatorInvoke) IsTerminator () { }
func (this *TerminatorInvoke) LLString () string {
buf := &strings.Builder{}
if _, ok := this.Type().(*TypeVoid); !ok {
fmt.Fprintf(buf, "%s = ", this.Name())
}
buf.WriteString("invoke")
// (optional) Address space.
if this.AddressSpace != 0 {
fmt.Fprintf(buf, " %s", this.AddressSpace)
}
// Use function signature instead of return type for variadic functions.
calleeType := this.Type()
if sig := this.Signature; sig.Variadic {
calleeType = sig
}
fmt.Fprintf(buf, " %s %s(", calleeType, this.Invokee)
for index, arg := range this.Arguments {
if index > 0 {
buf.WriteString(", ")
}
buf.WriteString(arg.String())
}
buf.WriteString(")")
fmt.Fprintf(buf, "\n\t\tto %s unwind %s", this.NormalTarget, this.ExceptionTarget)
return buf.String()
}
func (this *Block) NewInvoke (
invokee Value,
signature *TypeFunction,
args []Value,
normalTarget Value,
exceptionTarget Value,
) *TerminatorInvoke {
terminator := &TerminatorInvoke { }
terminator.Invokee = invokee
terminator.Arguments = args
terminator.NormalTarget = normalTarget
terminator.ExceptionTarget = exceptionTarget
terminator.Signature = signature
terminator.Ty = signature.Return
this.AddInstruction(terminator)
return terminator
}
type TerminatorResume struct {
X Value
}
func (*TerminatorResume) IsTerminator () { }
func (this *TerminatorResume) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "resume %s", this.X)
return buf.String()
}
func (this *Block) NewResume (x Value) *TerminatorResume {
terminator := &TerminatorResume { X: x }
this.AddInstruction(terminator)
return terminator
}
type TerminatorRet struct {
X Value
}
func (*TerminatorRet) IsTerminator () { }
func (this *TerminatorRet) LLString () string {
buf := &strings.Builder { }
if this.X == nil {
fmt.Fprintf(buf, "ret void")
} else {
fmt.Fprintf(buf, "ret %s", this.X)
}
return buf.String()
}
func (this *Block) NewRet (x Value) *TerminatorRet {
terminator := &TerminatorRet { X: x }
this.AddInstruction(terminator)
return terminator
}
type Case struct {
X Value
Target Value
}
func (*Case) IsTerminator () { }
func (this *Case) String () string {
return fmt.Sprintf("%s, %s", this.X, this.Target)
}
type TerminatorSwitch struct {
X Value
Default Value
Cases []*Case
}
func (*TerminatorSwitch) IsTerminator () { }
func (this *TerminatorSwitch) LLString () string {
buf := &strings.Builder{}
fmt.Fprintf(buf, "switch %s, %s [\n", this.X, this.Default)
for _, c := range this.Cases {
fmt.Fprintf(buf, "\t\t%s\n", c)
}
buf.WriteString("\t]")
return buf.String()
}
func (this *Block) NewSwitch (x, defaul Value, cases ...*Case) *TerminatorSwitch {
terminator := &TerminatorSwitch {
X: x,
Default: defaul,
Cases: cases,
}
this.AddInstruction(terminator)
return terminator
}
type TerminatorUnreachable struct {
}
func (*TerminatorUnreachable) IsTerminator () { }
func (this *TerminatorUnreachable) LLString () string {
buf := &strings.Builder{}
buf.WriteString("unreachable")
return buf.String()
}
func (this *Block) NewUnreachable () *TerminatorUnreachable {
terminator := &TerminatorUnreachable { }
this.AddInstruction(terminator)
return terminator
}