예제 #1
0
def Translate(mod: wasm.Module, addr_type: o.DK) -> ir.Unit:
    table_import = mod.sections.get(wasm.SECTION_ID.IMPORT)
    for i in table_import.items:
        assert isinstance(i, wasm.Import)
        assert isinstance(i.desc,
                          wasm.TypeIdx), f"cannot handle strange imports: {i}"

    bit_width = addr_type.bitwidth()
    unit = ir.Unit("unit")

    global_argv = unit.AddMem(
        ir.Mem("global_argv", 2 * bit_width // 8, o.MEM_KIND.RW))
    global_argv.AddData(ir.DataBytes(bit_width // 8, b"\0"))

    global_argc = unit.AddMem(ir.Mem("global_argc", 4, o.MEM_KIND.RW))
    global_argc.AddData(ir.DataBytes(4, b"\0"))

    memcpy = GenerateMemcpyFun(unit, addr_type)
    init_global = GenerateInitGlobalVarsFun(mod, unit, addr_type)
    init_data = GenerateInitDataFun(mod, unit, memcpy, addr_type)
    unit.AddFun(ir.Fun("__wasi_init", o.FUN_KIND.EXTERN, [], []))
    unit.AddFun(
        ir.Fun("__memory_grow", o.FUN_KIND.EXTERN, [o.DK.S32], [o.DK.S32]))

    main = None
    for wasm_fun in mod.functions:
        # forward declare everything since we cannot rely on a topological sort of the funs
        if isinstance(wasm_fun.impl, wasm.Import):
            assert wasm_fun.name in WASI_FUNCTIONS, f"unimplemented external function: {wasm_fun.name}"
        arguments = [addr_type] + TranslateTypeList(wasm_fun.func_type.args)
        returns = TranslateTypeList(wasm_fun.func_type.rets)
        # assert len(returns) <= 1
        unit.AddFun(
            ir.Fun(wasm_fun.name, o.FUN_KIND.EXTERN, returns, arguments))

    global_table = MaybeMakeGlobalTable(mod, unit, addr_type)

    for wasm_fun in mod.functions:
        if isinstance(wasm_fun.impl, wasm.Import):
            continue
        fun = unit.GetFun(wasm_fun.name)
        fun.kind = o.FUN_KIND.NORMAL
        if fun.name == "_start":
            fun.name = "$main"
            main = fun
        GenerateFun(unit, mod, wasm_fun, fun, global_table, addr_type)
        # print ("\n".join(serialize.FunRenderToAsm(fun)))
        sanity.FunCheck(fun, unit, check_cfg=False)

    initial_heap_size_pages = 0
    sec_memory = mod.sections.get(wasm.SECTION_ID.MEMORY)
    if sec_memory:
        assert len(sec_memory.items) == 1
        heap: wasm.Mem = sec_memory.items[0]
        initial_heap_size_pages = heap.mem_type.limits.min
    assert main, f"missing main function"
    GenerateStartup(unit, global_argc, global_argv, main, init_global,
                    init_data, initial_heap_size_pages, addr_type)

    return unit
예제 #2
0
파일: codegen.py 프로젝트: robertmuth/Cwerg
 def main():
     parser = argparse.ArgumentParser(description='CodeGenC')
     parser.add_argument('--trace', action='store_const',
                         const=True, default=False,
                         help='show info after every step')
     parser.add_argument('--debug_parser', action='store_const',
                         const=True, default=False,
                         help='dump module before starting execution')
     parser.add_argument('filename', type=str,
                         help='file to execute')
     args = parser.parse_args()
     if args.filename == "-":
         fin = sys.stdin
     else:
         fin = open(args.filename)
     unit = serialize.UnitParseFromAsm(fin, args.debug_parser)
     assert "main" in unit.fun_syms
     print(PROLOG)
     for fun in unit.funs:
         if fun.kind is o.FUN_KIND.BUILTIN:
             continue
         sanity.FunCheck(fun, unit, check_push_pop=True, check_cfg=False)
         EmitFunctionProto(fun, True)
         print(";")
     for mem in unit.mems:
         EmitMemory(mem)
     for fun in unit.funs:
         if fun.kind is o.FUN_KIND.BUILTIN:
             continue
         EmitFunction(fun)
     print(EPILOG)
예제 #3
0
파일: optimize.py 프로젝트: mbrukman/Cwerg
def FunCfgInit(fun: ir.Fun, unit: ir.Unit):
    cfg.FunSplitBbls(fun)
    cfg.FunInitCFG(fun)
    cfg.FunRemoveUnconditionalBranches(fun)
    cfg.FunRemoveEmptyBbls(fun)
    sanity.FunCheck(fun, unit, check_cfg=True,
                    check_push_pop=True,
                    check_fallthroughs=False)
예제 #4
0
def LegalizeAll(unit, opt_stats, fout, verbose=False):
    for fun in unit.funs:
        sanity.FunCheck(fun, unit, check_cfg=False, check_push_pop=True)

        if fun.kind is o.FUN_KIND.NORMAL:
            legalize.PhaseOptimize(fun, unit, opt_stats, fout)

    for fun in unit.funs:
        legalize.PhaseLegalization(fun, unit, opt_stats, fout)
예제 #5
0
파일: legalize.py 프로젝트: mbrukman/Cwerg
def PhaseLegalization(fun: ir.Fun, unit: ir.Unit, _opt_stats: Dict[str, int],
                      fout):
    """
    Does a lot of the heavily lifting so that the instruction selector can remain
    simple and table driven.
    * lift almost all regs to 32bit width
    * rewrite Ins that cannot be expanded
    * rewrite immediates that cannot be expanded except stack offsets which are dealt with in
      another pass

    TODO: missing is a function to change calling signature so that
    """

    lowering.FunRegWidthWidening(fun, o.DK.U8, o.DK.U32)
    lowering.FunRegWidthWidening(fun, o.DK.S8, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.S16, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.U16, o.DK.U32)

    fun.cpu_live_in = regs.GetCpuRegsForSignature(fun.input_types)
    fun.cpu_live_out = regs.GetCpuRegsForSignature(fun.output_types)
    if fun.kind is not o.FUN_KIND.NORMAL:
        return

    # ARM has no mod instruction
    lowering.FunEliminateRem(fun)

    # ARM has not support for these addressing modes
    lowering.FunEliminateStkLoadStoreWithRegOffset(fun,
                                                   base_kind=o.DK.A32,
                                                   offset_kind=o.DK.S32)
    # No floating point immediates
    lowering.FunMoveImmediatesToMemory(fun, unit, o.DK.F32)
    lowering.FunMoveImmediatesToMemory(fun, unit, o.DK.F64)
    # also handles ld_mem from two transformations above
    lowering.FunEliminateMemLoadStore(fun,
                                      base_kind=o.DK.A32,
                                      offset_kind=o.DK.S32)

    canonicalize.FunCanonicalize(fun)
    # TODO: add a cfg linearization pass to improve control flow
    optimize.FunCfgExit(
        fun, unit)  # not this may affect immediates as it flips branches

    # Handle most overflowing immediates.
    # This excludes immediates related to stack offsets which have not been determined yet
    lowering.FunEliminateImmediateStores(fun)  # handles st_stk immediates
    _FunRewriteOutOfBoundsImmediates(fun)
    # hack: some of the code expansion templates need a scratch reg
    # we do not want to reserve registers for this globally, so instead
    # we inject some nop instructions that reserve a register that we
    # use as a scratch for the instruction immediately following the nop
    isel_tab.FunAddNop1ForCodeSel(fun)
    sanity.FunCheck(fun, None)
예제 #6
0
def PhaseLegalization(fun: ir.Fun, unit: ir.Unit, _opt_stats: Dict[str, int], fout):
    """
    Does a lot of the heavily lifting so that the instruction selector can remain
    simple and table driven.
    * lift almost all regs to 32bit width
    * rewrite Ins that cannot be expanded
    * rewrite immediates that cannot be expanded except stack offsets which are dealt with in
      another pass

    TODO: missing is a function to change calling signature so that
    """

    lowering.FunRegWidthWidening(fun, o.DK.U8, o.DK.U32)
    lowering.FunRegWidthWidening(fun, o.DK.S8, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.S16, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.U16, o.DK.U32)

    fun.cpu_live_in = regs.PushPopInterface.GetCpuRegsForInSignature(fun.input_types)
    fun.cpu_live_out = regs.PushPopInterface.GetCpuRegsForOutSignature(fun.output_types)
    if fun.kind is not o.FUN_KIND.NORMAL:
        return

    # Getting rid of the pusharg/poparg now relieves us form having to pay to attention to  the
    # invariant that pushargs/popargs must be adjacent.
    lowering.FunPushargConversion(fun, regs.PushPopInterface)
    lowering.FunPopargConversion(fun, regs.PushPopInterface)

    # ARM has no mod instruction
    lowering.FunEliminateRem(fun)

    # A64 has not support for these addressing modes
    lowering.FunEliminateStkLoadStoreWithRegOffset(fun, base_kind=o.DK.A64,
                                                   offset_kind=o.DK.S32)

    # we cannot load/store directly from mem so expand the instruction to simpler
    # sequences
    lowering.FunEliminateMemLoadStore(fun, base_kind=o.DK.A64,
                                      offset_kind=o.DK.S32)

    canonicalize.FunCanonicalize(fun)
    # TODO: add a cfg linearization pass to improve control flow
    optimize.FunCfgExit(fun, unit)  # not this may affect immediates as it flips branches

    # Handle most overflowing immediates.
    # This excludes immediates related to stack offsets which have not been determined yet
    _FunRewriteOutOfBoundsImmediates(fun, unit)

    sanity.FunCheck(fun, None)
예제 #7
0
def RegAllocGlobal(unit, opt_stats, fout, verbose=False):
    for fun in unit.funs:
        sanity.FunCheck(fun, unit, check_cfg=False, check_push_pop=False)
        legalize.PhaseGlobalRegAlloc(fun, opt_stats, fout)
        if verbose:
            legalize.DumpFun("after global_reg_alloc", fun)
예제 #8
0
파일: optimize.py 프로젝트: mbrukman/Cwerg
def FunCfgExit(fun: ir.Fun, unit: ir.Unit):
    cfg.FunAddUnconditionalBranches(fun)
    sanity.FunCheck(fun, unit, check_fallthroughs=True)
예제 #9
0
def PhaseLegalization(fun: ir.Fun, unit: ir.Unit, _opt_stats: Dict[str, int],
                      fout):
    """
    Does a lot of the heavily lifting so that the instruction selector can remain
    simple and table driven.
    * lift almost all regs to 32bit width
    * rewrite Ins that cannot be expanded
    * rewrite immediates that cannot be expanded except stack offsets which are dealt with in
      another pass

    TODO: missing is a function to change calling signature so that
    """
    fun.cpu_live_in = regs.PushPopInterface.GetCpuRegsForInSignature(
        fun.input_types)
    fun.cpu_live_out = regs.PushPopInterface.GetCpuRegsForOutSignature(
        fun.output_types)
    if fun.kind is not o.FUN_KIND.NORMAL:
        return

    # Getting rid of the pusharg/poparg now relieves us form having to pay to attention to  the
    # invariant that pushargs/popargs must be adjacent.
    lowering.FunPushargConversion(fun, regs.PushPopInterface)
    lowering.FunPopargConversion(fun, regs.PushPopInterface)

    # We did not bother with this addressing mode
    # TODO: we like can avoid this by adding more cases to isel_tab.py
    lowering.FunEliminateStkLoadStoreWithRegOffset(fun,
                                                   base_kind=o.DK.A64,
                                                   offset_kind=o.DK.S32)

    # TODO: switch this to a WithRegOffset flavor
    lowering.FunEliminateMemLoadStore(fun,
                                      base_kind=o.DK.A64,
                                      offset_kind=o.DK.S32)

    lowering.FunEliminateCopySign(fun)
    # TODO: support a few special cases in the isel, e.g. cmpXX a 0, 1, x, y
    lowering.FunEliminateCmp(fun)

    canonicalize.FunCanonicalize(fun)
    # TODO: add a cfg linearization pass to improve control flow
    optimize.FunCfgExit(
        fun, unit)  # not this may affect immediates as it flips branches

    # Handle most overflowing immediates.
    # This excludes immediates related to stack offsets which have not been determined yet
    _FunRewriteOutOfBoundsImmediates(fun, unit)

    # mul/div/rem need special treatment
    _FunRewriteDivRem(fun)

    _FunRewriteIntoAABForm(fun, unit)

    # Recompute Everything (TODO: make this more selective to reduce work)
    reg_stats.FunComputeRegStatsExceptLAC(fun)
    reg_stats.FunDropUnreferencedRegs(fun)
    liveness.FunComputeLivenessInfo(fun)
    reg_stats.FunComputeRegStatsLAC(fun)
    reg_stats.FunSeparateLocalRegUsage(
        fun
    )  # this has special hacks to avoid undoing _FunRewriteIntoAABForm()
    # DumpRegStats(fun, local_reg_stats)

    # if fun.name == "fibonacci": DumpFun("end of legal", fun)
    # if fun.name == "write_s": exit(1)
    sanity.FunCheck(fun, None)
예제 #10
0
def PhaseLegalization(fun: ir.Fun, unit: ir.Unit, _opt_stats: Dict[str, int],
                      fout):
    """
    Does a lot of the heavily lifting so that the instruction selector can remain
    simple and table driven.
    * lift almost all regs to 32bit width
    * rewrite Ins that cannot be expanded
    * rewrite immediates that cannot be expanded (stack offsets which are not known yet
      are ignored and we rely on being able to select all (reasonable) stack offsets)

    TODO: missing is a function to change calling signature so that
    """
    # shifts on A32 are saturating but Cwerg requires (mod <bitwidth>)
    lowering.FunLimitShiftAmounts(fun, 32)
    # lift everything to 32 bit
    lowering.FunRegWidthWidening(fun, o.DK.U8, o.DK.U32)
    lowering.FunRegWidthWidening(fun, o.DK.S8, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.S16, o.DK.S32)
    lowering.FunRegWidthWidening(fun, o.DK.U16, o.DK.U32)

    fun.cpu_live_in = regs.PushPopInterface.GetCpuRegsForInSignature(
        fun.input_types)
    fun.cpu_live_out = regs.PushPopInterface.GetCpuRegsForOutSignature(
        fun.output_types)
    if fun.kind is not o.FUN_KIND.NORMAL:
        return
    # replaces pusharg and poparg instructions and replace them with moves
    # The moves will use pre-allocated regs (the once use for argument/result passing)
    # We eliminate pusharg/poparg early because out immediate elimination code may
    # introduce addtional instructions which make it difficult to perserve the invariant
    # that all poparg/pusharg related to a call be adjecent.
    lowering.FunPushargConversion(fun, regs.PushPopInterface)
    lowering.FunPopargConversion(fun, regs.PushPopInterface)

    # ARM has no mod instruction
    lowering.FunEliminateRem(fun)

    # A32 has not support for these addressing modes.
    # They will be rewritten  using lea.stk
    lowering.FunEliminateStkLoadStoreWithRegOffset(fun,
                                                   base_kind=o.DK.A32,
                                                   offset_kind=o.DK.S32)

    # we cannot load/store directly from mem so expand the instruction to simpler
    # sequences
    lowering.FunEliminateMemLoadStore(fun,
                                      base_kind=o.DK.A32,
                                      offset_kind=o.DK.S32)

    canonicalize.FunCanonicalize(fun)
    # TODO: add a cfg linearization pass to improve control flow
    optimize.FunCfgExit(
        fun, unit)  # not this may affect immediates as it flips branches

    # Handle most overflowing immediates.
    _FunRewriteOutOfBoundsImmediates(fun, unit)
    # hack: some of the code expansion templates need a scratch reg
    # we do not want to reserve registers for this globally, so instead
    # we inject some nop instructions that reserve a register that we
    # use as a scratch for the instruction immediately following the nop
    isel_tab.FunAddNop1ForCodeSel(fun)
    sanity.FunCheck(fun, None)