Implemented bitwise operations

This commit is contained in:
Eduard Urbach 2024-07-25 14:17:51 +02:00
parent b8900b518a
commit d1a8f0d66c
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
12 changed files with 287 additions and 5 deletions

View File

@ -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
View 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
View 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
View 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)
}

View File

@ -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())
} }

View File

@ -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 ""
} }

View File

@ -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)

View File

@ -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)

View 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)
}

View 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)
}

View 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)
}

View File

@ -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) {