Implemented division

This commit is contained in:
Eduard Urbach 2024-06-25 00:19:01 +02:00
parent 34af20d7a0
commit 2cbc064f14
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 89 additions and 3 deletions

View File

@ -10,9 +10,11 @@ hello() {
address += 4194304 address += 4194304
address += 1 address += 1
length += 5
length *= 2 length += 50
length -= 7 length -= 20
length *= 10
length /= 100
loop { loop {
syscall(write, stdout, address, length) syscall(write, stdout, address, length)

View File

@ -130,6 +130,10 @@ func (f *Function) CompileInstruction(line token.List) error {
case "*=": case "*=":
f.Assembler.RegisterNumber(asm.MUL, register, number) f.Assembler.RegisterNumber(asm.MUL, register, number)
return nil return nil
case "/=":
f.Assembler.RegisterNumber(asm.DIV, register, number)
return nil
} }
} }

20
src/build/arch/x64/Div.go Normal file
View File

@ -0,0 +1,20 @@
package x64
import "git.akyoto.dev/cli/q/src/build/cpu"
// DivReg divides RDX:RAX by the value in the register.
func DivReg(code []byte, divisor cpu.Register) []byte {
rex := byte(0x48)
if divisor >= 8 {
rex++
divisor -= 8
}
return append(
code,
rex,
0xF7,
0xF8+byte(divisor),
)
}

View File

@ -0,0 +1,39 @@
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 TestDivRegister(t *testing.T) {
usagePatterns := []struct {
Register cpu.Register
Code []byte
}{
{x64.RAX, []byte{0x48, 0xF7, 0xF8}},
{x64.RCX, []byte{0x48, 0xF7, 0xF9}},
{x64.RDX, []byte{0x48, 0xF7, 0xFA}},
{x64.RBX, []byte{0x48, 0xF7, 0xFB}},
{x64.RSP, []byte{0x48, 0xF7, 0xFC}},
{x64.RBP, []byte{0x48, 0xF7, 0xFD}},
{x64.RSI, []byte{0x48, 0xF7, 0xFE}},
{x64.RDI, []byte{0x48, 0xF7, 0xFF}},
{x64.R8, []byte{0x49, 0xF7, 0xF8}},
{x64.R9, []byte{0x49, 0xF7, 0xF9}},
{x64.R10, []byte{0x49, 0xF7, 0xFA}},
{x64.R11, []byte{0x49, 0xF7, 0xFB}},
{x64.R12, []byte{0x49, 0xF7, 0xFC}},
{x64.R13, []byte{0x49, 0xF7, 0xFD}},
{x64.R14, []byte{0x49, 0xF7, 0xFE}},
{x64.R15, []byte{0x49, 0xF7, 0xFF}},
}
for _, pattern := range usagePatterns {
t.Logf("idiv %s", pattern.Register)
code := x64.DivReg(nil, pattern.Register)
assert.DeepEqual(t, code, pattern.Code)
}
}

View File

@ -0,0 +1,7 @@
package x64
// ExtendRAXToRDX doubles the size of RAX by sign-extending it to RDX.
// This is also known as CQO.
func ExtendRAXToRDX(code []byte) []byte {
return append(code, 0x48, 0x99)
}

View File

@ -45,6 +45,16 @@ func (a *Assembler) Finalize() ([]byte, []byte) {
code = x64.MulRegNum(code, operands.Register, operands.Number) code = x64.MulRegNum(code, operands.Register, operands.Number)
} }
case DIV:
switch operands := x.Data.(type) {
case *RegisterNumber:
code = x64.MoveRegReg64(code, x64.RAX, operands.Register)
code = x64.MoveRegNum32(code, operands.Register, uint32(operands.Number))
code = x64.ExtendRAXToRDX(code)
code = x64.DivReg(code, operands.Register)
code = x64.MoveRegReg64(code, operands.Register, x64.RAX)
}
case CALL: case CALL:
code = x64.Call(code, 0x00_00_00_00) code = x64.Call(code, 0x00_00_00_00)
size := 4 size := 4

View File

@ -6,6 +6,7 @@ const (
NONE Mnemonic = iota NONE Mnemonic = iota
ADD ADD
CALL CALL
DIV
JUMP JUMP
MUL MUL
LABEL LABEL
@ -24,6 +25,9 @@ func (m Mnemonic) String() string {
case CALL: case CALL:
return "call" return "call"
case DIV:
return "div"
case JUMP: case JUMP:
return "jump" return "jump"