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
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
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}")
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
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
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}")