Refactored ssa to asm compilation
All checks were successful
/ test (push) Successful in 15s

This commit is contained in:
Eduard Urbach 2025-07-01 16:13:12 +02:00
parent 562c839835
commit c9c6b94c18
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
8 changed files with 133 additions and 86 deletions

View file

@ -41,8 +41,12 @@ func (c *compilerX86) Compile(instr Instruction) {
binary.LittleEndian.PutUint32(c.code[end-4:end], uint32(offset)) binary.LittleEndian.PutUint32(c.code[end-4:end], uint32(offset))
}) })
case *CallExtern: case *CallExtern:
c.code = x86.MoveRegisterRegister(c.code, x86.R5, x86.SP)
c.code = x86.AndRegisterNumber(c.code, x86.SP, -16)
c.code = x86.SubRegisterNumber(c.code, x86.SP, 32)
c.code = x86.CallAt(c.code, 0) c.code = x86.CallAt(c.code, 0)
end := len(c.code) end := len(c.code)
c.code = x86.MoveRegisterRegister(c.code, x86.SP, x86.R5)
c.Defer(func() { c.Defer(func() {
index := c.libraries.Index(instr.Library, instr.Function) index := c.libraries.Index(instr.Library, instr.Function)

View file

@ -1,13 +1,8 @@
package core package core
import ( import (
"slices"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/cpu"
"git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/ssa"
"git.urbach.dev/cli/q/src/types" "git.urbach.dev/cli/q/src/types"
"git.urbach.dev/cli/q/src/x86"
) )
// Compile turns a function into machine code. // Compile turns a function into machine code.
@ -64,84 +59,5 @@ func (f *Function) Compile() {
return return
} }
f.Assembler.Append(&asm.Label{Name: f.UniqueName}) f.ssaToAsm()
if !f.IsLeaf() && f.UniqueName != "core.init" {
f.Assembler.Append(&asm.FunctionStart{})
}
for instr := range f.Values {
switch instr := instr.(type) {
case *ssa.Call:
arg := instr.Arguments[0].(*ssa.Function)
fn := f.All.Functions[arg.UniqueName]
if fn.IsExtern() {
f.mv(instr.Arguments[1:], f.CPU.ExternCall)
f.Assembler.Append(&asm.MoveRegisterRegister{Destination: x86.R5, Source: x86.SP})
f.Assembler.Append(&asm.AndRegisterNumber{Destination: x86.SP, Source: x86.SP, Number: -16})
f.Assembler.Append(&asm.SubRegisterNumber{Destination: x86.SP, Source: x86.SP, Number: 32})
f.Assembler.Append(&asm.CallExtern{Library: fn.Package, Function: fn.Name})
f.Assembler.Append(&asm.MoveRegisterRegister{Destination: x86.SP, Source: x86.R5})
} else {
f.mv(instr.Arguments[1:], f.CPU.Call)
f.Assembler.Append(&asm.Call{Label: fn.UniqueName})
}
case *ssa.Syscall:
f.mv(instr.Arguments, f.CPU.Syscall)
f.Assembler.Append(&asm.Syscall{})
case *ssa.Return:
f.Assembler.Append(&asm.Return{})
}
}
if !f.IsLeaf() && f.UniqueName != "core.init" {
f.Assembler.Append(&asm.FunctionEnd{})
}
if f.UniqueName != "core.exit" {
f.Assembler.Append(&asm.Return{})
}
}
func (f *Function) mv(args []ssa.Value, registers []cpu.Register) {
extra := 0
for _, arg := range args {
switch arg.(type) {
case *ssa.Bytes:
extra++
}
}
for i, arg := range slices.Backward(args) {
switch arg := arg.(type) {
case *ssa.Int:
f.Assembler.Append(&asm.MoveRegisterNumber{
Destination: registers[i+extra],
Number: arg.Int,
})
case *ssa.Parameter:
f.Assembler.Append(&asm.MoveRegisterRegister{
Destination: registers[i+extra],
Source: f.CPU.Call[arg.Index],
})
case *ssa.Bytes:
f.Assembler.SetData("data0", arg.Bytes)
f.Assembler.Append(&asm.MoveRegisterNumber{
Destination: registers[i+extra],
Number: len(arg.Bytes),
})
extra--
f.Assembler.Append(&asm.MoveRegisterLabel{
Destination: registers[i+extra],
Label: "data0",
})
}
}
} }

20
src/core/CreateLabel.go Normal file
View file

@ -0,0 +1,20 @@
package core
import (
"strconv"
"strings"
"git.urbach.dev/cli/q/src/asm"
)
// CreateLabel creates a label that is tied to this function by using a suffix.
func (f *Function) CreateLabel(prefix string, count counter) *asm.Label {
tmp := strings.Builder{}
tmp.WriteString(prefix)
tmp.WriteString(" ")
tmp.WriteString(strconv.FormatUint(uint64(count), 10))
tmp.WriteString(" [")
tmp.WriteString(f.UniqueName)
tmp.WriteString("]")
return &asm.Label{Name: tmp.String()}
}

View file

@ -29,6 +29,7 @@ type Function struct {
CPU *cpu.CPU CPU *cpu.CPU
Type *types.Function Type *types.Function
Err error Err error
count count
} }
// NewFunction creates a new function. // NewFunction creates a new function.

8
src/core/count.go Normal file
View file

@ -0,0 +1,8 @@
package core
type counter = uint8
// count stores how often a certain statement appeared so we can generate a unique label from it.
type count struct {
data counter
}

46
src/core/ssaToAsm.go Normal file
View file

@ -0,0 +1,46 @@
package core
import (
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/ssa"
)
// ssaToAsm converts the SSA IR to assembler instructions.
func (f *Function) ssaToAsm() {
f.Assembler.Append(&asm.Label{Name: f.UniqueName})
if !f.IsLeaf() && f.UniqueName != "core.init" {
f.Assembler.Append(&asm.FunctionStart{})
}
for instr := range f.Values {
switch instr := instr.(type) {
case *ssa.Call:
arg := instr.Arguments[0].(*ssa.Function)
fn := f.All.Functions[arg.UniqueName]
if fn.IsExtern() {
f.ssaValuesToRegisters(instr.Arguments[1:], f.CPU.ExternCall)
f.Assembler.Append(&asm.CallExtern{Library: fn.Package, Function: fn.Name})
} else {
f.ssaValuesToRegisters(instr.Arguments[1:], f.CPU.Call)
f.Assembler.Append(&asm.Call{Label: fn.UniqueName})
}
case *ssa.Syscall:
f.ssaValuesToRegisters(instr.Arguments, f.CPU.Syscall)
f.Assembler.Append(&asm.Syscall{})
case *ssa.Return:
f.Assembler.Append(&asm.Return{})
}
}
if !f.IsLeaf() && f.UniqueName != "core.init" {
f.Assembler.Append(&asm.FunctionEnd{})
}
if f.UniqueName != "core.exit" {
f.Assembler.Append(&asm.Return{})
}
}

View file

@ -0,0 +1,52 @@
package core
import (
"slices"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/cpu"
"git.urbach.dev/cli/q/src/ssa"
)
// ssaValuesToRegisters generates assembler instructions to move the SSA values to the given registers.
func (f *Function) ssaValuesToRegisters(args []ssa.Value, registers []cpu.Register) {
extra := 0
for _, arg := range args {
switch arg.(type) {
case *ssa.Bytes:
extra++
}
}
for i, arg := range slices.Backward(args) {
switch arg := arg.(type) {
case *ssa.Int:
f.Assembler.Append(&asm.MoveRegisterNumber{
Destination: registers[i+extra],
Number: arg.Int,
})
case *ssa.Parameter:
f.Assembler.Append(&asm.MoveRegisterRegister{
Destination: registers[i+extra],
Source: f.CPU.Call[arg.Index],
})
case *ssa.Bytes:
f.count.data++
label := f.CreateLabel("data", f.count.data)
f.Assembler.SetData(label.Name, arg.Bytes)
f.Assembler.Append(&asm.MoveRegisterNumber{
Destination: registers[i+extra],
Number: len(arg.Bytes),
})
extra--
f.Assembler.Append(&asm.MoveRegisterLabel{
Destination: registers[i+extra],
Label: label.Name,
})
}
}
}