示例#1
0
def compile_multi3(context):
    """
    Compile the multi3() helper function used by LLVM
    for 128-bit multiplication on 32-bit platforms.
    """
    codegen = context.codegen()
    library = codegen.create_library("multi3")

    ir_mod = library.create_ir_module("multi3")

    i64 = ir.IntType(64)
    i128 = ir.IntType(128)
    lower_mask = ir.Constant(i64, 0xffffffff)
    _32 = ir.Constant(i64, 32)
    _64 = ir.Constant(i128, 64)

    fn_type = ir.FunctionType(i128, [i128, i128])
    fn = ir.Function(ir_mod, fn_type, name="multi3")

    a, b = fn.args
    bb = fn.append_basic_block()
    builder = ir.IRBuilder(bb)

    # This implementation mimicks compiler-rt's.
    al = builder.trunc(a, i64)
    bl = builder.trunc(b, i64)
    ah = builder.trunc(builder.ashr(a, _64), i64)
    bh = builder.trunc(builder.ashr(b, _64), i64)

    # Compute {rh, rl} = al * bl   (unsigned 64-bit multiplication)
    # rl = (al & 0xffffffff) * (bl & 0xffffffff)
    rl = builder.mul(builder.and_(al, lower_mask),
                     builder.and_(bl, lower_mask))
    # t = rl >> 32
    t = builder.lshr(rl, _32)
    # rl &= 0xffffffff
    rl = builder.and_(rl, lower_mask)
    # t += (al >> 32) * (bl & 0xffffffff)
    t = builder.add(
        t, builder.mul(builder.lshr(al, _32), builder.and_(bl, lower_mask)))
    # rl += t << 32
    rl = builder.add(rl, builder.shl(t, _32))
    # rh = t >> 32
    rh = builder.lshr(t, _32)
    # t = rl >> 32
    t = builder.lshr(rl, _32)
    # rl &= 0xffffffff
    rl = builder.and_(rl, lower_mask)
    # t += (bl >> 32) * (al & 0xffffffff)
    t = builder.add(
        t, builder.mul(builder.lshr(bl, _32), builder.and_(al, lower_mask)))
    # rl += t << 32
    rl = builder.add(rl, builder.shl(t, _32))
    # rh += t >> 32
    rh = builder.add(rh, builder.lshr(t, _32))
    # rh += (al >> 32) * (bl >> 32)
    rh = builder.add(rh,
                     builder.mul(builder.lshr(al, _32), builder.lshr(bl, _32)))

    # rh += (bh * al) + (bl * ah)
    rh = builder.add(rh, builder.mul(bh, al))
    rh = builder.add(rh, builder.mul(bl, ah))

    # r = rl + (rh << 64)
    r = builder.zext(rl, i128)
    r = builder.add(r, builder.shl(builder.zext(rh, i128), _64))
    builder.ret(r)

    library.add_ir_module(ir_mod)
    library.finalize()

    return library
示例#2
0
def call_external_function():
    """
    调用foo.c的外部函数foo
    void foo(int a){
        printf("in foo: %d\n",a);
    }

    运行:make run1

        此函数会生成test.s汇编文件,Makefile中和foo.c文件一起组成可执行文件。

    奇怪的现象:
    1. ll.Block() 似乎不会生成块
    :return:
    """
    # 1.生成一个module
    module = ll.Module(name="call_external_function")

    # 2.定义函数类型
    function_type = ll.FunctionType(ll.IntType(32), [ll.IntType(32)])

    # 3.创建main函数块
    main_function_type = ll.FunctionType(ll.IntType(32), [ll.IntType(32)])
    main_func = ll.Function(module, main_function_type, name="main")

    bb_entry = main_func.append_basic_block()

    # function = ll.NamedValue(module, type=function_type, name="x")
    # llvm.load_library_permanently("/tmp/foo.so")

    # 4.插入函数调用
    builder = ll.IRBuilder()
    builder.position_at_end(bb_entry)

    # func = CFUNCTYPE(c_int, c_int)(foo_function)   # 失败的尝试
    # func = ll.GlobalVariable(module, function_type, 'func')  # 失败的尝试
    func = ll.Function(module, function_type, "foo")

    builder = ll.IRBuilder(bb_entry)

    a = builder.function.args[0]
    builder.call(func, [a])
    # builder.call(func, [ll.Constant(ll.IntType(32), 1)])

    # 5.main函数return
    builder.position_at_end(bb_entry)
    builder.ret(ll.Constant(ll.IntType(32), 1))

    # print(str(module))
    x_module = llvm.parse_assembly(str(module))

    # 还不明白这一行的意思
    target_machine = llvm.Target.from_default_triple().create_target_machine()

    with llvm.create_mcjit_compiler(x_module, target_machine) as ee:
        ee.finalize_object()

        # 保存汇编代码
        with open("main.s", "w") as f:
            f.write(target_machine.emit_assembly(x_module))

    return module
示例#3
0
def astToLLVM(jast):
    """
    Convert the input json encoded AST to LLVM code properly, using llvm-lite
    JSON jast: the AST in JSON form produced by the main Haskell routine
    Returns the new function name, and an ir module containing the LLVM code matching the input json encoded AST
    """
    # create a module for the output
    l_module = ir.Module(name=__file__)

    curBlock = jast
    parents = []
    knownFuncs = ["print", "seq"]
    funcs = []
    annotations = []
    # traverse the AST matching functions to their corresponding body contents
    """
    expression:
    Will contain a function.
    If it is built in, will have the tag "BuiltIn" and its "contents"
    Otherwise, will contain 3 fields: "function", "tag", "body"
    
    function:
    Will contain 2 fields: "annotation", "expression"
    
    body:
    Will contain 2 fields: "annotation", "expression"
    
    "Arrow" tag:
    Defines an input and output
    
    "Constructor" tag:
    Defines a type
    
    "Application" tag:
    Defines a function
    
    "BuiltIn" tag:
    Defines a function literal
    
    Perhaps the best way to go is look at the tag first, then decide what to do next
    
    """
    try:
        if (curBlock.get("Right")):
            curBlock = curBlock["Right"]["expression"]
            while (True):
                if (curBlock.get("function")):
                    parents.append(curBlock)
                    annot = curBlock["function"]["annotation"]
                    curBlock = curBlock["function"]["expression"]
                    if (annot["tag"] == "Arrow"):  #grab arrow types
                        arrow_in = "NONE"
                        arrow_out = "NONE"
                        if (annot["input"]["tag"] == "Constructor"):
                            arrow_in = annot["input"]["contents"]
                        else:
                            pass  #TODO figure out what goes here
                        if (annot["output"]["tag"] == "Constructor"):
                            arrow_out = annot["output"]["contents"]
                        else:
                            pass  #TODO figure out what goes here
                        if (arrow_in != "NONE" and arrow_out != "NONE"):
                            annotations.append((arrow_in, arrow_out))

                    if (curBlock["tag"] == "BuiltIn"):
                        if (curBlock["contents"] in knownFuncs):
                            funcs.append([curBlock["contents"]])
                else:
                    curBlock = parents.pop()
                    curBlock = curBlock["body"]["expression"]
                    if (curBlock["tag"] == "BuiltIn"):
                        funcs[-1].append(curBlock["contents"])
        else:  #error occurred
            pass
    except:
        print("finished parsing AST. discovered code:", funcs)
    #now each function matched with it's input/output type. Use for more complex compilation
    func_and_types = list(zip(funcs, annotations))
    # define llvm types
    l_int = ir.IntType(
        32
    )  # TODO: replace hard-coded int with a type extracted from the AST, once type info is merged in
    l_funcType = ir.FunctionType(l_int, [])
    #l_funcType = ir.FunctionType(l_int, [*([l_int]*len(funcArgs))]) # match number of function arguments
    # declare our new function
    funcName = "main"
    l_func = ir.Function(l_module, l_funcType, name=funcName)

    # function entry point
    block = l_func.append_basic_block(name="entry")
    # create a builder for constructing the function code
    builder = ir.IRBuilder(block)

    #add printing support if our code uses it anywhere
    if ("print" == f[0] for f in funcs):
        # Source: https://blog.usejournal.com/writing-your-own-programming-language-and-compiler-with-python-a468970ae6df
        voidptr_ty = ir.IntType(8).as_pointer()
        fmt = "%i \n\0"
        c_fmt = ir.Constant(ir.ArrayType(ir.IntType(8), len(fmt)),
                            bytearray(fmt.encode("utf8")))
        global_fmt = ir.GlobalVariable(l_module, c_fmt.type, name="fstr")
        global_fmt.linkage = 'internal'
        global_fmt.global_constant = True
        global_fmt.initializer = c_fmt
        fmt_arg = builder.bitcast(global_fmt, voidptr_ty)
        printf_ty = ir.FunctionType(ir.IntType(32), [voidptr_ty], var_arg=True)
        printf = ir.Function(l_module, printf_ty, name="printf")

    # now add the code from our ast
    for f in funcs:
        if (f[0] == "print"):
            if (getTypeFromStr(f[1]) == "int"):
                builder.call(
                    printf,
                    [fmt_arg, ir.Constant(ir.IntType(32), int(f[1]))])
            else:
                #TODO: printing non-int primitives
                pass

    # return 0
    builder.ret(l_int(0))

    return funcName, l_module
示例#4
0
def _generic_array(context,
                   builder,
                   shape,
                   dtype,
                   symbol_name,
                   addrspace,
                   can_dynsized=False):
    elemcount = reduce(operator.mul, shape, 1)

    # Check for valid shape for this type of allocation.
    # Only 1d arrays can be dynamic.
    dynamic_smem = elemcount <= 0 and can_dynsized and len(shape) == 1
    if elemcount <= 0 and not dynamic_smem:
        raise ValueError("array length <= 0")

    # Check that we support the requested dtype
    other_supported_type = isinstance(dtype, (types.Record, types.Boolean))
    if dtype not in types.number_domain and not other_supported_type:
        raise TypeError("unsupported type: %s" % dtype)

    lldtype = context.get_data_type(dtype)
    laryty = ir.ArrayType(lldtype, elemcount)

    if addrspace == nvvm.ADDRSPACE_LOCAL:
        # Special case local address space allocation to use alloca
        # NVVM is smart enough to only use local memory if no register is
        # available
        dataptr = cgutils.alloca_once(builder, laryty, name=symbol_name)
    else:
        lmod = builder.module

        # Create global variable in the requested address space
        gvmem = cgutils.add_global_variable(lmod, laryty, symbol_name,
                                            addrspace)
        # Specify alignment to avoid misalignment bug
        align = context.get_abi_sizeof(lldtype)
        # Alignment is required to be a power of 2 for shared memory. If it is
        # not a power of 2 (e.g. for a Record array) then round up accordingly.
        gvmem.align = 1 << (align - 1).bit_length()

        if dynamic_smem:
            gvmem.linkage = 'external'
        else:
            ## Comment out the following line to workaround a NVVM bug
            ## which generates a invalid symbol name when the linkage
            ## is internal and in some situation.
            ## See _get_unique_smem_id()
            # gvmem.linkage = lc.LINKAGE_INTERNAL

            gvmem.initializer = ir.Constant(laryty, ir.Undefined)

        # Convert to generic address-space
        conv = nvvmutils.insert_addrspace_conv(lmod, ir.IntType(8), addrspace)
        addrspaceptr = gvmem.bitcast(ir.PointerType(ir.IntType(8), addrspace))
        dataptr = builder.call(conv, [addrspaceptr])

    targetdata = _get_target_data(context)
    lldtype = context.get_data_type(dtype)
    itemsize = lldtype.get_abi_size(targetdata)

    # Compute strides
    laststride = itemsize
    rstrides = []
    for i, lastsize in enumerate(reversed(shape)):
        rstrides.append(laststride)
        laststride *= lastsize
    strides = [s for s in reversed(rstrides)]
    kstrides = [context.get_constant(types.intp, s) for s in strides]

    # Compute shape
    if dynamic_smem:
        # Compute the shape based on the dynamic shared memory configuration.
        # Unfortunately NVVM does not provide an intrinsic for the
        # %dynamic_smem_size register, so we must read it using inline
        # assembly.
        get_dynshared_size = ir.InlineAsm(ir.FunctionType(ir.IntType(32), []),
                                          "mov.u32 $0, %dynamic_smem_size;",
                                          '=r',
                                          side_effect=True)
        dynsmem_size = builder.zext(builder.call(get_dynshared_size, []),
                                    ir.IntType(64))
        # Only 1-D dynamic shared memory is supported so the following is a
        # sufficient construction of the shape
        kitemsize = context.get_constant(types.intp, itemsize)
        kshape = [builder.udiv(dynsmem_size, kitemsize)]
    else:
        kshape = [context.get_constant(types.intp, s) for s in shape]

    # Create array object
    ndim = len(shape)
    aryty = types.Array(dtype=dtype, ndim=ndim, layout='C')
    ary = context.make_array(aryty)(context, builder)

    context.populate_array(ary,
                           data=builder.bitcast(dataptr, ary.data.type),
                           shape=kshape,
                           strides=kstrides,
                           itemsize=context.get_constant(types.intp, itemsize),
                           meminfo=None)
    return ary._getvalue()
示例#5
0
文件: boxing.py 项目: gdementen/numba
def box_record(c, typ, val):
    # Note we will create a copy of the record
    # This is the only safe way.
    size = ir.Constant(ir.IntType(32), val.type.pointee.count)
    ptr = c.builder.bitcast(val, ir.PointerType(ir.IntType(8)))
    return c.pyapi.recreate_record(ptr, size, typ.dtype, c.env_manager)
示例#6
0
 def from_argument(self, builder, value):
     out = ir.Constant(self.get_value_type(), ir.Undefined)
     for i, v in enumerate(value):
         v = self._elem_model.from_argument(builder, v)
         out = builder.insert_value(out, v, [i])
     return out
示例#7
0
 def get_data(value):
     valid = get_valid(value)
     data = self.get(builder, value, "data")
     return builder.select(valid, data, ir.Constant(data.type, None))
示例#8
0
    def __init__(self, llvm_module, vex_procedure):

        if debug_mode:
            self.emit_print = logger_emit_print
        else:
            self.emit_print = nothing_emit_print

        assert (isinstance(llvm_module, LLVMModule))
        self._llvm_module = llvm_module

        self._arch = llvm_module._arch

        if self._arch.__repr__() != '<Arch AMD64 (LE)>':
            assert_verbose(False, getframeinfo(
                currentframe())), "No support for {} arch yet".format(
                    self._arch.__repr__())

        # this is a fancy way to get rax
        self._ret_register_name = self._arch.translate_register_name(
            self._arch.ret_offset)
        self._register_type = llvm_module._register_type
        self._proc_name = vex_procedure[IndexedProcedure.name]

        # we start with the out val - rax, it must be kept as a register
        self._used_register_names = [self._ret_register_name]
        # collect all "imported" registers - ones we think are read before written into,
        # along with type, they will be allocated and imported from arguments we create
        for block in vex_procedure[IndexedProcedure.blocks]:
            for inst in block[IndexedProcedure.Block.vex]:
                if isinstance(inst, pyvex.stmt.WrTmp) and isinstance(
                        inst.data, pyvex.expr.Get):
                    register_name = self._arch.translate_register_name(
                        inst.data.offset)
                    if register_name not in self._used_register_names:
                        if "I64" not in inst.data.ty:
                            # This means we encountered a float register usage..
                            if "_F" in inst.data.ty:
                                raise FloatException(
                                    inst,
                                    "Encountered a float register usage (proc={}"
                                    .format(self._proc_name))

                            # logging.debug(
                            #    "Got a non 64bit register in registers collection - {} (inst={}, proc={})".format(
                            #        inst.data.ty, inst, self._proc_name))

                            # assert_verbose(False, getframeinfo((currentframe())),
                            #               "Got a non 64bit register in registers collection")
                        self._used_register_names.append(register_name)

        # create the llvm function for the strand
        self._function = ir.Function(
            self._llvm_module,
            ir.types.FunctionType(llvm_module._register_type, []),
            vex_procedure[IndexedProcedure.name])

        # create a mapping register -> argument in the llvm function,
        # after we get the first bb, we will replace this pointer to the alloca var (which will store this val)

        self._argument_register_name_prefix = "arg."

        self._ret_register_index = -1
        for index, reg_name in enumerate(
                self._used_register_names):  # add the registers as arguments
            arg = ir.Argument(self._function, self._register_type,
                              self._argument_register_name_prefix + reg_name)
            self._function.args += (arg, )

            if reg_name == self._ret_register_name:
                # this is the index of the reg register
                self._ret_register_index = index

        def create_def_for_cond_func(xxx_todo_changeme):
            (name, number_of_params) = xxx_todo_changeme
            cond_func_type_copy = ir.types.FunctionType(
                self._register_type, [self._register_type] * number_of_params)
            logger.debug("Creating {} cond function, {} params".format(
                name, number_of_params))
            return ir.Function(
                self._llvm_module, cond_func_type_copy,
                self._proc_name + "." + name + "." + str(number_of_params))

        self._cond_functions_dict = AwareDefaultDict(create_def_for_cond_func)

        def create_called_function(xxx_todo_changeme1):
            # TODO: handle floating inputs..
            (name, number_of_d_regs, number_of_f_regs) = xxx_todo_changeme1
            called_function = ir.types.FunctionType(
                self._register_type, [self._register_type] * number_of_d_regs)
            logger.debug(
                "Creating {} called function ({} input registers)".format(
                    name, number_of_d_regs))
            return ir.Function(
                self._llvm_module, called_function,
                self._proc_name + "." + name + "." + str(number_of_d_regs))

        self._called_functions_dict = AwareDefaultDict(create_called_function)

        self._tmps = OrderedDict()
        self._calc_condition_args = {}

        logger.debug("Init ready, starting vex2llvm for {}".format(
            self._proc_name))

        # A list of all bbs we created dynamically
        self._dynamic_bbs = []

        # A dict of startEA -> block instance for all blocks already translated in this module
        self._original_bbs_ea = {}
        self._original_bbs_index = {}

        self._init_bb = self._function.append_basic_block("ob-1.initialize")
        # we need to alloca all the registers & put the input values..
        self._init_bb_builder = ir.IRBuilder(self._init_bb)
        self._stored_register_name_prefix = "sr."

        def alloca_register(register_name):
            return self._init_bb_builder.alloca(
                self._register_type,
                name="{}{}".format(self._stored_register_name_prefix,
                                   register_name))

        self._register_as_allocated_var = AwareDefaultDict(alloca_register)

        # we need this ptr to perform the store from calls along the way..
        self._ret_register_ptr = None
        for index, reg_name in enumerate(self._used_register_names):
            reg_store_ptr = self._register_as_allocated_var[reg_name]
            self._init_bb_builder.store(self._function.args[index],
                                        reg_store_ptr)
            if index == self._ret_register_index:
                self._ret_register_ptr = reg_store_ptr

        bb_0 = None
        # hack - create all bbs now to preserve order and to allow for entry bb (bb=0) to be appended first
        for block in vex_procedure[IndexedProcedure.blocks]:
            new_bb = self._function.append_basic_block("ob{}".format(
                block[IndexedProcedure.Block.index]))
            if bb_0 is None:
                bb_0 = new_bb

            self._original_bbs_ea[block[
                IndexedProcedure.start_address]] = new_bb
            self._original_bbs_index[block[
                IndexedProcedure.Block.index]] = new_bb

        # TODO: think if now that we have bb-1 we can just do normal order...
        # traverse blocks in reverse so we will always have a block to jump to when needed
        for block in reversed(vex_procedure[IndexedProcedure.blocks]):
            try:
                self._curbb_part = 0
                self._curr_irsb = block[IndexedProcedure.Block.irsb]
                self._curbb = self._original_bbs_index[block[
                    IndexedProcedure.Block.index]]
                self._bb_builder = ir.IRBuilder(self._curbb)
                self._cur_block = block
                self._cur_block_name = "ob{}".format(
                    block[IndexedProcedure.Block.index])
                self.tmp_prefix = "{}.t".format(self._cur_block_name)
                self.tmp_prefix_internal_counter = 0

                # copy all instructions, one by one
                for instruction in block[IndexedProcedure.Block.vex]:
                    logger.debug("VEX.in: " + str(instruction))
                    if getattr(instruction, 'tag', None) is None:
                        raise NotImplementedError("Call nimrod")
                    getattr(
                        self, '_copy_' + str(instruction.tag),
                        self._missing_instruction_implementation)(instruction)

                    # pyvex will do a if() {} exit and follow it with get(pc)..
                    if self._curbb.is_terminated:
                        break

                self._error_state = False
                logger.debug("Strand translating done, emitting ret")

                if not self._curbb.is_terminated:
                    if len(self._cur_block[
                            IndexedProcedure.Block.successor]) == 0:

                        # TODO: this is intel only syntax!

                        if "call" in block['dsm'][-1][1]:
                            # this is an error exit node (_abort/_exit etc.)
                            pass
                        elif any([
                                block['dsm'][-1][1].startswith(x)
                                for x in ["ret", "leave", "rep retn", "hlt"]
                        ]):
                            # why "rep retn"? -> http://repzret.org/p/repzret/
                            # this is a "normal" exit node
                            pass
                        elif block['dsm'][-1][1].startswith("jmp"):
                            # we have an unresolved jump table or indirect jump, or weird call as jump
                            split_inst = [
                                x for x in block['dsm'][-1][1].split(" ")
                                if len(x) > 0
                            ]
                            if len(split_inst) < 2:
                                # jmp eax OK, jmp short <some func> OK.
                                raise hell
                            else:
                                if split_inst[-1] in self._arch.registers:
                                    raise IndirectJump(
                                        block['dsm'][-1][1],
                                        "Incountered Indirect jump at bb end.")
                                elif split_inst[-1].startswith("_"):
                                    # this is a hack to detect jumps to imported procs
                                    pass
                                else:
                                    # TODO check that this is a jump to a func and not an offset.
                                    # for now pass
                                    pass
                        else:
                            # This is just any termination of a bb caused by IDA's error..
                            # e.g., gcc-5__Ou__apwal-0.4.5__apwal__sub_415AB0 => NOP
                            # e.g., gcc-5__Ou__apwal-0.4.5__apwal__sub_40D9C0 => XCH
                            raise SPAnalysisFail(
                                block['dsm'][-1][1],
                                "Encountered IDA-SP-ERROR at bb end.")

                        out_reg_val = self.emit_print(
                            self._bb_builder.load(self._ret_register_ptr))
                        self._bb_builder.ret(out_reg_val)
                    elif len(self._cur_block[
                            IndexedProcedure.Block.successor]) == 1:
                        # this is a fall through bb, we bridge it to the next bb
                        succ = str(self._cur_block[
                            IndexedProcedure.Block.successor][0])
                        try:
                            self._bb_builder.branch(
                                self._original_bbs_index[succ])
                        except KeyError as e:
                            raise CodeOutSideProcException(
                                "<no inst>",
                                "Looking for bb={} in proc {} (404)".format(
                                    succ, vex_procedure['full_name']))
                    else:
                        last_inst_dsm = block['dsm'][-1][1]
                        last_inst_addr = block['dsm'][-1][0]
                        dsm_split = last_inst_dsm.split(";")
                        dsm_has_comment = len(dsm_split) > 1

                        # tar__tar___update_archive has a pretty interesting case of multiple jumptables..
                        if dsm_has_comment and "switch" in dsm_split[1]:
                            my_index = int(block[IndexedProcedure.Block.index])
                            for pred_index in reversed(list(range(0,
                                                                  my_index))):
                                pred_block = vex_procedure[
                                    IndexedProcedure.blocks][pred_index]
                                if my_index in pred_block[
                                        IndexedProcedure.Block.successor]:
                                    other_succs = [
                                        x for x in pred_block[
                                            IndexedProcedure.Block.successor]
                                        if x != my_index
                                    ]
                                    break
                            else:
                                raise SwitchJumpException(
                                    block['dsm'][-1][1],
                                    "Switch case encountered - bad structure")

                            if len(other_succs) != 1:
                                raise SwitchJumpException(
                                    block['dsm'][-1][1],
                                    "Switch case encountered - bad default connection"
                                )
                            pred_last_inst_dsm = vex_procedure[
                                IndexedProcedure.
                                blocks][pred_index]['dsm'][-1][1]
                            pred_dsm_split = pred_last_inst_dsm.split(";")
                            pred_dsm_has_comment = len(pred_dsm_split) > 1

                            if not pred_dsm_has_comment or "default case" not in pred_dsm_split[
                                    1]:
                                raise SwitchJumpException(
                                    block['dsm'][-1][1],
                                    "Switch case encountered - bad default comment"
                                )

                            register_name = dsm_split[0].split(
                                "jmp")[1].strip()
                            loaded_reg = self.emit_print(
                                self._bb_builder.load(
                                    self.
                                    _register_as_allocated_var[register_name]))

                            switch_inst = self._bb_builder.switch(
                                loaded_reg,
                                self._original_bbs_index[str(other_succs[0])])
                            for switch_target in self._cur_block[
                                    IndexedProcedure.Block.successor]:
                                target_comment_dsm_line = \
                                    vex_procedure[IndexedProcedure.blocks][int(switch_target)]['dsm'][0][
                                        1].split(";")[1]

                                target_comment_dsm_line_split = [
                                    x for x in [
                                        str(x).strip() for x in
                                        target_comment_dsm_line.split(" ")
                                    ] if len(x) > 0
                                ]
                                # 0==jumptable, 1==addr of jumptable, 2+3=="cases <int> || <int,int>" || "deafult case"

                                # jumptable      0000000000426639 default case
                                # jumptable      0000000000426639 cases 1, 3
                                # jumptable      0000000000426639 cases 1-5, 8
                                # jumptable      0000000000426639 case 0

                                if target_comment_dsm_line_split[
                                        0] != "jumptable":
                                    raise SwitchJumpException(
                                        block['dsm'][-1][1],
                                        "Switch case encountered - jumptable out of place"
                                    )

                                jumptable_addr = int(
                                    target_comment_dsm_line_split[1], 16)

                                if jumptable_addr != last_inst_addr:
                                    raise SwitchJumpException(
                                        block['dsm'][-1][1],
                                        "Case confusion - jt={} vs case={}".
                                        format(last_inst_addr, jumptable_addr))

                                cases_ints = []
                                if target_comment_dsm_line_split[2] == "cases":
                                    cases_list = target_comment_dsm_line_split[
                                        3].split(",")
                                    for case_struct in cases_list:
                                        if "-" in case_struct:
                                            case_split = case_struct.split("-")
                                            cases_ints.extend(
                                                list(
                                                    range(
                                                        int(case_split[0]),
                                                        int(case_split[1]) +
                                                        1)))
                                        else:
                                            cases_ints.append(int(case_struct))
                                elif target_comment_dsm_line_split[
                                        2] == "default" and target_comment_dsm_line_split[
                                            3] == "case":
                                    pass
                                    # this happens some time when you have some ranges (i.e., 2-6) with holes (0-1 and 7)
                                    # example - get_status_for_err@wget
                                else:
                                    cases_ints.append(
                                        int(target_comment_dsm_line_split[3]))

                                for case_int in cases_ints:
                                    switch_inst.add_case(
                                        ir.Constant(self._register_type,
                                                    case_int),
                                        self._original_bbs_index[str(
                                            switch_target)])

                            self.emit_print(switch_inst)
                        else:
                            # what is this?!
                            raise hell

            except InstructionException as ie:
                self._function._set_name(self._function._get_name() +
                                         function_dropped_prefix)
                self._error_state = True
                raise

        # we finished creating all basic blocks, we now have all registers we used, we can connect bb-1 to bb0
        self._init_bb_builder.branch(bb_0)
示例#9
0
    def _copy_Ist_WrTmp(self, inst):
        my_tyenv = self._curr_irsb.get_stmt_irsb(inst)._tyenv
        for condition_arg in list(self._calc_condition_args.keys()):
            if condition_arg in list(map(str, extract_uses(inst, self._arch))):
                if isinstance(inst.data, pyvex.expr.Get):
                    self._calc_condition_args[str(extract_def(
                        inst))] = self._calc_condition_args[condition_arg]
                elif isinstance(inst.data, pyvex.expr.Binop) and \
                        inst.data.op.startswith("Iop_Or") and isinstance(inst.data.args[1], pyvex.expr.Const):
                    self._calc_condition_args[str(extract_def(inst))] = self._calc_condition_args[condition_arg] | \
                                                                        int(str(inst.data.args[1]), 16)

        if isinstance(inst.data, pyvex.expr.Get):
            register_as_input = self._register_as_allocated_var[
                self._arch.translate_register_name(inst.data.offset)]
            register_loaded_val = self._bb_builder.load(
                register_as_input, self.tmp_prefix + str(inst.tmp))
            self.emit_print(register_loaded_val)
            result_type = translate_var_type(inst.data.result_type(my_tyenv))
            if result_type.width == self._arch.bits:
                out_tmp = register_loaded_val
            else:
                # we need to convert, this is really a "!r?x" not "r?x?" (ie eax not rax)
                logger.debug(
                    "LLVM.EMIT: getting full register before trunc/ext - " +
                    str(register_loaded_val))
                out_tmp = self._var_width_helper(
                    register_loaded_val, result_type,
                    self.tmp_prefix + str(inst.tmp))

        elif isinstance(inst.data, pyvex.expr.GetI):
            raise FloatException(
                inst,
                "isinstance(inst.data, pyvex.expr.GetI):@_copy_Ist_WrTmp")
        elif isinstance(inst.data, pyvex.expr.Binop):
            args = inst.data.args
            assert (len(args) == 2)

            def do_binary_op(func):
                translated_args = list(map(self.get_translated_arg, args))
                return self.emit_print(
                    func(
                        translated_args[0],
                        self._var_width_helper(translated_args[1],
                                               translated_args[0].type),
                        self.tmp_prefix + str(inst.tmp)))

            if inst.data.op.startswith("Iop_Sub"):
                out_tmp = do_binary_op(self._bb_builder.sub)
            elif inst.data.op.startswith("Iop_Add"):
                out_tmp = do_binary_op(self._bb_builder.add)
            elif inst.data.op.startswith("Iop_And"):
                out_tmp = do_binary_op(self._bb_builder.and_)
            elif inst.data.op.startswith("Iop_Or"):
                out_tmp = do_binary_op(self._bb_builder.or_)
            elif inst.data.op.startswith("Iop_Shl"):
                out_tmp = do_binary_op(self._bb_builder.shl)
            elif inst.data.op.startswith("Iop_Shr"):
                out_tmp = do_binary_op(self._bb_builder.lshr)
            elif inst.data.op.startswith("Iop_Xor"):
                out_tmp = do_binary_op(self._bb_builder.xor)
            elif inst.data.op.startswith("Iop_Sar"):
                out_tmp = do_binary_op(self._bb_builder.ashr)
            elif inst.data.op.startswith("Iop_Mul"):
                if inst.data.op.startswith("Iop_Mull"):
                    # we need to do widening here and not in the binop because CMP has a result op of i1
                    # widening
                    translated_args = list(map(self.get_translated_arg, args))
                    res_type = translate_var_type(
                        inst.data.result_type(my_tyenv))
                    widen_translated_args = self._var_width_helper(
                        translated_args[0], res_type), self._var_width_helper(
                            translated_args[1], res_type)

                    out_tmp = self.emit_print(
                        self._bb_builder.mul(widen_translated_args[0],
                                             widen_translated_args[1],
                                             self.tmp_prefix + str(inst.tmp)))
                else:
                    out_tmp = do_binary_op(self._bb_builder.mul)
                    # elif inst.data.op.startswith("Iop_Div?"):
            elif inst.data.op.startswith("Iop_CmpORD"):
                """ CmpORD32{S,U} does PowerPC-style 3-way comparisons:
                        CmpORD32S(x,y) = 1<<3   if  x <s y
                                       = 1<<2   if  x >s y
                                       = 1<<1   if  x == y
                    and similarly the unsigned variant.
                """
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_Cmp"):
                cond_type = translate_cond_type(inst.data.op, inst)
                out_tmp = do_binary_op(
                    partial(self._bb_builder.icmp_signed, cond_type))
            elif inst.data.op.startswith("Iop_ExpCmp"):
                cond_type = translate_exp_cond_type(inst.data.op, inst)
                out_tmp = do_binary_op(
                    partial(self._bb_builder.icmp_signed, cond_type))
            elif inst.data.op.startswith("Iop_DivU"):
                out_tmp = do_binary_op(self._bb_builder.udiv)
            elif inst.data.op.startswith("Iop_DivS"):
                out_tmp = do_binary_op(self._bb_builder.sdiv)
            elif inst.data.op.startswith("Iop_Interleave"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_QAdd"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_QSub"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_DivMod"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_Avg"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_QNarrowBin"):
                # TODO: think what to do with this
                raise InstructionException(inst, "")
            elif inst.data.op.startswith("Iop_CasCmp"):
                # TODO: think what to do with this
                raise CASException(inst, "")
            elif "HLto" in inst.data.op:
                # TODO: think what to do with this
                raise FloatException(inst,
                                     "HLto in inst.data.op:@_copy_Ist_WrTmp")
            elif "toF" in inst.data.op:
                # TODO: think what to do with this
                raise FloatException(inst,
                                     "toF in inst.data.op:@_copy_Ist_WrTmp")
            elif SIMD_re.match(inst.data.op):
                raise VectorException(
                    inst, "SIMD_re.match(inst.data.op)@_copy_Ist_WrTmp")
            elif any([
                    inst.data.op.split("Iop_")[1].startswith(x)
                    for x in ["Min", "Max", "Perm"]
            ]):
                # Iop_Min8Ux8, #Iop_Max8Sx8, #Iop_Perm8x8
                raise InstructionException(inst, "")
            elif "Max" in inst.data.op:
                raise InstructionException(inst, "")
            else:
                raise NotImplementedError(
                    "Unknown vex Binary operator {}".format(inst.data.op))
        elif isinstance(inst.data, pyvex.expr.RdTmp):
            out_tmp = self._tmps[inst.data.tmp]
            logger.debug("LLVM.EMIT: Not emiting tmp assignment")
        elif isinstance(inst.data, pyvex.expr.Const):
            out_tmp = ir.Constant(
                translate_var_type(inst.data.result_type(my_tyenv)),
                inst.data.con.value)
        elif isinstance(inst.data, pyvex.expr.Load):
            translated_addr = self.get_translated_arg(inst.data.addr)

            addr = self._addr_helper(translated_addr,
                                     inst.data.result_type(my_tyenv))
            out_tmp = self.emit_print(
                self._bb_builder.load(addr, self.tmp_prefix + str(inst.tmp)))
        elif isinstance(inst.data, pyvex.expr.Unop):
            assert len(inst.data.args) == 1
            cast_match = cast_re.match(inst.data.op)
            if cast_match is not None:
                assert len(inst.data.args) == 1
                translated_value = self.get_translated_arg(inst.data.args[0])
                llvm_result_type = translate_var_type(
                    inst.data.result_type(my_tyenv))
                if translated_value.type.width < llvm_result_type.width:
                    if cast_match.groups()[2] == "U":
                        if cast_match.groups()[3] is not None:
                            pass
                        out_tmp = self.emit_print(
                            self._bb_builder.zext(
                                translated_value, llvm_result_type,
                                self.tmp_prefix + str(inst.tmp)))
                    else:
                        out_tmp = self.emit_print(
                            self._bb_builder.sext(
                                translated_value, llvm_result_type,
                                self.tmp_prefix + str(inst.tmp)))
                elif translated_value.type.width > llvm_result_type.width:
                    out_tmp = self.emit_print(
                        self._bb_builder.trunc(
                            translated_value, llvm_result_type,
                            self.tmp_prefix + str(inst.tmp)))
                else:
                    raise NotImplementedError("extend to same size?")
            elif inst.data.op.startswith("Iop_Not"):
                translated_value = self.get_translated_arg(inst.data.args[0])
                llvm_result_type = translate_var_type(
                    inst.data.result_type(my_tyenv))
                var_width_value = self._var_width_helper(
                    translated_value, llvm_result_type)
                out_tmp = self.emit_print(
                    self._bb_builder.neg(var_width_value,
                                         self.tmp_prefix + str(inst.tmp)))
            elif inst.data.op.startswith("Iop_Clz"):
                out_tmp = ir.Constant(
                    translate_var_type(inst.data.result_type(my_tyenv)), 0)
                logger.debug("LLVM.EMIT: side-stepping Iop_Clz")
            elif inst.data.op.startswith("Iop_Ctz"):
                out_tmp = ir.Constant(
                    translate_var_type(inst.data.result_type(my_tyenv)), 0)
                logger.debug("LLVM.EMIT: side-stepping Iop_Ctz")
            elif inst.data.op.startswith("Iop_Reinterp"):
                out_tmp = ir.Constant(
                    translate_var_type(inst.data.result_type(my_tyenv)), 0)
                logger.debug("LLVM.EMIT: side-stepping Iop_Reinterp")
            elif inst.data.op.startswith("Iop_Dup"):
                raise VectorException(
                    inst, "inst.data.op.startswith(Iop_Dup)@_copy_Ist_WrTmp")
            else:
                raise NotImplementedError("Unknown vex Unop {}".format(
                    inst.data.op))
        elif isinstance(inst.data, pyvex.expr.Triop):
            if inst.data.op.startswith("Iop_SetElem"):
                raise VectorException(
                    inst,
                    "inst.data.op.startswith(Iop_SetElem)@_copy_Ist_WrTmp")
            else:
                raise NotImplementedError("Unknown vex Triop {}".format(
                    inst.data.op))
        elif isinstance(inst.data, pyvex.expr.Qop):
            if inst.data.op.startswith("Iop_64x4toV256"):
                raise VectorException(
                    inst,
                    "inst.data.op.startswith(Iop_64x4toV256)@_copy_Ist_WrTmp")
            else:
                raise NotImplementedError("Unknown vex Qop {}".format(
                    inst.data.op))
        elif isinstance(inst.data, pyvex.expr.ITE):
            phi_var_type = translate_var_type(inst.data.result_type(my_tyenv))
            pred = self.get_translated_arg(inst.data.cond)
            bb = self._bb_builder.basic_block
            bb_prefix = "{}.{}".format(bb.name, self._curbb_part)
            bbif = self._bb_builder.append_basic_block(
                name=bb_prefix + '.if.' + self.tmp_prefix + str(inst.tmp))
            if_arg = self._var_width_helper(
                self.get_translated_arg(inst.data.iftrue), phi_var_type)
            bbelse = self._bb_builder.append_basic_block(
                name=bb_prefix + '.else.' + self.tmp_prefix + str(inst.tmp))
            else_arg = self._var_width_helper(
                self.get_translated_arg(inst.data.iffalse), phi_var_type)
            self._curbb_part += 1

            # in the move to python3 & new LLVM (3.8 -> 10) it seems the long name broke phi nodes
            # (created by multiple ITEs, e.g., in ydhms_diff@wget)
            bb_new_prefix = "ob{}.{}".format(self._cur_block['index'],
                                             self._curbb_part)
            bbend = self._bb_builder.append_basic_block(name=bb_new_prefix +
                                                        '.endif')

            self._dynamic_bbs.extend([bbif, bbelse, bbend])

            self.emit_print(self._bb_builder.cbranch(pred, bbif, bbelse))

            self._bb_builder.position_at_end(bbif)
            self.emit_print(bbif)
            self.emit_print(self._bb_builder.branch(bbend))
            self._bb_builder.position_at_end(bbelse)
            self.emit_print(bbif)
            self.emit_print(self._bb_builder.branch(bbend))

            self._bb_builder.position_at_end(bbend)
            self._curbb = bbend

            # builder was moved to the end basic block (then & otherwise are connected to it)
            phi = self._bb_builder.phi(phi_var_type,
                                       self.tmp_prefix + str(inst.tmp))

            phi.add_incoming(if_arg, bbif)
            phi.add_incoming(else_arg, bbelse)

            self.emit_print(phi)
            out_tmp = phi
        elif isinstance(inst.data, pyvex.expr.CCall):
            if inst.data.callee.name.startswith("amd64g"):
                translated_args = list(
                    map(self.get_translated_arg, inst.data.args))
                cond_func = self._cond_functions_dict[(inst.data.callee.name,
                                                       len(translated_args))]
                out_tmp = self.emit_print(
                    self._bb_builder.call(cond_func, translated_args,
                                          self.tmp_prefix + str(inst.tmp)))
            else:
                raise UnknownCallException(
                    inst, "Unknown call - " + str(inst.data.callee.name) +
                    "@_copy_Ist_WrTmp")

        else:
            raise NotImplementedError("Unknown op {} in Ist_WrTmp".format(
                inst.data))

        self._last_tmp = out_tmp
        self._tmps[inst.tmp] = out_tmp
示例#10
0
    def generate_declaration(self, n, status=0, motifiers=[]):
        """
            status == 0: allocate local
            status == 1: allocate global
            status == 2: return element type
        """
        typ = type(n)

        if typ == ast.IdentifierType:

            current = self.get_element(n.spec[0], None)
            decl = motifiers.pop(0)
            name = decl.name
            for m in motifiers:
                current = self.get_element(m, current)

            if status == 0:
                self.g_named_memory[n.name] = self.g_llvm_builder.alloca(current, name=name)
            elif status == 1:
                self.g_global_variable[name] = \
                    ir.GlobalVariable(self.g_llvm_module, current, name=name)
                self.g_global_variable[name].initializer = ir.Constant(current, None)
            elif status == 2:
                if len(motifiers) > 0 and type(motifiers[0]) == ast.FuncDecl:
                    function = ir.Function(self.g_llvm_module, current, name=name)
                    if motifiers[0].args:
                        paranames = [param.name for param in motifiers[0].args.params]
                        for arg, arg_name in zip(function.args, paranames):
                            arg.name = arg_name
                            # Add arguments to variable symbol table.
                            self.g_named_argument[arg_name] = arg
                            # Set signed extension for char
                            if isinstance(arg.type, ir.IntType) and arg.type.width == 8:
                                arg.add_attribute('signext')
                    self.g_named_function[name] = function
                    return function
                else:
                    return current

        elif typ == ast.Struct:
            context = self.g_llvm_module.context
            current = context.get_identified_type(n.name)

            # define struct
            if n.name not in self.g_type_define:
                self.g_type_define[n.name] = [ele.name for ele in n.decls]
                types = [self.generate_declaration(ele, status=2) for ele in n.decls]
                current.set_body(*types)

            decl = motifiers.pop(0)
            name = decl.name
            for m in motifiers:
                current = self.get_element(m, current)

            if status == 0:
                return current
            elif status == 1:
                self.g_global_variable[name] = \
                    ir.GlobalVariable(self.g_llvm_module, current, name=name)
                self.g_global_variable[name].initializer = ir.Constant(current, None)

            elif len(motifiers) > 0 and type(motifiers[0]) == ast.FuncDecl:
                function = ir.Function(self.g_llvm_module, current, name=name)
                paranames = [param.name for param in motifiers[0].args]
                for arg, arg_name in zip(function.args, paranames):
                    arg.name = arg_name
                    # Add arguments to variable symbol table.
                    self.g_named_argument[arg_name] = arg
                self.g_named_function[name] = function
                return function
            else:
                return current

        elif typ in {ast.ArrayDecl, ast.FuncDecl, ast.PtrDecl, ast.Decl}:
            return self.generate_declaration(n.type, status, motifiers+[n])
示例#11
0
def _python_list_to_native(typ, obj, c, size, listptr, errorptr):
    """
    Construct a new native list from a Python list.
    """
    def check_element_type(nth, itemobj, expected_typobj):
        typobj = nth.typeof(itemobj)
        # Check if *typobj* is NULL
        with c.builder.if_then(
                cgutils.is_null(c.builder, typobj),
                likely=False,
        ):
            c.builder.store(cgutils.true_bit, errorptr)
            loop.do_break()
        # Mandate that objects all have the same exact type
        type_mismatch = c.builder.icmp_signed('!=', typobj, expected_typobj)

        with c.builder.if_then(type_mismatch, likely=False):
            c.builder.store(cgutils.true_bit, errorptr)
            if IS_PY3:
                c.pyapi.err_format(
                    "PyExc_TypeError",
                    "can't unbox heterogeneous list: %S != %S",
                    expected_typobj,
                    typobj,
                )
            else:
                # Python2 doesn't have "%S" format string.
                c.pyapi.err_set_string(
                    "PyExc_TypeError",
                    "can't unbox heterogeneous list",
                )
            c.pyapi.decref(typobj)
            loop.do_break()
        c.pyapi.decref(typobj)

    # Allocate a new native list
    ok, list = listobj.ListInstance.allocate_ex(c.context, c.builder, typ,
                                                size)
    with c.builder.if_else(ok, likely=True) as (if_ok, if_not_ok):
        with if_ok:
            list.size = size
            zero = ir.Constant(size.type, 0)
            with c.builder.if_then(c.builder.icmp_signed('>', size, zero),
                                   likely=True):
                # Traverse Python list and unbox objects into native list
                with _NumbaTypeHelper(c) as nth:
                    # Note: *expected_typobj* can't be NULL
                    expected_typobj = nth.typeof(
                        c.pyapi.list_getitem(obj, zero))
                    with cgutils.for_range(c.builder, size) as loop:
                        itemobj = c.pyapi.list_getitem(obj, loop.index)
                        check_element_type(nth, itemobj, expected_typobj)
                        # XXX we don't call native cleanup for each
                        # list element, since that would require keeping
                        # of which unboxings have been successful.
                        native = c.unbox(typ.dtype, itemobj)
                        with c.builder.if_then(native.is_error, likely=False):
                            c.builder.store(cgutils.true_bit, errorptr)
                            loop.do_break()
                        # The reference is borrowed so incref=False
                        list.setitem(loop.index, native.value, incref=False)
                    c.pyapi.decref(expected_typobj)
            if typ.reflected:
                list.parent = obj
            # Stuff meminfo pointer into the Python object for
            # later reuse.
            with c.builder.if_then(c.builder.not_(c.builder.load(errorptr)),
                                   likely=False):
                c.pyapi.object_set_private_data(obj, list.meminfo)
            list.set_dirty(False)
            c.builder.store(list.value, listptr)

        with if_not_ok:
            c.builder.store(cgutils.true_bit, errorptr)

    # If an error occurred, drop the whole native list
    with c.builder.if_then(c.builder.load(errorptr)):
        c.context.nrt.decref(c.builder, typ, list.value)
示例#12
0
    def extern_function(self, n):
        """
            NOTE: since we don't have pre-processing, so we write hard code to support the following external
             functions: printf, gets, isdigital, atoi, memcpy, strlen
        """
        if n.name.name == 'printf':
            func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer()], var_arg=True)
            args = []
            for index, arg in enumerate(n.args.exprs):
                if index == 0:
                    args.append(self.visit(arg))
                else:
                    args.append(self.visit(arg, status=1))

            return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args

        if n.name.name == 'gets':
            func_type = ir.FunctionType(ir.IntType(32), [], var_arg=True)
            args = []
            for arg in n.args.exprs:
                zero = ir.Constant(ir.IntType(32), 0)
                ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True)
                args.append(ptr)

            return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args

        if n.name.name == 'isdigit':
            func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(32)], var_arg=False)
            args = []
            for arg in n.args.exprs:
                ext = self.g_llvm_builder.sext(self.visit(arg, status=1), ir.IntType(32))
                args.append(ext)
            return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args

        if n.name.name == 'atoi':
            func_type = ir.FunctionType(ir.IntType(32), [], var_arg=True)
            args = []
            for arg in n.args.exprs:
                zero = ir.Constant(ir.IntType(32), 0)
                ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True)
                args.append(ptr)

            return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args

        if n.name.name == 'memcpy':
            args = []
            for index, arg in enumerate(n.args.exprs):
                if index == 2:
                    args.append(self.visit(arg, status=1))
                else:
                    array_addr = self.visit(arg, status=0)
                    if isinstance(array_addr.type, ir.PointerType) and \
                            isinstance(array_addr.type.pointee, ir.ArrayType):
                        zero = ir.Constant(ir.IntType(32), 0)
                        array_addr = self.g_llvm_builder.gep(array_addr, [zero, zero], inbounds=True)
                    args.append(array_addr)
            args.append(ir.Constant(ir.IntType(32), 1))
            args.append(ir.Constant(ir.IntType(1), 0))

            pint8 = ir.PointerType(ir.IntType(8))
            k = self.g_llvm_module.declare_intrinsic('llvm.memcpy', [pint8, pint8, ir.IntType(32)]), args
            return k

        if n.name.name == 'strlen':
            func_type = ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer()], var_arg=False)
            args = []
            for arg in n.args.exprs:
                zero = ir.Constant(ir.IntType(32), 0)
                ptr = self.g_llvm_builder.gep(self.visit(arg, status=0), [zero, zero], inbounds=True)
                args.append(ptr)

            return self.g_llvm_module.declare_intrinsic(n.name.name, (), func_type), args
示例#13
0
llvm.initialize_native_target()
llvm.initialize_native_asmprinter()  # yes, even this one

module = ll.Module()

mainfn_type = ll.FunctionType(ll.IntType(64), [])

func = ll.Function(module, mainfn_type, name='main')

bb_entry = func.append_basic_block('entry')

builder = ll.IRBuilder()
builder.position_at_end(bb_entry)
# builder.ret(mulinstr)

ll.Constant(ll.IntType(64), 190)

stackint = builder.alloca(ll.IntType(64), name='myint')
builder.store(ll.Constant(stackint.type.pointee, 123), stackint)
myint = builder.load(stackint, 'myint')
builder.ret(myint)

# -------------------------------------------------------------------------------------------------------------------------
# fntype = ll.FunctionType(ll.IntType(32), [ll.IntType(32), ll.IntType(32)])
#
# module = ll.Module()
#
# func = ll.Function(module, fntype, name='foo')
# bb_entry = func.append_basic_block()
#
# builder = ll.IRBuilder()
示例#14
0
 def traverse(self, builder, value):
     data = self.get(builder, value, "data")
     valid = self.get(builder, value, "valid")
     data = builder.select(valid, data, ir.Constant(data.type, None))
     return [(self.get_type("data"), data), (self.get_type("valid"), valid)]
示例#15
0
 def visit_num(node):
     return ir.Constant(type_map[node.val_type], node.value)
示例#16
0
 def visit_Cst(self, e):
     return ll.Constant(IntType(e.nbits), e.n)
示例#17
0
  g = 10;
  h = 10.0;
  a = a + 10;
  b = b + h;

  return 0;
}
'''

# Cria o módulo.
module = ir.Module('meu_modulo.bc')

# Variável inteira global g
g = ir.GlobalVariable(module, ir.IntType(32), "g")
# Inicializa a variavel g
g.initializer = ir.Constant(ir.IntType(32), 0)
# Linkage = common
g.linkage = "common"
# Define o alinhamento em 4
g.align = 4

# Variável float global h
h = ir.GlobalVariable(module, ir.FloatType(), "h")
# Inicializa a variavel h
h.initializer = ir.Constant(ir.FloatType(), 0.0)
# Linkage = common
h.linkage = "common"
# Define o alinhamento em 4
h.align = 4

# Define o retorno da função main
示例#18
0
builder = ll.IRBuilder()
builder.position_at_end(bb_entry)

# 引数のx, y
x, y = func.args

# 変数a,b,c,dを定義
ptr_a = builder.alloca(i32)
ptr_b = builder.alloca(i32)
ptr_c = builder.alloca(i32)
ptr_d = builder.alloca(i32)

# store
builder.store(x, ptr_a)
builder.store(y, ptr_b)
builder.store(ll.Constant(i32, 1000), ptr_c)

# load
a = builder.load(ptr_a)
b = builder.load(ptr_b)
c = builder.load(ptr_c)

# またstore
builder.store(a, ptr_d)

# 加算して、Returnする
ret1 = builder.add(a, b, name="res")
ret2 = builder.add(ret1, c, name="res2")
ret3 = builder.add(ret2, builder.load(ptr_d), name="res3")
builder.ret(ret3)
示例#19
0
 def as_return(self, builder, value):
     elems = self._as("as_data", builder, value)
     struct = ir.Constant(self.get_data_type(), ir.Undefined)
     for i, el in enumerate(elems):
         struct = builder.insert_value(struct, el, [i])
     return struct
示例#20
0
def int_as_bool(context, builder, sig, args):
    [val] = args
    return builder.icmp_unsigned('!=', val, ir.Constant(val.type, 0))
示例#21
0
def g(node, mod):
    if isinstance(node, list):
        for stmt in node:
            code = g(stmt, mod)
        return None

    elif isinstance(node, Integer):
        return ir.Constant(int_type, int(node.value))

    elif isinstance(node, Float):
        return ir.Constant(float_type, float(node.value))

    elif isinstance(node, UnaryOp):
        nodetype = node.type
        llvmtype = mod.getllvmtype(nodetype)
        operand = g(node.operand, mod)
        op = node.op

        if nodetype == 'int':
            if op == '-':
                return mod.builder.sub(ir.Constant(llvmtype, 0), operand)

        elif nodetype == 'float':
            if op == '-':
                return mod.builder.fsub(ir.Constant(llvmtype, 0), operand)

    elif isinstance(node, Print):
        node_type = mod.gettype(node.expression)
        value = g(node.expression, mod)
        if node_type == 'int':
            return mod.builder.call(mod._printi, [value])
        elif node_type == 'float':
            return mod.builder.call(mod._printf, [value])
        else:
            raise RuntimeError(f"Cannot print expression {node}")

    elif isinstance(node, BinOp):
        leftval = g(node.left, mod)
        rightval = g(node.right, mod)
        lefttype = mod.gettype(node.left)

        if lefttype in {'int'}:
            if node.op == '+':
                return mod.builder.add(leftval, rightval)
            if node.op == '-':
                return mod.builder.sub(leftval, rightval)
            if node.op == '*':
                return mod.builder.mul(leftval, rightval)
            if node.op == '/':
                return mod.builder.sdiv(leftval, rightval)

        elif lefttype in {'float'}:
            if node.op == '+':
                return mod.builder.fadd(leftval, rightval)
            if node.op == '-':
                return mod.builder.fsub(leftval, rightval)
            if node.op == '*':
                return mod.builder.fmul(leftval, rightval)
            if node.op == '/':
                return mod.builder.fdiv(leftval, rightval)
        else:
            raise RuntimeError(f"Cannot evaluate BinOp operator {node}")

    elif isinstance(node, (DeclareConst, DeclareVar)):
        # Get node type and llvm type
        nodetype = mod.gettype(node)
        llvmtype = mod.getllvmtype(nodetype)

        # Declare variable with name, node.name
        var = mod.builder.alloca(llvmtype, name=node.name)

        if node.value:
            value = g(node.value, mod)
            mod.builder.store(value, var)
        mod.env[node.name] = var  # Store variable in environment

    elif isinstance(node, Load):
        return mod.builder.load(mod.env[node.location])

    else:
        raise RuntimeError(f"Can't generate code for {node}")
示例#22
0
def float_as_bool(context, builder, sig, args):
    [val] = args
    return builder.fcmp(lc.FCMP_UNE, val, ir.Constant(val.type, 0.0))
示例#23
0
class LLVMConstants:
    ZERO_INT = ir.Constant(LLVMTypes.T_INT, 0)
    ZERO_REAL = ir.Constant(LLVMTypes.T_REAL, 0)
    NIL = ir.Constant(LLVMTypes.T_NIL, 0)
示例#24
0
 def _codegen_NumberExprAST(self, node):
     return ir.Constant(ir.DoubleType(), float(node.val))
示例#25
0
文件: boxing.py 项目: gdementen/numba
def unbox_boolean(c, typ, obj):
    istrue = c.pyapi.object_istrue(obj)
    zero = ir.Constant(istrue.type, 0)
    val = c.builder.icmp_signed('!=', istrue, zero)
    return NativeValue(val, is_error=c.pyapi.c_api_error())
示例#26
0
    def _codegen_ForExprAST(self, node):
        # Output this as:
        #   var = alloca double
        #   ...
        #   start = startexpr
        #   store start -> var
        #   goto loop
        # loop:
        #   ...
        #   bodyexpr
        #   ...
        # loopend:
        #   step = stepexpr
        #   endcond = endexpr
        #   curvar = load var
        #   nextvariable = curvar + step
        #   store nextvar -> var
        #   br endcond, loop, afterloop
        # afterloop:

        # Create an alloca for the induction var. Save and restore location of
        # our builder because _create_entry_block_alloca may modify it (llvmlite
        # issue #44).
        saved_block = self.builder.block
        var_addr = self._create_entry_block_alloca(node.id_name)
        self.builder.position_at_end(saved_block)

        # Emit the start expr first, without the variable in scope. Store it
        # into the var.
        start_val = self._codegen(node.start_expr)
        self.builder.store(start_val, var_addr)
        loop_bb = self.builder.function.append_kalei_block('loop')

        # Insert an explicit fall through from the current block to loop_bb
        self.builder.branch(loop_bb)
        self.builder.position_at_start(loop_bb)

        # Within the loop, the variable now refers to our alloca slot. If it
        # shadows an existing variable, we'll have to restore, so save it now.
        old_var_addr = self.func_symtab.get(node.id_name)
        self.func_symtab[node.id_name] = var_addr

        # Emit the body of the loop. This, like any other expr, can change the
        # current BB. Note that we ignore the value computed by the body.
        body_val = self._codegen(node.body)

        # Compute the end condition
        endcond = self._codegen(node.end_expr)
        cmp = self.builder.fcmp_ordered(
            '!=', endcond, ir.Constant(ir.DoubleType(), 0.0),
            'loopcond')

        if node.step_expr is None:
            stepval = ir.Constant(ir.DoubleType(), 1.0)
        else:
            stepval = self._codegen(node.step_expr)
        cur_var = self.builder.load(var_addr, node.id_name)
        nextval = self.builder.fadd(cur_var, stepval, 'nextvar')
        self.builder.store(nextval, var_addr)

        # Create the 'after loop' block and insert it
        after_bb = self.builder.function.append_kalei_block('afterloop')

        # Insert the conditional branch into the end of loop_end_bb
        self.builder.cbranch(cmp, loop_bb, after_bb)

        # New code will be inserted into after_bb
        self.builder.position_at_start(after_bb)

        # Restore the old var address if it was shadowed.
        if old_var_addr is not None:
            self.func_symtab[node.id_name] = old_var_addr
        else:
            del self.func_symtab[node.id_name]

        # The 'for' expression always returns 0
        return ir.Constant(ir.DoubleType(), 0.0)
示例#27
0
def _const_int(code):
    return ir.Constant(errcode_t, code)
示例#28
0
 def stringz(string):
     n = len(string) + 1
     buf = bytearray((' ' * n).encode('ascii'))
     buf[-1] = 0
     buf[:-1] = string.encode('utf-8')
     return ir.Constant(ir.ArrayType(type_map[INT8], n), buf)
示例#29
0
from llvmlite import ir

from oxygen.compiler.base import type_map
from oxygen.grammar import *

ARRAY_INITIAL_CAPACITY = ir.Constant(type_map[INT], 16)

zero = ir.Constant(type_map[INT], 0)
one = ir.Constant(type_map[INT], 1)
two = ir.Constant(type_map[INT], 2)
eight = ir.Constant(type_map[INT], 8)
ten = ir.Constant(type_map[INT], 10)
zero_32 = ir.Constant(type_map[INT32], 0)
one_32 = ir.Constant(type_map[INT32], 1)
two_32 = ir.Constant(type_map[INT32], 2)

array_types = [type_map[INT]]


def define_builtins(self):
    str_struct = self.module.context.get_identified_type('i64.array')
    str_struct.name = 'i64.array'
    str_struct.type = OBJECT
    str_struct.set_body(type_map[INT], type_map[INT],
                        type_map[INT].as_pointer())

    self.define('str', str_struct)
    self.define('i64.array', str_struct)
    str_struct_ptr = str_struct.as_pointer()
    self.define('str_ptr', str_struct_ptr)
    type_map[STR] = str_struct
示例#30
0
def setitem_list(context, builder, sig, args):
    dest = ListInstance(context, builder, sig.args[0], args[0])
    src = ListInstance(context, builder, sig.args[2], args[2])

    slice = context.make_helper(builder, sig.args[1], args[1])
    slicing.guard_invalid_slice(context, builder, sig.args[1], slice)
    dest.fix_slice(slice)

    src_size = src.size
    avail_size = slicing.get_slice_length(builder, slice)
    size_delta = builder.sub(src.size, avail_size)

    zero = ir.Constant(size_delta.type, 0)
    one = ir.Constant(size_delta.type, 1)

    with builder.if_else(builder.icmp_signed('==', slice.step,
                                             one)) as (then, otherwise):
        with then:
            # Slice step == 1 => we can resize

            # Compute the real stop, e.g. for dest[2:0] = [...]
            real_stop = builder.add(slice.start, avail_size)
            # Size of the list tail, after the end of slice
            tail_size = builder.sub(dest.size, real_stop)

            with builder.if_then(builder.icmp_signed('>', size_delta, zero)):
                # Grow list then move list tail
                dest.resize(builder.add(dest.size, size_delta))
                dest.move(builder.add(real_stop, size_delta), real_stop,
                          tail_size)

            with builder.if_then(builder.icmp_signed('<', size_delta, zero)):
                # Move list tail then shrink list
                dest.move(builder.add(real_stop, size_delta), real_stop,
                          tail_size)
                dest.resize(builder.add(dest.size, size_delta))

            dest_offset = slice.start

            with cgutils.for_range(builder, src_size) as loop:
                value = src.getitem(loop.index)
                dest.setitem(builder.add(loop.index, dest_offset),
                             value,
                             incref=True)

        with otherwise:
            with builder.if_then(builder.icmp_signed('!=', size_delta, zero)):
                msg = "cannot resize extended list slice with step != 1"
                context.call_conv.return_user_exc(builder, ValueError, (msg, ))

            with cgutils.for_range_slice_generic(builder, slice.start,
                                                 slice.stop,
                                                 slice.step) as (pos_range,
                                                                 neg_range):
                with pos_range as (index, count):
                    value = src.getitem(count)
                    dest.setitem(index, value, incref=True)
                with neg_range as (index, count):
                    value = src.getitem(count)
                    dest.setitem(index, value, incref=True)

    return context.get_dummy_value()