def _InsRewriteDivRemShifts(ins: ir.Ins, fun: ir.Fun) -> Optional[List[ir.Ins]]: opc = ins.opcode ops = ins.operands if opc is o.DIV and ops[0].kind.flavor() != o.DK_FLAVOR_F: # note: we could leave it to the register allocator to pick a CpuReg for ops[2] # but then we would somehow have to ensure that the reg is NOT rdx. # By forcing rcx for ops[2] we sidestep the issue rax = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rax"], ops[0].kind) rcx = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rcx"], ops[0].kind) rdx = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rdx"], ops[0].kind) return [ ir.Ins(o.MOV, [rax, ops[1]]), ir.Ins(o.MOV, [rcx, ops[2]]), ir.Ins(o.DIV, [rdx, rax, rcx ]), # note the notion of src/dst regs is murky here ir.Ins(o.MOV, [ops[0], rax]) ] elif opc is o.REM and ops[0].kind.flavor() != o.DK_FLAVOR_F: rax = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rax"], ops[0].kind) rcx = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rcx"], ops[0].kind) rdx = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rdx"], ops[0].kind) return [ ir.Ins(o.MOV, [rax, ops[1]]), ir.Ins(o.MOV, [rcx, ops[2]]), ir.Ins(o.DIV, [rdx, rax, rcx ]), # note the notion of src/dst regs is murky here ir.Ins(o.MOV, [ops[0], rdx]) ] elif opc in {o.SHR, o.SHL} and isinstance(ops[2], ir.Reg): rcx = fun.FindOrAddCpuReg(regs.CPU_REGS_MAP["rcx"], ops[0].kind) mov = ir.Ins(o.MOV, [rcx, ops[2]]) ops[2] = rcx mask = _SHIFT_MASK.get(ops[0].kind) if mask: return [mov, ir.Ins(o.AND, [rcx, rcx, mask]), ins] else: return [mov, ins] else: return None
def _InsPushargConversionReverse(ins: ir.Ins, fun: ir.Fun, params: List[ir.CpuReg]) -> Optional[ List[ir.Ins]]: """ This pass converts pusharg reg -> mov arg_reg = reg Note: * params is passed around between calls to this function * pusharg's always precede calls or returns """ if ins.opcode is o.PUSHARG: cpu_reg = params.pop(0) src = ins.operands[0] reg = fun.FindOrAddCpuReg(cpu_reg, src.kind) return [ir.Ins(o.MOV, [reg, src])] assert not params, f"params {params} should be empty at ins {ins} {ins.operands}" if ins.opcode.is_call(): callee: ir.Fun = cfg.InsCallee(ins) assert isinstance(callee, ir.Fun) params += GetCpuRegsForSignature(callee.input_types) elif ins.opcode is o.RET: params += GetCpuRegsForSignature(fun.output_types) return None
def _InsPopargConversion(ins: ir.Ins, fun: ir.Fun, params: List[ir.CpuReg]) -> Optional[List[ir.Ins]]: """ This pass converts `poparg reg` -> `mov reg = arg_reg` it must used in a forward pass over the Bbl and will update `param` for use with the next Ins in the BBl. The initial value of `param` reflects the Fun's arguments. """ if ins.opcode is o.POPARG: cpu_reg = params.pop(0) dst = ins.operands[0] # assert dst.kind == cpu_reg.kind reg = fun.FindOrAddCpuReg(cpu_reg, dst.kind) return [ir.Ins(o.MOV, [dst, reg])] assert not params, f"params {params} should be empty at ins {ins}" if ins.opcode.is_call(): callee: ir.Fun = cfg.InsCallee(ins) assert isinstance(callee, ir.Fun) params += GetCpuRegsForSignature(callee.output_types) return None