Implemented register push and pop

This commit is contained in:
Eduard Urbach 2024-06-25 16:19:47 +02:00
parent 2cbc064f14
commit a87775a1db
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
6 changed files with 128 additions and 6 deletions

16
src/build/arch/x64/Pop.go Normal file
View File

@ -0,0 +1,16 @@
package x64
import "git.akyoto.dev/cli/q/src/build/cpu"
// PopReg pops a value from the stack and saves it into the register.
func PopReg(code []byte, register cpu.Register) []byte {
if register >= 8 {
code = append(code, REX(0, 0, 0, 1))
register -= 8
}
return append(
code,
0x58+byte(register),
)
}

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 TestPopRegister(t *testing.T) {
usagePatterns := []struct {
Register cpu.Register
Code []byte
}{
{x64.RAX, []byte{0x58}},
{x64.RCX, []byte{0x59}},
{x64.RDX, []byte{0x5A}},
{x64.RBX, []byte{0x5B}},
{x64.RSP, []byte{0x5C}},
{x64.RBP, []byte{0x5D}},
{x64.RSI, []byte{0x5E}},
{x64.RDI, []byte{0x5F}},
{x64.R8, []byte{0x41, 0x58}},
{x64.R9, []byte{0x41, 0x59}},
{x64.R10, []byte{0x41, 0x5A}},
{x64.R11, []byte{0x41, 0x5B}},
{x64.R12, []byte{0x41, 0x5C}},
{x64.R13, []byte{0x41, 0x5D}},
{x64.R14, []byte{0x41, 0x5E}},
{x64.R15, []byte{0x41, 0x5F}},
}
for _, pattern := range usagePatterns {
t.Logf("pop %s", pattern.Register)
code := x64.PopReg(nil, pattern.Register)
assert.DeepEqual(t, code, pattern.Code)
}
}

View File

@ -0,0 +1,16 @@
package x64
import "git.akyoto.dev/cli/q/src/build/cpu"
// PushReg pushes the value inside the register onto the stack.
func PushReg(code []byte, register cpu.Register) []byte {
if register >= 8 {
code = append(code, REX(0, 0, 0, 1))
register -= 8
}
return append(
code,
0x50+byte(register),
)
}

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 TestPushRegister(t *testing.T) {
usagePatterns := []struct {
Register cpu.Register
Code []byte
}{
{x64.RAX, []byte{0x50}},
{x64.RCX, []byte{0x51}},
{x64.RDX, []byte{0x52}},
{x64.RBX, []byte{0x53}},
{x64.RSP, []byte{0x54}},
{x64.RBP, []byte{0x55}},
{x64.RSI, []byte{0x56}},
{x64.RDI, []byte{0x57}},
{x64.R8, []byte{0x41, 0x50}},
{x64.R9, []byte{0x41, 0x51}},
{x64.R10, []byte{0x41, 0x52}},
{x64.R11, []byte{0x41, 0x53}},
{x64.R12, []byte{0x41, 0x54}},
{x64.R13, []byte{0x41, 0x55}},
{x64.R14, []byte{0x41, 0x56}},
{x64.R15, []byte{0x41, 0x57}},
}
for _, pattern := range usagePatterns {
t.Logf("push %s", pattern.Register)
code := x64.PushReg(nil, pattern.Register)
assert.DeepEqual(t, code, pattern.Code)
}
}

View File

@ -48,11 +48,23 @@ func (a *Assembler) Finalize() ([]byte, []byte) {
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)
if operands.Register == x64.RAX {
code = x64.PushReg(code, x64.RCX)
code = x64.MoveRegNum32(code, x64.RCX, uint32(operands.Number))
code = x64.ExtendRAXToRDX(code)
code = x64.DivReg(code, x64.RCX)
code = x64.PopReg(code, x64.RCX)
} else {
code = x64.PushReg(code, x64.RAX)
code = x64.PushReg(code, x64.RDX)
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)
code = x64.PopReg(code, x64.RDX)
code = x64.PopReg(code, x64.RAX)
}
}
case CALL:

View File

@ -14,5 +14,5 @@ type RegisterNumber struct {
// String returns a human readable version.
func (data *RegisterNumber) String() string {
return fmt.Sprintf("%s, %x", data.Register, data.Number)
return fmt.Sprintf("%s, %Xₕ", data.Register, data.Number)
}