/ assembly.go
assembly.go
  1  // Copyright (c) 2021 Timo Savola. All rights reserved.
  2  // Use of this source code is governed by a BSD-style
  3  // license that can be found in the LICENSE file.
  4  
  5  package ga
  6  
  7  import (
  8  	"bytes"
  9  	"fmt"
 10  	"strings"
 11  )
 12  
 13  const header1 = `// Generated by gate.computer/ga, DO NOT EDIT!
 14  `
 15  
 16  const header2 = `
 17  .section .note.GNU-stack,"",%progbits
 18  .section .text
 19  `
 20  
 21  type Cond uint8
 22  
 23  const (
 24  	EQ Cond = iota
 25  	NE
 26  	LT
 27  	LE
 28  	GT
 29  	GE
 30  )
 31  
 32  type Shift uint8
 33  
 34  const (
 35  	Left Shift = iota
 36  	RightLogical
 37  	RightArithmetic
 38  )
 39  
 40  type FloatReg uint8
 41  
 42  func global(name string) bool {
 43  	return !strings.HasPrefix(name, ".")
 44  }
 45  
 46  func symbol(name string) string {
 47  	if global(name) {
 48  		return name
 49  	}
 50  	return strings.Replace(name, ".", ".L", 1)
 51  }
 52  
 53  type Assembly struct {
 54  	Arch
 55  	ArchAssembly
 56  	*System
 57  	*buffer
 58  }
 59  
 60  func NewAssembly(arch Arch, sys *System) *Assembly {
 61  	buf := new(buffer)
 62  	a := &Assembly{
 63  		Arch:         arch,
 64  		ArchAssembly: arch.newAssembly(sys, buf),
 65  		System:       sys,
 66  		buffer:       buf,
 67  	}
 68  	a.Reset()
 69  	return a
 70  }
 71  
 72  func (a *Assembly) Reset(regs ...Reg) {
 73  	for i := range a.regUsage {
 74  		a.regUsage[i] = ""
 75  	}
 76  	for _, r := range regs {
 77  		a.Set(r)
 78  	}
 79  	a.Set(a.StackPtr)
 80  }
 81  
 82  func (a *Assembly) String() string {
 83  	return a.buffer.String()
 84  }
 85  
 86  type ArchAssembly interface {
 87  	Set(Reg)
 88  	Label(name string)
 89  	FunctionEpilogue()
 90  	Function(name string)
 91  	FunctionWithoutPrologue(name string)
 92  	Return()
 93  	ReturnWithoutEpilogue()
 94  	Address(dest Reg, name string)
 95  	MoveDef(dest Reg, name string)
 96  	MoveImm(dest Reg, value int)
 97  	MoveImm64(dest Reg, value uint64)
 98  	MoveReg(dest, src Reg)
 99  	MoveRegFloat(dest Reg, src FloatReg)
100  	AddImm(dest, src Reg, value int)
101  	AddReg(dest, src1, src2 Reg)
102  	SubtractImm(dest Reg, value int)
103  	SubtractReg(dest, src Reg)
104  	MultiplyImm(dest, src Reg, value int, temp Reg)
105  	AndImm(dest Reg, value int)
106  	AndReg(dest, src Reg)
107  	OrImm(dest Reg, value int)
108  	OrReg(dest, src Reg)
109  	ShiftImm(s Shift, r Reg, count int)
110  	Load(dest, base Reg, offset int)
111  	Load4Bytes(dest, base Reg, offset int)
112  	LoadByte(dest, base Reg, offset int)
113  	Store(base Reg, offset int, src Reg)
114  	Store4Bytes(base Reg, offset int, src Reg)
115  	Push(Reg)
116  	Pop(Reg)
117  	Call(name string)
118  	Jump(name string)
119  	JumpRegRoutine(r Reg, internalNamePrefix string)
120  	JumpIfBitSet(r Reg, bit uint, name string)
121  	JumpIfBitNotSet(r Reg, bit uint, name string)
122  	JumpIfImm(c Cond, r Reg, value int, name string)
123  	JumpIfReg(c Cond, dest, src Reg, name string)
124  	Syscall(Syscall)
125  	Unreachable()
126  }
127  
128  type buffer struct {
129  	bytes.Buffer
130  	regUsage [32]string
131  }
132  
133  func (b *buffer) checkUsage(reg uint8, use string) {
134  	switch existing := b.regUsage[reg]; existing {
135  	case use:
136  	case "":
137  		panic(fmt.Sprintf("register #%d (%s) not in use", reg, use))
138  	default:
139  		panic(fmt.Sprintf("existing register #%d (%s) usage: %s", reg, use, existing))
140  	}
141  }
142  
143  func (b *buffer) label(name string) {
144  	b.printf("%s:", symbol(name))
145  }
146  
147  func (b *buffer) insn(mnemonic string, operands ...string) {
148  	b.WriteString("\t" + mnemonic)
149  
150  	for i, field := range operands {
151  		switch i {
152  		case 0:
153  			b.WriteString("\t")
154  		default:
155  			b.WriteString(", ")
156  		}
157  
158  		b.WriteString(field)
159  	}
160  
161  	fmt.Fprintln(&b.Buffer)
162  }
163  
164  func (b *buffer) insnf(format string, args ...interface{}) {
165  	for i, field := range strings.Fields(fmt.Sprintf(format, args...)) {
166  		switch i {
167  		case 0, 1:
168  			b.WriteString("\t")
169  		default:
170  			b.WriteString(" ")
171  		}
172  
173  		b.WriteString(field)
174  	}
175  
176  	fmt.Fprintln(&b.Buffer)
177  }
178  
179  func (b *buffer) printf(format string, args ...interface{}) {
180  	for i, field := range strings.Fields(fmt.Sprintf(format, args...)) {
181  		switch i {
182  		case 0:
183  		case 1:
184  			b.WriteString("\t")
185  		default:
186  			b.WriteString(" ")
187  		}
188  
189  		b.WriteString(field)
190  	}
191  
192  	fmt.Fprintln(&b.Buffer)
193  }