From 8c74b4b05fe85853e9265ed3fb16ea015bfce56f Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 21 Jun 2024 22:16:42 +0200 Subject: [PATCH] Added CPU type --- errors_test.go | 4 +-- src/build/Finalize.go | 4 +-- src/build/Function.go | 7 +++-- src/build/arch/x64/Registers.go | 28 +++++++++++++++++ src/build/arch/x64/Syscall.go | 8 ----- src/build/compile.go | 31 +++++++++++-------- src/build/cpu/CPU.go | 31 +++++++++++++++++++ src/build/scan.go | 7 +++++ ...ifier.q => InvalidInstructionIdentifier.q} | 0 ...on-Number.q => InvalidInstructionNumber.q} | 0 10 files changed, 92 insertions(+), 28 deletions(-) create mode 100644 src/build/arch/x64/Registers.go create mode 100644 src/build/cpu/CPU.go rename tests/errors/{InvalidInstruction-Identifier.q => InvalidInstructionIdentifier.q} (100%) rename tests/errors/{InvalidInstruction-Number.q => InvalidInstructionNumber.q} (100%) diff --git a/errors_test.go b/errors_test.go index 5512f08..c38a382 100644 --- a/errors_test.go +++ b/errors_test.go @@ -18,8 +18,8 @@ func TestErrors(t *testing.T) { {"ExpectedFunctionDefinition.q", errors.ExpectedFunctionDefinition}, {"ExpectedFunctionName.q", errors.ExpectedFunctionName}, {"ExpectedFunctionParameters.q", errors.ExpectedFunctionParameters}, - {"InvalidInstruction-Identifier.q", &errors.InvalidInstruction{Instruction: "abc"}}, - {"InvalidInstruction-Number.q", &errors.InvalidInstruction{Instruction: "123"}}, + {"InvalidInstructionIdentifier.q", &errors.InvalidInstruction{Instruction: "abc"}}, + {"InvalidInstructionNumber.q", &errors.InvalidInstruction{Instruction: "123"}}, {"MissingAssignValue.q", errors.MissingAssignValue}, {"MissingBlockEnd.q", errors.MissingBlockEnd}, {"MissingBlockStart.q", errors.MissingBlockStart}, diff --git a/src/build/Finalize.go b/src/build/Finalize.go index 333b849..915b42b 100644 --- a/src/build/Finalize.go +++ b/src/build/Finalize.go @@ -29,8 +29,8 @@ func Finalize(functions map[string]*Function) ([]byte, []byte) { func entry() *asm.Assembler { entry := asm.New() entry.Call("main") - entry.MoveRegisterNumber(x64.SyscallArgs[0], linux.Exit) - entry.MoveRegisterNumber(x64.SyscallArgs[1], 0) + entry.MoveRegisterNumber(x64.SyscallRegisters[0], linux.Exit) + entry.MoveRegisterNumber(x64.SyscallRegisters[1], 0) entry.Syscall() return entry } diff --git a/src/build/Function.go b/src/build/Function.go index 9b70b36..1c2dc0c 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -4,8 +4,8 @@ import ( "fmt" "strconv" - "git.akyoto.dev/cli/q/src/build/arch/x64" "git.akyoto.dev/cli/q/src/build/asm" + "git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/token" @@ -21,6 +21,7 @@ type Function struct { Body token.List Variables map[string]*Variable Assembler asm.Assembler + CPU cpu.CPU Error error } @@ -169,12 +170,12 @@ func (f *Function) CompileFunctionCall(expr *expression.Expression) error { } n, _ := strconv.Atoi(variable.Value.Token.Text()) - f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n)) + f.Assembler.MoveRegisterNumber(f.CPU.Syscall[i], uint64(n)) case token.Number: value := parameter.Token.Text() n, _ := strconv.Atoi(value) - f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n)) + f.Assembler.MoveRegisterNumber(f.CPU.Syscall[i], uint64(n)) default: panic("Unknown expression") diff --git a/src/build/arch/x64/Registers.go b/src/build/arch/x64/Registers.go new file mode 100644 index 0000000..7aaa3c8 --- /dev/null +++ b/src/build/arch/x64/Registers.go @@ -0,0 +1,28 @@ +package x64 + +import "git.akyoto.dev/cli/q/src/build/cpu" + +const ( + rax = iota + rcx + rdx + rbx + rsp + rbp + rsi + rdi + r8 + r9 + r10 + r11 + r12 + r13 + r14 + r15 +) + +const SyscallReturn = rax + +var GeneralRegisters = []cpu.Register{rbx, rbp, r12, r13, r14, r15} +var SyscallRegisters = []cpu.Register{rax, rdi, rsi, rdx, r10, r8, r9} +var ReturnValueRegisters = []cpu.Register{rax, rcx, r11} diff --git a/src/build/arch/x64/Syscall.go b/src/build/arch/x64/Syscall.go index 6251de9..94b07d2 100644 --- a/src/build/arch/x64/Syscall.go +++ b/src/build/arch/x64/Syscall.go @@ -1,13 +1,5 @@ package x64 -import "git.akyoto.dev/cli/q/src/build/cpu" - -const ( - SyscallReturn = 0 // rax -) - -var SyscallArgs = []cpu.Register{0, 7, 6, 2, 10, 8, 9} - // Syscall is the primary way to communicate with the OS kernel. func Syscall(code []byte) []byte { return append(code, 0x0f, 0x05) diff --git a/src/build/compile.go b/src/build/compile.go index 528fa43..6088e5a 100644 --- a/src/build/compile.go +++ b/src/build/compile.go @@ -4,7 +4,7 @@ import ( "sync" ) -// compile waits for all functions to finish compilation. +// compile waits for the scan to finish and compiles all functions. func compile(functions <-chan *Function, errors <-chan error) (map[string]*Function, error) { allFunctions := map[string]*Function{} @@ -28,18 +28,7 @@ func compile(functions <-chan *Function, errors <-chan error) (map[string]*Funct } } - wg := sync.WaitGroup{} - - for _, function := range allFunctions { - wg.Add(1) - - go func() { - defer wg.Done() - function.Compile() - }() - } - - wg.Wait() + compileFunctions(allFunctions) for _, function := range allFunctions { if function.Error != nil { @@ -49,3 +38,19 @@ func compile(functions <-chan *Function, errors <-chan error) (map[string]*Funct return allFunctions, nil } + +// compileFunctions starts a goroutine for each function compilation and waits for completion. +func compileFunctions(functions map[string]*Function) { + wg := sync.WaitGroup{} + + for _, function := range functions { + wg.Add(1) + + go func() { + defer wg.Done() + function.Compile() + }() + } + + wg.Wait() +} diff --git a/src/build/cpu/CPU.go b/src/build/cpu/CPU.go new file mode 100644 index 0000000..7e28e22 --- /dev/null +++ b/src/build/cpu/CPU.go @@ -0,0 +1,31 @@ +package cpu + +// CPU represents the processor. +type CPU struct { + General []Register + Syscall []Register + Return []Register + usage uint64 +} + +func (c *CPU) Use(reg Register) { + c.usage |= (1 << reg) +} + +func (c *CPU) Free(reg Register) { + c.usage &= ^(1 << reg) +} + +func (c *CPU) IsFree(reg Register) bool { + return c.usage&(1<