# Source code for binaryninja.lowlevelil

    # Copyright (c) 2015-2017 Vector 35 LLC
    #
    # Permission is hereby granted, free of charge, to any person obtaining a copy
    # of this software and associated documentation files (the "Software"), to
    # deal in the Software without restriction, including without limitation the
    # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    # sell copies of the Software, and to permit persons to whom the Software is
    # furnished to do so, subject to the following conditions:
    #
    # The above copyright notice and this permission notice shall be included in
    # all copies or substantial portions of the Software.
    #
    # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    # IN THE SOFTWARE.

    import ctypes
    import struct

    # Binary Ninja components
    import binaryninja
    from binaryninja import _binaryninjacore as core
    from binaryninja.enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType
    from binaryninja import basicblock #required for LowLevelILBasicBlock

    # 2-3 compatibility
    from binaryninja import range

    class LowLevelILLabel(object):
    	def __init__(self, handle = None):
    		if handle is None:
    			self.handle = (core.BNLowLevelILLabel * 1)()
    			core.BNLowLevelILInitLabel(self.handle)
    		else:
    			self.handle = handle

    class ILRegister(object):
    	def __init__(self, arch, reg):
    		self.arch = arch
    		self.index = reg
    		self.temp = (self.index & 0x80000000) != 0
    		if self.temp:
    			self.name = "temp%d" % (self.index & 0x7fffffff)
    		else:
    			self.name = self.arch.get_reg_name(self.index)

    	@property
    	def info(self):
    		return self.arch.regs[self.name]

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    	def __eq__(self, other):
    		return self.info == other.info

    class ILRegisterStack(object):
    	def __init__(self, arch, reg_stack):
    		self.arch = arch
    		self.index = reg_stack
    		self.name = self.arch.get_reg_stack_name(self.index)

    	@property
    	def info(self):
    		return self.arch.reg_stacks[self.name]

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    	def __eq__(self, other):
    		return self.info == other.info

    class ILFlag(object):
    	def __init__(self, arch, flag):
    		self.arch = arch
    		self.index = flag
    		self.temp = (self.index & 0x80000000) != 0
    		if self.temp:
    			self.name = "cond:%d" % (self.index & 0x7fffffff)
    		else:
    			self.name = self.arch.get_flag_name(self.index)

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    class ILSemanticFlagClass(object):
    	def __init__(self, arch, sem_class):
    		self.arch = arch
    		self.index = sem_class
    		self.name = self.arch.get_semantic_flag_class_name(self.index)

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    	def __eq__(self, other):
    		return self.index == other.index

    class ILSemanticFlagGroup(object):
    	def __init__(self, arch, sem_group):
    		self.arch = arch
    		self.index = sem_group
    		self.name = self.arch.get_semantic_flag_group_name(self.index)

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    	def __eq__(self, other):
    		return self.index == other.index

    class ILIntrinsic(object):
    	def __init__(self, arch, intrinsic):
    		self.arch = arch
    		self.index = intrinsic
    		self.name = self.arch.get_intrinsic_name(self.index)
    		if self.name in self.arch.intrinsics:
    			self.inputs = self.arch.intrinsics[self.name].inputs
    			self.outputs = self.arch.intrinsics[self.name].outputs

    	def __str__(self):
    		return self.name

    	def __repr__(self):
    		return self.name

    	def __eq__(self, other):
    		return self.index == other.index

    class SSARegister(object):
    	def __init__(self, reg, version):
    		self.reg = reg
    		self.version = version

    	def __repr__(self):
    		return "<ssa %s version %d>" % (repr(self.reg), self.version)

    class SSARegisterStack(object):
    	def __init__(self, reg_stack, version):
    		self.reg_stack = reg_stack
    		self.version = version

    	def __repr__(self):
    		return "<ssa %s version %d>" % (repr(self.reg_stack), self.version)

    class SSAFlag(object):
    	def __init__(self, flag, version):
    		self.flag = flag
    		self.version = version

    	def __repr__(self):
    		return "<ssa %s version %d>" % (repr(self.flag), self.version)

    class SSARegisterOrFlag(object):
    	def __init__(self, reg_or_flag, version):
    		self.reg_or_flag = reg_or_flag
    		self.version = version

    	def __repr__(self):
    		return "<ssa %s version %d>" % (repr(self.reg_or_flag), self.version)

    class LowLevelILOperationAndSize(object):
    	def __init__(self, operation, size):
    		self.operation = operation
    		self.size = size

    	def __repr__(self):
    		if self.size == 0:
    			return "<%s>" % self.operation.name
    		return "<%s %d>" % (self.operation.name, self.size)

    class LowLevelILInstruction(object):
    	"""
    	``class LowLevelILInstruction`` Low Level Intermediate Language Instructions are infinite length tree-based
    	instructions. Tree-based instructions use infix notation with the left hand operand being the destination operand.
    	Infix notation is thus more natural to read than other notations (e.g. x86 ``mov eax, 0`` vs. LLIL ``eax = 0``).
    	"""

    	ILOperations = {
    		LowLevelILOperation.LLIL_NOP: [],
    		LowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_STACK_REL: [("stack", "reg_stack"), ("dest", "expr"), ("src", "expr")],
    		LowLevelILOperation.LLIL_REG_STACK_PUSH: [("stack", "reg_stack"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")],
    		LowLevelILOperation.LLIL_LOAD: [("src", "expr")],
    		LowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")],
    		LowLevelILOperation.LLIL_PUSH: [("src", "expr")],
    		LowLevelILOperation.LLIL_POP: [],
    		LowLevelILOperation.LLIL_REG: [("src", "reg")],
    		LowLevelILOperation.LLIL_REG_SPLIT: [("hi", "reg"), ("lo", "reg")],
    		LowLevelILOperation.LLIL_REG_STACK_REL: [("stack", "reg_stack"), ("src", "expr")],
    		LowLevelILOperation.LLIL_REG_STACK_POP: [("stack", "reg_stack")],
    		LowLevelILOperation.LLIL_REG_STACK_FREE_REG: [("dest", "reg")],
    		LowLevelILOperation.LLIL_REG_STACK_FREE_REL: [("stack", "reg_stack"), ("dest", "expr")],
    		LowLevelILOperation.LLIL_CONST: [("constant", "int")],
    		LowLevelILOperation.LLIL_CONST_PTR: [("constant", "int")],
    		LowLevelILOperation.LLIL_FLOAT_CONST: [("constant", "float")],
    		LowLevelILOperation.LLIL_FLAG: [("src", "flag")],
    		LowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")],
    		LowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_ADC: [("left", "expr"), ("right", "expr"), ("carry", "expr")],
    		LowLevelILOperation.LLIL_SUB: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_SBB: [("left", "expr"), ("right", "expr"), ("carry", "expr")],
    		LowLevelILOperation.LLIL_AND: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_OR: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_XOR: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_LSL: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_LSR: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_ASR: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_ROL: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_RLC: [("left", "expr"), ("right", "expr"), ("carry", "expr")],
    		LowLevelILOperation.LLIL_ROR: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_RRC: [("left", "expr"), ("right", "expr"), ("carry", "expr")],
    		LowLevelILOperation.LLIL_MUL: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_DIVU_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_DIVS_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MODU_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_MODS_DP: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_NEG: [("src", "expr")],
    		LowLevelILOperation.LLIL_NOT: [("src", "expr")],
    		LowLevelILOperation.LLIL_SX: [("src", "expr")],
    		LowLevelILOperation.LLIL_ZX: [("src", "expr")],
    		LowLevelILOperation.LLIL_LOW_PART: [("src", "expr")],
    		LowLevelILOperation.LLIL_JUMP: [("dest", "expr")],
    		LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")],
    		LowLevelILOperation.LLIL_CALL: [("dest", "expr")],
    		LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")],
    		LowLevelILOperation.LLIL_TAILCALL: [("dest", "expr")],
    		LowLevelILOperation.LLIL_RET: [("dest", "expr")],
    		LowLevelILOperation.LLIL_NORET: [],
    		LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")],
    		LowLevelILOperation.LLIL_GOTO: [("dest", "int")],
    		LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond"), ("semantic_class", "sem_class")],
    		LowLevelILOperation.LLIL_FLAG_GROUP: [("semantic_group", "sem_group")],
    		LowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_ULT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_SLE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_ULE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_SGE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_UGE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")],
    		LowLevelILOperation.LLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_SYSCALL: [],
    		LowLevelILOperation.LLIL_INTRINSIC: [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")],
    		LowLevelILOperation.LLIL_INTRINSIC_SSA: [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")],
    		LowLevelILOperation.LLIL_BP: [],
    		LowLevelILOperation.LLIL_TRAP: [("vector", "int")],
    		LowLevelILOperation.LLIL_UNDEF: [],
    		LowLevelILOperation.LLIL_UNIMPL: [],
    		LowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")],
    		LowLevelILOperation.LLIL_FADD: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FSUB: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FMUL: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FDIV: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FSQRT: [("src", "expr")],
    		LowLevelILOperation.LLIL_FNEG: [("src", "expr")],
    		LowLevelILOperation.LLIL_FABS: [("src", "expr")],
    		LowLevelILOperation.LLIL_FLOAT_TO_INT: [("src", "expr")],
    		LowLevelILOperation.LLIL_INT_TO_FLOAT: [("src", "expr")],
    		LowLevelILOperation.LLIL_FLOAT_CONV: [("src", "expr")],
    		LowLevelILOperation.LLIL_ROUND_TO_INT: [("src", "expr")],
    		LowLevelILOperation.LLIL_FLOOR: [("src", "expr")],
    		LowLevelILOperation.LLIL_CEIL: [("src", "expr")],
    		LowLevelILOperation.LLIL_FTRUNC: [("src", "expr")],
    		LowLevelILOperation.LLIL_FCMP_E: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_NE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_LT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_LE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_GE: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_GT: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_O: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_FCMP_UO: [("left", "expr"), ("right", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_SSA: [("dest", "reg_ssa"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("dest", "reg"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_SPLIT_SSA: [("hi", "expr"), ("lo", "expr"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_STACK_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr"), ("src", "expr")],
    		LowLevelILOperation.LLIL_SET_REG_STACK_ABS_SSA: [("stack", "expr"), ("dest", "reg"), ("src", "expr")],
    		LowLevelILOperation.LLIL_REG_SPLIT_DEST_SSA: [("dest", "reg_ssa")],
    		LowLevelILOperation.LLIL_REG_STACK_DEST_SSA: [("src", "reg_stack_ssa_dest_and_src")],
    		LowLevelILOperation.LLIL_REG_SSA: [("src", "reg_ssa")],
    		LowLevelILOperation.LLIL_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("src", "reg")],
    		LowLevelILOperation.LLIL_REG_SPLIT_SSA: [("hi", "reg_ssa"), ("lo", "reg_ssa")],
    		LowLevelILOperation.LLIL_REG_STACK_REL_SSA: [("stack", "reg_stack_ssa"), ("src", "expr"), ("top", "expr")],
    		LowLevelILOperation.LLIL_REG_STACK_ABS_SSA: [("stack", "reg_stack_ssa"), ("src", "reg")],
    		LowLevelILOperation.LLIL_REG_STACK_FREE_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr")],
    		LowLevelILOperation.LLIL_REG_STACK_FREE_ABS_SSA: [("stack", "expr"), ("dest", "reg")],
    		LowLevelILOperation.LLIL_SET_FLAG_SSA: [("dest", "flag_ssa"), ("src", "expr")],
    		LowLevelILOperation.LLIL_FLAG_SSA: [("src", "flag_ssa")],
    		LowLevelILOperation.LLIL_FLAG_BIT_SSA: [("src", "flag_ssa"), ("bit", "int")],
    		LowLevelILOperation.LLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")],
    		LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")],
    		LowLevelILOperation.LLIL_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("stack", "expr"), ("param", "expr")],
    		LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")],
    		LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg_ssa"), ("src_memory", "int")],
    		LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_list")],
    		LowLevelILOperation.LLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")],
    		LowLevelILOperation.LLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")],
    		LowLevelILOperation.LLIL_REG_PHI: [("dest", "reg_ssa"), ("src", "reg_ssa_list")],
    		LowLevelILOperation.LLIL_REG_STACK_PHI: [("dest", "reg_stack_ssa"), ("src", "reg_stack_ssa_list")],
    		LowLevelILOperation.LLIL_FLAG_PHI: [("dest", "flag_ssa"), ("src", "flag_ssa_list")],
    		LowLevelILOperation.LLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")]
    	}

    	def __init__(self, func, expr_index, instr_index=None):
    		instr = core.BNGetLowLevelILByIndex(func.handle, expr_index)
    		self.function = func
    		self.expr_index = expr_index
    		self.instr_index = instr_index
    		self.operation = LowLevelILOperation(instr.operation)
    		self.size = instr.size
    		self.address = instr.address
    		self.source_operand = instr.sourceOperand
    		if instr.flags == 0:
    			self.flags = None
    		else:
    			self.flags = func.arch.get_flag_write_type_name(instr.flags)
    		if self.source_operand == 0xffffffff:
    			self.source_operand = None
    		operands = LowLevelILInstruction.ILOperations[instr.operation]
    		self.operands = []
    		i = 0
    		for operand in operands:
    			name, operand_type = operand
    			if operand_type == "int":
    				value = instr.operands[i]
    			elif operand_type == "float":
    				if instr.size == 4:
    					value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0]
    				elif instr.size == 8:
    					value = struct.unpack("d", struct.pack("Q", instr.operands[i]))[0]
    				else:
    					value = instr.operands[i]
    			elif operand_type == "expr":
    				value = LowLevelILInstruction(func, instr.operands[i])
    			elif operand_type == "reg":
    				value = ILRegister(func.arch, instr.operands[i])
    			elif operand_type == "reg_stack":
    				value = ILRegisterStack(func.arch, instr.operands[i])
    			elif operand_type == "intrinsic":
    				value = ILIntrinsic(func.arch, instr.operands[i])
    			elif operand_type == "reg_ssa":
    				reg = ILRegister(func.arch, instr.operands[i])
    				i += 1
    				value = SSARegister(reg, instr.operands[i])
    			elif operand_type == "reg_stack_ssa":
    				reg_stack = ILRegisterStack(func.arch, instr.operands[i])
    				i += 1
    				value = SSARegisterStack(reg_stack, instr.operands[i])
    			elif operand_type == "reg_stack_ssa_dest_and_src":
    				reg_stack = ILRegisterStack(func.arch, instr.operands[i])
    				i += 1
    				value = SSARegisterStack(reg_stack, instr.operands[i])
    				i += 1
    				self.operands.append(value)
    				self.dest = value
    				value = SSARegisterStack(reg_stack, instr.operands[i])
    			elif operand_type == "flag":
    				value = ILFlag(func.arch, instr.operands[i])
    			elif operand_type == "flag_ssa":
    				flag = ILFlag(func.arch, instr.operands[i])
    				i += 1
    				value = SSAFlag(flag, instr.operands[i])
    			elif operand_type == "sem_class":
    				if instr.operands[i] == 0:
    					value = None
    				else:
    					value = ILSemanticFlagClass(func.arch, instr.operands[i])
    			elif operand_type == "sem_group":
    				value = ILSemanticFlagGroup(func.arch, instr.operands[i])
    			elif operand_type == "cond":
    				value = LowLevelILFlagCondition(instr.operands[i])
    			elif operand_type == "int_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value):
    					value.append(operand_list[j])
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "expr_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value):
    					value.append(LowLevelILInstruction(func, operand_list[j]))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "reg_or_flag_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value):
    					if (operand_list[j] & (1 << 32)) != 0:
    						value.append(ILFlag(func.arch, operand_list[j] & 0xffffffff))
    					else:
    						value.append(ILRegister(func.arch, operand_list[j] & 0xffffffff))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "reg_ssa_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value // 2):
    					reg = operand_list[j * 2]
    					reg_version = operand_list[(j * 2) + 1]
    					value.append(SSARegister(ILRegister(func.arch, reg), reg_version))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "reg_stack_ssa_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value // 2):
    					reg_stack = operand_list[j * 2]
    					reg_version = operand_list[(j * 2) + 1]
    					value.append(SSARegisterStack(ILRegisterStack(func.arch, reg_stack), reg_version))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "flag_ssa_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value // 2):
    					flag = operand_list[j * 2]
    					flag_version = operand_list[(j * 2) + 1]
    					value.append(SSAFlag(ILFlag(func.arch, flag), flag_version))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "reg_or_flag_ssa_list":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = []
    				for j in range(count.value // 2):
    					if (operand_list[j * 2] & (1 << 32)) != 0:
    						reg_or_flag = ILFlag(func.arch, operand_list[j * 2] & 0xffffffff)
    					else:
    						reg_or_flag = ILRegister(func.arch, operand_list[j * 2] & 0xffffffff)
    					reg_version = operand_list[(j * 2) + 1]
    					value.append(SSARegisterOrFlag(reg_or_flag, reg_version))
    				core.BNLowLevelILFreeOperandList(operand_list)
    			elif operand_type == "reg_stack_adjust":
    				count = ctypes.c_ulonglong()
    				operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count)
    				i += 1
    				value = {}
    				for j in range(count.value // 2):
    					reg_stack = operand_list[j * 2]
    					adjust = operand_list[(j * 2) + 1]
    					if adjust & 0x80000000:
    						adjust |= ~0x80000000
    					value[func.arch.get_reg_stack_name(reg_stack)] = adjust
    				core.BNLowLevelILFreeOperandList(operand_list)
    			self.operands.append(value)
    			self.__dict__[name] = value
    			i += 1

    	def __str__(self):
    		tokens = self.tokens
    		if tokens is None:
    			return "invalid"
    		result = ""
    		for token in tokens:
    			result += token.text
    		return result

    	def __repr__(self):
    		return "<il: %s>" % str(self)

    	@property
    	def tokens(self):
    		"""LLIL tokens (read-only)"""
    		count = ctypes.c_ulonglong()
    		tokens = ctypes.POINTER(core.BNInstructionTextToken)()
    		if (self.instr_index is not None) and (self.function.source_function is not None):
    			if not core.BNGetLowLevelILInstructionText(self.function.handle, self.function.source_function.handle,
    				self.function.arch.handle, self.instr_index, tokens, count):
    				return None
    		else:
    			if not core.BNGetLowLevelILExprText(self.function.handle, self.function.arch.handle,
    				self.expr_index, tokens, count):
    				return None
    		result = []
    		for i in range(0, count.value):
    			token_type = InstructionTextTokenType(tokens[i].type)
    			text = tokens[i].text
    			value = tokens[i].value
    			size = tokens[i].size
    			operand = tokens[i].operand
    			context = tokens[i].context
    			confidence = tokens[i].confidence
    			address = tokens[i].address
    			result.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
    		core.BNFreeInstructionText(tokens, count.value)
    		return result

    	@property
    	def ssa_form(self):
    		"""SSA form of expression (read-only)"""
    		return LowLevelILInstruction(self.function.ssa_form,
    			core.BNGetLowLevelILSSAExprIndex(self.function.handle, self.expr_index))

    	@property
    	def non_ssa_form(self):
    		"""Non-SSA form of expression (read-only)"""
    		return LowLevelILInstruction(self.function.non_ssa_form,
    			core.BNGetLowLevelILNonSSAExprIndex(self.function.handle, self.expr_index))

    	@property
    	def medium_level_il(self):
    		"""Gets the medium level IL expression corresponding to this expression (may be None for eliminated instructions)"""
    		expr = self.function.get_medium_level_il_expr_index(self.expr_index)
    		if expr is None:
    			return None
    		return binaryninja.mediumlevelil.MediumLevelILInstruction(self.function.medium_level_il, expr)

    	@property
    	def mapped_medium_level_il(self):
    		"""Gets the mapped medium level IL expression corresponding to this expression"""
    		expr = self.function.get_mapped_medium_level_il_expr_index(self.expr_index)
    		if expr is None:
    			return None
    		return binaryninja.mediumlevelil.MediumLevelILInstruction(self.function.mapped_medium_level_il, expr)

    	@property
    	def value(self):
    		"""Value of expression if constant or a known value (read-only)"""
    		value = core.BNGetLowLevelILExprValue(self.function.handle, self.expr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	@property
    	def possible_values(self):
    		"""Possible values of expression using path-sensitive static data flow analysis (read-only)"""
    		value = core.BNGetLowLevelILPossibleExprValues(self.function.handle, self.expr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	@property
    	def prefix_operands(self):
    		"""All operands in the expression tree in prefix order"""
    		result = [LowLevelILOperationAndSize(self.operation, self.size)]
    		for operand in self.operands:
    			if isinstance(operand, LowLevelILInstruction):
    				result += operand.prefix_operands
    			else:
    				result.append(operand)
    		return result

    	@property
    	def postfix_operands(self):
    		"""All operands in the expression tree in postfix order"""
    		result = []
    		for operand in self.operands:
    			if isinstance(operand, LowLevelILInstruction):
    				result += operand.postfix_operands
    			else:
    				result.append(operand)
    		result.append(LowLevelILOperationAndSize(self.operation, self.size))
    		return result

    	def get_reg_value(self, reg):
    		reg = self.function.arch.get_reg_index(reg)
    		value = core.BNGetLowLevelILRegisterValueAtInstruction(self.function.handle, reg, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_reg_value_after(self, reg):
    		reg = self.function.arch.get_reg_index(reg)
    		value = core.BNGetLowLevelILRegisterValueAfterInstruction(self.function.handle, reg, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_possible_reg_values(self, reg):
    		reg = self.function.arch.get_reg_index(reg)
    		value = core.BNGetLowLevelILPossibleRegisterValuesAtInstruction(self.function.handle, reg, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def get_possible_reg_values_after(self, reg):
    		reg = self.function.arch.get_reg_index(reg)
    		value = core.BNGetLowLevelILPossibleRegisterValuesAfterInstruction(self.function.handle, reg, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def get_flag_value(self, flag):
    		flag = self.function.arch.get_flag_index(flag)
    		value = core.BNGetLowLevelILFlagValueAtInstruction(self.function.handle, flag, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_flag_value_after(self, flag):
    		flag = self.function.arch.get_flag_index(flag)
    		value = core.BNGetLowLevelILFlagValueAfterInstruction(self.function.handle, flag, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_possible_flag_values(self, flag):
    		flag = self.function.arch.get_flag_index(flag)
    		value = core.BNGetLowLevelILPossibleFlagValuesAtInstruction(self.function.handle, flag, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def get_possible_flag_values_after(self, flag):
    		flag = self.function.arch.get_flag_index(flag)
    		value = core.BNGetLowLevelILPossibleFlagValuesAfterInstruction(self.function.handle, flag, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def get_stack_contents(self, offset, size):
    		value = core.BNGetLowLevelILStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_stack_contents_after(self, offset, size):
    		value = core.BNGetLowLevelILStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index)
    		result = binaryninja.function.RegisterValue(self.function.arch, value)
    		return result

    	def get_possible_stack_contents(self, offset, size):
    		value = core.BNGetLowLevelILPossibleStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def get_possible_stack_contents_after(self, offset, size):
    		value = core.BNGetLowLevelILPossibleStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index)
    		result = binaryninja.function.PossibleValueSet(self.function.arch, value)
    		core.BNFreePossibleValueSet(value)
    		return result

    	def __setattr__(self, name, value):
    		try:
    			object.__setattr__(self, name, value)
    		except AttributeError:
    			raise AttributeError("attribute '%s' is read only" % name)

    class LowLevelILExpr(object):
    	"""
    	``class LowLevelILExpr`` hold the index of IL Expressions.

    	.. note:: This class shouldn't be instantiated directly. Rather the helper members of LowLevelILFunction should be \
    	used instead.
    	"""
    	def __init__(self, index):
    		self.index = index

    class LowLevelILFunction(object):
    	"""
    	``class LowLevelILFunction`` contains the list of LowLevelILExpr objects that make up a binaryninja.function. LowLevelILExpr
    	objects can be added to the LowLevelILFunction by calling ``append`` and passing the result of the various class
    	methods which return LowLevelILExpr objects.

    	LowLevelILFlagCondition values used as parameters in the ``flag_condition`` method.

    		======================= ========== ===============================
    		LowLevelILFlagCondition Operator   Description
    		======================= ========== ===============================
    		LLFC_E                  ==         Equal
    		LLFC_NE                 !=         Not equal
    		LLFC_SLT                s<         Signed less than
    		LLFC_ULT                u<         Unsigned less than
    		LLFC_SLE                s<=        Signed less than or equal
    		LLFC_ULE                u<=        Unsigned less than or equal
    		LLFC_SGE                s>=        Signed greater than or equal
    		LLFC_UGE                u>=        Unsigned greater than or equal
    		LLFC_SGT                s>         Signed greather than
    		LLFC_UGT                u>         Unsigned greater than
    		LLFC_NEG                -          Negative
    		LLFC_POS                +          Positive
    		LLFC_O                  overflow   Overflow
    		LLFC_NO                 !overflow  No overflow
    		======================= ========== ===============================
    	"""
    	def __init__(self, arch, handle = None, source_func = None):
    		self.arch = arch
    		self.source_function = source_func
    		if handle is not None:
    			self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction)
    		else:
    			func_handle = None
    			if self.source_function is not None:
    				func_handle = self.source_function.handle
    			self.handle = core.BNCreateLowLevelILFunction(arch.handle, func_handle)

    	def __del__(self):
    		core.BNFreeLowLevelILFunction(self.handle)

    	def __eq__(self, value):
    		if not isinstance(value, LowLevelILFunction):
    			return False
    		return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)

    	def __ne__(self, value):
    		if not isinstance(value, LowLevelILFunction):
    			return True
    		return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)

    	@property
    	def current_address(self):
    		"""Current IL Address (read/write)"""
    		return core.BNLowLevelILGetCurrentAddress(self.handle)

    	@current_address.setter
    	def current_address(self, value):
    		core.BNLowLevelILSetCurrentAddress(self.handle, self.arch.handle, value)

    	def set_current_address(self, value, arch = None):
    		if arch is None:
    			arch = self.arch
    		core.BNLowLevelILSetCurrentAddress(self.handle, arch.handle, value)

    	@property
    	def temp_reg_count(self):
    		"""Number of temporary registers (read-only)"""
    		return core.BNGetLowLevelILTemporaryRegisterCount(self.handle)

    	@property
    	def temp_flag_count(self):
    		"""Number of temporary flags (read-only)"""
    		return core.BNGetLowLevelILTemporaryFlagCount(self.handle)

    	@property
    	def basic_blocks(self):
    		"""list of LowLevelILBasicBlock objects (read-only)"""
    		count = ctypes.c_ulonglong()
    		blocks = core.BNGetLowLevelILBasicBlockList(self.handle, count)
    		result = []
    		view = None
    		if self.source_function is not None:
    			view = self.source_function.view
    		for i in range(0, count.value):
    			result.append(LowLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self))
    		core.BNFreeBasicBlockList(blocks, count.value)
    		return result

    	@property
    	def ssa_form(self):
    		"""Low level IL in SSA form (read-only)"""
    		result = core.BNGetLowLevelILSSAForm(self.handle)
    		if not result:
    			return None
    		return LowLevelILFunction(self.arch, result, self.source_function)

    	@property
    	def non_ssa_form(self):
    		"""Low level IL in non-SSA (default) form (read-only)"""
    		result = core.BNGetLowLevelILNonSSAForm(self.handle)
    		if not result:
    			return None
    		return LowLevelILFunction(self.arch, result, self.source_function)

    	@property
    	def medium_level_il(self):
    		"""Medium level IL for this low level IL."""
    		result = core.BNGetMediumLevelILForLowLevelIL(self.handle)
    		if not result:
    			return None
    		return binaryninja.mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)

    	@property
    	def mapped_medium_level_il(self):
    		"""Medium level IL with mappings between low level IL and medium level IL. Unused stores are not removed.
    		Typically, this should only be used to answer queries on assembly or low level IL where the query is
    		easier to perform on medium level IL."""
    		result = core.BNGetMappedMediumLevelIL(self.handle)
    		if not result:
    			return None
    		return binaryninja.mediumlevelil.MediumLevelILFunction(self.arch, result, self.source_function)

    	def __setattr__(self, name, value):
    		try:
    			object.__setattr__(self, name, value)
    		except AttributeError:
    			raise AttributeError("attribute '%s' is read only" % name)

    	def __len__(self):
    		return int(core.BNGetLowLevelILInstructionCount(self.handle))

    	def __getitem__(self, i):
    		if isinstance(i, slice) or isinstance(i, tuple):
    			raise IndexError("expected integer instruction index")
    		if isinstance(i, LowLevelILExpr):
    			return LowLevelILInstruction(self, i.index)
    		if (i < 0) or (i >= len(self)):
    			raise IndexError("index out of range")
    		return LowLevelILInstruction(self, core.BNGetLowLevelILIndexForInstruction(self.handle, i), i)

    	def __setitem__(self, i, j):
    		raise IndexError("instruction modification not implemented")

    	def __iter__(self):
    		count = ctypes.c_ulonglong()
    		blocks = core.BNGetLowLevelILBasicBlockList(self.handle, count)
    		view = None
    		if self.source_function is not None:
    			view = self.source_function.view
    		try:
    			for i in range(0, count.value):
    				yield LowLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)
    		finally:
    			core.BNFreeBasicBlockList(blocks, count.value)

    	def get_instruction_start(self, addr, arch = None):
    		if arch is None:
    			arch = self.arch
    		result = core.BNLowLevelILGetInstructionStart(self.handle, arch.handle, addr)
    		if result >= core.BNGetLowLevelILInstructionCount(self.handle):
    			return None
    		return result

    	def clear_indirect_branches(self):
    		core.BNLowLevelILClearIndirectBranches(self.handle)

    	def set_indirect_branches(self, branches):
    		branch_list = (core.BNArchitectureAndAddress * len(branches))()
    		for i in range(len(branches)):
    			branch_list[i].arch = branches[i][0].handle
    			branch_list[i].address = branches[i][1]
    		core.BNLowLevelILSetIndirectBranches(self.handle, branch_list, len(branches))

    	def expr(self, operation, a = 0, b = 0, c = 0, d = 0, size = 0, flags = None):
    		if isinstance(operation, str):
    			operation = LowLevelILOperation[operation]
    		elif isinstance(operation, LowLevelILOperation):
    			operation = operation.value
    		if isinstance(flags, str):
    			flags = self.arch.get_flag_write_type_by_name(flags)
    		elif flags is None:
    			flags = 0
    		return LowLevelILExpr(core.BNLowLevelILAddExpr(self.handle, operation, size, flags, a, b, c, d))

    	def append(self, expr):
    		"""
    		``append`` adds the LowLevelILExpr ``expr`` to the current LowLevelILFunction.

    		:param LowLevelILExpr expr: the LowLevelILExpr to add to the current LowLevelILFunction
    		:return: number of LowLevelILExpr in the current function
    		:rtype: int
    		"""
    		return core.BNLowLevelILAddInstruction(self.handle, expr.index)

    	def nop(self):
    		"""
    		``nop`` no operation, this instruction does nothing

    		:return: The no operation expression
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_NOP)

    	def set_reg(self, size, reg, value, flags = 0):
    		"""
    		``set_reg`` sets the register ``reg`` of size ``size`` to the expression ``value``

    		:param int size: size of the register parameter in bytes
    		:param str reg: the register name
    		:param LowLevelILExpr value: an expression to set the register to
    		:param str flags: which flags are set by this operation
    		:return: The expression ``reg = value``
    		:rtype: LowLevelILExpr
    		"""
    		reg = self.arch.get_reg_index(reg)
    		return self.expr(LowLevelILOperation.LLIL_SET_REG, reg, value.index, size = size, flags = flags)

    	def set_reg_split(self, size, hi, lo, value, flags = 0):
    		"""
    		``set_reg_split`` uses ``hi`` and ``lo`` as a single extended register setting ``hi:lo`` to the expression
    		``value``.

    		:param int size: size of the register parameter in bytes
    		:param str hi: the high register name
    		:param str lo: the low register name
    		:param LowLevelILExpr value: an expression to set the split regiters to
    		:param str flags: which flags are set by this operation
    		:return: The expression ``hi:lo = value``
    		:rtype: LowLevelILExpr
    		"""
    		hi = self.arch.get_reg_index(hi)
    		lo = self.arch.get_reg_index(lo)
    		return self.expr(LowLevelILOperation.LLIL_SET_REG_SPLIT, hi, lo, value.index, size = size, flags = flags)

    	def set_reg_stack_top_relative(self, size, reg_stack, entry, value, flags = 0):
    		"""
    		``set_reg_stack_top_relative`` sets the top-relative entry ``entry`` of size ``size`` in register
    		stack ``reg_stack`` to the expression ``value``

    		:param int size: size of the register parameter in bytes
    		:param str reg_stack: the register stack name
    		:param LowLevelILExpr entry: an expression for which stack entry to set
    		:param LowLevelILExpr value: an expression to set the entry to
    		:param str flags: which flags are set by this operation
    		:return: The expression ``reg_stack[entry] = value``
    		:rtype: LowLevelILExpr
    		"""
    		reg_stack = self.arch.get_reg_stack_index(reg_stack)
    		return self.expr(LowLevelILOperation.LLIL_SET_REG_STACK_REL, reg_stack, entry.index, value.index,
    			size = size, flags = flags)

    	def reg_stack_push(self, size, reg_stack, value, flags = 0):
    		"""
    		``reg_stack_push`` pushes the expression ``value`` of size ``size`` onto the top of the register
    		stack ``reg_stack``

    		:param int size: size of the register parameter in bytes
    		:param str reg_stack: the register stack name
    		:param LowLevelILExpr value: an expression to push
    		:param str flags: which flags are set by this operation
    		:return: The expression ``reg_stack.push(value)``
    		:rtype: LowLevelILExpr
    		"""
    		reg_stack = self.arch.get_reg_stack_index(reg_stack)
    		return self.expr(LowLevelILOperation.LLIL_REG_STACK_PUSH, reg_stack, value.index, size = size, flags = flags)

    	def set_flag(self, flag, value):
    		"""
    		``set_flag`` sets the flag ``flag`` to the LowLevelILExpr ``value``

    		:param str flag: the low register name
    		:param LowLevelILExpr value: an expression to set the flag to
    		:return: The expression FLAG.flag = value
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_SET_FLAG, self.arch.get_flag_by_name(flag), value.index)

    	def load(self, size, addr):
    		"""
    		``load`` Reads ``size`` bytes from the expression ``addr``

    		:param int size: number of bytes to read
    		:param LowLevelILExpr addr: the expression to read memory from
    		:return: The expression ``[addr].size``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_LOAD, addr.index, size=size)

    	def store(self, size, addr, value, flags=None):
    		"""
    		``store`` Writes ``size`` bytes to expression ``addr`` read from expression ``value``

    		:param int size: number of bytes to write
    		:param LowLevelILExpr addr: the expression to write to
    		:param LowLevelILExpr value: the expression to be written
    		:param str flags: which flags are set by this operation
    		:return: The expression ``[addr].size = value``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_STORE, addr.index, value.index, size=size, flags=flags)

    	def push(self, size, value):
    		"""
    		``push`` writes ``size`` bytes from expression ``value`` to the stack, adjusting the stack by ``size``.

    		:param int size: number of bytes to write and adjust the stack by
    		:param LowLevelILExpr value: the expression to write
    		:return: The expression push(value)
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_PUSH, value.index, size=size)

    	def pop(self, size):
    		"""
    		``pop`` reads ``size`` bytes from the stack, adjusting the stack by ``size``.

    		:param int size: number of bytes to read from the stack
    		:return: The expression ``pop``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_POP, size=size)

    	def reg(self, size, reg):
    		"""
    		``reg`` returns a register of size ``size`` with name ``reg``

    		:param int size: the size of the register in bytes
    		:param str reg: the name of the register
    		:return: A register expression for the given string
    		:rtype: LowLevelILExpr
    		"""
    		reg = self.arch.get_reg_index(reg)
    		return self.expr(LowLevelILOperation.LLIL_REG, reg, size=size)

    	def reg_split(self, size, hi, lo):
    		"""
    		``reg_split`` combines registers of size ``size`` with names ``hi`` and ``lo``

    		:param int size: the size of the register in bytes
    		:param str hi: register holding high part of value
    		:param str lo: register holding low part of value
    		:return: The expression ``hi:lo``
    		:rtype: LowLevelILExpr
    		"""
    		hi = self.arch.get_reg_index(hi)
    		lo = self.arch.get_reg_index(lo)
    		return self.expr(LowLevelILOperation.LLIL_REG_SPLIT, hi, lo, size=size)

    	def reg_stack_top_relative(self, size, reg_stack, entry):
    		"""
    		``reg_stack_top_relative`` returns a register stack entry of size ``size`` at top-relative
    		location ``entry`` in register stack with name ``reg_stack``

    		:param int size: the size of the register in bytes
    		:param str reg_stack: the name of the register stack
    		:param LowLevelILExpr entry: an expression for which stack entry to fetch
    		:return: The expression ``reg_stack[entry]``
    		:rtype: LowLevelILExpr
    		"""
    		reg_stack = self.arch.get_reg_stack_index(reg_stack)
    		return self.expr(LowLevelILOperation.LLIL_REG_STACK_REL, reg_stack, entry.index, size=size)

    	def reg_stack_pop(self, size, reg_stack):
    		"""
    		``reg_stack_pop`` returns the top entry of size ``size`` in register stack with name ``reg_stack``, and
    		removes the entry from the stack

    		:param int size: the size of the register in bytes
    		:param str reg_stack: the name of the register stack
    		:return: The expression ``reg_stack.pop``
    		:rtype: LowLevelILExpr
    		"""
    		reg_stack = self.arch.get_reg_stack_index(reg_stack)
    		return self.expr(LowLevelILOperation.LLIL_REG_STACK_POP, reg_stack, size=size)

    	def const(self, size, value):
    		"""
    		``const`` returns an expression for the constant integer ``value`` with size ``size``

    		:param int size: the size of the constant in bytes
    		:param int value: integer value of the constant
    		:return: A constant expression of given value and size
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CONST, value, size=size)

    	def const_pointer(self, size, value):
    		"""
    		``const_pointer`` returns an expression for the constant pointer ``value`` with size ``size``

    		:param int size: the size of the pointer in bytes
    		:param int value: address referenced by pointer
    		:return: A constant expression of given value and size
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CONST_PTR, value, size=size)

    	def float_const_raw(self, size, value):
    		"""
    		``float_const_raw`` returns an expression for the constant raw binary floating point
    		value ``value`` with size ``size``

    		:param int size: the size of the constant in bytes
    		:param int value: integer value for the raw binary representation of the constant
    		:return: A constant expression of given value and size
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, value, size=size)

    	def float_const_single(self, value):
    		"""
    		``float_const_single`` returns an expression for the single precision floating point value ``value``

    		:param float value: float value for the constant
    		:return: A constant expression of given value and size
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, struct.unpack("I", struct.pack("f", value))[0], size=4)

    	def float_const_double(self, value):
    		"""
    		``float_const_double`` returns an expression for the double precision floating point value ``value``

    		:param float value: float value for the constant
    		:return: A constant expression of given value and size
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, struct.unpack("Q", struct.pack("d", value))[0], size=8)

    	def flag(self, reg):
    		"""
    		``flag`` returns a flag expression for the given flag name.

    		:param str reg: name of the flag expression to retrieve
    		:return: A flag expression of given flag name
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLAG, self.arch.get_flag_by_name(reg))

    	def flag_bit(self, size, reg, bit):
    		"""
    		``flag_bit`` sets the flag named ``reg`` and size ``size`` to the constant integer value ``bit``

    		:param int size: the size of the flag
    		:param str reg: flag value
    		:param int bit: integer value to set the bit to
    		:return: A constant expression of given value and size ``FLAG.reg = bit``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLAG_BIT, self.arch.get_flag_by_name(reg), bit, size=size)

    	def add(self, size, a, b, flags=None):
    		"""
    		``add`` adds expression ``a`` to expression ``b`` potentially setting flags ``flags`` and returning
    		an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``add.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ADD, a.index, b.index, size=size, flags=flags)

    	def add_carry(self, size, a, b, carry, flags=None):
    		"""
    		``add_carry`` adds with carry expression ``a`` to expression ``b`` potentially setting flags ``flags`` and
    		returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param LowLevelILExpr carry: Carry flag expression
    		:param str flags: flags to set
    		:return: The expression ``adc.<size>{<flags>}(a, b, carry)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ADC, a.index, b.index, carry.index, size=size, flags=flags)

    	def sub(self, size, a, b, flags=None):
    		"""
    		``sub`` subtracts expression ``b`` from expression ``a`` potentially setting flags ``flags`` and returning
    		an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``sub.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_SUB, a.index, b.index, size=size, flags=flags)

    	def sub_borrow(self, size, a, b, carry, flags=None):
    		"""
    		``sub_borrow`` subtracts with borrow expression ``b`` from expression ``a`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param LowLevelILExpr carry: Carry flag expression
    		:param str flags: flags to set
    		:return: The expression ``sbb.<size>{<flags>}(a, b, carry)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_SBB, a.index, b.index, carry.index, size=size, flags=flags)

    	def and_expr(self, size, a, b, flags=None):
    		"""
    		``and_expr`` bitwise and's expression ``a`` and expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``and.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_AND, a.index, b.index, size=size, flags=flags)

    	def or_expr(self, size, a, b, flags=None):
    		"""
    		``or_expr`` bitwise or's expression ``a`` and expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``or.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_OR, a.index, b.index, size=size, flags=flags)

    	def xor_expr(self, size, a, b, flags=None):
    		"""
    		``xor_expr`` xor's expression ``a`` with expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``xor.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_XOR, a.index, b.index, size=size, flags=flags)

    	def shift_left(self, size, a, b, flags=None):
    		"""
    		``shift_left`` subtracts with borrow expression ``b`` from expression ``a`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``lsl.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_LSL, a.index, b.index, size=size, flags=flags)

    	def logical_shift_right(self, size, a, b, flags=None):
    		"""
    		``logical_shift_right`` shifts logically right expression ``a`` by expression ``b`` potentially setting flags
    		``flags``and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``lsr.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_LSR, a.index, b.index, size=size, flags=flags)

    	def arith_shift_right(self, size, a, b, flags=None):
    		"""
    		``arith_shift_right`` shifts arithmatic right expression ``a`` by expression ``b``  potentially setting flags
    		``flags`` and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``asr.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ASR, a.index, b.index, size=size, flags=flags)

    	def rotate_left(self, size, a, b, flags=None):
    		"""
    		``rotate_left`` bitwise rotates left expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``rol.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ROL, a.index, b.index, size=size, flags=flags)

    	def rotate_left_carry(self, size, a, b, carry, flags=None):
    		"""
    		``rotate_left_carry`` bitwise rotates left with carry expression ``a`` by expression ``b`` potentially setting
    		flags ``flags`` and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param LowLevelILExpr carry: Carry flag expression
    		:param str flags: optional, flags to set
    		:return: The expression ``rlc.<size>{<flags>}(a, b, carry)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_RLC, a.index, b.index, carry.index, size=size, flags=flags)

    	def rotate_right(self, size, a, b, flags=None):
    		"""
    		``rotate_right`` bitwise rotates right expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``ror.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ROR, a.index, b.index, size=size, flags=flags)

    	def rotate_right_carry(self, size, a, b, carry, flags=None):
    		"""
    		``rotate_right_carry`` bitwise rotates right with carry expression ``a`` by expression ``b`` potentially setting
    		flags ``flags`` and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param LowLevelILExpr carry: Carry flag expression
    		:param str flags: optional, flags to set
    		:return: The expression ``rrc.<size>{<flags>}(a, b, carry)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_RRC, a.index, b.index, carry.index, size=size, flags=flags)

    	def mult(self, size, a, b, flags=None):
    		"""
    		``mult`` multiplies expression ``a`` by expression ``b`` potentially setting flags ``flags`` and returning an
    		expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``sbc.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MUL, a.index, b.index, size=size, flags=flags)

    	def mult_double_prec_signed(self, size, a, b, flags=None):
    		"""
    		``mult_double_prec_signed`` multiplies signed with double precision expression ``a`` by expression ``b``
    		potentially setting flags ``flags`` and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``muls.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MULS_DP, a.index, b.index, size=size, flags=flags)

    	def mult_double_prec_unsigned(self, size, a, b, flags=None):
    		"""
    		``mult_double_prec_unsigned`` multiplies unsigned with double precision expression ``a`` by expression ``b``
    		potentially setting flags ``flags`` and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``mulu.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size=size, flags=flags)

    	def div_signed(self, size, a, b, flags=None):
    		"""
    		``div_signed`` signed divide expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``divs.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags)

    	def div_double_prec_signed(self, size, a, b, flags=None):
    		"""
    		``div_double_prec_signed`` signed double precision divide using expression ``a`` as a
    		single double precision register by expression ``b`` potentially  setting flags ``flags`` and returning an
    		expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``divs.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_DIVS_DP, a.index, b.index, size=size, flags=flags)

    	def div_unsigned(self, size, a, b, flags=None):
    		"""
    		``div_unsigned`` unsigned divide expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``divu.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_DIVU, a.index, b.index, size=size, flags=flags)

    	def div_double_prec_unsigned(self, size, a, b, flags=None):
    		"""
    		``div_double_prec_unsigned`` unsigned double precision divide using expression ``a`` as
    		a single double precision register by expression ``b`` potentially  setting flags ``flags`` and returning an
    		expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``divu.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_DIVU_DP, a.index, b.index, size=size, flags=flags)

    	def mod_signed(self, size, a, b, flags=None):
    		"""
    		``mod_signed`` signed modulus expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``mods.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags)

    	def mod_double_prec_signed(self, size, a, b, flags=None):
    		"""
    		``mod_double_prec_signed`` signed double precision modulus using expression ``a`` as a single
    		double precision register by expression ``b`` potentially  setting flags ``flags`` and returning an expression
    		of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``mods.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MODS_DP, a.index, b.index, size=size, flags=flags)

    	def mod_unsigned(self, size, a, b, flags=None):
    		"""
    		``mod_unsigned`` unsigned modulus expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``modu.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MODU, a.index, b.index, size=size, flags=flags)

    	def mod_double_prec_unsigned(self, size, a, b, flags=None):
    		"""
    		``mod_double_prec_unsigned`` unsigned double precision modulus using expression ``a`` as
    		a single double precision register by expression ``b`` potentially  setting flags ``flags`` and returning an
    		expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: optional, flags to set
    		:return: The expression ``modu.dp.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_MODU_DP, a.index, b.index, size=size, flags=flags)

    	def neg_expr(self, size, value, flags=None):
    		"""
    		``neg_expr`` two's complement sign negation of expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``neg.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_NEG, value.index, size=size, flags=flags)

    	def not_expr(self, size, value, flags=None):
    		"""
    		``not_expr`` bitwise inverse of expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to bitwise invert
    		:param str flags: optional, flags to set
    		:return: The expression ``not.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_NOT, value.index, size=size, flags=flags)

    	def sign_extend(self, size, value, flags=None):
    		"""
    		``sign_extend`` two's complement sign-extends the expression in ``value`` to ``size`` bytes

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to sign extn
    		:param str flags: optional, flags to set
    		:return: The expression ``sx.<size>(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_SX, value.index, size=size, flags=flags)

    	def zero_extend(self, size, value, flags=None):
    		"""
    		``zero_extend`` zero-extends the expression in ``value`` to ``size`` bytes

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to zero extend
    		:return: The expression ``zx.<size>(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ZX, value.index, size=size, flags=flags)

    	def low_part(self, size, value, flags=None):
    		"""
    		``low_part`` truncates ``value`` to ``size`` bytes

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to zero extend
    		:return: The expression ``(value).<size>``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_LOW_PART, value.index, size=size, flags=flags)

    	def jump(self, dest):
    		"""
    		``jump`` returns an expression which jumps (branches) to the expression ``dest``

    		:param LowLevelILExpr dest: the expression to jump to
    		:return: The expression ``jump(dest)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_JUMP, dest.index)

    	def call(self, dest):
    		"""
    		``call`` returns an expression which first pushes the address of the next instruction onto the stack then jumps
    		(branches) to the expression ``dest``

    		:param LowLevelILExpr dest: the expression to call
    		:return: The expression ``call(dest)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CALL, dest.index)

    	def call_stack_adjust(self, dest, stack_adjust):
    		"""
    		``call_stack_adjust`` returns an expression which first pushes the address of the next instruction onto the stack
    		then jumps (branches) to the expression ``dest``. After the function exits, ``stack_adjust`` is added to the
    		stack pointer register.

    		:param LowLevelILExpr dest: the expression to call
    		:return: The expression ``call(dest), stack += stack_adjust``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CALL_STACK_ADJUST, dest.index, stack_adjust)

    	def tailcall(self, dest):
    		"""
    		``tailcall`` returns an expression which jumps (branches) to the expression ``dest``

    		:param LowLevelILExpr dest: the expression to jump to
    		:return: The expression ``tailcall(dest)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_TAILCALL, dest.index)

    	def ret(self, dest):
    		"""
    		``ret`` returns an expression which jumps (branches) to the expression ``dest``. ``ret`` is a special alias for
    		jump that makes the disassembler stop disassembling.

    		:param LowLevelILExpr dest: the expression to jump to
    		:return: The expression ``jump(dest)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_RET, dest.index)

    	def no_ret(self):
    		"""
    		``no_ret`` returns an expression halts disassembly

    		:return: The expression ``noreturn``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_NORET)

    	def flag_condition(self, cond, sem_class = None):
    		"""
    		``flag_condition`` returns a flag_condition expression for the given LowLevelILFlagCondition

    		:param LowLevelILFlagCondition cond: Flag condition expression to retrieve
    		:param str sem_class: Optional semantic flag class
    		:return: A flag_condition expression
    		:rtype: LowLevelILExpr
    		"""
    		if isinstance(cond, str):
    			cond = LowLevelILFlagCondition[cond]
    		elif isinstance(cond, LowLevelILFlagCondition):
    			cond = cond.value
    		class_index = self.arch.get_semantic_flag_class_index(sem_class)
    		return self.expr(LowLevelILOperation.LLIL_FLAG_COND, cond, class_index)

    	def flag_group(self, sem_group):
    		"""
    		``flag_group`` returns a flag_group expression for the given semantic flag group

    		:param str sem_group: Semantic flag group to access
    		:return: A flag_group expression
    		:rtype: LowLevelILExpr
    		"""
    		group = self.arch.get_semantic_flag_group_index(sem_group)
    		return self.expr(LowLevelILOperation.LLIL_FLAG_GROUP, group)

    	def compare_equal(self, size, a, b):
    		"""
    		``compare_equal`` returns comparison expression of size ``size`` checking if expression ``a`` is equal to
    		expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_E, a.index, b.index, size = size)

    	def compare_not_equal(self, size, a, b):
    		"""
    		``compare_not_equal`` returns comparison expression of size ``size`` checking if expression ``a`` is not equal to
    		expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_NE, a.index, b.index, size = size)

    	def compare_signed_less_than(self, size, a, b):
    		"""
    		``compare_signed_less_than`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		signed less than expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_SLT, a.index, b.index, size = size)

    	def compare_unsigned_less_than(self, size, a, b):
    		"""
    		``compare_unsigned_less_than`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		unsigned less than expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_ULT, a.index, b.index, size = size)

    	def compare_signed_less_equal(self, size, a, b):
    		"""
    		``compare_signed_less_equal`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		signed less than or equal to expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_SLE, a.index, b.index, size = size)

    	def compare_unsigned_less_equal(self, size, a, b):
    		"""
    		``compare_unsigned_less_equal`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		unsigned less than or equal to expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_ULE, a.index, b.index, size = size)

    	def compare_signed_greater_equal(self, size, a, b):
    		"""
    		``compare_signed_greater_equal`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		signed greater than or equal toexpression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_SGE, a.index, b.index, size = size)

    	def compare_unsigned_greater_equal(self, size, a, b):
    		"""
    		``compare_unsigned_greater_equal`` returns comparison expression of size ``size`` checking if expression ``a``
    		is unsigned greater than or equal to expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_UGE, a.index, b.index, size = size)

    	def compare_signed_greater_than(self, size, a, b):
    		"""
    		``compare_signed_greater_than`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		signed greater than or equal to expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_SGT, a.index, b.index, size = size)

    	def compare_unsigned_greater_than(self, size, a, b):
    		"""
    		``compare_unsigned_greater_than`` returns comparison expression of size ``size`` checking if expression ``a`` is
    		unsigned greater than or equal to expression ``b``

    		:param int size: size in bytes
    		:param LowLevelILExpr a: LHS of comparison
    		:param LowLevelILExpr b: RHS of comparison
    		:return: a comparison expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CMP_UGT, a.index, b.index, size = size)

    	def test_bit(self, size, a, b):
    		return self.expr(LowLevelILOperation.LLIL_TEST_BIT, a.index, b.index, size = size)

    	def system_call(self):
    		"""
    		``system_call`` return a system call expression.

    		:return: a system call expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_SYSCALL)

    	def intrinsic(self, outputs, intrinsic, params, flags=None):
    		"""
    		``intrinsic`` return an intrinsic expression.

    		:return: an intrinsic expression.
    		:rtype: LowLevelILExpr
    		"""
    		output_list = []
    		for output in outputs:
    			if isinstance(output, ILFlag):
    				output_list.append((1 << 32) | output.index)
    			else:
    				output_list.append(output.index)
    		param_list = []
    		for param in params:
    			param_list.append(param.index)
    		call_param = self.expr(LowLevelILOperation.LLIL_CALL_PARAM, len(params), self.add_operand_list(param_list).index)
    		return self.expr(LowLevelILOperation.LLIL_INTRINSIC, len(outputs), self.add_operand_list(output_list).index,
    			self.arch.get_intrinsic_index(intrinsic), call_param.index, flags = flags)

    	def breakpoint(self):
    		"""
    		``breakpoint`` returns a processor breakpoint expression.

    		:return: a breakpoint expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_BP)

    	def trap(self, value):
    		"""
    		``trap`` returns a processor trap (interrupt) expression of the given integer ``value``.

    		:param int value: trap (interrupt) number
    		:return: a trap expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_TRAP, value)

    	def undefined(self):
    		"""
    		``undefined`` returns the undefined expression. This should be used for instructions which perform functions but
    		aren't important for dataflow or partial emulation purposes.

    		:return: the unimplemented expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_UNDEF)

    	def unimplemented(self):
    		"""
    		``unimplemented`` returns the unimplemented expression. This should be used for all instructions which aren't
    		implemented.

    		:return: the unimplemented expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_UNIMPL)

    	def unimplemented_memory_ref(self, size, addr):
    		"""
    		``unimplemented_memory_ref`` a memory reference to expression ``addr`` of size ``size`` with unimplemented operation.

    		:param int size: size in bytes of the memory reference
    		:param LowLevelILExpr addr: expression to reference memory
    		:return: the unimplemented memory reference expression.
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr.index, size = size)

    	def float_add(self, size, a, b, flags=None):
    		"""
    		``float_add`` adds floating point expression ``a`` to expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``fadd.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FADD, a.index, b.index, size=size, flags=flags)

    	def float_sub(self, size, a, b, flags=None):
    		"""
    		``float_sub`` subtracts floating point expression ``b`` from expression ``a`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``fsub.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FSUB, a.index, b.index, size=size, flags=flags)

    	def float_mult(self, size, a, b, flags=None):
    		"""
    		``float_mult`` multiplies floating point expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``fmul.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FMUL, a.index, b.index, size=size, flags=flags)

    	def float_div(self, size, a, b, flags=None):
    		"""
    		``float_div`` divides floating point expression ``a`` by expression ``b`` potentially setting flags ``flags``
    		and returning an expression of ``size`` bytes.

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``fdiv.<size>{<flags>}(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FDIV, a.index, b.index, size=size, flags=flags)

    	def float_sqrt(self, size, value, flags=None):
    		"""
    		``float_sqrt`` returns square root of floating point expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``sqrt.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FSQRT, value.index, size=size, flags=flags)

    	def float_neg(self, size, value, flags=None):
    		"""
    		``float_neg`` returns sign negation of floating point expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``fneg.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FNEG, value.index, size=size, flags=flags)

    	def float_abs(self, size, value, flags=None):
    		"""
    		``float_abs`` returns absolute value of floating point expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``fabs.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FABS, value.index, size=size, flags=flags)

    	def float_to_int(self, size, value, flags=None):
    		"""
    		``float_to_int`` returns integer value of floating point expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``int.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOAT_TO_INT, value.index, size=size, flags=flags)

    	def int_to_float(self, size, value, flags=None):
    		"""
    		``int_to_float`` returns floating point value of integer expression ``value`` of size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``float.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_INT_TO_FLOAT, value.index, size=size, flags=flags)

    	def float_convert(self, size, value, flags=None):
    		"""
    		``int_to_float`` converts floating point value of expression ``value`` to size ``size`` potentially setting flags

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``fconvert.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOAT_CONV, value.index, size=size, flags=flags)

    	def round_to_int(self, size, value, flags=None):
    		"""
    		``round_to_int`` rounds a floating point value to the nearest integer

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``roundint.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_ROUND_TO_INT, value.index, size=size, flags=flags)

    	def floor(self, size, value, flags=None):
    		"""
    		``floor`` rounds a floating point value to an integer towards negative infinity

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``roundint.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FLOOR, value.index, size=size, flags=flags)

    	def ceil(self, size, value, flags=None):
    		"""
    		``ceil`` rounds a floating point value to an integer towards positive infinity

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``roundint.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_CEIL, value.index, size=size, flags=flags)

    	def float_trunc(self, size, value, flags=None):
    		"""
    		``float_trunc`` rounds a floating point value to an integer towards zero

    		:param int size: the size of the result in bytes
    		:param LowLevelILExpr value: the expression to negate
    		:param str flags: optional, flags to set
    		:return: The expression ``roundint.<size>{<flags>}(value)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FTRUNC, value.index, size=size, flags=flags)

    	def float_compare_equal(self, size, a, b):
    		"""
    		``float_compare_equal`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is equal to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f== b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_E, a.index, b.index)

    	def float_compare_not_equal(self, size, a, b):
    		"""
    		``float_compare_not_equal`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is not equal to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f!= b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_NE, a.index, b.index)

    	def float_compare_less_than(self, size, a, b):
    		"""
    		``float_compare_less_than`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is less than to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f< b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_LT, a.index, b.index)

    	def float_compare_less_equal(self, size, a, b):
    		"""
    		``float_compare_less_equal`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is less than or equal to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f<= b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_LE, a.index, b.index)

    	def float_compare_greater_equal(self, size, a, b):
    		"""
    		``float_compare_greater_equal`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is greater than or equal to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f>= b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_GE, a.index, b.index)

    	def float_compare_greater_than(self, size, a, b):
    		"""
    		``float_compare_greater_than`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is greater than or equal to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``a f> b``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_GT, a.index, b.index)

    	def float_compare_unordered(self, size, a, b):
    		"""
    		``float_compare_unordered`` returns floating point comparison expression of size ``size`` checking if
    		expression ``a`` is unordered relative to expression ``b``

    		:param int size: the size of the operands in bytes
    		:param LowLevelILExpr a: LHS expression
    		:param LowLevelILExpr b: RHS expression
    		:param str flags: flags to set
    		:return: The expression ``is_unordered(a, b)``
    		:rtype: LowLevelILExpr
    		"""
    		return self.expr(LowLevelILOperation.LLIL_FCMP_UO, a.index, b.index)

    	def goto(self, label):
    		"""
    		``goto`` returns a goto expression which jumps to the provided LowLevelILLabel.

    		:param LowLevelILLabel label: Label to jump to
    		:return: the LowLevelILExpr that jumps to the provided label
    		:rtype: LowLevelILExpr
    		"""
    		return LowLevelILExpr(core.BNLowLevelILGoto(self.handle, label.handle))

    	def if_expr(self, operand, t, f):
    		"""
    		``if_expr`` returns the ``if`` expression which depending on condition ``operand`` jumps to the LowLevelILLabel
    		``t`` when the condition expression ``operand`` is non-zero and ``f`` when it's zero.

    		:param LowLevelILExpr operand: comparison expression to evaluate.
    		:param LowLevelILLabel t: Label for the true branch
    		:param LowLevelILLabel f: Label for the false branch
    		:return: the LowLevelILExpr for the if expression
    		:rtype: LowLevelILExpr
    		"""
    		return LowLevelILExpr(core.BNLowLevelILIf(self.handle, operand.index, t.handle, f.handle))

    	def mark_label(self, label):
    		"""
    		``mark_label`` assigns a LowLevelILLabel to the current IL address.

    		:param LowLevelILLabel label:
    		:rtype: None
    		"""
    		core.BNLowLevelILMarkLabel(self.handle, label.handle)

    	def add_label_list(self, labels):
    		"""
    		``add_label_list`` returns a label list expression for the given list of LowLevelILLabel objects.

    		:param list(LowLevelILLabel) lables: the list of LowLevelILLabel to get a label list expression from
    		:return: the label list expression
    		:rtype: LowLevelILExpr
    		"""
    		label_list = (ctypes.POINTER(core.BNLowLevelILLabel) * len(labels))()
    		for i in range(len(labels)):
    			label_list[i] = labels[i].handle
    		return LowLevelILExpr(core.BNLowLevelILAddLabelList(self.handle, label_list, len(labels)))

    	def add_operand_list(self, operands):
    		"""
    		``add_operand_list`` returns an operand list expression for the given list of integer operands.

    		:param list(int) operands: list of operand numbers
    		:return: an operand list expression
    		:rtype: LowLevelILExpr
    		"""
    		operand_list = (ctypes.c_ulonglong * len(operands))()
    		for i in range(len(operands)):
    			operand_list[i] = operands[i]
    		return LowLevelILExpr(core.BNLowLevelILAddOperandList(self.handle, operand_list, len(operands)))

    	def operand(self, n, expr):
    		"""
    		``operand`` sets the operand number of the expression ``expr`` and passes back ``expr`` without modification.

    		:param int n:
    		:param LowLevelILExpr expr:
    		:return: returns the expression ``expr`` unmodified
    		:rtype: LowLevelILExpr
    		"""
    		core.BNLowLevelILSetExprSourceOperand(self.handle, expr.index, n)
    		return expr

    	def finalize(self):
    		"""
    		``finalize`` ends the function and computes the list of basic blocks.

    		:rtype: None
    		"""
    		core.BNFinalizeLowLevelILFunction(self.handle)

    	def add_label_for_address(self, arch, addr):
    		"""
    		``add_label_for_address`` adds a low-level IL label for the given architecture ``arch`` at the given virtual
    		address ``addr``

    		:param Architecture arch: Architecture to add labels for
    		:param int addr: the IL address to add a label at
    		"""
    		if arch is not None:
    			arch = arch.handle
    		core.BNAddLowLevelILLabelForAddress(self.handle, arch, addr)

    	def get_label_for_address(self, arch, addr):
    		"""
    		``get_label_for_address`` returns the LowLevelILLabel for the given Architecture ``arch`` and IL address ``addr``.

    		:param Architecture arch:
    		:param int addr: IL Address label to retrieve
    		:return: the LowLevelILLabel for the given IL address
    		:rtype: LowLevelILLabel
    		"""
    		if arch is not None:
    			arch = arch.handle
    		label = core.BNGetLowLevelILLabelForAddress(self.handle, arch, addr)
    		if label is None:
    			return None
    		return LowLevelILLabel(label)

    	def get_ssa_instruction_index(self, instr):
    		return core.BNGetLowLevelILSSAInstructionIndex(self.handle, instr)

    	def get_non_ssa_instruction_index(self, instr):
    		return core.BNGetLowLevelILNonSSAInstructionIndex(self.handle, instr)

    	def get_ssa_reg_definition(self, reg_ssa):
    		reg = self.arch.get_reg_index(reg_ssa.reg)
    		result = core.BNGetLowLevelILSSARegisterDefinition(self.handle, reg, reg_ssa.version)
    		if result >= core.BNGetLowLevelILInstructionCount(self.handle):
    			return None
    		return result

    	def get_ssa_flag_definition(self, flag_ssa):
    		flag = self.arch.get_flag_index(flag_ssa.flag)
    		result = core.BNGetLowLevelILSSAFlagDefinition(self.handle, flag, flag_ssa.version)
    		if result >= core.BNGetLowLevelILInstructionCount(self.handle):
    			return None
    		return result

    	def get_ssa_memory_definition(self, index):
    		result = core.BNGetLowLevelILSSAMemoryDefinition(self.handle, index)
    		if result >= core.BNGetLowLevelILInstructionCount(self.handle):
    			return None
    		return result

    	def get_ssa_reg_uses(self, reg_ssa):
    		reg = self.arch.get_reg_index(reg_ssa.reg)
    		count = ctypes.c_ulonglong()
    		instrs = core.BNGetLowLevelILSSARegisterUses(self.handle, reg, reg_ssa.version, count)
    		result = []
    		for i in range(0, count.value):
    			result.append(instrs[i])
    		core.BNFreeILInstructionList(instrs)
    		return result

    	def get_ssa_flag_uses(self, flag_ssa):
    		flag = self.arch.get_flag_index(flag_ssa.flag)
    		count = ctypes.c_ulonglong()
    		instrs = core.BNGetLowLevelILSSAFlagUses(self.handle, flag, flag_ssa.version, count)
    		result = []
    		for i in range(0, count.value):
    			result.append(instrs[i])
    		core.BNFreeILInstructionList(instrs)
    		return result

    	def get_ssa_memory_uses(self, index):
    		count = ctypes.c_ulonglong()
    		instrs = core.BNGetLowLevelILSSAMemoryUses(self.handle, index, count)
    		result = []
    		for i in range(0, count.value):
    			result.append(instrs[i])
    		core.BNFreeILInstructionList(instrs)
    		return result

    	def get_ssa_reg_value(self, reg_ssa):
    		reg = self.arch.get_reg_index(reg_ssa.reg)
    		value = core.BNGetLowLevelILSSARegisterValue(self.handle, reg, reg_ssa.version)
    		result = binaryninja.function.RegisterValue(self.arch, value)
    		return result

    	def get_ssa_flag_value(self, flag_ssa):
    		flag = self.arch.get_flag_index(flag_ssa.flag)
    		value = core.BNGetLowLevelILSSAFlagValue(self.handle, flag, flag_ssa.version)
    		result = binaryninja.function.RegisterValue(self.arch, value)
    		return result

    	def get_medium_level_il_instruction_index(self, instr):
    		med_il = self.medium_level_il
    		if med_il is None:
    			return None
    		result = core.BNGetMediumLevelILInstructionIndex(self.handle, instr)
    		if result >= core.BNGetMediumLevelILInstructionCount(med_il.handle):
    			return None
    		return result

    	def get_medium_level_il_expr_index(self, expr):
    		med_il = self.medium_level_il
    		if med_il is None:
    			return None
    		result = core.BNGetMediumLevelILExprIndex(self.handle, expr)
    		if result >= core.BNGetMediumLevelILExprCount(med_il.handle):
    			return None
    		return result

    	def get_mapped_medium_level_il_instruction_index(self, instr):
    		med_il = self.mapped_medium_level_il
    		if med_il is None:
    			return None
    		result = core.BNGetMappedMediumLevelILInstructionIndex(self.handle, instr)
    		if result >= core.BNGetMediumLevelILInstructionCount(med_il.handle):
    			return None
    		return result

    	def get_mapped_medium_level_il_expr_index(self, expr):
    		med_il = self.mapped_medium_level_il
    		if med_il is None:
    			return None
    		result = core.BNGetMappedMediumLevelILExprIndex(self.handle, expr)
    		if result >= core.BNGetMediumLevelILExprCount(med_il.handle):
    			return None
    		return result

    class LowLevelILBasicBlock(basicblock.BasicBlock):
    	def __init__(self, view, handle, owner):
    		super(LowLevelILBasicBlock, self).__init__(view, handle)
    		self.il_function = owner

    	def __iter__(self):
    		for idx in range(self.start, self.end):
    			yield self.il_function[idx]

    	def __getitem__(self, idx):
    		size = self.end - self.start
    		if idx > size or idx < -size:
    			raise IndexError("list index is out of range")
    		if idx >= 0:
    			return self.il_function[idx + self.start]
    		else:
    			return self.il_function[self.end + idx]

    	def _create_instance(self, view, handle):
    		"""Internal method by super to instantiante child instances"""
    		return LowLevelILBasicBlock(view, handle, self.il_function)

    	def __hash__(self):
    		return hash((self.start, self.end, self.il_function))

    def LLIL_TEMP(n):
    	return n | 0x80000000

    def LLIL_REG_IS_TEMP(n):
    	return (n & 0x80000000) != 0

    def LLIL_GET_TEMP_REG_INDEX(n):
    	return n & 0x7fffffff