diff --git a/examples/hello/hello.q b/examples/hello/hello.q index c5324ab..4f30709 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -11,7 +11,8 @@ hello() { address += 4194304 address += 1 length += 5 - length -= 2 + length *= 2 + length -= 7 loop { syscall(write, stdout, address, length) diff --git a/src/build/Finalize.go b/src/build/Finalize.go index 915b42b..dadf7f6 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.SyscallRegisters[0], linux.Exit) - entry.MoveRegisterNumber(x64.SyscallRegisters[1], 0) + entry.RegisterNumber(asm.MOVE, x64.SyscallRegisters[0], linux.Exit) + entry.RegisterNumber(asm.MOVE, x64.SyscallRegisters[1], 0) entry.Syscall() return entry } diff --git a/src/build/Function.go b/src/build/Function.go index cc86f47..f0298e7 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -120,11 +120,15 @@ func (f *Function) CompileInstruction(line token.List) error { switch expr.Token.Text() { case "+=": - f.Assembler.AddRegisterNumber(register, number) + f.Assembler.RegisterNumber(asm.ADD, register, number) return nil case "-=": - f.Assembler.SubRegisterNumber(register, number) + f.Assembler.RegisterNumber(asm.SUB, register, number) + return nil + + case "*=": + f.Assembler.RegisterNumber(asm.MUL, register, number) return nil } } @@ -164,7 +168,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return err } - f.Assembler.MoveRegisterNumber(register, n) + f.Assembler.RegisterNumber(asm.MOVE, register, n) return nil case token.String: diff --git a/src/build/arch/x64/Add_test.go b/src/build/arch/x64/Add_test.go index 221dbbe..80abc27 100644 --- a/src/build/arch/x64/Add_test.go +++ b/src/build/arch/x64/Add_test.go @@ -14,22 +14,23 @@ func TestAddRegisterNumber(t *testing.T) { Number int Code []byte }{ - {x64.RAX, 1, []byte{0x48, 0x83, 0xc0, 0x01}}, - {x64.RCX, 1, []byte{0x48, 0x83, 0xc1, 0x01}}, - {x64.RDX, 1, []byte{0x48, 0x83, 0xc2, 0x01}}, - {x64.RBX, 1, []byte{0x48, 0x83, 0xc3, 0x01}}, - {x64.RSP, 1, []byte{0x48, 0x83, 0xc4, 0x01}}, - {x64.RBP, 1, []byte{0x48, 0x83, 0xc5, 0x01}}, - {x64.RSI, 1, []byte{0x48, 0x83, 0xc6, 0x01}}, - {x64.RDI, 1, []byte{0x48, 0x83, 0xc7, 0x01}}, - {x64.R8, 1, []byte{0x49, 0x83, 0xc0, 0x01}}, - {x64.R9, 1, []byte{0x49, 0x83, 0xc1, 0x01}}, - {x64.R10, 1, []byte{0x49, 0x83, 0xc2, 0x01}}, - {x64.R11, 1, []byte{0x49, 0x83, 0xc3, 0x01}}, - {x64.R12, 1, []byte{0x49, 0x83, 0xc4, 0x01}}, - {x64.R13, 1, []byte{0x49, 0x83, 0xc5, 0x01}}, - {x64.R14, 1, []byte{0x49, 0x83, 0xc6, 0x01}}, - {x64.R15, 1, []byte{0x49, 0x83, 0xc7, 0x01}}, + {x64.RAX, 1, []byte{0x48, 0x83, 0xC0, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0x83, 0xC1, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0x83, 0xC2, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0x83, 0xC3, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0x83, 0xC4, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0x83, 0xC5, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0x83, 0xC6, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0x83, 0xC7, 0x01}}, + {x64.R8, 1, []byte{0x49, 0x83, 0xC0, 0x01}}, + {x64.R9, 1, []byte{0x49, 0x83, 0xC1, 0x01}}, + {x64.R10, 1, []byte{0x49, 0x83, 0xC2, 0x01}}, + {x64.R11, 1, []byte{0x49, 0x83, 0xC3, 0x01}}, + {x64.R12, 1, []byte{0x49, 0x83, 0xC4, 0x01}}, + {x64.R13, 1, []byte{0x49, 0x83, 0xC5, 0x01}}, + {x64.R14, 1, []byte{0x49, 0x83, 0xC6, 0x01}}, + {x64.R15, 1, []byte{0x49, 0x83, 0xC7, 0x01}}, + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xC0, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xC1, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xC2, 0xFF, 0xFF, 0xFF, 0x7F}}, diff --git a/src/build/arch/x64/Mul.go b/src/build/arch/x64/Mul.go new file mode 100644 index 0000000..d952b2b --- /dev/null +++ b/src/build/arch/x64/Mul.go @@ -0,0 +1,8 @@ +package x64 + +import "git.akyoto.dev/cli/q/src/build/cpu" + +// MulRegNum multiplies a register with a number. +func MulRegNum(code []byte, destination cpu.Register, number int) []byte { + return numRegReg(code, 0x6B, 0x69, byte(destination), byte(destination), number) +} diff --git a/src/build/arch/x64/Mul_test.go b/src/build/arch/x64/Mul_test.go new file mode 100644 index 0000000..1a81fd3 --- /dev/null +++ b/src/build/arch/x64/Mul_test.go @@ -0,0 +1,57 @@ +package x64_test + +import ( + "testing" + + "git.akyoto.dev/cli/q/src/build/arch/x64" + "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/go/assert" +) + +func TestMulRegisterNumber(t *testing.T) { + usagePatterns := []struct { + Register cpu.Register + Number int + Code []byte + }{ + {x64.RAX, 1, []byte{0x48, 0x6B, 0xC0, 0x01}}, + {x64.RCX, 1, []byte{0x48, 0x6B, 0xC9, 0x01}}, + {x64.RDX, 1, []byte{0x48, 0x6B, 0xD2, 0x01}}, + {x64.RBX, 1, []byte{0x48, 0x6B, 0xDB, 0x01}}, + {x64.RSP, 1, []byte{0x48, 0x6B, 0xE4, 0x01}}, + {x64.RBP, 1, []byte{0x48, 0x6B, 0xED, 0x01}}, + {x64.RSI, 1, []byte{0x48, 0x6B, 0xF6, 0x01}}, + {x64.RDI, 1, []byte{0x48, 0x6B, 0xFF, 0x01}}, + {x64.R8, 1, []byte{0x4D, 0x6B, 0xC0, 0x01}}, + {x64.R9, 1, []byte{0x4D, 0x6B, 0xC9, 0x01}}, + {x64.R10, 1, []byte{0x4D, 0x6B, 0xD2, 0x01}}, + {x64.R11, 1, []byte{0x4D, 0x6B, 0xDB, 0x01}}, + {x64.R12, 1, []byte{0x4D, 0x6B, 0xE4, 0x01}}, + {x64.R13, 1, []byte{0x4D, 0x6B, 0xED, 0x01}}, + {x64.R14, 1, []byte{0x4D, 0x6B, 0xF6, 0x01}}, + {x64.R15, 1, []byte{0x4D, 0x6B, 0xFF, 0x01}}, + + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x69, 0xC0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x69, 0xC9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x69, 0xD2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBX, 0x7FFFFFFF, []byte{0x48, 0x69, 0xDB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSP, 0x7FFFFFFF, []byte{0x48, 0x69, 0xE4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RBP, 0x7FFFFFFF, []byte{0x48, 0x69, 0xED, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RSI, 0x7FFFFFFF, []byte{0x48, 0x69, 0xF6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.RDI, 0x7FFFFFFF, []byte{0x48, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R8, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xC0, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R9, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xC9, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R10, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xD2, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R11, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xDB, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R12, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xE4, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R13, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xED, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R14, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xF6, 0xFF, 0xFF, 0xFF, 0x7F}}, + {x64.R15, 0x7FFFFFFF, []byte{0x4D, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}}, + } + + for _, pattern := range usagePatterns { + t.Logf("mul %s, %x", pattern.Register, pattern.Number) + code := x64.MulRegNum(nil, pattern.Register, pattern.Number) + assert.DeepEqual(t, code, pattern.Code) + } +} diff --git a/src/build/arch/x64/Sub_test.go b/src/build/arch/x64/Sub_test.go index a0b0b10..5dcf691 100644 --- a/src/build/arch/x64/Sub_test.go +++ b/src/build/arch/x64/Sub_test.go @@ -30,6 +30,7 @@ func TestSubRegisterNumber(t *testing.T) { {x64.R13, 1, []byte{0x49, 0x83, 0xED, 0x01}}, {x64.R14, 1, []byte{0x49, 0x83, 0xEE, 0x01}}, {x64.R15, 1, []byte{0x49, 0x83, 0xEF, 0x01}}, + {x64.RAX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE8, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.RCX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xE9, 0xFF, 0xFF, 0xFF, 0x7F}}, {x64.RDX, 0x7FFFFFFF, []byte{0x48, 0x81, 0xEA, 0xFF, 0xFF, 0xFF, 0x7F}}, diff --git a/src/build/arch/x64/numberToRegister.go b/src/build/arch/x64/numRegReg.go similarity index 100% rename from src/build/arch/x64/numberToRegister.go rename to src/build/arch/x64/numRegReg.go diff --git a/src/build/asm/Assembler.go b/src/build/asm/Assembler.go index 6dbb8bd..959aea2 100644 --- a/src/build/asm/Assembler.go +++ b/src/build/asm/Assembler.go @@ -39,6 +39,12 @@ func (a *Assembler) Finalize() ([]byte, []byte) { code = x64.SubRegNum(code, operands.Register, operands.Number) } + case MUL: + switch operands := x.Data.(type) { + case *RegisterNumber: + code = x64.MulRegNum(code, operands.Register, operands.Number) + } + case CALL: code = x64.Call(code, 0x00_00_00_00) size := 4 diff --git a/src/build/asm/Instructions.go b/src/build/asm/Instructions.go index efd6920..7eb041f 100644 --- a/src/build/asm/Instructions.go +++ b/src/build/asm/Instructions.go @@ -2,32 +2,10 @@ package asm import "git.akyoto.dev/cli/q/src/build/cpu" -// AddRegisterNumber adds a number to the given register. -func (a *Assembler) AddRegisterNumber(reg cpu.Register, number int) { +// RegisterNumber adds an instruction with a register and a number. +func (a *Assembler) RegisterNumber(mnemonic Mnemonic, reg cpu.Register, number int) { a.Instructions = append(a.Instructions, Instruction{ - Mnemonic: ADD, - Data: &RegisterNumber{ - Register: reg, - Number: number, - }, - }) -} - -// SubRegisterNumber subtracts a number from the given register. -func (a *Assembler) SubRegisterNumber(reg cpu.Register, number int) { - a.Instructions = append(a.Instructions, Instruction{ - Mnemonic: SUB, - Data: &RegisterNumber{ - Register: reg, - Number: number, - }, - }) -} - -// MoveRegisterNumber moves a number into the given register. -func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number int) { - a.Instructions = append(a.Instructions, Instruction{ - Mnemonic: MOVE, + Mnemonic: mnemonic, Data: &RegisterNumber{ Register: reg, Number: number, diff --git a/src/build/asm/Mnemonic.go b/src/build/asm/Mnemonic.go index c5309eb..6b97585 100644 --- a/src/build/asm/Mnemonic.go +++ b/src/build/asm/Mnemonic.go @@ -7,6 +7,7 @@ const ( ADD CALL JUMP + MUL LABEL MOVE RETURN @@ -32,6 +33,9 @@ func (m Mnemonic) String() string { case MOVE: return "move" + case MUL: + return "mul" + case RETURN: return "return"