190 lines
4.0 KiB
Go
190 lines
4.0 KiB
Go
package llvm
|
|
|
|
import "fmt"
|
|
import "strings"
|
|
|
|
type Function struct {
|
|
FunctionName string
|
|
|
|
Signature *TypeFunction
|
|
Parameters []*Parameter
|
|
Blocks []*Block
|
|
|
|
AddressSpace AddressSpace
|
|
|
|
// TODO complete this
|
|
}
|
|
|
|
type Parameter struct {
|
|
Register
|
|
}
|
|
|
|
func (this *Parameter) LLString () string {
|
|
return this.String()
|
|
}
|
|
|
|
func NewParameter (name string, ty Type) *Parameter {
|
|
parameter := &Parameter { }
|
|
parameter.RegisterName = name
|
|
parameter.Ty = ty
|
|
return parameter
|
|
}
|
|
|
|
func (this *Function) NewBlock () *Block {
|
|
block := &Block {
|
|
Parent: this,
|
|
}
|
|
this.Blocks = append(this.Blocks, block)
|
|
return block
|
|
}
|
|
|
|
func (this *Function) LLString () string {
|
|
this.assignIDs()
|
|
buffer := &strings.Builder { }
|
|
if len(this.Blocks) == 0 {
|
|
// Function declaration.
|
|
buffer.WriteString("declare")
|
|
buffer.WriteString(this.headerString())
|
|
buffer.WriteString("\n")
|
|
return buffer.String()
|
|
} else {
|
|
// Function definition.
|
|
buffer.WriteString("define")
|
|
buffer.WriteString(this.headerString())
|
|
fmt.Fprintf(buffer, " %s", this.bodyString())
|
|
return buffer.String()
|
|
}
|
|
}
|
|
|
|
func (this *Function) Type () Type {
|
|
return Pointer
|
|
}
|
|
|
|
func (this *Function) Name () string {
|
|
return this.FunctionName
|
|
}
|
|
|
|
func (this *Function) Identifier () string {
|
|
return EncodeFunctionName(this.Name())
|
|
}
|
|
|
|
func (this *Function) SetName (name string) {
|
|
this.FunctionName = name
|
|
}
|
|
|
|
func (this *Function) String () string {
|
|
return fmt.Sprintf("ptr %v", this.Identifier())
|
|
}
|
|
|
|
func (this *Function) assignIDs () {
|
|
counter := 0
|
|
for _, block := range this.Blocks {
|
|
block.SetName(fmt.Sprint(counter))
|
|
counter ++
|
|
block.assignIDs(&counter)
|
|
}
|
|
}
|
|
|
|
func (this *Function) headerString () string {
|
|
buffer := &strings.Builder { }
|
|
fmt.Fprintf(buffer, " %v", this.Signature.Return)
|
|
fmt.Fprintf(buffer, " %v(", this.Identifier())
|
|
for index, param := range this.Parameters {
|
|
if index > 0 { buffer.WriteString(", ") }
|
|
buffer.WriteString(param.LLString())
|
|
}
|
|
if this.Signature.Variadic {
|
|
if len(this.Parameters) > 0 {
|
|
buffer.WriteString(", ")
|
|
}
|
|
buffer.WriteString("...")
|
|
}
|
|
buffer.WriteString(")")
|
|
if this.AddressSpace != 0 {
|
|
fmt.Fprintf(buffer, " %v", this.AddressSpace)
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
func (this *Function) bodyString () string {
|
|
buffer := &strings.Builder { }
|
|
buffer.WriteString("{\n")
|
|
for _, block := range this.Blocks {
|
|
fmt.Fprintf(buffer, "%s", block.LLString())
|
|
}
|
|
buffer.WriteString("}\n")
|
|
return buffer.String()
|
|
}
|
|
|
|
type Block struct {
|
|
BlockName string
|
|
Parent *Function
|
|
Instructions []Instruction
|
|
}
|
|
|
|
func (this *Block) LLString () string {
|
|
buffer := &strings.Builder { }
|
|
fmt.Fprintf(buffer, "%s:\n", this.Name())
|
|
for _, instruction := range this.Instructions {
|
|
fmt.Fprintf(buffer, "\t%s\n", instruction.LLString())
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
func (this *Block) Name () string {
|
|
return this.BlockName
|
|
}
|
|
|
|
func (this *Block) SetName (name string) {
|
|
this.BlockName = name
|
|
}
|
|
|
|
func (this *Block) Identifier () string {
|
|
return EncodeRegisterName(this.Name())
|
|
}
|
|
|
|
func (this *Block) String () string {
|
|
return fmt.Sprintf("%v %v", this.Type(), this.Identifier())
|
|
}
|
|
|
|
func (this *Block) Type () Type {
|
|
return Label
|
|
}
|
|
|
|
func (this *Block) AddInstruction (instruction Instruction) {
|
|
if this.Terminated() {
|
|
panic("block is already terminated")
|
|
}
|
|
this.Instructions = append(this.Instructions, instruction)
|
|
}
|
|
|
|
func (this *Block) Terminated () bool {
|
|
if len(this.Instructions) == 0 { return false }
|
|
_, ok := this.Instructions[len(this.Instructions) - 1].(Terminator)
|
|
return ok
|
|
}
|
|
|
|
func (this *Block) SetTerminator (terminator Terminator) {
|
|
if this.Terminated() {
|
|
this.Instructions[len(this.Instructions) - 1] = terminator
|
|
} else {
|
|
this.AddInstruction(terminator)
|
|
}
|
|
}
|
|
|
|
func (this *Block) assignIDs (counter *int) {
|
|
for _, instruction := range this.Instructions {
|
|
if instruction, ok := instruction.(ValueInstruction); ok {
|
|
if !isVoid(instruction) {
|
|
instruction.SetName(fmt.Sprint(*counter))
|
|
*counter ++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func isVoid (instruction ValueInstruction) bool {
|
|
_, ok := instruction.Type().(*TypeVoid)
|
|
return ok
|
|
}
|