479 lines
19 KiB
Python
479 lines
19 KiB
Python
import six
|
|
from peachpy.c.types import Type, \
|
|
int8_t, int16_t, int32_t, int64_t, \
|
|
uint8_t, uint16_t, uint32_t, uint64_t, \
|
|
float_, double_
|
|
from peachpy.parse import parse_assigned_variable_name
|
|
from peachpy.name import Name
|
|
|
|
|
|
class Constant:
|
|
_supported_sizes = [1, 2, 4, 8, 16, 32, 64]
|
|
_supported_types = [uint8_t, uint16_t, uint32_t, uint64_t,
|
|
int8_t, int16_t, int32_t, int64_t,
|
|
float_, double_]
|
|
|
|
def __init__(self, size, repeats, data, element_ctype, name):
|
|
assert isinstance(size, six.integer_types), "Constant size must be an integer"
|
|
assert size in Constant._supported_sizes, "Unsupported size %s: the only supported sizes are %s" \
|
|
% (str(size), ", ".join(map(str, sorted(Constant._supported_sizes))))
|
|
assert isinstance(repeats, six.integer_types), "The number of contant repeats must be an integer"
|
|
assert size % repeats == 0, "The number of constant repeats must divide constant size without remainder"
|
|
assert isinstance(element_ctype, Type), "Element type must be an instance of peachpy.c.Type"
|
|
assert element_ctype in Constant._supported_types, "The only supported types are %s" \
|
|
% ", ".join(Constant._supported_types)
|
|
assert isinstance(name, Name)
|
|
|
|
self.size = size
|
|
self.repeats = repeats
|
|
self.element_ctype = element_ctype
|
|
self.data = data
|
|
|
|
self.name = (name,)
|
|
|
|
self.label = None
|
|
self.prefix = None
|
|
|
|
def __str__(self):
|
|
format_spec = "%%0%dX" % (self.size / self.repeats * 2)
|
|
return "<" + ", ".join(format_spec % data for data in self.data) + ">"
|
|
|
|
def __hash__(self):
|
|
return hash(self.data) ^ hash(self.size) ^ hash(self.repeats)
|
|
|
|
def __eq__(self, other):
|
|
return isinstance(other, Constant) and self.data == other.data and self.element_ctype == other.element_ctype
|
|
|
|
def encode(self, encoder):
|
|
from peachpy.encoder import Encoder
|
|
assert isinstance(encoder, Encoder)
|
|
encode_function = {
|
|
1: encoder.uint8,
|
|
2: encoder.uint16,
|
|
4: encoder.uint32,
|
|
8: encoder.uint64
|
|
}[self.size / self.repeats]
|
|
return bytearray().join([encode_function(data) for data in self.data])
|
|
|
|
@property
|
|
def alignment(self):
|
|
if self.size == 10:
|
|
return 16
|
|
else:
|
|
return self.size
|
|
|
|
@property
|
|
def as_hex(self):
|
|
from peachpy.encoder import Encoder, Endianness
|
|
bytestring = self.encode(Encoder(Endianness.Little))
|
|
return "".join("%02X" % byte for byte in bytestring)
|
|
|
|
def format(self, assembly_format):
|
|
if assembly_format == "go":
|
|
return "const0x" + self.as_hex + "(SB)"
|
|
else:
|
|
return str(self)
|
|
|
|
@staticmethod
|
|
def _uint64xN(name, n, *args):
|
|
from peachpy.util import is_int, is_int64
|
|
assert is_int(n)
|
|
args = [arg for arg in args if arg is not None]
|
|
if len(args) == 0:
|
|
raise ValueError("At least one constant value must be specified")
|
|
if len(args) != 1 and len(args) != n:
|
|
raise ValueError("Either 1 or %d values must be specified" % n)
|
|
for i, number in enumerate(args):
|
|
if not is_int(number):
|
|
raise TypeError("The value %s is not an integer" % str(number))
|
|
if not is_int64(number):
|
|
raise ValueError("The number %d is not a 64-bit integer" % number)
|
|
if number < 0:
|
|
args[i] += 0x10000000000000000
|
|
if len(args) == 1:
|
|
args = [args[0]] * n
|
|
return Constant(8 * n, n, tuple(args), uint64_t, name)
|
|
|
|
@staticmethod
|
|
def _uint32xN(name, n, *args):
|
|
from peachpy.util import is_int, is_int32
|
|
assert is_int(n)
|
|
args = [arg for arg in args if arg is not None]
|
|
if len(args) == 0:
|
|
raise ValueError("At least one constant value must be specified")
|
|
if len(args) != 1 and len(args) != n:
|
|
raise ValueError("Either 1 or %d values must be specified" % n)
|
|
for i, number in enumerate(args):
|
|
if not is_int(number):
|
|
raise TypeError("The value %s is not an integer" % str(number))
|
|
if not is_int32(number):
|
|
raise ValueError("The number %d is not a 32-bit integer" % number)
|
|
if number < 0:
|
|
args[i] += 0x100000000
|
|
if len(args) == 1:
|
|
args = [args[0]] * n
|
|
return Constant(4 * n, n, tuple(args), uint32_t, name)
|
|
|
|
@staticmethod
|
|
def _uint16xN(name, n, *args):
|
|
from peachpy.util import is_int, is_int32
|
|
assert is_int(n)
|
|
args = [arg for arg in args if arg is not None]
|
|
if len(args) == 0:
|
|
raise ValueError("At least one constant value must be specified")
|
|
if len(args) != 1 and len(args) != n:
|
|
raise ValueError("Either 1 or %d values must be specified" % n)
|
|
for i, number in enumerate(args):
|
|
if not is_int(number):
|
|
raise TypeError("The value %s is not an integer" % str(number))
|
|
if not is_int32(number):
|
|
raise ValueError("The number %d is not a 16-bit integer" % number)
|
|
if number < 0:
|
|
args[i] += 0x100000000
|
|
if len(args) == 1:
|
|
args = [args[0]] * n
|
|
return Constant(2 * n, n, tuple(args), uint32_t, name)
|
|
|
|
@staticmethod
|
|
def _float64xN(name, n, *args):
|
|
args = [arg for arg in args if arg is not None]
|
|
if len(args) == 0:
|
|
raise ValueError("At least one constant value must be specified")
|
|
if len(args) != 1 and len(args) != n:
|
|
raise ValueError("Either 1 or %d values must be specified" % n)
|
|
args = [Constant._parse_float64(arg) for arg in args]
|
|
if len(args) == 1:
|
|
args = [args[0]] * n
|
|
return Constant(8 * n, n, tuple(args), double_, name)
|
|
|
|
@staticmethod
|
|
def _float32xN(name, n, *args):
|
|
args = [arg for arg in args if arg is not None]
|
|
if len(args) == 0:
|
|
raise ValueError("At least one constant value must be specified")
|
|
if len(args) != 1 and len(args) != n:
|
|
raise ValueError("Either 1 or %d values must be specified" % n)
|
|
args = [Constant._parse_float32(arg) for arg in args]
|
|
if len(args) == 1:
|
|
args = [args[0]] * n
|
|
return Constant(4 * n, n, tuple(args), double_, name)
|
|
|
|
@staticmethod
|
|
def uint64(number, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint64"))
|
|
|
|
return Constant._uint64xN(name, 1, number)
|
|
|
|
@staticmethod
|
|
def uint64x2(number1, number2=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint64x2"))
|
|
|
|
return Constant._uint64xN(name, 2, number1, number2)
|
|
|
|
@staticmethod
|
|
def uint64x4(number1, number2=None, number3=None, number4=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint64x4"))
|
|
|
|
return Constant._uint64xN(name, 4, number1, number2, number3, number4)
|
|
|
|
@staticmethod
|
|
def uint64x8(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint64x8"))
|
|
|
|
return Constant._uint64xN(name, 8,
|
|
number1, number2, number3, number4, number5, number6, number7, number8)
|
|
|
|
@staticmethod
|
|
def uint32(number, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint32"))
|
|
|
|
return Constant._uint32xN(name, 1, number)
|
|
|
|
@staticmethod
|
|
def uint32x2(number1, number2=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint32x2"))
|
|
|
|
return Constant._uint32xN(name, 2, number1, number2)
|
|
|
|
@staticmethod
|
|
def uint32x4(number1, number2=None, number3=None, number4=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint32x4"))
|
|
|
|
return Constant._uint32xN(name, 4, number1, number2, number3, number4)
|
|
|
|
@staticmethod
|
|
def uint32x8(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint32x8"))
|
|
|
|
return Constant._uint32xN(name, 8,
|
|
number1, number2, number3, number4, number5, number6, number7, number8)
|
|
|
|
@staticmethod
|
|
def uint32x16(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
number9=None, number10=None, number11=None, number12=None,
|
|
number13=None, number14=None, number15=None, number16=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint32x16"))
|
|
|
|
return Constant._uint32xN(name, 16,
|
|
number1, number2, number3, number4, number5, number6, number7, number8,
|
|
number9, number10, number11, number12, number13, number14, number15, number16)
|
|
|
|
@staticmethod
|
|
def uint16x8(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint16x8"))
|
|
|
|
return Constant._uint16xN(name, 8,
|
|
number1, number2, number3, number4, number5, number6, number7, number8)
|
|
|
|
@staticmethod
|
|
def uint16x16(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
number9=None, number10=None, number11=None, number12=None,
|
|
number13=None, number14=None, number15=None, number16=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.uint16x16"))
|
|
|
|
return Constant._uint16xN(name, 16,
|
|
number1, number2, number3, number4, number5, number6, number7, number8,
|
|
number9, number10, number11, number12, number13, number14, number15, number16)
|
|
|
|
@staticmethod
|
|
def float64(number, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float64"))
|
|
|
|
return Constant._float64xN(name, 1, number)
|
|
|
|
@staticmethod
|
|
def float64x2(number1, number2=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float64x2"))
|
|
|
|
return Constant._float64xN(name, 2, number1, number2)
|
|
|
|
@staticmethod
|
|
def float64x4(number1, number2=None, number3=None, number4=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float64x4"))
|
|
|
|
return Constant._float64xN(name, 4, number1, number2, number3, number4)
|
|
|
|
@staticmethod
|
|
def float32(number, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float32"))
|
|
|
|
return Constant._float32xN(name, 1, number)
|
|
|
|
@staticmethod
|
|
def float32x2(number1, number2=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float32x2"))
|
|
|
|
return Constant._float32xN(name, 2, number1, number2)
|
|
|
|
@staticmethod
|
|
def float32x4(number1, number2=None, number3=None, number4=None, name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float32x4"))
|
|
|
|
return Constant._float32xN(name, 4, number1, number2, number3, number4)
|
|
|
|
@staticmethod
|
|
def float32x8(number1, number2=None, number3=None, number4=None,
|
|
number5=None, number6=None, number7=None, number8=None,
|
|
name=None):
|
|
if name is not None:
|
|
Name.check_name(name)
|
|
name = Name(name=name)
|
|
else:
|
|
import inspect
|
|
name = Name(prename=parse_assigned_variable_name(inspect.stack(), "Constant.float32x8"))
|
|
|
|
return Constant._float32xN(name, 8,
|
|
number1, number2, number3, number4, number5, number6, number7, number8)
|
|
|
|
@staticmethod
|
|
def _convert_to_float32(number):
|
|
import array
|
|
float_array = array.array('f', [number])
|
|
return float_array[0]
|
|
|
|
@staticmethod
|
|
def _parse_float32(number):
|
|
if isinstance(number, float):
|
|
number = float.hex(Constant._convert_to_float32(number))
|
|
elif isinstance(number, str):
|
|
# Validity check
|
|
try:
|
|
number = float.hex(Constant._convert_to_float32(float.fromhex(number)))
|
|
except ValueError:
|
|
raise ValueError("The string %s is not a hexadecimal floating-point number" % number)
|
|
else:
|
|
raise TypeError("Unsupported type of constant number %s" % str(number))
|
|
if number == "inf" or number == "+inf":
|
|
return 0x7F800000
|
|
elif number == "-inf":
|
|
return 0xFF800000
|
|
elif number == "nan":
|
|
return 0x7FC00000
|
|
is_negative = number.startswith("-")
|
|
point_position = number.index('.')
|
|
exp_position = number.rindex('p')
|
|
number_prefix = number[int(is_negative):point_position]
|
|
assert number_prefix == '0x0' or number_prefix == '0x1'
|
|
mantissa = number[point_position + 1:exp_position]
|
|
if number_prefix == '0x0' and int(mantissa) == 0:
|
|
# Zero
|
|
return int(is_negative) << 31
|
|
else:
|
|
exponent = number[exp_position + 1:]
|
|
mantissa_bits = len(mantissa) * 4
|
|
if mantissa_bits == 23:
|
|
mantissa = int(mantissa, 16)
|
|
elif mantissa_bits < 23:
|
|
mantissa = int(mantissa, 16) << (23 - mantissa_bits)
|
|
else:
|
|
mantissa = int(mantissa, 16) >> (mantissa_bits - 23)
|
|
exponent = int(exponent)
|
|
if exponent <= -127:
|
|
# Denormals
|
|
mantissa = (mantissa + (1 << 23)) >> -(exponent + 126)
|
|
exponent = -127
|
|
return mantissa + (int(exponent + 127) << 23) + (int(is_negative) << 31)
|
|
|
|
@staticmethod
|
|
def _parse_float64(number):
|
|
if isinstance(number, float):
|
|
number = float.hex(number)
|
|
elif isinstance(number, str):
|
|
# Validity check
|
|
try:
|
|
number = float.hex(float.fromhex(number))
|
|
except ValueError:
|
|
raise ValueError("The string %s is not a hexadecimal floating-point number" % number)
|
|
else:
|
|
raise TypeError("Unsupported type of constant number %s" % str(number))
|
|
if number == "inf" or number == "+inf":
|
|
return 0x7FF0000000000000
|
|
if number == "-inf":
|
|
return 0xFFF0000000000000
|
|
if number == "nan":
|
|
return 0x7FF8000000000000
|
|
is_negative = number.startswith("-")
|
|
point_position = number.index('.')
|
|
exp_position = number.rindex('p')
|
|
number_prefix = number[int(is_negative):point_position]
|
|
assert number_prefix == '0x0' or number_prefix == '0x1'
|
|
mantissa = number[point_position + 1:exp_position]
|
|
if number_prefix == '0x0':
|
|
# Zero
|
|
assert int(mantissa) == 0
|
|
return int(is_negative) << 63
|
|
else:
|
|
exponent = number[exp_position + 1:]
|
|
mantissa_bits = len(mantissa) * 4
|
|
if mantissa_bits == 52:
|
|
mantissa = int(mantissa, 16)
|
|
elif mantissa_bits < 52:
|
|
mantissa = int(mantissa, 16) << (52 - mantissa_bits)
|
|
else:
|
|
mantissa = int(mantissa, 16) >> (mantissa_bits - 52)
|
|
exponent = int(exponent)
|
|
if exponent <= -1023:
|
|
# Denormals
|
|
mantissa = (mantissa + (1 << 52)) >> -(exponent + 1022)
|
|
exponent = -1023
|
|
elif exponent > 1023:
|
|
# Infinity
|
|
mantissa = 0
|
|
exponent = 1023
|
|
return mantissa + (int(exponent + 1023) << 52) + (int(is_negative) << 63)
|