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 }