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
|
||||
return len(instrs) > 0 and instrs[-1].is_terminator
|
||||
|
||||
def _is_struct(ty):
|
||||
return isinstance(ty, lc.StructType)
|
||||
|
||||
def _is_cstruct(ty):
|
||||
try:
|
||||
return issubclass(ty, CStruct)
|
||||
|
|
@ -67,6 +70,10 @@ def _change_block_temporarily(builder, bb):
|
|||
def _change_block_temporarily_dummy(*args):
|
||||
yield
|
||||
|
||||
class CastError(TypeError):
|
||||
def __init__(self, orig, to):
|
||||
super(CastError, self).__init__("Cannot cast from %s to %s" % (orig, to))
|
||||
|
||||
class _IfElse(object):
|
||||
'''if-else construct.
|
||||
|
||||
|
|
@ -399,7 +406,7 @@ class CBuilder(object):
|
|||
def check_arg(x):
|
||||
if isinstance(x, int):
|
||||
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.")
|
||||
return x
|
||||
|
||||
|
|
@ -675,7 +682,11 @@ class CBuilder(object):
|
|||
def alignment(self, 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):
|
||||
'''insert instruction that causes segfault some platform (Intel),
|
||||
|
|
@ -828,301 +839,335 @@ class CDefinition(CBuilder):
|
|||
raise NotImplementedError
|
||||
|
||||
class CValue(object):
|
||||
'''
|
||||
Signedness
|
||||
----------
|
||||
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.
|
||||
def __init__(self, parent, handle):
|
||||
self.__parent = parent
|
||||
self.__handle = handle
|
||||
|
||||
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 = {
|
||||
# op-name : (signed int, unsigned int, real)
|
||||
'add' : (lc.Builder.add, lc.Builder.add, lc.Builder.fadd),
|
||||
'sub' : (lc.Builder.sub, lc.Builder.sub, lc.Builder.fsub),
|
||||
'mul' : (lc.Builder.mul, lc.Builder.mul, lc.Builder.fmul),
|
||||
'div' : (lc.Builder.sdiv, lc.Builder.udiv, lc.Builder.fdiv),
|
||||
'mod' : (lc.Builder.srem, lc.Builder.urem, lc.Builder.frem),
|
||||
}
|
||||
def _get_operator_provider(ty):
|
||||
if _is_pointer(ty):
|
||||
return PointerValue
|
||||
elif _is_int(ty):
|
||||
return IntegerValue
|
||||
elif _is_real(ty):
|
||||
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 = {
|
||||
# op-name : (signed int, unsigned int)
|
||||
'lshift' : (lc.Builder.shl, lc.Builder.shl),
|
||||
'rshift' : (lc.Builder.lshr, lc.Builder.ashr),
|
||||
'and' : (lc.Builder.and_, lc.Builder.and_),
|
||||
'or' : (lc.Builder.or_, lc.Builder.or_),
|
||||
'xor' : (lc.Builder.xor, lc.Builder.xor),
|
||||
}
|
||||
class CTemp(CValue):
|
||||
def __new__(cls, parent, handle):
|
||||
meta = _get_operator_provider(handle.type)
|
||||
base = type(str('%s_%s' % (cls.__name__, handle.type)), (cls, meta), {})
|
||||
return object.__new__(base)
|
||||
|
||||
_CMP_MAP = {
|
||||
# op-name : (signed int, unsigned int, real)
|
||||
'eq' : (lc.ICMP_EQ, lc.ICMP_EQ, lc.FCMP_OEQ),
|
||||
'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, *args, **kws):
|
||||
super(CTemp, self).__init__(*args, **kws)
|
||||
self._init_mixin()
|
||||
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
@property
|
||||
def value(self):
|
||||
return self.handle
|
||||
|
||||
def _use_binop(self, op):
|
||||
'''implements binary operations
|
||||
'''
|
||||
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
|
||||
@property
|
||||
def type(self):
|
||||
return self.value.type
|
||||
|
||||
def _use_bitwise(self, op):
|
||||
'''implements bitwise operations
|
||||
'''
|
||||
def wrapped(rhs):
|
||||
self._ensure_same_type(rhs)
|
||||
if not self.is_int:
|
||||
errmsg = "Bitwise operation %s does not support type %s"
|
||||
raise TypeError(op, self.type)
|
||||
if not self.unsigned:
|
||||
idx = 0
|
||||
else:
|
||||
idx = 1
|
||||
res = self._BITWISE_MAP[idx](self.parent.builder,
|
||||
self.value, rhs.value)
|
||||
return CTemp(self.parent, res)
|
||||
return wrapped
|
||||
class CVar(CValue):
|
||||
def __new__(cls, parent, ptr):
|
||||
meta = _get_operator_provider(ptr.type.pointee)
|
||||
base = type(str('%s_%s' % (cls.__name__, ptr.type.pointee)), (cls, meta), {})
|
||||
return object.__new__(base)
|
||||
|
||||
def __init__(self, parent, ptr):
|
||||
super(CVar, self).__init__(parent, ptr)
|
||||
self._init_mixin()
|
||||
self.invariant = False
|
||||
|
||||
def reference(self):
|
||||
return self._temp(self.handle)
|
||||
|
||||
@property
|
||||
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):
|
||||
return self._use_binop('add')(rhs)
|
||||
return self._temp(self.parent.builder.add(self.value, rhs.value))
|
||||
|
||||
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):
|
||||
return self._use_binop('mul')(rhs)
|
||||
return self._temp(self.parent.builder.mul(self.value, rhs.value))
|
||||
|
||||
def __div__(self, rhs):
|
||||
return self._use_binop('div')(rhs)
|
||||
|
||||
def __truediv__(self, rhs):
|
||||
return self.__div__(rhs)
|
||||
if self.unsigned:
|
||||
return self._temp(self.parent.builder.udiv(self.value, rhs.value))
|
||||
else:
|
||||
return self._temp(self.parent.builder.sdiv(self.value, rhs.value))
|
||||
|
||||
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):
|
||||
return self._use_bitwise('lshift')(rhs)
|
||||
def __ilshift__(self, rhs):
|
||||
return self._temp(self.parent.builder.shl(self.value, rhs.value))
|
||||
|
||||
def __rshift__(self, rhs):
|
||||
return self._use_bitwise('rshift')(rhs)
|
||||
def __irshift__(self, 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):
|
||||
return self._use_bitwise('and')(rhs)
|
||||
def __iand__(self, rhs):
|
||||
return self._temp(self.parent.builder.and_(self.value, rhs.value))
|
||||
|
||||
def __or__(self, rhs):
|
||||
return self._use_bitwise('or')(rhs)
|
||||
def __ior__(self, rhs):
|
||||
return self._temp(self.parent.builder.or_(self.value, rhs.value))
|
||||
|
||||
def __xor__(self, rhs):
|
||||
return self._use_bitwise('xor')(rhs)
|
||||
|
||||
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 __ixor__(self, rhs):
|
||||
return self._temp(self.parent.builder.xor(self.value, rhs.value))
|
||||
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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
|
||||
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)
|
||||
|
||||
class PointerIndexing(OperatorMixin):
|
||||
def __getitem__(self, idx):
|
||||
'''implement access indexing
|
||||
|
||||
Uses GEP.
|
||||
'''
|
||||
bldr = self.parent.builder
|
||||
if self.is_pointer:
|
||||
if type(idx) is slice:
|
||||
# just handle case by case
|
||||
# Case #1: A[idx:] get poointer offset by idx
|
||||
if not idx.step and not idx.stop:
|
||||
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)
|
||||
if type(idx) is slice:
|
||||
# just handle case by case
|
||||
# Case #1: A[idx:] get pointer offset by idx
|
||||
if not idx.step and not idx.stop:
|
||||
idx = _auto_coerce_index(self.parent, idx.start)
|
||||
ptr = bldr.gep(self.value, [idx.value])
|
||||
return CVar(self.parent, ptr)
|
||||
elif self.is_vector:
|
||||
return CArray(self.parent, ptr)
|
||||
else: # return an variable at idx
|
||||
idx = _auto_coerce_index(self.parent, idx)
|
||||
val = bldr.extract_element(self.value, idx.value)
|
||||
return CTemp(self.parent, val)
|
||||
else:
|
||||
raise TypeError("Must be a pointer or vector; got %s" % self.type)
|
||||
ptr = bldr.gep(self.value, [idx.value])
|
||||
return CVar(self.parent, ptr)
|
||||
|
||||
def __setitem__(self, idx, val):
|
||||
idx = _auto_coerce_index(self.parent, idx)
|
||||
bldr = self.parent.builder
|
||||
if self.is_vector:
|
||||
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)
|
||||
self[idx].assign(val)
|
||||
|
||||
def load(self, volatile=False, invariant=False):
|
||||
'''memory load for pointer types
|
||||
'''
|
||||
self._ensure_is_pointer()
|
||||
loaded = self.parent.builder.load(self.value, volatile=volatile,
|
||||
invariant=invariant)
|
||||
return CTemp(self.parent, loaded)
|
||||
class PointerCasting(OperatorMixin):
|
||||
def cast(self, ty):
|
||||
if ty == self.type:
|
||||
return self._temp(self.value)
|
||||
|
||||
def store(self, val, volatile=False, nontemporal=False):
|
||||
'''memory store for pointer types
|
||||
if _is_pointer(ty):
|
||||
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()
|
||||
inst = self.parent.builder.store(val.value, self.value,
|
||||
volatile=volatile)
|
||||
bldr = self.parent.builder
|
||||
idx = _auto_coerce_index(self.parent, idx)
|
||||
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:
|
||||
self.parent.set_memop_non_temporal(inst)
|
||||
|
||||
|
|
@ -1135,12 +1180,11 @@ class CValue(object):
|
|||
|
||||
Other parameters are the same as `CBuilder.atomic_load`
|
||||
'''
|
||||
self._ensure_is_pointer()
|
||||
if align is None:
|
||||
align = self.parent.alignment(self.type.pointee)
|
||||
inst = self.parent.builder.atomic_load(self.value, ordering, align,
|
||||
crossthread=crossthread)
|
||||
return CTemp(self.parent, inst)
|
||||
return self._temp(inst)
|
||||
|
||||
def atomic_store(self, value, ordering, align=None, crossthread=True):
|
||||
'''atomic memory store for pointer types
|
||||
|
|
@ -1150,7 +1194,6 @@ class CValue(object):
|
|||
|
||||
Other parameters are the same as `CBuilder.atomic_store`
|
||||
'''
|
||||
self._ensure_is_pointer()
|
||||
if align is None:
|
||||
align = self.parent.alignment(self.type.pointee)
|
||||
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`
|
||||
'''
|
||||
self._ensure_is_pointer()
|
||||
inst = self.parent.builder.atomic_cmpxchg(self.value, old.value,
|
||||
new.value, ordering,
|
||||
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
|
||||
'''
|
||||
def __init__(self, parent, func):
|
||||
super(CFunc, self).__init__(parent)
|
||||
self.function = func
|
||||
super(CFunc, self).__init__(parent, func)
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
return self.handle
|
||||
|
||||
def __call__(self, *args, **opts):
|
||||
'''Call the function with the given arguments
|
||||
|
|
@ -1188,13 +1246,15 @@ class CFunc(CValue):
|
|||
"argument %d mismatch: %s != %s"
|
||||
% (self.function.name, i, exp, got.type))
|
||||
res = self.parent.builder.call(self.function, arg_values)
|
||||
|
||||
if hasattr(self.function, 'calling_convention'):
|
||||
res.calling_convention = self.function.calling_convention
|
||||
|
||||
if opts.get('inline'):
|
||||
self.parent.add_auto_inline(res)
|
||||
|
||||
return CTemp(self.parent, res)
|
||||
if ftype.return_type != lc.Type.void():
|
||||
return CTemp(self.parent, res)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
|
|
@ -1204,123 +1264,25 @@ class CFunc(CValue):
|
|||
def type(self):
|
||||
return self.function.type
|
||||
|
||||
class CTemp(CValue):
|
||||
'''Wraps temporary values
|
||||
'''
|
||||
def __init__(self, parent, value):
|
||||
super(CTemp, self).__init__(parent)
|
||||
self.value = value
|
||||
|
||||
@property
|
||||
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):
|
||||
class CArray(CValue, PointerIndexing, PointerCasting):
|
||||
'''wraps a array
|
||||
|
||||
Similar to C arrays
|
||||
'''
|
||||
def __init__(self, parent, base):
|
||||
super(CArray, self).__init__(parent)
|
||||
self.base_ptr = base
|
||||
super(CArray, self).__init__(parent, base)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.base_ptr
|
||||
return self.handle
|
||||
|
||||
def reference(self):
|
||||
return CTemp(self.parent, self.base_ptr)
|
||||
return self._temp(self.value)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self.base_ptr.type
|
||||
return self.value.type
|
||||
|
||||
def vector_load(self, count, align=0):
|
||||
parent = self.parent
|
||||
|
|
@ -1328,9 +1290,9 @@ class CArray(CValue):
|
|||
values = [self[i] for i in range(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)
|
||||
return CTemp(parent, vec)
|
||||
return self._temp(vec)
|
||||
|
||||
def vector_store(self, vec, align=0):
|
||||
if vec.type.element != self.type.pointee:
|
||||
|
|
@ -1338,10 +1300,11 @@ class CArray(CValue):
|
|||
(vec.type.element, self.type.pointee))
|
||||
parent = self.parent
|
||||
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)
|
||||
return self
|
||||
|
||||
|
||||
class CStruct(CValue):
|
||||
'''Wraps a structure
|
||||
|
||||
|
|
@ -1358,9 +1321,9 @@ class CStruct(CValue):
|
|||
return lc.Type.struct([v for k, v in cls._fields_])
|
||||
|
||||
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
|
||||
self.ptr = ptr
|
||||
|
||||
for i, (fd, _) in enumerate(self._fields_):
|
||||
gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)])
|
||||
gep.name = "%s.%s" % (type(self).__name__, fd)
|
||||
|
|
@ -1369,7 +1332,7 @@ class CStruct(CValue):
|
|||
setattr(self, fd, CVar(self.parent, gep))
|
||||
|
||||
def reference(self):
|
||||
return CTemp(self.parent, self.ptr)
|
||||
return self._temp(self.handle)
|
||||
|
||||
|
||||
class CExternal(object):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue