Implemented register push and pop
This commit is contained in:
parent
2cbc064f14
commit
a87775a1db
16
src/build/arch/x64/Pop.go
Normal file
16
src/build/arch/x64/Pop.go
Normal 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),
|
||||
)
|
||||
}
|
39
src/build/arch/x64/Pop_test.go
Normal file
39
src/build/arch/x64/Pop_test.go
Normal 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)
|
||||
}
|
||||
}
|
16
src/build/arch/x64/Push.go
Normal file
16
src/build/arch/x64/Push.go
Normal 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),
|
||||
)
|
||||
}
|
39
src/build/arch/x64/Push_test.go
Normal file
39
src/build/arch/x64/Push_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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:
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user