Implemented bitwise operations
This commit is contained in:
parent
b8900b518a
commit
d1a8f0d66c
@ -150,12 +150,12 @@ This is what generates expressions from tokens.
|
|||||||
- [x] `=`, `:=`
|
- [x] `=`, `:=`
|
||||||
- [x] `+`, `-`, `*`, `/`, `%`
|
- [x] `+`, `-`, `*`, `/`, `%`
|
||||||
- [x] `+=`, `-=`, `*=`, `/=`, `%=`
|
- [x] `+=`, `-=`, `*=`, `/=`, `%=`
|
||||||
- [ ] `&`, `|`, `^`
|
- [x] `&`, `|`, `^`
|
||||||
- [ ] `&=`, `|=`, `^=`
|
- [x] `&=`, `|=`, `^=`
|
||||||
- [ ] `<<`, `>>`
|
|
||||||
- [ ] `<<=`, `>>=`
|
|
||||||
- [x] `==`, `!=`, `<`, `<=`, `>`, `>=`
|
- [x] `==`, `!=`, `<`, `<=`, `>`, `>=`
|
||||||
- [x] `&&`, `||`
|
- [x] `&&`, `||`
|
||||||
|
- [ ] `<<`, `>>`
|
||||||
|
- [ ] `<<=`, `>>=`
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
|
|
||||||
|
15
src/build/arch/x64/And.go
Normal file
15
src/build/arch/x64/And.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package x64
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AndRegisterNumber performs a bitwise AND using a register and a number.
|
||||||
|
func AndRegisterNumber(code []byte, destination cpu.Register, number int) []byte {
|
||||||
|
return encodeNum(code, AddressDirect, 0b100, destination, number, 0x83, 0x81)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AndRegisterRegister performs a bitwise AND using two registers.
|
||||||
|
func AndRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte {
|
||||||
|
return encode(code, AddressDirect, operand, destination, 8, 0x21)
|
||||||
|
}
|
15
src/build/arch/x64/Or.go
Normal file
15
src/build/arch/x64/Or.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package x64
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OrRegisterNumber performs a bitwise OR using a register and a number.
|
||||||
|
func OrRegisterNumber(code []byte, destination cpu.Register, number int) []byte {
|
||||||
|
return encodeNum(code, AddressDirect, 0b001, destination, number, 0x83, 0x81)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrRegisterRegister performs a bitwise OR using two registers.
|
||||||
|
func OrRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte {
|
||||||
|
return encode(code, AddressDirect, operand, destination, 8, 0x09)
|
||||||
|
}
|
15
src/build/arch/x64/Xor.go
Normal file
15
src/build/arch/x64/Xor.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package x64
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XorRegisterNumber performs a bitwise XOR using a register and a number.
|
||||||
|
func XorRegisterNumber(code []byte, destination cpu.Register, number int) []byte {
|
||||||
|
return encodeNum(code, AddressDirect, 0b110, destination, number, 0x83, 0x81)
|
||||||
|
}
|
||||||
|
|
||||||
|
// XorRegisterRegister performs a bitwise XOR using two registers.
|
||||||
|
func XorRegisterRegister(code []byte, destination cpu.Register, operand cpu.Register) []byte {
|
||||||
|
return encode(code, AddressDirect, operand, destination, 8, 0x31)
|
||||||
|
}
|
@ -26,6 +26,14 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
code = x64.AddRegisterRegister(code, operands.Destination, operands.Source)
|
code = x64.AddRegisterRegister(code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AND:
|
||||||
|
switch operands := x.Data.(type) {
|
||||||
|
case *RegisterNumber:
|
||||||
|
code = x64.AndRegisterNumber(code, operands.Register, operands.Number)
|
||||||
|
case *RegisterRegister:
|
||||||
|
code = x64.AndRegisterRegister(code, operands.Destination, operands.Source)
|
||||||
|
}
|
||||||
|
|
||||||
case SUB:
|
case SUB:
|
||||||
switch operands := x.Data.(type) {
|
switch operands := x.Data.(type) {
|
||||||
case *RegisterNumber:
|
case *RegisterNumber:
|
||||||
@ -153,6 +161,14 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OR:
|
||||||
|
switch operands := x.Data.(type) {
|
||||||
|
case *RegisterNumber:
|
||||||
|
code = x64.OrRegisterNumber(code, operands.Register, operands.Number)
|
||||||
|
case *RegisterRegister:
|
||||||
|
code = x64.OrRegisterRegister(code, operands.Destination, operands.Source)
|
||||||
|
}
|
||||||
|
|
||||||
case POP:
|
case POP:
|
||||||
switch operands := x.Data.(type) {
|
switch operands := x.Data.(type) {
|
||||||
case *Register:
|
case *Register:
|
||||||
@ -177,6 +193,14 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
case SYSCALL:
|
case SYSCALL:
|
||||||
code = x64.Syscall(code)
|
code = x64.Syscall(code)
|
||||||
|
|
||||||
|
case XOR:
|
||||||
|
switch operands := x.Data.(type) {
|
||||||
|
case *RegisterNumber:
|
||||||
|
code = x64.XorRegisterNumber(code, operands.Register, operands.Number)
|
||||||
|
case *RegisterRegister:
|
||||||
|
code = x64.XorRegisterRegister(code, operands.Destination, operands.Source)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unknown mnemonic: " + x.Mnemonic.String())
|
panic("unknown mnemonic: " + x.Mnemonic.String())
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ type Mnemonic uint8
|
|||||||
const (
|
const (
|
||||||
NONE Mnemonic = iota
|
NONE Mnemonic = iota
|
||||||
ADD
|
ADD
|
||||||
|
AND
|
||||||
CALL
|
CALL
|
||||||
COMMENT
|
COMMENT
|
||||||
COMPARE
|
COMPARE
|
||||||
@ -21,12 +22,14 @@ const (
|
|||||||
LOAD
|
LOAD
|
||||||
MODULO
|
MODULO
|
||||||
MOVE
|
MOVE
|
||||||
|
OR
|
||||||
POP
|
POP
|
||||||
PUSH
|
PUSH
|
||||||
RETURN
|
RETURN
|
||||||
STORE
|
STORE
|
||||||
SUB
|
SUB
|
||||||
SYSCALL
|
SYSCALL
|
||||||
|
XOR
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns a human readable version.
|
// String returns a human readable version.
|
||||||
@ -34,6 +37,8 @@ func (m Mnemonic) String() string {
|
|||||||
switch m {
|
switch m {
|
||||||
case ADD:
|
case ADD:
|
||||||
return "add"
|
return "add"
|
||||||
|
case AND:
|
||||||
|
return "and"
|
||||||
case CALL:
|
case CALL:
|
||||||
return "call"
|
return "call"
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
@ -66,6 +71,8 @@ func (m Mnemonic) String() string {
|
|||||||
return "move"
|
return "move"
|
||||||
case MUL:
|
case MUL:
|
||||||
return "mul"
|
return "mul"
|
||||||
|
case OR:
|
||||||
|
return "or"
|
||||||
case POP:
|
case POP:
|
||||||
return "pop"
|
return "pop"
|
||||||
case PUSH:
|
case PUSH:
|
||||||
@ -78,6 +85,8 @@ func (m Mnemonic) String() string {
|
|||||||
return "store"
|
return "store"
|
||||||
case SYSCALL:
|
case SYSCALL:
|
||||||
return "syscall"
|
return "syscall"
|
||||||
|
case XOR:
|
||||||
|
return "xor"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,15 @@ func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Reg
|
|||||||
case token.Mod, token.ModAssign:
|
case token.Mod, token.ModAssign:
|
||||||
f.RegisterNumber(asm.MODULO, register, number)
|
f.RegisterNumber(asm.MODULO, register, number)
|
||||||
|
|
||||||
|
case token.And, token.AndAssign:
|
||||||
|
f.RegisterNumber(asm.AND, register, number)
|
||||||
|
|
||||||
|
case token.Or, token.OrAssign:
|
||||||
|
f.RegisterNumber(asm.OR, register, number)
|
||||||
|
|
||||||
|
case token.Xor, token.XorAssign:
|
||||||
|
f.RegisterNumber(asm.XOR, register, number)
|
||||||
|
|
||||||
case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual:
|
case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual:
|
||||||
f.RegisterNumber(asm.COMPARE, register, number)
|
f.RegisterNumber(asm.COMPARE, register, number)
|
||||||
|
|
||||||
|
@ -25,6 +25,15 @@ func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cp
|
|||||||
case token.Mod, token.ModAssign:
|
case token.Mod, token.ModAssign:
|
||||||
f.RegisterRegister(asm.MODULO, destination, source)
|
f.RegisterRegister(asm.MODULO, destination, source)
|
||||||
|
|
||||||
|
case token.And, token.AndAssign:
|
||||||
|
f.RegisterRegister(asm.AND, destination, source)
|
||||||
|
|
||||||
|
case token.Or, token.OrAssign:
|
||||||
|
f.RegisterRegister(asm.OR, destination, source)
|
||||||
|
|
||||||
|
case token.Xor, token.XorAssign:
|
||||||
|
f.RegisterRegister(asm.XOR, destination, source)
|
||||||
|
|
||||||
case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual:
|
case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual:
|
||||||
f.RegisterRegister(asm.COMPARE, destination, source)
|
f.RegisterRegister(asm.COMPARE, destination, source)
|
||||||
|
|
||||||
|
61
tests/programs/bitwise-and.q
Normal file
61
tests/programs/bitwise-and.q
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if 0 & 0 != 0 {
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 & 1 != 0 {
|
||||||
|
sys.exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 & 0 != 0 {
|
||||||
|
sys.exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 & 1 != 1 {
|
||||||
|
sys.exit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 & 2 != 0 {
|
||||||
|
sys.exit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 & 3 != 1 {
|
||||||
|
sys.exit(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 & 0 != 0 {
|
||||||
|
sys.exit(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 & 1 != 0 {
|
||||||
|
sys.exit(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 & 2 != 2 {
|
||||||
|
sys.exit(9)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 & 3 != 2 {
|
||||||
|
sys.exit(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 & 0 != 0 {
|
||||||
|
sys.exit(11)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 & 1 != 1 {
|
||||||
|
sys.exit(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 & 2 != 2 {
|
||||||
|
sys.exit(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 & 3 != 3 {
|
||||||
|
sys.exit(14)
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
}
|
61
tests/programs/bitwise-or.q
Normal file
61
tests/programs/bitwise-or.q
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if 0 | 0 != 0 {
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 | 1 != 1 {
|
||||||
|
sys.exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 | 0 != 1 {
|
||||||
|
sys.exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 | 1 != 1 {
|
||||||
|
sys.exit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 | 2 != 3 {
|
||||||
|
sys.exit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 | 3 != 3 {
|
||||||
|
sys.exit(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 | 0 != 2 {
|
||||||
|
sys.exit(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 | 1 != 3 {
|
||||||
|
sys.exit(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 | 2 != 2 {
|
||||||
|
sys.exit(9)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 | 3 != 3 {
|
||||||
|
sys.exit(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 | 0 != 3 {
|
||||||
|
sys.exit(11)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 | 1 != 3 {
|
||||||
|
sys.exit(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 | 2 != 3 {
|
||||||
|
sys.exit(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 | 3 != 3 {
|
||||||
|
sys.exit(14)
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
}
|
61
tests/programs/bitwise-xor.q
Normal file
61
tests/programs/bitwise-xor.q
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if 0 ^ 0 != 0 {
|
||||||
|
sys.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 ^ 1 != 1 {
|
||||||
|
sys.exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 ^ 0 != 1 {
|
||||||
|
sys.exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 ^ 1 != 0 {
|
||||||
|
sys.exit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 ^ 2 != 3 {
|
||||||
|
sys.exit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 ^ 3 != 2 {
|
||||||
|
sys.exit(6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 ^ 0 != 2 {
|
||||||
|
sys.exit(7)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 ^ 1 != 3 {
|
||||||
|
sys.exit(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 ^ 2 != 0 {
|
||||||
|
sys.exit(9)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 2 ^ 3 != 1 {
|
||||||
|
sys.exit(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 ^ 0 != 3 {
|
||||||
|
sys.exit(11)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 ^ 1 != 2 {
|
||||||
|
sys.exit(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 ^ 2 != 1 {
|
||||||
|
sys.exit(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 3 ^ 3 != 0 {
|
||||||
|
sys.exit(14)
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
}
|
@ -32,10 +32,13 @@ var programs = []struct {
|
|||||||
{"branch-and", "", "", 0},
|
{"branch-and", "", "", 0},
|
||||||
{"branch-or", "", "", 0},
|
{"branch-or", "", "", 0},
|
||||||
{"branch-both", "", "", 0},
|
{"branch-both", "", "", 0},
|
||||||
|
{"bitwise-and", "", "", 0},
|
||||||
|
{"bitwise-or", "", "", 0},
|
||||||
|
{"bitwise-xor", "", "", 0},
|
||||||
|
{"remainder", "", "", 0},
|
||||||
{"jump-near", "", "", 0},
|
{"jump-near", "", "", 0},
|
||||||
{"loop", "", "", 0},
|
{"loop", "", "", 0},
|
||||||
{"loop-lifetime", "", "", 0},
|
{"loop-lifetime", "", "", 0},
|
||||||
{"remainder", "", "", 0},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrograms(t *testing.T) {
|
func TestPrograms(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user