This commit is contained in:
parent
562c839835
commit
c9c6b94c18
8 changed files with 133 additions and 86 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
20
src/core/CreateLabel.go
Normal 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()}
|
||||||
|
}
|
|
@ -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
8
src/core/count.go
Normal 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
46
src/core/ssaToAsm.go
Normal 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{})
|
||||||
|
}
|
||||||
|
}
|
52
src/core/ssaValuesToRegisters.go
Normal file
52
src/core/ssaValuesToRegisters.go
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue