/ 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 }