from llvmlite import ir
import xml.etree.ElementTree as et

int32 = ir.IntType(32)
int64 = ir.IntType(64)
int1 = ir.IntType(1)
void_type = ir.VoidType()
function_names = []
registers, functions, uniques, extracts = {}, {}, {}, {}
internal_functions = {}
memory = {}
flags = ["ZF", "CF", "OF", "SF"]
pointers = ["RSP", "RIP", "RBP", "EBP", "ESP"]


def lift(filename):
    root = et.parse(filename).getroot()
    module = ir.Module(name="lifted")

    for register in root.find('globals').findall('register'):
        if register.get('name') in flags:
            var = ir.GlobalVariable(module, ir.IntType(1), register.get('name'))
            var.initializer = ir.Constant(ir.IntType(1), None)
            var.linkage = 'internal'
            registers[register.get('name')] = var
        elif register.get('name') in pointers:
            var = ir.GlobalVariable(module, ir.PointerType(ir.IntType(8)), register.get('name'))
            var.initializer = ir.Constant(ir.PointerType(ir.IntType(8)), None)
            var.linkage = 'internal'
            registers[register.get('name')] = var
        else:
            var = ir.GlobalVariable(module, ir.IntType(8 * int(register.get('size'))), register.get('name'))
            var.initializer = ir.Constant(ir.IntType(8 * int(register.get('size'))), None)
            var.linkage = 'internal'
            registers[register.get('name')] = var

    for memory_location in root.find('memory').findall('memory'):
        var = ir.GlobalVariable(module, ir.IntType(8 * int(memory_location.get('size'))), memory_location.get('name'))
        var.initializer = ir.Constant(ir.IntType(8 * int(memory_location.get('size'))), None)
        var.linkage = 'internal'
        memory[memory_location.get('name')] = var

    func_return = ir.VoidType()
    fnty = ir.FunctionType(func_return, [])
    ir_func = ir.Function(module, fnty, "intra_function_branch")
    internal_functions["intra_function_branch"] = ir_func

    func_return = ir.VoidType()
    fnty = ir.FunctionType(func_return, [])
    ir_func = ir.Function(module, fnty, "call_indirect")
    internal_functions["call_indirect"] = ir_func

    func_return = ir.VoidType()
    fnty = ir.FunctionType(func_return, [])
    ir_func = ir.Function(module, fnty, "bit_extraction")
    internal_functions["bit_extraction"] = ir_func

    for function in root.findall('function'):
        name = function.get('name')
        x = 1
        while name in function_names:
            name = name + "_" + str(x)
            x += 1
        function_names.append(name)
        address = function.get('address')
        functions[address] = [build_function(name, module), function]

    for address in functions:
        ir_func, function = functions[address]
        populate_func(ir_func, function)

    return module


def populate_func(ir_func, function):
    builders, blocks = build_cfg(function, ir_func)
    if blocks == {}:
        return
    populate_cfg(function, builders, blocks)


def build_function(name, module):
    func_return = ir.VoidType()
    fnty = ir.FunctionType(func_return, [])
    ir_func = ir.Function(module, fnty, name)
    return ir_func


def build_cfg(function, ir_func):
    builders, blocks = {}, {}
    instructions = function.find("instructions")
    if instructions:
        block = ir_func.append_basic_block("entry")
        blocks["entry"] = block
        builders["entry"] = ir.IRBuilder(block)
        for instruction in instructions:
            address = instruction.find("address").text
            block = ir_func.append_basic_block(address)
            blocks[address] = block
            builders[address] = ir.IRBuilder(block)
    return builders, blocks


# noinspection DuplicatedCode
def populate_cfg(function, builders, blocks):
    builder = builders["entry"]
    stack_size = 10 * 1024 * 1024
    stack = builder.alloca(ir.IntType(8), stack_size, name="stack")
    stack_top = builder.gep(stack, [ir.Constant(int64, stack_size - 8)], name="stack_top")
    builder.store(stack_top, registers["RSP"])
    builder.branch(list(blocks.values())[1])
    block_iterator = 1
    instr = 0
    quiter = False
    for instruction in function.find("instructions"):
        if quiter:
            break
        address = instruction.find("address").text
        if address in builders:
            builder = builders[address]
        pcodes = instruction.find("pcodes")
        pc = 0
        no_branch = True
        for pcode in pcodes:
            pc += 1
            mnemonic = pcode.find("name")
            if mnemonic.text == "COPY":
                output = pcode.find("output")
                if output.text in flags and pcode.find("input_0").get("storage") == "constant":
                    source = ir.Constant(ir.IntType(1), int(pcode.find("input_0").text, 0))
                else:
                    source = fetch_input_varnode(builder, pcode.find("input_0"))
                update_output(builder, pcode.find("output"), source)
            elif mnemonic.text == "LOAD":
                input_1 = pcode.find("input_1")
                output = pcode.find("output")
                rhs = fetch_input_varnode(builder, input_1)
                if input_1.get("storage") == "unique" and output.get("storage") == "unique":
                    # This is incorrect. This is treating it as a copy, should load the memory address in the input 1
                    update_output(builder, output, rhs)
                else:
                    if input_1.text in pointers:
                        rhs = builder.gep(rhs, [ir.Constant(int64, 0)])
                    result = builder.load(rhs)
                    update_output(builder, output, result)
            elif mnemonic.text == "STORE":
                input_1 = pcode.find("input_1")  # target
                input_2 = pcode.find("input_2")  # source
                rhs = fetch_input_varnode(builder, input_2)
                lhs = fetch_output_varnode(input_1)
                lhs2 = builder.gep(lhs, [ir.Constant(int64, 0)])
                if lhs2.type != rhs.type.as_pointer():
                    lhs2 = builder.bitcast(lhs2, rhs.type.as_pointer())
                builder.store(rhs, lhs2)
            elif mnemonic.text == "BRANCH":
                value = pcode.find("input_0").text[2:-2]
                if value in functions:
                    target = functions[value][0]
                    builder.call(target, [])
                elif value in blocks:
                    target = blocks[value]
                    builder.branch(target)
                    no_branch = False
                else:
                    # weird jump into some label in another function
                    # might be solved with callbr instruction?
                    builder.call(internal_functions["intra_function_branch"], [])
            elif mnemonic.text == "CBRANCH":
                true_target = blocks[pcode.find("input_0").text[2:-2]]
                false_target = list(blocks.values())[block_iterator + 1]
                condition = fetch_input_varnode(builder, pcode.find("input_1"))
                no_branch = False
                builder.cbranch(condition, true_target, false_target)
            elif mnemonic.text == "BRANCHIND":
                no_branch = False
                target = fetch_input_varnode(builder, pcode.find("input_0"))
                if not target.type.is_pointer:
                    target = builder.inttoptr(target, target.type.as_pointer())
                builder.branch_indirect(target)
            elif mnemonic.text == "CALL":
                target = functions[pcode.find("input_0").text[2:-2]][0]
                builder.call(target, [])
            elif mnemonic.text == "CALLIND":
                # target = pcode.find("input_0").text[2:-2]
                builder.call(internal_functions["call_indirect"], [])
            elif mnemonic.text == "USERDEFINED":
                raise Exception("Not implemented")
            elif mnemonic.text == "RETURN":
                input_1 = pcode.find("input_1")
                no_branch = False
                if input_1 is None:
                    builder.ret_void()
                else:
                    raise Exception("Return value being passed")
            elif mnemonic.text == "PIECE":
                raise Exception("PIECE operation needs to be tested")
            elif mnemonic.text == "SUBPIECE":
                output = pcode.find("output")
                input_0 = pcode.find("input_0")
                input_1 = pcode.find("input_1")
                if input_1.text == "0x0":
                    val = fetch_input_varnode(builder, input_0)
                    result = builder.trunc(val, ir.IntType(int(output.get("size")) * 8))
                    update_output(builder, output, result)
                else:
                    builder.call(internal_functions['bit_extraction'], [])
            elif mnemonic.text == "INT_EQUAL":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_unsigned('==', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_NOTEQUAL":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_unsigned('!=', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_LESS":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_unsigned('<', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_SLESS":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_signed('<', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_LESSEQUAL":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_unsigned('<=', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_SLESS_EQUAL":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.icmp_signed('<=', lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_ZEXT":
                rhs = fetch_input_varnode(builder, pcode.find("input_0"))
                if rhs.type.is_pointer:
                    rhs = builder.ptrtoint(rhs, rhs.type.pointee)
                output = builder.zext(rhs, ir.IntType(int(pcode.find("output").get("size")) * 8))
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_SEXT":
                rhs = fetch_input_varnode(builder, pcode.find("input_0"))
                if rhs.type.is_pointer:
                    rhs = builder.ptrtoint(rhs, rhs.type.pointee)
                output = builder.sext(rhs, ir.IntType(int(pcode.find("output").get("size")) * 8))
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_ADD":
                input_0 = pcode.find("input_0")
                input_1 = pcode.find("input_1")
                lhs = fetch_input_varnode(builder, input_0)
                rhs = fetch_input_varnode(builder, input_1)
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                if input_0.text in pointers and input_1.get("storage") == "constant":
                    result = builder.gep(lhs, [ir.Constant(int64, int(input_1.text, 16))])
                else:
                    lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                    result = builder.add(lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_SUB":
                input_0 = pcode.find("input_0")
                input_1 = pcode.find("input_1")
                lhs = fetch_input_varnode(builder, input_0)
                rhs = fetch_input_varnode(builder, input_1)
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                if input_0.text in pointers and input_1.get("storage") == "constant":
                    result = builder.gep(lhs, [ir.Constant(int64, -int(input_1.text, 16))])
                else:
                    lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                    result = builder.sub(lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_CARRY":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.uadd_with_overflow(lhs, rhs)
                result = builder.extract_value(result, 1)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_SCARRY":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.sadd_with_overflow(lhs, rhs)
                result = builder.extract_value(result, 1)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_SBORROW":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                lhs, rhs = int_comparison_check_inputs(builder, lhs, rhs)
                result = builder.sadd_with_overflow(lhs, rhs)
                result = builder.extract_value(result, 1)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_2COMP":
                val = fetch_input_varnode(builder, pcode.find("input_0"))
                result = builder.not_(val)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_NEGATE":
                val = fetch_input_varnode(builder, pcode.find("input_0"))
                result = builder.neg(val)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "INT_XOR":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.xor(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_AND":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.and_(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_OR":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.or_(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_LEFT":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = check_shift_inputs(builder, lhs, rhs, target)
                output = builder.shl(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_RIGHT":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = check_shift_inputs(builder, lhs, rhs, target)
                output = builder.lshr(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_SRIGHT":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = check_shift_inputs(builder, lhs, rhs, target)
                output = builder.ashr(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_MULT":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.mul(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_DIV":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.div(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_REM":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.urem(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_SDIV":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.sdiv(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "INT_SREM":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                target = ir.IntType(int(pcode.find("output").get("size")) * 8)
                lhs, rhs = int_check_inputs(builder, lhs, rhs, target)
                output = builder.srem(lhs, rhs)
                update_output(builder, pcode.find("output"), output)
            elif mnemonic.text == "BOOL_NEGATE":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                result = builder.neg(lhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "BOOL_XOR":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                result = builder.xor(lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "BOOL_AND":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                result = builder.and_(lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "BOOL_OR":
                lhs = fetch_input_varnode(builder, pcode.find("input_0"))
                rhs = fetch_input_varnode(builder, pcode.find("input_1"))
                result = builder.or_(lhs, rhs)
                update_output(builder, pcode.find("output"), result)
            elif mnemonic.text == "FLOAT_EQUAL":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_NOTEQUAL":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_LESS":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_LESSEQUAL":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_ADD":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_SUB":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_MULT":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_DIV":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_NEG":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_ABS":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_SQRT":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_CEIL":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_FLOOR":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_ROUND":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT_NAN":
                raise Exception("Not implemented")
            elif mnemonic.text == "INT2FLOAT":
                raise Exception("Not implemented")
            elif mnemonic.text == "FLOAT2FLOAT":
                raise Exception("Not implemented")
            elif mnemonic.text == "TRUNC":
                raise Exception("Not implemented")
            elif mnemonic.text == "CPOOLREF":
                raise Exception("Not implemented")
            elif mnemonic.text == "NEW":
                raise Exception("Not implemented")
            elif mnemonic.text == "MULTIEQUAL":
                raise Exception("Not implemented")
            elif mnemonic.text == "INDIRECT":
                raise Exception("Not implemented")
            elif mnemonic.text == "PTRADD":
                raise Exception("Not implemented")
            elif mnemonic.text == "PTRSUB":
                raise Exception("Not implemented")
            elif mnemonic.text == "CAST":
                raise Exception("Not implemented")
            else:
                raise Exception("Not a standard pcode instruction")
        block_iterator += 1
        instr += 1
        if block_iterator < len(blocks) and no_branch:
            builder.branch(list(blocks.values())[block_iterator])


def fetch_input_varnode(builder, name):
    var_type = name.get("storage")
    var_size = int(name.get("size")) * 8
    if var_type == "register":
        return builder.load(registers[name.text])
    elif var_type == "unique":
        if name.text not in list(uniques.keys()):
            raise Exception("Temporary variable referenced before defined")
        return uniques[name.text]
    elif var_type == "constant":
        var = ir.Constant(ir.IntType(var_size), int(name.text, 0))
        return var
    elif var_type == "memory":
        return memory[name.text]



def update_output(builder, name, output):
    var_type = name.get("storage")
    if var_type == "register":
        reg = registers[name.text]
        if reg.type != output.type.as_pointer():
            reg = builder.bitcast(reg, output.type.as_pointer())
        builder.store(output, reg)
    elif var_type == "unique":
        uniques[name.text] = output


def fetch_output_varnode(name):
    var_type = name.get("storage")
    if var_type == "register":
        return registers[name.text]
    elif var_type == "unique":
        if name.text not in uniques:
            uniques[name.text] = None
        return uniques[name.text]


def int_check_inputs(builder, lhs, rhs, target):
    if lhs.type != target:
        if lhs.type.is_pointer:
            lhs2 = lhs
            lhs = builder.ptrtoint(lhs, target)
            if lhs2 == rhs:
                rhs = lhs
    if rhs.type != target and lhs != rhs:
        if rhs.type.is_pointer:
            rhs = builder.ptrtoint(rhs, target)
    return lhs, rhs


def check_shift_inputs(builder, lhs, rhs, target):
    if lhs.type != target:
        if lhs.type.is_pointer:
            lhs = builder.ptrtoint(lhs, target)
        else:
            lhs = builder.zext(lhs, target)
    if rhs.type != target:
        if rhs.type.is_pointer:
            rhs = builder.ptrtoint(rhs, target)
        else:
            rhs = builder.zext(rhs, target)

    return lhs, rhs


def int_comparison_check_inputs(builder, lhs, rhs):
    # For integer comparison operations. We assume rhs is the correct type.
    if lhs.type.is_pointer:
        lhs = builder.ptrtoint(lhs, rhs.type)
    return lhs, rhs
[((4, 8, 4, 22), 'llvmlite.ir.IntType', 'ir.IntType', ({(4, 19, 4, 21): '32'}, {}), '(32)', False, 'from llvmlite import ir\n'), ((5, 8, 5, 22), 'llvmlite.ir.IntType', 'ir.IntType', ({(5, 19, 5, 21): '64'}, {}), '(64)', False, 'from llvmlite import ir\n'), ((6, 7, 6, 20), 'llvmlite.ir.IntType', 'ir.IntType', ({(6, 18, 6, 19): '1'}, {}), '(1)', False, 'from llvmlite import ir\n'), ((7, 12, 7, 25), 'llvmlite.ir.VoidType', 'ir.VoidType', ({}, {}), '()', False, 'from llvmlite import ir\n'), ((18, 13, 18, 37), 'llvmlite.ir.Module', 'ir.Module', (), '', False, 'from llvmlite import ir\n'), ((43, 18, 43, 31), 'llvmlite.ir.VoidType', 'ir.VoidType', ({}, {}), '()', False, 'from llvmlite import ir\n'), ((44, 11, 44, 43), 'llvmlite.ir.FunctionType', 'ir.FunctionType', ({(44, 27, 44, 38): 'func_return', (44, 40, 44, 42): '[]'}, {}), '(func_return, [])', False, 'from llvmlite import ir\n'), ((45, 14, 45, 64), 'llvmlite.ir.Function', 'ir.Function', ({(45, 26, 45, 32): 'module', (45, 34, 45, 38): 'fnty', (45, 40, 45, 63): '"""intra_function_branch"""'}, {}), "(module, fnty, 'intra_function_branch')", False, 'from llvmlite import ir\n'), ((48, 18, 48, 31), 'llvmlite.ir.VoidType', 'ir.VoidType', ({}, {}), '()', False, 'from llvmlite import ir\n'), ((49, 11, 49, 43), 'llvmlite.ir.FunctionType', 'ir.FunctionType', ({(49, 27, 49, 38): 'func_return', (49, 40, 49, 42): '[]'}, {}), '(func_return, [])', False, 'from llvmlite import ir\n'), ((50, 14, 50, 56), 'llvmlite.ir.Function', 'ir.Function', ({(50, 26, 50, 32): 'module', (50, 34, 50, 38): 'fnty', (50, 40, 50, 55): '"""call_indirect"""'}, {}), "(module, fnty, 'call_indirect')", False, 'from llvmlite import ir\n'), ((53, 18, 53, 31), 'llvmlite.ir.VoidType', 'ir.VoidType', ({}, {}), '()', False, 'from llvmlite import ir\n'), ((54, 11, 54, 43), 'llvmlite.ir.FunctionType', 'ir.FunctionType', ({(54, 27, 54, 38): 'func_return', (54, 40, 54, 42): '[]'}, {}), '(func_return, [])', False, 'from llvmlite import ir\n'), ((55, 14, 55, 57), 'llvmlite.ir.Function', 'ir.Function', ({(55, 26, 55, 32): 'module', (55, 34, 55, 38): 'fnty', (55, 40, 55, 56): '"""bit_extraction"""'}, {}), "(module, fnty, 'bit_extraction')", False, 'from llvmlite import ir\n'), ((83, 18, 83, 31), 'llvmlite.ir.VoidType', 'ir.VoidType', ({}, {}), '()', False, 'from llvmlite import ir\n'), ((84, 11, 84, 43), 'llvmlite.ir.FunctionType', 'ir.FunctionType', ({(84, 27, 84, 38): 'func_return', (84, 40, 84, 42): '[]'}, {}), '(func_return, [])', False, 'from llvmlite import ir\n'), ((85, 14, 85, 45), 'llvmlite.ir.Function', 'ir.Function', ({(85, 26, 85, 32): 'module', (85, 34, 85, 38): 'fnty', (85, 40, 85, 44): 'name'}, {}), '(module, fnty, name)', False, 'from llvmlite import ir\n'), ((95, 28, 95, 47), 'llvmlite.ir.IRBuilder', 'ir.IRBuilder', ({(95, 41, 95, 46): 'block'}, {}), '(block)', False, 'from llvmlite import ir\n'), ((108, 27, 108, 40), 'llvmlite.ir.IntType', 'ir.IntType', ({(108, 38, 108, 39): '8'}, {}), '(8)', False, 'from llvmlite import ir\n'), ((17, 11, 17, 29), 'xml.etree.ElementTree.parse', 'et.parse', ({(17, 20, 17, 28): 'filename'}, {}), '(filename)', True, 'import xml.etree.ElementTree as et\n'), ((100, 32, 100, 51), 'llvmlite.ir.IRBuilder', 'ir.IRBuilder', ({(100, 45, 100, 50): 'block'}, {}), '(block)', False, 'from llvmlite import ir\n'), ((109, 36, 109, 70), 'llvmlite.ir.Constant', 'ir.Constant', ({(109, 48, 109, 53): 'int64', (109, 55, 109, 69): 'stack_size - 8'}, {}), '(int64, stack_size - 8)', False, 'from llvmlite import ir\n'), ((22, 44, 22, 57), 'llvmlite.ir.IntType', 'ir.IntType', ({(22, 55, 22, 56): '1'}, {}), '(1)', False, 'from llvmlite import ir\n'), ((23, 42, 23, 55), 'llvmlite.ir.IntType', 'ir.IntType', ({(23, 53, 23, 54): '1'}, {}), '(1)', False, 'from llvmlite import ir\n'), ((472, 26, 472, 46), 'llvmlite.ir.IntType', 'ir.IntType', ({(472, 37, 472, 45): 'var_size'}, {}), '(var_size)', False, 'from llvmlite import ir\n'), ((27, 59, 27, 72), 'llvmlite.ir.IntType', 'ir.IntType', ({(27, 70, 27, 71): '8'}, {}), '(8)', False, 'from llvmlite import ir\n'), ((28, 57, 28, 70), 'llvmlite.ir.IntType', 'ir.IntType', ({(28, 68, 28, 69): '8'}, {}), '(8)', False, 'from llvmlite import ir\n'), ((130, 41, 130, 54), 'llvmlite.ir.IntType', 'ir.IntType', ({(130, 52, 130, 53): '1'}, {}), '(1)', False, 'from llvmlite import ir\n'), ((151, 41, 151, 62), 'llvmlite.ir.Constant', 'ir.Constant', ({(151, 53, 151, 58): 'int64', (151, 60, 151, 61): '0'}, {}), '(int64, 0)', False, 'from llvmlite import ir\n'), ((143, 48, 143, 69), 'llvmlite.ir.Constant', 'ir.Constant', ({(143, 60, 143, 65): 'int64', (143, 67, 143, 68): '0'}, {}), '(int64, 0)', False, 'from llvmlite import ir\n')]