Bit shifting

This commit is contained in:
Johan B.W. de Vries 2022-08-16 20:55:20 +02:00
parent 75d7e05519
commit d051160244
4 changed files with 44 additions and 7 deletions

View File

@ -82,7 +82,7 @@ _CRC32_Table: u32[256] = [
] ]
def _crc32_f(crc: u32, byt: u8) -> u32: def _crc32_f(crc: u32, byt: u8) -> u32:
return (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ byt] return (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ u32(byt)]
@exported @exported
def crc32(data: bytes) -> u32: def crc32(data: bytes) -> u32:

View File

@ -77,8 +77,11 @@ OPERATOR_MAP = {
U8_OPERATOR_MAP = { U8_OPERATOR_MAP = {
# Under the hood, this is an i32 # Under the hood, this is an i32
# Implementing XOR, OR, AND is fine since the 3 remaining # Implementing Right Shift XOR, OR, AND is fine since the 3 remaining
# bytes stay zero after this operation # bytes stay zero after this operation
# Since it's unsigned an unsigned value, Logical or Arithmetic shift right
# are the same operation
'>>': 'shr_u',
'^': 'xor', '^': 'xor',
'|': 'or', '|': 'or',
'&': 'and', '&': 'and',
@ -89,6 +92,8 @@ U32_OPERATOR_MAP = {
'>': 'gt_u', '>': 'gt_u',
'<=': 'le_u', '<=': 'le_u',
'>=': 'ge_u', '>=': 'ge_u',
'<<': 'shl',
'>>': 'shr_u',
'^': 'xor', '^': 'xor',
'|': 'or', '|': 'or',
'&': 'and', '&': 'and',
@ -99,6 +104,8 @@ U64_OPERATOR_MAP = {
'>': 'gt_u', '>': 'gt_u',
'<=': 'le_u', '<=': 'le_u',
'>=': 'ge_u', '>=': 'ge_u',
'<<': 'shl',
'>>': 'shr_u',
'^': 'xor', '^': 'xor',
'|': 'or', '|': 'or',
'&': 'and', '&': 'and',

View File

@ -244,6 +244,10 @@ class OurVisitor:
operator = '-' operator = '-'
elif isinstance(node.op, ast.Mult): elif isinstance(node.op, ast.Mult):
operator = '*' operator = '*'
elif isinstance(node.op, ast.LShift):
operator = '<<'
elif isinstance(node.op, ast.RShift):
operator = '>>'
elif isinstance(node.op, ast.BitOr): elif isinstance(node.op, ast.BitOr):
operator = '|' operator = '|'
elif isinstance(node.op, ast.BitXor): elif isinstance(node.op, ast.BitXor):
@ -433,16 +437,14 @@ class OurVisitor:
if func.returns.__class__ != func.posonlyargs[0][1].__class__: if func.returns.__class__ != func.posonlyargs[0][1].__class__:
_raise_static_error(node, f'Expected a foldable function, {func.name} returns a {codestyle.type_(func.returns)} but expects a {codestyle.type_(func.posonlyargs[0][1])}') _raise_static_error(node, f'Expected a foldable function, {func.name} returns a {codestyle.type_(func.returns)} but expects a {codestyle.type_(func.posonlyargs[0][1])}')
t_u8 = module.types['u8'] if module.types['u8'].__class__ != func.posonlyargs[1][1].__class__:
if t_u8.__class__ != func.posonlyargs[1][1].__class__:
_raise_static_error(node, 'Only folding over bytes (u8) is supported at this time') _raise_static_error(node, 'Only folding over bytes (u8) is supported at this time')
return Fold( return Fold(
exp_type, exp_type,
Fold.Direction.LEFT, Fold.Direction.LEFT,
func, func,
self.visit_Module_FunctionDef_expr(module, function, our_locals, t_u8, node.args[1]), self.visit_Module_FunctionDef_expr(module, function, our_locals, func.returns, node.args[1]),
self.visit_Module_FunctionDef_expr(module, function, our_locals, module.types['bytes'], node.args[2]), self.visit_Module_FunctionDef_expr(module, function, our_locals, module.types['bytes'], node.args[2]),
) )
else: else:
@ -550,7 +552,7 @@ class OurVisitor:
_raise_static_error(node, 'Expected integer value') _raise_static_error(node, 'Expected integer value')
if node.value < 0 or node.value > 255: if node.value < 0 or node.value > 255:
_raise_static_error(node, 'Integer value out of range') _raise_static_error(node, f'Integer value out of range; expected 0..255, actual {node.value}')
return ConstantUInt8(exp_type, node.value) return ConstantUInt8(exp_type, node.value)

View File

@ -60,6 +60,34 @@ def testEntry() -> {type_}:
assert 7 == result.returned_value assert 7 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value) assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['u32', 'u64']) # FIXME: Support u8, requires an extra AND operation
def test_logical_left_shift(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return 10 << 3
"""
result = Suite(code_py).run_code()
assert 80 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
def test_logical_right_shift(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return 10 >> 3
"""
result = Suite(code_py).run_code()
assert 1 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test @pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64']) @pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
def test_bitwise_or(type_): def test_bitwise_or(type_):