diff --git a/README.md b/README.md index 8fcdcac..988d4c8 100644 --- a/README.md +++ b/README.md @@ -152,10 +152,10 @@ This is what generates expressions from tokens. - [x] `+=`, `-=`, `*=`, `/=`, `%=` - [x] `&`, `|`, `^` - [x] `&=`, `|=`, `^=` +- [x] `<<`, `>>` +- [x] `<<=`, `>>=` - [x] `==`, `!=`, `<`, `<=`, `>`, `>=` - [x] `&&`, `||` -- [ ] `<<`, `>>` -- [ ] `<<=`, `>>=` ### Architecture diff --git a/src/build/arch/x64/Shift.go b/src/build/arch/x64/Shift.go new file mode 100644 index 0000000..2f88cb1 --- /dev/null +++ b/src/build/arch/x64/Shift.go @@ -0,0 +1,17 @@ +package x64 + +import ( + "git.akyoto.dev/cli/q/src/build/cpu" +) + +// ShiftLeftNumber shifts the register value by `bitCount` bits to the left. +func ShiftLeftNumber(code []byte, register cpu.Register, bitCount byte) []byte { + code = encode(code, AddressDirect, 0b100, register, 8, 0xC1) + return append(code, bitCount) +} + +// ShiftRightSignedNumber shifts the signed register value by `bitCount` bits to the right. +func ShiftRightSignedNumber(code []byte, register cpu.Register, bitCount byte) []byte { + code = encode(code, AddressDirect, 0b111, register, 8, 0xC1) + return append(code, bitCount) +} diff --git a/src/build/asm/Finalize.go b/src/build/asm/Finalize.go index c7bdc94..cdd5633 100644 --- a/src/build/asm/Finalize.go +++ b/src/build/asm/Finalize.go @@ -184,6 +184,18 @@ func (a Assembler) Finalize() ([]byte, []byte) { case RETURN: code = x64.Return(code) + case SHIFTL: + switch operands := x.Data.(type) { + case *RegisterNumber: + code = x64.ShiftLeftNumber(code, operands.Register, byte(operands.Number)&0b111111) + } + + case SHIFTRS: + switch operands := x.Data.(type) { + case *RegisterNumber: + code = x64.ShiftRightSignedNumber(code, operands.Register, byte(operands.Number)&0b111111) + } + case STORE: switch operands := x.Data.(type) { case *MemoryNumber: diff --git a/src/build/asm/Mnemonic.go b/src/build/asm/Mnemonic.go index 7ed32ca..78070f8 100644 --- a/src/build/asm/Mnemonic.go +++ b/src/build/asm/Mnemonic.go @@ -26,6 +26,8 @@ const ( POP PUSH RETURN + SHIFTL + SHIFTRS STORE SUB SYSCALL @@ -79,6 +81,10 @@ func (m Mnemonic) String() string { return "push" case RETURN: return "return" + case SHIFTL: + return "shift l" + case SHIFTRS: + return "shift rs" case SUB: return "sub" case STORE: diff --git a/src/build/core/ExecuteRegisterNumber.go b/src/build/core/ExecuteRegisterNumber.go index 6f29527..e2e4171 100644 --- a/src/build/core/ExecuteRegisterNumber.go +++ b/src/build/core/ExecuteRegisterNumber.go @@ -34,6 +34,12 @@ func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Reg case token.Xor, token.XorAssign: f.RegisterNumber(asm.XOR, register, number) + case token.Shl, token.ShlAssign: + f.RegisterNumber(asm.SHIFTL, register, number) + + case token.Shr, token.ShrAssign: + f.RegisterNumber(asm.SHIFTRS, register, number) + case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual: f.RegisterNumber(asm.COMPARE, register, number) diff --git a/tests/programs/shift.q b/tests/programs/shift.q new file mode 100644 index 0000000..1fd1ddf --- /dev/null +++ b/tests/programs/shift.q @@ -0,0 +1,57 @@ +import sys + +main() { + if 0 << 0 != 0 { + sys.exit(1) + } + + if 0 >> 0 != 0 { + sys.exit(2) + } + + if 1 << 0 != 1 { + sys.exit(3) + } + + if 1 >> 0 != 1 { + sys.exit(4) + } + + if 1 >> 1 != 0 { + sys.exit(5) + } + + if 1 << 1 != 2 { + sys.exit(6) + } + + if 1 << 2 != 4 { + sys.exit(7) + } + + if 1 << 3 != 8 { + sys.exit(8) + } + + if 1 << 4 != 16 { + sys.exit(9) + } + + if 16 >> 1 != 8 { + sys.exit(10) + } + + if 16 >> 2 != 4 { + sys.exit(11) + } + + if 16 >> 3 != 2 { + sys.exit(12) + } + + if 16 >> 4 != 1 { + sys.exit(13) + } + + sys.exit(0) +} \ No newline at end of file diff --git a/tests/programs_test.go b/tests/programs_test.go index 6eac176..8e8bf54 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -35,6 +35,7 @@ var programs = []struct { {"bitwise-and", "", "", 0}, {"bitwise-or", "", "", 0}, {"bitwise-xor", "", "", 0}, + {"shift", "", "", 0}, {"remainder", "", "", 0}, {"jump-near", "", "", 0}, {"loop", "", "", 0},