385 lines
8.8 KiB
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
|
|
}
|