refactor llvm_cbuilder
This commit is contained in:
parent
af44641bb9
commit
8a159b35f0
1 changed files with 329 additions and 366 deletions
695
builder.py
695
builder.py
|
|
@ -42,6 +42,9 @@ def _is_block_terminated(bb):
|
||||||
instrs = bb.instructions
|
instrs = bb.instructions
|
||||||
return len(instrs) > 0 and instrs[-1].is_terminator
|
return len(instrs) > 0 and instrs[-1].is_terminator
|
||||||
|
|
||||||
|
def _is_struct(ty):
|
||||||
|
return isinstance(ty, lc.StructType)
|
||||||
|
|
||||||
def _is_cstruct(ty):
|
def _is_cstruct(ty):
|
||||||
try:
|
try:
|
||||||
return issubclass(ty, CStruct)
|
return issubclass(ty, CStruct)
|
||||||
|
|
@ -67,6 +70,10 @@ def _change_block_temporarily(builder, bb):
|
||||||
def _change_block_temporarily_dummy(*args):
|
def _change_block_temporarily_dummy(*args):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
class CastError(TypeError):
|
||||||
|
def __init__(self, orig, to):
|
||||||
|
super(CastError, self).__init__("Cannot cast from %s to %s" % (orig, to))
|
||||||
|
|
||||||
class _IfElse(object):
|
class _IfElse(object):
|
||||||
'''if-else construct.
|
'''if-else construct.
|
||||||
|
|
||||||
|
|
@ -399,7 +406,7 @@ class CBuilder(object):
|
||||||
def check_arg(x):
|
def check_arg(x):
|
||||||
if isinstance(x, int):
|
if isinstance(x, int):
|
||||||
return self.constant(types.int, x)
|
return self.constant(types.int, x)
|
||||||
if not x.is_int:
|
if not isinstance(x, IntegerValue):
|
||||||
raise TypeError(x, "All args must be of integer type.")
|
raise TypeError(x, "All args must be of integer type.")
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
@ -675,7 +682,11 @@ class CBuilder(object):
|
||||||
def alignment(self, ty):
|
def alignment(self, ty):
|
||||||
'''get minimum alignment of `ty`
|
'''get minimum alignment of `ty`
|
||||||
'''
|
'''
|
||||||
return self.target_data.abi_alignment(ty)
|
return self.abi.abi_alignment(ty)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def abi(self):
|
||||||
|
return self.target_data
|
||||||
|
|
||||||
def unreachable(self):
|
def unreachable(self):
|
||||||
'''insert instruction that causes segfault some platform (Intel),
|
'''insert instruction that causes segfault some platform (Intel),
|
||||||
|
|
@ -828,301 +839,335 @@ class CDefinition(CBuilder):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class CValue(object):
|
class CValue(object):
|
||||||
'''
|
def __init__(self, parent, handle):
|
||||||
Signedness
|
self.__parent = parent
|
||||||
----------
|
self.__handle = handle
|
||||||
Since LLVM type does not provide signedness attribute. This information
|
|
||||||
is provided in the CValue.unsigned attribute. The default value is
|
|
||||||
`None`, meaning that this attribute is not set.
|
|
||||||
|
|
||||||
In casting operation, signednss information is passed as an optional arg.
|
@property
|
||||||
|
def handle(self):
|
||||||
|
return self.__handle
|
||||||
|
|
||||||
In binary operation, signedness of the left operand is used.
|
@property
|
||||||
'''
|
def parent(self):
|
||||||
|
return self.__parent
|
||||||
|
|
||||||
unsigned = None # attribute for for integer values.
|
def _temp(self, val):
|
||||||
|
return CTemp(self.parent, val)
|
||||||
|
|
||||||
_BINOP_MAP = {
|
def _get_operator_provider(ty):
|
||||||
# op-name : (signed int, unsigned int, real)
|
if _is_pointer(ty):
|
||||||
'add' : (lc.Builder.add, lc.Builder.add, lc.Builder.fadd),
|
return PointerValue
|
||||||
'sub' : (lc.Builder.sub, lc.Builder.sub, lc.Builder.fsub),
|
elif _is_int(ty):
|
||||||
'mul' : (lc.Builder.mul, lc.Builder.mul, lc.Builder.fmul),
|
return IntegerValue
|
||||||
'div' : (lc.Builder.sdiv, lc.Builder.udiv, lc.Builder.fdiv),
|
elif _is_real(ty):
|
||||||
'mod' : (lc.Builder.srem, lc.Builder.urem, lc.Builder.frem),
|
return RealValue
|
||||||
}
|
elif _is_vector(ty):
|
||||||
|
inner = _get_operator_provider(ty.element)
|
||||||
|
return type(str(ty), (inner, VectorIndexing), {})
|
||||||
|
elif _is_struct(ty):
|
||||||
|
return StructValue
|
||||||
|
else:
|
||||||
|
assert False, (str(ty), type(ty))
|
||||||
|
|
||||||
_BITWISE_MAP = {
|
class CTemp(CValue):
|
||||||
# op-name : (signed int, unsigned int)
|
def __new__(cls, parent, handle):
|
||||||
'lshift' : (lc.Builder.shl, lc.Builder.shl),
|
meta = _get_operator_provider(handle.type)
|
||||||
'rshift' : (lc.Builder.lshr, lc.Builder.ashr),
|
base = type(str('%s_%s' % (cls.__name__, handle.type)), (cls, meta), {})
|
||||||
'and' : (lc.Builder.and_, lc.Builder.and_),
|
return object.__new__(base)
|
||||||
'or' : (lc.Builder.or_, lc.Builder.or_),
|
|
||||||
'xor' : (lc.Builder.xor, lc.Builder.xor),
|
|
||||||
}
|
|
||||||
|
|
||||||
_CMP_MAP = {
|
def __init__(self, *args, **kws):
|
||||||
# op-name : (signed int, unsigned int, real)
|
super(CTemp, self).__init__(*args, **kws)
|
||||||
'eq' : (lc.ICMP_EQ, lc.ICMP_EQ, lc.FCMP_OEQ),
|
self._init_mixin()
|
||||||
'ne' : (lc.ICMP_NE, lc.ICMP_NE, lc.FCMP_ONE),
|
|
||||||
'lt' : (lc.ICMP_SLT, lc.ICMP_ULT, lc.FCMP_OLT),
|
|
||||||
'le' : (lc.ICMP_SLE, lc.ICMP_ULE, lc.FCMP_OLE),
|
|
||||||
'gt' : (lc.ICMP_SGT, lc.ICMP_UGT, lc.FCMP_OGT),
|
|
||||||
'ge' : (lc.ICMP_SGE, lc.ICMP_UGE, lc.FCMP_OGE),
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
@property
|
||||||
self.parent = parent
|
def value(self):
|
||||||
|
return self.handle
|
||||||
|
|
||||||
def _use_binop(self, op):
|
@property
|
||||||
'''implements binary operations
|
def type(self):
|
||||||
'''
|
return self.value.type
|
||||||
def wrapped(rhs):
|
|
||||||
self._ensure_same_type(rhs)
|
|
||||||
binop = self._BINOP_MAP[op]
|
|
||||||
if self.is_int:
|
|
||||||
if not self.unsigned:
|
|
||||||
idx = 0
|
|
||||||
else:
|
|
||||||
idx = 1
|
|
||||||
elif self.is_real:
|
|
||||||
idx = 2
|
|
||||||
else:
|
|
||||||
errmsg = "Binary operation %s does not support type %s"
|
|
||||||
raise TypeError(errmsg % (op, self.type))
|
|
||||||
res = binop[idx](self.parent.builder, self.value, rhs.value)
|
|
||||||
return CTemp(self.parent, res)
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
def _use_bitwise(self, op):
|
class CVar(CValue):
|
||||||
'''implements bitwise operations
|
def __new__(cls, parent, ptr):
|
||||||
'''
|
meta = _get_operator_provider(ptr.type.pointee)
|
||||||
def wrapped(rhs):
|
base = type(str('%s_%s' % (cls.__name__, ptr.type.pointee)), (cls, meta), {})
|
||||||
self._ensure_same_type(rhs)
|
return object.__new__(base)
|
||||||
if not self.is_int:
|
|
||||||
errmsg = "Bitwise operation %s does not support type %s"
|
def __init__(self, parent, ptr):
|
||||||
raise TypeError(op, self.type)
|
super(CVar, self).__init__(parent, ptr)
|
||||||
if not self.unsigned:
|
self._init_mixin()
|
||||||
idx = 0
|
self.invariant = False
|
||||||
else:
|
|
||||||
idx = 1
|
def reference(self):
|
||||||
res = self._BITWISE_MAP[idx](self.parent.builder,
|
return self._temp(self.handle)
|
||||||
self.value, rhs.value)
|
|
||||||
return CTemp(self.parent, res)
|
@property
|
||||||
return wrapped
|
def ref(self):
|
||||||
|
return self.reference()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
return self.parent.builder.load(self.ref.value,
|
||||||
|
invariant=self.invariant)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self.ref.type.pointee
|
||||||
|
|
||||||
|
def assign(self, val, **kws):
|
||||||
|
if self.invariant:
|
||||||
|
raise TypeError("Storing to invariant variable.")
|
||||||
|
self.parent.builder.store(val.value, self.ref.value, **kws)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __iadd__(self, rhs):
|
||||||
|
return self.assign(self.__add__(rhs))
|
||||||
|
|
||||||
|
def __isub__(self, rhs):
|
||||||
|
return self.assign(self.__sub__(rhs))
|
||||||
|
|
||||||
|
def __imul__(self, rhs):
|
||||||
|
return self.assign(self.__mul__(rhs))
|
||||||
|
|
||||||
|
def __idiv__(self, rhs):
|
||||||
|
return self.assign(self.__div__(rhs))
|
||||||
|
|
||||||
|
def __imod__(self, rhs):
|
||||||
|
return self.assign(self.__mod__(rhs))
|
||||||
|
|
||||||
|
def __ilshift__(self, rhs):
|
||||||
|
return self.assign(self.__lshift__(rhs))
|
||||||
|
|
||||||
|
def __irshift__(self, rhs):
|
||||||
|
return self.assign(self.__rshift__(rhs))
|
||||||
|
|
||||||
|
def __iand__(self, rhs):
|
||||||
|
return self.assign(self.__and__(rhs))
|
||||||
|
|
||||||
|
def __ior__(self, rhs):
|
||||||
|
return self.assign(self.__or__(rhs))
|
||||||
|
|
||||||
|
def __ixor__(self, rhs):
|
||||||
|
return self.assign(self.__xor__(rhs))
|
||||||
|
|
||||||
|
|
||||||
|
class OperatorMixin(object):
|
||||||
|
def _init_mixin(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class IntegerValue(OperatorMixin):
|
||||||
|
|
||||||
|
def _init_mixin(self):
|
||||||
|
self._unsigned = False
|
||||||
|
|
||||||
|
def _get_unsigned(self):
|
||||||
|
return self._unsigned
|
||||||
|
|
||||||
|
def _set_unsigned(self, unsigned):
|
||||||
|
self._unsigned = bool(unsigned)
|
||||||
|
|
||||||
|
unsigned = property(_get_unsigned, _set_unsigned)
|
||||||
|
|
||||||
def __add__(self, rhs):
|
def __add__(self, rhs):
|
||||||
return self._use_binop('add')(rhs)
|
return self._temp(self.parent.builder.add(self.value, rhs.value))
|
||||||
|
|
||||||
def __sub__(self, rhs):
|
def __sub__(self, rhs):
|
||||||
return self._use_binop('sub')(rhs)
|
return self._temp(self.parent.builder.sub(self.value, rhs.value))
|
||||||
|
|
||||||
def __mul__(self, rhs):
|
def __mul__(self, rhs):
|
||||||
return self._use_binop('mul')(rhs)
|
return self._temp(self.parent.builder.mul(self.value, rhs.value))
|
||||||
|
|
||||||
def __div__(self, rhs):
|
def __div__(self, rhs):
|
||||||
return self._use_binop('div')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.udiv(self.value, rhs.value))
|
||||||
def __truediv__(self, rhs):
|
else:
|
||||||
return self.__div__(rhs)
|
return self._temp(self.parent.builder.sdiv(self.value, rhs.value))
|
||||||
|
|
||||||
def __mod__(self, rhs):
|
def __mod__(self, rhs):
|
||||||
return self._use_binop('mod')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.urem(self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.srem(self.value, rhs.value))
|
||||||
|
|
||||||
def __lshift__(self, rhs):
|
def __ilshift__(self, rhs):
|
||||||
return self._use_bitwise('lshift')(rhs)
|
return self._temp(self.parent.builder.shl(self.value, rhs.value))
|
||||||
|
|
||||||
def __rshift__(self, rhs):
|
def __irshift__(self, rhs):
|
||||||
return self._use_bitwise('rshift')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.self.parent.builder.lshr(self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.ashr(self.value, rhs.value))
|
||||||
|
|
||||||
def __and__(self, rhs):
|
def __iand__(self, rhs):
|
||||||
return self._use_bitwise('and')(rhs)
|
return self._temp(self.parent.builder.and_(self.value, rhs.value))
|
||||||
|
|
||||||
def __or__(self, rhs):
|
def __ior__(self, rhs):
|
||||||
return self._use_bitwise('or')(rhs)
|
return self._temp(self.parent.builder.or_(self.value, rhs.value))
|
||||||
|
|
||||||
def __xor__(self, rhs):
|
def __ixor__(self, rhs):
|
||||||
return self._use_bitwise('xor')(rhs)
|
return self._temp(self.parent.builder.xor(self.value, rhs.value))
|
||||||
|
|
||||||
def _ensure_same_type(self, val):
|
|
||||||
'''ensure that this instance has the same type as `val`
|
|
||||||
|
|
||||||
Raises TypeError if `self.type != val.type`
|
|
||||||
'''
|
|
||||||
if self.type != val.type:
|
|
||||||
errmsg = "Type mismatch: %s != %s"
|
|
||||||
raise TypeError(errmsg % (self.type, val.type))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_int(self):
|
|
||||||
return _is_int(self.type) or _is_vector(self.type, _is_int)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_real(self):
|
|
||||||
return _is_real(self.type) or _is_vector(self.type, _is_real)
|
|
||||||
|
|
||||||
def cast(self, ty, unsigned=False):
|
|
||||||
'''cast to another type
|
|
||||||
|
|
||||||
If `ty == self.type`, then pass thru
|
|
||||||
'''
|
|
||||||
make = lambda X: CTemp(self.parent, X)
|
|
||||||
if self.type == ty:
|
|
||||||
return self # pass thru
|
|
||||||
elif self.is_pointer and _is_pointer(ty):
|
|
||||||
builder = self.parent.builder
|
|
||||||
return make(builder.bitcast(self.value, ty))
|
|
||||||
elif self.is_int:
|
|
||||||
if _is_int(ty):
|
|
||||||
if self.type.width < ty.width:
|
|
||||||
if not unsigned:
|
|
||||||
return make(self.parent.builder.sext(self.value, ty))
|
|
||||||
else:
|
|
||||||
return make(self.parent.builder.zext(self.value, ty))
|
|
||||||
else:
|
|
||||||
return make(self.parent.builder.trunc(self.value, ty))
|
|
||||||
elif _is_real(ty):
|
|
||||||
if not unsigned:
|
|
||||||
return make(self.parent.builder.sitofp(self.value, ty))
|
|
||||||
else:
|
|
||||||
return make(self.parent.builder.uitofp(self.value, ty))
|
|
||||||
elif self.is_real:
|
|
||||||
if _is_int(ty):
|
|
||||||
if not unsigned:
|
|
||||||
return make(self.parent.builder.fptosi(self.value, ty))
|
|
||||||
else:
|
|
||||||
return make(self.parent.builder.fptoui(self.value, ty))
|
|
||||||
else:
|
|
||||||
if ty == types.double:
|
|
||||||
assert self.type == types.float
|
|
||||||
return make(self.parent.builder.fpext(self.value, ty))
|
|
||||||
else:
|
|
||||||
assert ty == types.float
|
|
||||||
assert self.type == types.double
|
|
||||||
return make(self.parent.builder.fptrunc(self.value, ty))
|
|
||||||
|
|
||||||
errmsg = "Cast from %s to %s is not possible."
|
|
||||||
raise TypeError(errmsg % (self.type, ty))
|
|
||||||
|
|
||||||
def ptrtoint(self):
|
|
||||||
self._ensure_is_pointer()
|
|
||||||
builder = self.parent.builder
|
|
||||||
return CTemp(self.parent, builder.ptrtoint(self.value, types.intp))
|
|
||||||
|
|
||||||
def inttoptr(self, ty):
|
|
||||||
if not self.is_int:
|
|
||||||
raise TypeError("Must be an integer")
|
|
||||||
builder = self.parent.builder
|
|
||||||
return CTemp(self.parent, builder.inttoptr(self.value, ty))
|
|
||||||
|
|
||||||
def _cmp_op(self, name):
|
|
||||||
'''implements comparison operations
|
|
||||||
'''
|
|
||||||
def wrapped(rhs):
|
|
||||||
make = lambda X: CTemp(self.parent, X)
|
|
||||||
self._ensure_same_type(rhs)
|
|
||||||
|
|
||||||
flag_bag = self._CMP_MAP[name]
|
|
||||||
if self.is_int:
|
|
||||||
comparator = self.parent.builder.icmp
|
|
||||||
if not self.unsigned:
|
|
||||||
flag = flag_bag[0]
|
|
||||||
else:
|
|
||||||
flag = flag_bag[1]
|
|
||||||
elif self.is_real:
|
|
||||||
comparator = self.parent.builder.fcmp
|
|
||||||
flag = flag_bag[2]
|
|
||||||
else:
|
|
||||||
errmsg = "Comparision between %s and %s is not supported."
|
|
||||||
raise TypeError(errmsg % (self.type, rhs.type))
|
|
||||||
|
|
||||||
return CTemp(self.parent, comparator(flag, self.value, rhs.value))
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
def __eq__(self, rhs):
|
|
||||||
return self._cmp_op('eq')(rhs)
|
|
||||||
|
|
||||||
def __ne__(self, rhs):
|
|
||||||
return self._cmp_op('ne')(rhs)
|
|
||||||
|
|
||||||
def __lt__(self, rhs):
|
def __lt__(self, rhs):
|
||||||
return self._cmp_op('lt')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_ULT, self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_SLT, self.value, rhs.value))
|
||||||
|
|
||||||
def __le__(self, rhs):
|
def __le__(self, rhs):
|
||||||
return self._cmp_op('le')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_ULE, self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_SLE, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __eq__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_EQ, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __ne__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_NE, self.value, rhs.value))
|
||||||
|
|
||||||
def __gt__(self, rhs):
|
def __gt__(self, rhs):
|
||||||
return self._cmp_op('gt')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_UGT, self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_SGT, self.value, rhs.value))
|
||||||
|
|
||||||
def __ge__(self, rhs):
|
def __ge__(self, rhs):
|
||||||
return self._cmp_op('ge')(rhs)
|
if self.unsigned:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_UGE, self.value, rhs.value))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.icmp(lc.ICMP_SGE, self.value, rhs.value))
|
||||||
|
|
||||||
|
def cast(self, ty, unsigned=False):
|
||||||
|
if ty == self.type:
|
||||||
|
return self._temp(self.value)
|
||||||
|
|
||||||
|
if _is_real(ty):
|
||||||
|
if self.unsigned or unsigned:
|
||||||
|
return self._temp(self.parent.builder.uitofp(self.value, ty))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.sitofp(self.value, ty))
|
||||||
|
elif _is_int(ty):
|
||||||
|
if self.parent.abi.size(self.type) < self.parent.abi.size(ty):
|
||||||
|
if self.unsigned or unsigned:
|
||||||
|
return self._temp(self.parent.builder.zext(self.value, ty))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.sext(self.value, ty))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.trunc(self.value, ty))
|
||||||
|
raise CastError(self.type, ty)
|
||||||
|
|
||||||
|
class RealValue(OperatorMixin):
|
||||||
|
def __add__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fadd(self.value, rhs.value))
|
||||||
|
|
||||||
|
def __sub__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fsub(self.value, rhs.value))
|
||||||
|
|
||||||
|
def __mul__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fmul(self.value, rhs.value))
|
||||||
|
|
||||||
|
def __div__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fdiv(self.value, rhs.value))
|
||||||
|
|
||||||
|
def __mod__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.frem(self.value, rhs.value))
|
||||||
|
|
||||||
|
def __lt__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_OLT, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __le__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_OLE, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __eq__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_OEQ, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __ne__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_ONE, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __gt__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_OGT, self.value, rhs.value))
|
||||||
|
|
||||||
|
def __ge__(self, rhs):
|
||||||
|
return self._temp(self.parent.builder.fcmp(lc.FCMP_OGE, self.value, rhs.value))
|
||||||
|
|
||||||
|
def cast(self, ty, unsigned=False):
|
||||||
|
if ty == self.type:
|
||||||
|
return self._temp(self.value)
|
||||||
|
|
||||||
|
if _is_int(ty):
|
||||||
|
if unsigned:
|
||||||
|
return self._temp(self.parent.builder.fptoui(self.value, ty))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.fptosi(self.value, ty))
|
||||||
|
|
||||||
|
if _is_real(ty):
|
||||||
|
if self.parent.abi.size(self.type) > self.parent.abi.size(ty):
|
||||||
|
return self._temp(self.parent.builder.fptrunc(self.value, ty))
|
||||||
|
else:
|
||||||
|
return self._temp(self.parent.builder.fpext(self.value, ty))
|
||||||
|
|
||||||
|
raise CastError(self.type, ty)
|
||||||
|
|
||||||
|
|
||||||
@property
|
class PointerIndexing(OperatorMixin):
|
||||||
def is_vector(self):
|
|
||||||
return _is_vector(self.type)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_pointer(self):
|
|
||||||
return _is_pointer(self.type)
|
|
||||||
|
|
||||||
def _ensure_is_pointer(self):
|
|
||||||
if not self.is_pointer:
|
|
||||||
raise TypeError("Must be a pointer; got %s" % self.type)
|
|
||||||
|
|
||||||
def _ensure_is_vector(self):
|
|
||||||
if not self.is_vector:
|
|
||||||
raise TypeError("Must be a vector; got %s" % self.type)
|
|
||||||
|
|
||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
'''implement access indexing
|
'''implement access indexing
|
||||||
|
|
||||||
Uses GEP.
|
Uses GEP.
|
||||||
'''
|
'''
|
||||||
bldr = self.parent.builder
|
bldr = self.parent.builder
|
||||||
if self.is_pointer:
|
if type(idx) is slice:
|
||||||
if type(idx) is slice:
|
# just handle case by case
|
||||||
# just handle case by case
|
# Case #1: A[idx:] get pointer offset by idx
|
||||||
# Case #1: A[idx:] get poointer offset by idx
|
if not idx.step and not idx.stop:
|
||||||
if not idx.step and not idx.stop:
|
idx = _auto_coerce_index(self.parent, idx.start)
|
||||||
idx = _auto_coerce_index(self.parent, idx.start)
|
|
||||||
ptr = bldr.gep(self.value, [idx.value])
|
|
||||||
return CArray(self.parent, ptr)
|
|
||||||
else: # return an variable at idx
|
|
||||||
idx = _auto_coerce_index(self.parent, idx)
|
|
||||||
ptr = bldr.gep(self.value, [idx.value])
|
ptr = bldr.gep(self.value, [idx.value])
|
||||||
return CVar(self.parent, ptr)
|
return CArray(self.parent, ptr)
|
||||||
elif self.is_vector:
|
else: # return an variable at idx
|
||||||
idx = _auto_coerce_index(self.parent, idx)
|
idx = _auto_coerce_index(self.parent, idx)
|
||||||
val = bldr.extract_element(self.value, idx.value)
|
ptr = bldr.gep(self.value, [idx.value])
|
||||||
return CTemp(self.parent, val)
|
return CVar(self.parent, ptr)
|
||||||
else:
|
|
||||||
raise TypeError("Must be a pointer or vector; got %s" % self.type)
|
|
||||||
|
|
||||||
def __setitem__(self, idx, val):
|
def __setitem__(self, idx, val):
|
||||||
idx = _auto_coerce_index(self.parent, idx)
|
idx = _auto_coerce_index(self.parent, idx)
|
||||||
bldr = self.parent.builder
|
bldr = self.parent.builder
|
||||||
if self.is_vector:
|
self[idx].assign(val)
|
||||||
vec = bldr.insert_element(self.value, val.value, idx.value)
|
|
||||||
bldr.store(vec, self.ptr)
|
|
||||||
elif self.is_pointer:
|
|
||||||
self[idx].assign(val)
|
|
||||||
else:
|
|
||||||
raise TypeError("Must be a pointer or vector; got %s" % self.type)
|
|
||||||
|
|
||||||
def load(self, volatile=False, invariant=False):
|
class PointerCasting(OperatorMixin):
|
||||||
'''memory load for pointer types
|
def cast(self, ty):
|
||||||
'''
|
if ty == self.type:
|
||||||
self._ensure_is_pointer()
|
return self._temp(self.value)
|
||||||
loaded = self.parent.builder.load(self.value, volatile=volatile,
|
|
||||||
invariant=invariant)
|
|
||||||
return CTemp(self.parent, loaded)
|
|
||||||
|
|
||||||
def store(self, val, volatile=False, nontemporal=False):
|
if _is_pointer(ty):
|
||||||
'''memory store for pointer types
|
return self._temp(self.parent.builder.bitcast(self.value, ty))
|
||||||
|
raise CastError(self.type, ty)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VectorIndexing(OperatorMixin):
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
'''implement access indexing
|
||||||
|
|
||||||
|
Uses GEP.
|
||||||
'''
|
'''
|
||||||
self._ensure_is_pointer()
|
bldr = self.parent.builder
|
||||||
inst = self.parent.builder.store(val.value, self.value,
|
idx = _auto_coerce_index(self.parent, idx)
|
||||||
volatile=volatile)
|
val = bldr.extract_element(self.value, idx.value)
|
||||||
|
return CTemp(self.parent, val)
|
||||||
|
|
||||||
|
def __setitem__(self, idx, val):
|
||||||
|
idx = _auto_coerce_index(self.parent, idx)
|
||||||
|
bldr = self.parent.builder
|
||||||
|
vec = bldr.insert_element(self.value, val.value, idx.value)
|
||||||
|
bldr.store(vec, self.ref.value)
|
||||||
|
|
||||||
|
class PointerValue(PointerIndexing, PointerCasting):
|
||||||
|
|
||||||
|
def load(self, **kws):
|
||||||
|
return self._temp(self.parent.builder.load(self.value, **kws))
|
||||||
|
|
||||||
|
def store(self, val, nontemporal=False, **kws):
|
||||||
|
inst = self.parent.builder.store(val.value, self.value, **kws)
|
||||||
if nontemporal:
|
if nontemporal:
|
||||||
self.parent.set_memop_non_temporal(inst)
|
self.parent.set_memop_non_temporal(inst)
|
||||||
|
|
||||||
|
|
@ -1135,12 +1180,11 @@ class CValue(object):
|
||||||
|
|
||||||
Other parameters are the same as `CBuilder.atomic_load`
|
Other parameters are the same as `CBuilder.atomic_load`
|
||||||
'''
|
'''
|
||||||
self._ensure_is_pointer()
|
|
||||||
if align is None:
|
if align is None:
|
||||||
align = self.parent.alignment(self.type.pointee)
|
align = self.parent.alignment(self.type.pointee)
|
||||||
inst = self.parent.builder.atomic_load(self.value, ordering, align,
|
inst = self.parent.builder.atomic_load(self.value, ordering, align,
|
||||||
crossthread=crossthread)
|
crossthread=crossthread)
|
||||||
return CTemp(self.parent, inst)
|
return self._temp(inst)
|
||||||
|
|
||||||
def atomic_store(self, value, ordering, align=None, crossthread=True):
|
def atomic_store(self, value, ordering, align=None, crossthread=True):
|
||||||
'''atomic memory store for pointer types
|
'''atomic memory store for pointer types
|
||||||
|
|
@ -1150,7 +1194,6 @@ class CValue(object):
|
||||||
|
|
||||||
Other parameters are the same as `CBuilder.atomic_store`
|
Other parameters are the same as `CBuilder.atomic_store`
|
||||||
'''
|
'''
|
||||||
self._ensure_is_pointer()
|
|
||||||
if align is None:
|
if align is None:
|
||||||
align = self.parent.alignment(self.type.pointee)
|
align = self.parent.alignment(self.type.pointee)
|
||||||
self.parent.builder.atomic_store(value.ptr, self.value, ordering,
|
self.parent.builder.atomic_store(value.ptr, self.value, ordering,
|
||||||
|
|
@ -1161,19 +1204,34 @@ class CValue(object):
|
||||||
|
|
||||||
Other parameters are the same as `CBuilder.atomic_cmpxchg`
|
Other parameters are the same as `CBuilder.atomic_cmpxchg`
|
||||||
'''
|
'''
|
||||||
self._ensure_is_pointer()
|
|
||||||
inst = self.parent.builder.atomic_cmpxchg(self.value, old.value,
|
inst = self.parent.builder.atomic_cmpxchg(self.value, old.value,
|
||||||
new.value, ordering,
|
new.value, ordering,
|
||||||
crossthread=crossthread)
|
crossthread=crossthread)
|
||||||
return CTemp(self.parent, inst)
|
return self._temp(inst)
|
||||||
|
|
||||||
|
def as_struct(self, cstruct_class, volatile=False):
|
||||||
|
'''load a pointer to a structure and assume a structure interface
|
||||||
|
'''
|
||||||
|
ptr = self.parent.builder.load(self.value, volatile=volatile)
|
||||||
|
return cstruct_class(self.parent, self.value)
|
||||||
|
|
||||||
|
class StructValue(OperatorMixin):
|
||||||
|
|
||||||
|
def as_struct(self, cstruct_class):
|
||||||
|
'''assume a structure interface
|
||||||
|
'''
|
||||||
|
return cstruct_class(self.parent, self.ref.value)
|
||||||
|
|
||||||
|
|
||||||
class CFunc(CValue):
|
class CFunc(CValue, PointerCasting):
|
||||||
'''Wraps function pointer
|
'''Wraps function pointer
|
||||||
'''
|
'''
|
||||||
def __init__(self, parent, func):
|
def __init__(self, parent, func):
|
||||||
super(CFunc, self).__init__(parent)
|
super(CFunc, self).__init__(parent, func)
|
||||||
self.function = func
|
|
||||||
|
@property
|
||||||
|
def function(self):
|
||||||
|
return self.handle
|
||||||
|
|
||||||
def __call__(self, *args, **opts):
|
def __call__(self, *args, **opts):
|
||||||
'''Call the function with the given arguments
|
'''Call the function with the given arguments
|
||||||
|
|
@ -1188,13 +1246,15 @@ class CFunc(CValue):
|
||||||
"argument %d mismatch: %s != %s"
|
"argument %d mismatch: %s != %s"
|
||||||
% (self.function.name, i, exp, got.type))
|
% (self.function.name, i, exp, got.type))
|
||||||
res = self.parent.builder.call(self.function, arg_values)
|
res = self.parent.builder.call(self.function, arg_values)
|
||||||
|
|
||||||
if hasattr(self.function, 'calling_convention'):
|
if hasattr(self.function, 'calling_convention'):
|
||||||
res.calling_convention = self.function.calling_convention
|
res.calling_convention = self.function.calling_convention
|
||||||
|
|
||||||
if opts.get('inline'):
|
if opts.get('inline'):
|
||||||
self.parent.add_auto_inline(res)
|
self.parent.add_auto_inline(res)
|
||||||
|
|
||||||
return CTemp(self.parent, res)
|
if ftype.return_type != lc.Type.void():
|
||||||
|
return CTemp(self.parent, res)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
|
@ -1204,123 +1264,25 @@ class CFunc(CValue):
|
||||||
def type(self):
|
def type(self):
|
||||||
return self.function.type
|
return self.function.type
|
||||||
|
|
||||||
class CTemp(CValue):
|
|
||||||
'''Wraps temporary values
|
|
||||||
'''
|
|
||||||
def __init__(self, parent, value):
|
|
||||||
super(CTemp, self).__init__(parent)
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
@property
|
class CArray(CValue, PointerIndexing, PointerCasting):
|
||||||
def type(self):
|
|
||||||
return self.value.type
|
|
||||||
|
|
||||||
class CVar(CValue):
|
|
||||||
'''Wraps variables
|
|
||||||
|
|
||||||
Similar to C variables.
|
|
||||||
'''
|
|
||||||
|
|
||||||
def __init__(self, parent, ptr):
|
|
||||||
super(CVar, self).__init__(parent)
|
|
||||||
self.ptr = ptr
|
|
||||||
self.invariant = False
|
|
||||||
|
|
||||||
def _inplace_binop(self, op):
|
|
||||||
def wrapped(rhs):
|
|
||||||
res = self._use_binop(op)(rhs)
|
|
||||||
self.assign(res)
|
|
||||||
return self
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
def __iadd__(self, rhs):
|
|
||||||
return self._inplace_binop('add')(rhs)
|
|
||||||
|
|
||||||
def __isub__(self, rhs):
|
|
||||||
return self._inplace_binop('sub')(rhs)
|
|
||||||
|
|
||||||
def __imul__(self, rhs):
|
|
||||||
return self._inplace_binop('mul')(rhs)
|
|
||||||
|
|
||||||
def __idiv__(self, rhs):
|
|
||||||
return self._inplace_binop('div')(rhs)
|
|
||||||
|
|
||||||
def __imod__(self, rhs):
|
|
||||||
return self._inplace_binop('mod')(rhs)
|
|
||||||
|
|
||||||
def _inplace_bitwise(self, op):
|
|
||||||
def wrapped(rhs):
|
|
||||||
res = self._use_bitwise(op)(rhs)
|
|
||||||
self.assign(res)
|
|
||||||
return self
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
def __ilshift__(self, rhs):
|
|
||||||
return self._inplace_bitwise('lshift')(rhs)
|
|
||||||
|
|
||||||
def __irshift__(self, rhs):
|
|
||||||
return self._inplace_bitwise('rshift')(rhs)
|
|
||||||
|
|
||||||
def __iand__(self, rhs):
|
|
||||||
return self._inplace_bitwise('and')(rhs)
|
|
||||||
|
|
||||||
def __ior__(self, rhs):
|
|
||||||
return self._inplace_bitwise('or')(rhs)
|
|
||||||
|
|
||||||
def __ixor__(self, rhs):
|
|
||||||
return self._inplace_bitwise('xor')(rhs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self):
|
|
||||||
return self.parent.builder.load(self.ptr, invariant=self.invariant)
|
|
||||||
|
|
||||||
def assign(self, val, nontemporal=False):
|
|
||||||
'''assign new value to the variable
|
|
||||||
'''
|
|
||||||
if self.invariant: raise TypeError("Assignment to invariant variable")
|
|
||||||
self._ensure_same_type(val)
|
|
||||||
inst = self.parent.builder.store(val.value, self.ptr)
|
|
||||||
if nontemporal:
|
|
||||||
self.parent.set_memop_non_temporal(inst)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def type(self):
|
|
||||||
return self.ptr.type.pointee
|
|
||||||
|
|
||||||
def reference(self):
|
|
||||||
'''get a pointer reference of the variable
|
|
||||||
'''
|
|
||||||
return CTemp(self.parent, self.ptr)
|
|
||||||
|
|
||||||
def as_struct(self, cstruct_class, volatile=False):
|
|
||||||
'''load a pointer to a structure and assume a structure interface
|
|
||||||
'''
|
|
||||||
if _is_pointer(self.type):
|
|
||||||
ptr = self.parent.builder.load(self.ptr, volatile=volatile)
|
|
||||||
return cstruct_class(self.parent, ptr)
|
|
||||||
else:
|
|
||||||
return cstruct_class(self.parent, self.ptr)
|
|
||||||
|
|
||||||
|
|
||||||
class CArray(CValue):
|
|
||||||
'''wraps a array
|
'''wraps a array
|
||||||
|
|
||||||
Similar to C arrays
|
Similar to C arrays
|
||||||
'''
|
'''
|
||||||
def __init__(self, parent, base):
|
def __init__(self, parent, base):
|
||||||
super(CArray, self).__init__(parent)
|
super(CArray, self).__init__(parent, base)
|
||||||
self.base_ptr = base
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
return self.base_ptr
|
return self.handle
|
||||||
|
|
||||||
def reference(self):
|
def reference(self):
|
||||||
return CTemp(self.parent, self.base_ptr)
|
return self._temp(self.value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
return self.base_ptr.type
|
return self.value.type
|
||||||
|
|
||||||
def vector_load(self, count, align=0):
|
def vector_load(self, count, align=0):
|
||||||
parent = self.parent
|
parent = self.parent
|
||||||
|
|
@ -1328,9 +1290,9 @@ class CArray(CValue):
|
||||||
values = [self[i] for i in range(count)]
|
values = [self[i] for i in range(count)]
|
||||||
|
|
||||||
vecty = types.vector(self.type.pointee, count)
|
vecty = types.vector(self.type.pointee, count)
|
||||||
vec = builder.load(builder.bitcast(self.base_ptr, types.pointer(vecty)),
|
vec = builder.load(builder.bitcast(self.value, types.pointer(vecty)),
|
||||||
align=align)
|
align=align)
|
||||||
return CTemp(parent, vec)
|
return self._temp(vec)
|
||||||
|
|
||||||
def vector_store(self, vec, align=0):
|
def vector_store(self, vec, align=0):
|
||||||
if vec.type.element != self.type.pointee:
|
if vec.type.element != self.type.pointee:
|
||||||
|
|
@ -1338,10 +1300,11 @@ class CArray(CValue):
|
||||||
(vec.type.element, self.type.pointee))
|
(vec.type.element, self.type.pointee))
|
||||||
parent = self.parent
|
parent = self.parent
|
||||||
builder = parent.builder
|
builder = parent.builder
|
||||||
vecptr = builder.bitcast(self.base_ptr, types.pointer(vec.type))
|
vecptr = builder.bitcast(self.value, types.pointer(vec.type))
|
||||||
builder.store(vec.value, vecptr, align=align)
|
builder.store(vec.value, vecptr, align=align)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class CStruct(CValue):
|
class CStruct(CValue):
|
||||||
'''Wraps a structure
|
'''Wraps a structure
|
||||||
|
|
||||||
|
|
@ -1358,9 +1321,9 @@ class CStruct(CValue):
|
||||||
return lc.Type.struct([v for k, v in cls._fields_])
|
return lc.Type.struct([v for k, v in cls._fields_])
|
||||||
|
|
||||||
def __init__(self, parent, ptr):
|
def __init__(self, parent, ptr):
|
||||||
super(CStruct, self).__init__(parent)
|
super(CStruct, self).__init__(parent, ptr)
|
||||||
makeind = lambda x: self.parent.constant(types.int, x).value
|
makeind = lambda x: self.parent.constant(types.int, x).value
|
||||||
self.ptr = ptr
|
|
||||||
for i, (fd, _) in enumerate(self._fields_):
|
for i, (fd, _) in enumerate(self._fields_):
|
||||||
gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)])
|
gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)])
|
||||||
gep.name = "%s.%s" % (type(self).__name__, fd)
|
gep.name = "%s.%s" % (type(self).__name__, fd)
|
||||||
|
|
@ -1369,7 +1332,7 @@ class CStruct(CValue):
|
||||||
setattr(self, fd, CVar(self.parent, gep))
|
setattr(self, fd, CVar(self.parent, gep))
|
||||||
|
|
||||||
def reference(self):
|
def reference(self):
|
||||||
return CTemp(self.parent, self.ptr)
|
return self._temp(self.handle)
|
||||||
|
|
||||||
|
|
||||||
class CExternal(object):
|
class CExternal(object):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue