Ejemplo n.º 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
Ejemplo n.º 2
0
def BuildExample() -> ir.Unit:
    unit = ir.Unit("fib")
    fun_fib = unit.AddFun(
        ir.Fun("fib", o.FUN_KIND.NORMAL, [o.DK.U32], [o.DK.U32]))
    bbl_start = fun_fib.AddBbl(ir.Bbl("start"))
    bbl_difficult = fun_fib.AddBbl(ir.Bbl("difficult"))

    reg_in = fun_fib.AddReg(ir.Reg("in", o.DK.U32))
    reg_x = fun_fib.AddReg(ir.Reg("x", o.DK.U32))
    reg_out = fun_fib.AddReg(ir.Reg("out", o.DK.U32))

    bbl_start.AddIns(ir.Ins(o.POPARG, [reg_in]))
    bbl_start.AddIns(
        ir.Ins(o.BLT, [ir.Const(o.DK.U32, 1), reg_in, bbl_difficult]))
    bbl_start.AddIns(ir.Ins(o.PUSHARG, [reg_in]))
    bbl_start.AddIns(ir.Ins(o.RET, []))

    bbl_difficult.AddIns(ir.Ins(o.MOV, [reg_out, ir.Const(o.DK.U32, 0)]))
    bbl_difficult.AddIns(ir.Ins(o.SUB, [reg_x, reg_in, ir.Const(o.DK.U32, 1)]))

    bbl_difficult.AddIns(ir.Ins(o.PUSHARG, [reg_x]))
    bbl_difficult.AddIns(ir.Ins(o.BSR, [fun_fib]))
    bbl_difficult.AddIns(ir.Ins(o.POPARG, [reg_x]))
    bbl_difficult.AddIns(ir.Ins(o.ADD, [reg_out, reg_out, reg_x]))

    bbl_difficult.AddIns(ir.Ins(o.SUB, [reg_x, reg_in, ir.Const(o.DK.U32, 2)]))
    bbl_difficult.AddIns(ir.Ins(o.PUSHARG, [reg_x]))
    bbl_difficult.AddIns(ir.Ins(o.BSR, [fun_fib]))
    bbl_difficult.AddIns(ir.Ins(o.POPARG, [reg_x]))
    bbl_difficult.AddIns(ir.Ins(o.ADD, [reg_out, reg_out, reg_x]))

    bbl_difficult.AddIns(ir.Ins(o.PUSHARG, [reg_out]))
    bbl_difficult.AddIns(ir.Ins(o.RET, []))
    return unit
Ejemplo n.º 3
0
def GenerateMemcpyFun(unit: ir.Unit, addr_type: o.DK) -> ir.Fun:
    fun = unit.AddFun(
        ir.Fun("$memcpy", o.FUN_KIND.NORMAL, [],
               [addr_type, addr_type, o.DK.U32]))
    dst = fun.AddReg(ir.Reg("dst", addr_type))
    src = fun.AddReg(ir.Reg("src", addr_type))
    cnt = fun.AddReg(ir.Reg("cnt", o.DK.U32))
    data = fun.AddReg(ir.Reg("data", o.DK.U8))

    prolog = fun.AddBbl(ir.Bbl("prolog"))
    loop = fun.AddBbl(ir.Bbl("loop"))
    epilog = fun.AddBbl(ir.Bbl("epilog"))

    prolog.AddIns(ir.Ins(o.POPARG, [dst]))
    prolog.AddIns(ir.Ins(o.POPARG, [src]))
    prolog.AddIns(ir.Ins(o.POPARG, [cnt]))
    prolog.AddIns(ir.Ins(o.BRA, [epilog]))

    loop.AddIns(ir.Ins(o.SUB, [cnt, cnt, ONE]))
    loop.AddIns(ir.Ins(o.LD, [data, src, cnt]))
    loop.AddIns(ir.Ins(o.ST, [dst, cnt, data]))

    epilog.AddIns(ir.Ins(o.BLT, [ZERO, cnt, loop]))
    epilog.AddIns(ir.Ins(o.RET, []))
    return fun
Ejemplo n.º 4
0
def GenerateInitGlobalVarsFun(mod: wasm.Module, unit: ir.Unit,
                              addr_type: o.DK) -> ir.Fun:
    fun = unit.AddFun(ir.Fun("init_global_vars_fun", o.FUN_KIND.NORMAL, [],
                             []))
    bbl = fun.AddBbl(ir.Bbl("start"))
    epilog = fun.AddBbl(ir.Bbl("end"))
    epilog.AddIns(ir.Ins(o.RET, []))

    section = mod.sections.get(wasm.SECTION_ID.GLOBAL)
    if not section:
        return fun
    val32 = fun.AddReg(ir.Reg("val32", o.DK.U32))
    val64 = fun.AddReg(ir.Reg("val64", o.DK.U64))
    for n, data in enumerate(section.items):
        kind = o.MEM_KIND.RO if data.global_type.mut is wasm.MUT.CONST else o.MEM_KIND.RW
        mem = unit.AddMem(ir.Mem(f"global_vars_{n}", 16, kind))
        ins = GetInsFromInitializerExpression(data.expr)
        var_type = data.global_type.value_type
        if ins.opcode is wasm_opc.GLOBAL_GET:
            mem.AddData(
                ir.DataBytes(1, b"\0" * (4 if var_type.is_32bit() else 8)))
            src_mem = unit.GetMem(f"global_vars_{int(ins.args[0])}")
            reg = val32 if var_type.is_32bit() else val64
            bbl.AddIns(ir.Ins(o.LD_MEM, [reg, src_mem, ZERO]))
            bbl.AddIns(ir.Ins(o.ST_MEM, [mem, ZERO, reg]))
        elif ins.opcode.kind is wasm_opc.OPC_KIND.CONST:
            mem.AddData(
                ir.DataBytes(1, ExtractBytesFromConstIns(ins, var_type)))
        else:
            assert False, f"unsupported init instructions {ins}"
    return fun
Ejemplo n.º 5
0
def DirFun(unit: ir.Unit, operands: List):
    name, kind, output_types, input_types = operands
    if len(input_types) > o.MAX_PARAMETERS or len(
            output_types) > o.MAX_PARAMETERS:
        raise ParseError(f"parameter list too long {name}")
    fun = unit.GetFun(name)
    if fun is None:
        fun = ir.Fun(name, kind, output_types, input_types)
        unit.AddFun(fun)
    elif fun.forward_declared:
        unit.InitForwardDeclaredFun(fun, kind, output_types, input_types)
    else:
        raise ParseError(f"duplicate Fun {name}")
Ejemplo n.º 6
0
def GenerateStartup(unit: ir.Unit, global_argc, global_argv, main: ir.Fun,
                    init_global: ir.Fun, init_data: ir.Fun,
                    initial_heap_size_pages: int, addr_type: o.DK) -> ir.Fun:
    bit_width = addr_type.bitwidth()

    global_mem_base = unit.AddMem(ir.Mem("__memory_base", 0,
                                         o.MEM_KIND.EXTERN))

    fun = unit.AddFun(
        ir.Fun("main", o.FUN_KIND.NORMAL, [o.DK.U32], [o.DK.U32, addr_type]))
    argc = fun.AddReg(ir.Reg("argc", o.DK.U32))
    argv = fun.AddReg(ir.Reg("argv", addr_type))

    bbl = fun.AddBbl(ir.Bbl("start"))
    bbl.AddIns(ir.Ins(o.POPARG, [argc]))
    bbl.AddIns(ir.Ins(o.POPARG, [argv]))
    bbl.AddIns(ir.Ins(o.ST_MEM, [global_argc, ZERO, argc]))
    bbl.AddIns(ir.Ins(o.ST_MEM, [global_argv, ZERO, argv]))

    bbl.AddIns(ir.Ins(o.BSR, [unit.GetFun("__wasi_init")]))
    if initial_heap_size_pages:
        bbl.AddIns(
            ir.Ins(o.PUSHARG, [ir.Const(o.DK.S32, initial_heap_size_pages)]))
        bbl.AddIns(ir.Ins(o.BSR, [unit.GetFun("__memory_grow")]))
        bbl.AddIns(ir.Ins(o.POPARG, [fun.AddReg(ir.Reg("dummy", o.DK.S32))]))

    mem_base = fun.AddReg(ir.Reg("mem_base", addr_type))
    bbl.AddIns(ir.Ins(o.LD_MEM, [mem_base, global_mem_base, ZERO]))

    if init_global:
        bbl.AddIns(ir.Ins(o.BSR, [init_global]))
    if init_data:
        bbl.AddIns(ir.Ins(o.PUSHARG, [mem_base]))
        bbl.AddIns(ir.Ins(o.BSR, [init_data]))

    bbl.AddIns(ir.Ins(o.PUSHARG, [mem_base]))
    bbl.AddIns(ir.Ins(o.BSR, [main]))
    bbl.AddIns(ir.Ins(o.PUSHARG, [ir.Const(o.DK.U32, 0)]))
    bbl.AddIns(ir.Ins(o.RET, []))
    return fun
Ejemplo n.º 7
0
def GenerateInitDataFun(mod: wasm.Module, unit: ir.Unit, memcpy: ir.Fun,
                        addr_type: o.DK) -> typing.Optional[ir.Fun]:
    fun = unit.AddFun(
        ir.Fun("init_data_fun", o.FUN_KIND.NORMAL, [], [addr_type]))
    bbl = fun.AddBbl(ir.Bbl("start"))
    epilog = fun.AddBbl(ir.Bbl("end"))
    epilog.AddIns(ir.Ins(o.RET, []))
    section = mod.sections.get(wasm.SECTION_ID.DATA)

    mem_base = fun.AddReg(ir.Reg("mem_base", addr_type))
    bbl.AddIns(ir.Ins(o.POPARG, [mem_base]))
    if not section:
        return None

    offset = fun.AddReg(ir.Reg("offset", o.DK.S32))
    src = fun.AddReg(ir.Reg("src", addr_type))
    dst = fun.AddReg(ir.Reg("dst", addr_type))

    for n, data in enumerate(section.items):
        assert data.memory_index == 0
        assert isinstance(data.offset, wasm.Expression)
        ins = GetInsFromInitializerExpression(data.offset)
        init = unit.AddMem(ir.Mem(f"global_init_mem_{n}", 16, o.MEM_KIND.RO))
        init.AddData(ir.DataBytes(1, data.init))
        if ins.opcode is wasm_opc.GLOBAL_GET:
            src_mem = unit.GetMem(f"global_vars_{int(ins.args[0])}")
            bbl.AddIns(ir.Ins(o.LD_MEM, [offset, src_mem, ZERO]))
        elif ins.opcode is wasm_opc.I32_CONST:
            bbl.AddIns(ir.Ins(o.MOV,
                              [offset, ir.Const(o.DK.S32, ins.args[0])]))
        else:
            assert False, f"unsupported init instructions {ins}"
        bbl.AddIns(ir.Ins(o.LEA, [dst, mem_base, offset]))
        bbl.AddIns(ir.Ins(o.LEA_MEM, [src, init, ZERO]))
        bbl.AddIns(ir.Ins(o.PUSHARG, [ir.Const(o.DK.U32, len(data.init))]))
        bbl.AddIns(ir.Ins(o.PUSHARG, [src]))
        bbl.AddIns(ir.Ins(o.PUSHARG, [dst]))
        bbl.AddIns(ir.Ins(o.BSR, [memcpy]))
    return fun
Ejemplo n.º 8
0
def DirFun(unit: ir.Unit, operands: List):
    name, kind, output_types, input_types = operands
    if len(input_types) > o.MAX_PARAMETERS or len(
            output_types) > o.MAX_PARAMETERS:
        raise ParseError(f"parameter list too long {name}")
    fun = unit.GetFun(name)
    if fun is None:
        fun = ir.Fun(name, kind, output_types, input_types)
        unit.AddFun(fun)
    elif fun.kind is o.FUN_KIND.INVALID:  # forward_declared
        unit.InitForwardDeclaredFun(fun, kind, output_types, input_types)
    elif fun.kind is o.FUN_KIND.EXTERN or kind is o.FUN_KIND.EXTERN:
        assert output_types == fun.output_types
        assert input_types == fun.input_types
        if kind is o.FUN_KIND.EXTERN:
            # we already have a proper function
            return
        # definition of a formerly extern functions
        fun.kind = kind
        # move fun to make it current
        unit.funs.remove(fun)
        unit.funs.append(fun)
    else:
        raise ParseError(f"duplicate Fun {name}")