def emit_cond_call(self, op, arglocs, regalloc): resloc = arglocs[0] arglocs = arglocs[1:] fcond = self.guard_success_cc self.guard_success_cc = c.cond_none assert fcond.value != c.cond_none.value jmp_adr = self.mc.get_relative_pos() self.mc.reserve_cond_jump() # patched later to a relative branch # save away r2, r3, r4, r5, r11 into the jitframe should_be_saved = [ reg for reg in self._regalloc.rm.reg_bindings.itervalues() if reg in self._COND_CALL_SAVE_REGS ] self._push_core_regs_to_jitframe(self.mc, should_be_saved) self.push_gcmap(self.mc, regalloc.get_gcmap([resloc])) # # load the 0-to-4 arguments into these registers, with the address of # the function to call into r11 remap_frame_layout(self, arglocs, [r.r11, r.r2, r.r3, r.r4, r.r5][:len(arglocs)], r.SCRATCH) # # figure out which variant of cond_call_slowpath to call, and call it callee_only = False floats = False for reg in regalloc.rm.reg_bindings.values(): if reg not in regalloc.rm.save_around_call_regs: break else: callee_only = True if regalloc.fprm.reg_bindings: floats = True cond_call_adr = self.cond_call_slowpath[floats * 2 + callee_only] self.mc.load_imm(r.r14, cond_call_adr) self.mc.BASR(r.r14, r.r14) # restoring the registers saved above, and doing pop_gcmap(), is left # to the cond_call_slowpath helper. We never have any result value. if resloc is not None: self.mc.LGR(resloc, r.SCRATCH2) relative_target = self.mc.currpos() - jmp_adr pmc = OverwritingBuilder(self.mc, jmp_adr, 1) pmc.BRCL(fcond, l.imm(relative_target)) pmc.overwrite() # might be overridden again to skip over the following # guard_no_exception too self.previous_cond_call_jcond = jmp_adr, fcond
def emit_cond_call(self, op, arglocs, regalloc): fcond = self.guard_success_cc self.guard_success_cc = c.cond_none assert fcond.value != c.cond_none.value fcond = c.negate(fcond) jmp_adr = self.mc.get_relative_pos() self.mc.reserve_cond_jump() # patched later to a relative branch # save away r2, r3, r4, r5, r11 into the jitframe should_be_saved = [ reg for reg in self._regalloc.rm.reg_bindings.itervalues() if reg in self._COND_CALL_SAVE_REGS] self._push_core_regs_to_jitframe(self.mc, should_be_saved) # load gc map into unusual location: r0 self.load_gcmap(self.mc, r.SCRATCH2, regalloc.get_gcmap()) # # load the 0-to-4 arguments into these registers, with the address of # the function to call into r11 remap_frame_layout(self, arglocs, [r.r11, r.r2, r.r3, r.r4, r.r5][:len(arglocs)], r.SCRATCH) # # figure out which variant of cond_call_slowpath to call, and call it callee_only = False floats = False for reg in regalloc.rm.reg_bindings.values(): if reg not in regalloc.rm.save_around_call_regs: break else: callee_only = True if regalloc.fprm.reg_bindings: floats = True cond_call_adr = self.cond_call_slowpath[floats * 2 + callee_only] self.mc.load_imm(r.r14, cond_call_adr) self.mc.BASR(r.r14, r.r14) # restoring the registers saved above, and doing pop_gcmap(), is left # to the cond_call_slowpath helper. We never have any result value. relative_target = self.mc.currpos() - jmp_adr pmc = OverwritingBuilder(self.mc, jmp_adr, 1) pmc.BRCL(fcond, l.imm(relative_target)) pmc.overwrite() # might be overridden again to skip over the following # guard_no_exception too self.previous_cond_call_jcond = jmp_adr, fcond
def prepare_arguments(self): self.subtracted_to_sp = 0 # Prepare arguments. Note that this follows the convention where # a prototype is in scope, and doesn't take "..." arguments. If # you were to call a C function with a "..." argument with cffi, # it would not go there but instead via libffi. If you pretend # instead that it takes fixed arguments, then it would arrive here # but the convention is bogus for floating-point arguments. (And, # to add to the mess, at least CPython's ctypes cannot be used # to call a "..." function with floating-point arguments. As I # guess that it's a problem with libffi, it means PyPy inherits # the same problem.) arglocs = self.arglocs num_args = len(arglocs) max_gpr_in_reg = 5 max_fpr_in_reg = 4 non_float_locs = [] non_float_regs = [] float_locs = [] # the IBM zarch manual states: # """ # A function will be passed a frame on the runtime stack by the function which # called it, and may allocate a new stack frame. A new stack frame is required if the # called function will in turn call further functions (which must be passed the # address of the new frame). This stack grows downwards from high addresses # """ gpr_regs = 0 fpr_regs = 0 stack_params = [] for i in range(num_args): loc = arglocs[i] if not arglocs[i].is_float(): if gpr_regs < max_gpr_in_reg: non_float_locs.append(arglocs[i]) non_float_regs.append(self.GPR_ARGS[gpr_regs]) gpr_regs += 1 else: stack_params.append(i) else: if fpr_regs < max_fpr_in_reg: float_locs.append(arglocs[i]) fpr_regs += 1 else: stack_params.append(i) self.subtracted_to_sp += len(stack_params) * WORD base = len(stack_params) * WORD if self.is_call_release_gil: self.subtracted_to_sp += 8*WORD base += 8*WORD for idx,i in enumerate(stack_params): loc = arglocs[i] offset = STD_FRAME_SIZE_IN_BYTES - base + 8 * idx if loc.type == FLOAT: if loc.is_fp_reg(): src = loc else: src = r.FP_SCRATCH self.asm.regalloc_mov(loc, src) self.mc.STDY(src, l.addr(offset, r.SP)) else: if loc.is_core_reg(): src = loc else: src = r.SCRATCH self.asm.regalloc_mov(loc, src) self.mc.STG(src, l.addr(offset, r.SP)) # We must also copy fnloc into FNREG non_float_locs.append(self.fnloc) non_float_regs.append(r.RETURN) if float_locs: assert len(float_locs) <= len(self.FPR_ARGS) remap_frame_layout(self.asm, float_locs, self.FPR_ARGS[:len(float_locs)], r.FP_SCRATCH) remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.SCRATCH)
def prepare_arguments(self): self.subtracted_to_sp = 0 # Prepare arguments. Note that this follows the convention where # a prototype is in scope, and doesn't take "..." arguments. If # you were to call a C function with a "..." argument with cffi, # it would not go there but instead via libffi. If you pretend # instead that it takes fixed arguments, then it would arrive here # but the convention is bogus for floating-point arguments. (And, # to add to the mess, at least CPython's ctypes cannot be used # to call a "..." function with floating-point arguments. As I # guess that it's a problem with libffi, it means PyPy inherits # the same problem.) arglocs = self.arglocs num_args = len(arglocs) max_gpr_in_reg = 5 max_fpr_in_reg = 4 non_float_locs = [] non_float_regs = [] float_locs = [] # the IBM zarch manual states: # """ # A function will be passed a frame on the runtime stack by the function which # called it, and may allocate a new stack frame. A new stack frame is required if the # called function will in turn call further functions (which must be passed the # address of the new frame). This stack grows downwards from high addresses # """ gpr_regs = 0 fpr_regs = 0 stack_params = [] for i in range(num_args): loc = arglocs[i] if not arglocs[i].is_float(): if gpr_regs < max_gpr_in_reg: non_float_locs.append(arglocs[i]) non_float_regs.append(self.GPR_ARGS[gpr_regs]) gpr_regs += 1 else: stack_params.append(i) else: if fpr_regs < max_fpr_in_reg: float_locs.append(arglocs[i]) fpr_regs += 1 else: stack_params.append(i) self.subtracted_to_sp += len(stack_params) * WORD base = len(stack_params) * WORD if self.is_call_release_gil: self.subtracted_to_sp += 8 * WORD base += 8 * WORD for idx, i in enumerate(stack_params): loc = arglocs[i] offset = STD_FRAME_SIZE_IN_BYTES - base + 8 * idx if loc.type == FLOAT: if loc.is_fp_reg(): src = loc else: src = r.FP_SCRATCH self.asm.regalloc_mov(loc, src) self.mc.STDY(src, l.addr(offset, r.SP)) else: if loc.is_core_reg(): src = loc else: src = r.SCRATCH self.asm.regalloc_mov(loc, src) self.mc.STG(src, l.addr(offset, r.SP)) # We must also copy fnloc into FNREG non_float_locs.append(self.fnloc) non_float_regs.append(r.RETURN) if float_locs: assert len(float_locs) <= len(self.FPR_ARGS) remap_frame_layout(self.asm, float_locs, self.FPR_ARGS[:len(float_locs)], r.FP_SCRATCH) remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.SCRATCH)