Improved x64 encoder

This commit is contained in:
Eduard Urbach 2024-06-24 21:54:03 +02:00
parent 862598cfc1
commit 625e8d5e2e
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
5 changed files with 46 additions and 23 deletions

View File

@ -114,17 +114,17 @@ func (f *Function) CompileInstruction(line token.List) error {
} }
if expr.Token.Kind == token.Operator { if expr.Token.Kind == token.Operator {
name := expr.Children[0].Token.Text()
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
register := f.Variables[name].Register
switch expr.Token.Text() { switch expr.Token.Text() {
case "+=": case "+=":
name := expr.Children[0].Token.Text() f.Assembler.AddRegisterNumber(register, number)
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.AddRegisterNumber(f.Variables[name].Register, number)
return nil return nil
case "-=": case "-=":
name := expr.Children[0].Token.Text() f.Assembler.SubRegisterNumber(register, number)
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.SubRegisterNumber(f.Variables[name].Register, number)
return nil return nil
} }
} }

View File

@ -6,5 +6,5 @@ import (
// AddRegNum adds a number to the given register. // AddRegNum adds a number to the given register.
func AddRegNum(code []byte, destination cpu.Register, number int) []byte { func AddRegNum(code []byte, destination cpu.Register, number int) []byte {
return numberToRegister(0x83, 0x81, 0b000, code, destination, number) return numRegReg(code, 0x83, 0x81, 0, byte(destination), number)
} }

View File

@ -6,5 +6,5 @@ import (
// SubRegNum subtracts a number from the given register. // SubRegNum subtracts a number from the given register.
func SubRegNum(code []byte, destination cpu.Register, number int) []byte { func SubRegNum(code []byte, destination cpu.Register, number int) []byte {
return numberToRegister(0x83, 0x81, 0b101, code, destination, number) return numRegReg(code, 0x83, 0x81, 0b101, byte(destination), number)
} }

View File

@ -1,24 +1,27 @@
package x64 package x64
import ( // numRegReg encodes an instruction with up to two registers and a number parameter.
"math" func numRegReg(code []byte, opCode8 byte, opCode32 byte, reg byte, rm byte, number int) []byte {
w := byte(1) // Indicates a 64-bit register.
r := byte(0) // Extension to the "reg" field in ModRM.
x := byte(0) // Extension to the SIB index field.
b := byte(0) // Extension to the "rm" field in ModRM or the SIB base (r8 up to r15 use this).
mod := byte(0b11) // Direct addressing mode, no register offsets.
"git.akyoto.dev/cli/q/src/build/cpu" if reg > 0b111 {
) r = 1
reg &= 0b111
// numberToRegister encodes an instruction with a register and a number parameter.
func numberToRegister(opCode8 byte, opCode32 byte, reg byte, code []byte, destination cpu.Register, number int) []byte {
b := byte(0)
if destination >= 8 {
b = 1
destination -= 8
} }
rex := REX(1, 0, 0, b) if rm > 0b111 {
modRM := ModRM(0b11, reg, byte(destination)) b = 1
rm &= 0b111
}
if number >= math.MinInt8 && number <= math.MaxInt8 { rex := REX(w, r, x, b)
modRM := ModRM(mod, reg, rm)
if sizeOf(number) == 1 {
return append( return append(
code, code,
rex, rex,

View File

@ -0,0 +1,20 @@
package x64
import "math"
// sizeOf tells you how many bytes are needed to encode this number.
func sizeOf(number int) int {
switch {
case number >= math.MinInt8 && number <= math.MaxInt8:
return 1
case number >= math.MinInt16 && number <= math.MaxInt16:
return 2
case number >= math.MinInt32 && number <= math.MaxInt32:
return 4
default:
return 8
}
}