def transitive_imply(self, other, opt, loop): if self.op.getopnum() != other.op.getopnum(): # stronger restriction, intermixing e.g. <= and < would be possible return None if self.getleftkey() is not other.getleftkey(): return None if not self.rhs.is_identity(): # stronger restriction return None # this is a valid transitive guard that eliminates the loop guard opnum = self.transitive_cmpop(self.cmp_op.getopnum()) box_rhs = self.emit_varops(opt, self.rhs, self.cmp_op.getarg(1)) other_rhs = self.emit_varops(opt, other.rhs, other.cmp_op.getarg(1)) compare = ResOperation(opnum, [box_rhs, other_rhs]) opt.emit_operation(compare) # guard descr = CompileLoopVersionDescr() descr.copy_all_attributes_from(self.op.getdescr()) descr.rd_vector_info = None # do not copy the accum list assert isinstance(descr, AbstractFailDescr) guard = ResOperation(self.op.getopnum(), [compare], descr=descr) guard.setfailargs(loop.label.getarglist_copy()) opt.emit_operation(guard) return guard
def create_op(self, opnum, args, res, descr, fail_args): res = ResOperation(opnum, args, descr) if fail_args is not None: res.setfailargs(fail_args) if self._postproces: self._postproces(res) return res
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) v_cond = builder.get_bool_var(r) subset = builder.subset_of_intvars(r)[:4] for i in range(len(subset)): if r.random() < 0.35: subset[i] = ConstInt(r.random_integer()) # seen = [] def call_me(*args): if len(seen) == 0: seen.append(args) else: assert seen[0] == args # TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), call_me) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [v_cond, c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def force_box(self, op, optforce): if not self.is_virtual(): return op optforce.forget_numberings() if self.mode is mode_string: s = self.get_constant_string_spec(optforce, mode_string) if s is not None: c_s = get_const_ptr_for_string(s) optforce.get_box_replacement(op).set_forwarded(c_s) return c_s else: s = self.get_constant_string_spec(optforce, mode_unicode) if s is not None: c_s = get_const_ptr_for_unicode(s) optforce.get_box_replacement(op).set_forwarded(c_s) return c_s self._is_virtual = False lengthbox = self.getstrlen(op, optforce.optimizer.optstring, self.mode) newop = ResOperation(self.mode.NEWSTR, [lengthbox]) if not we_are_translated(): newop.name = 'FORCE' optforce.emit_operation(newop) newop = optforce.getlastop() newop.set_forwarded(self) op = optforce.get_box_replacement(op) op.set_forwarded(newop) optstring = optforce.optimizer.optstring self.initialize_forced_string(op, optstring, op, CONST_0, self.mode) return newop
def has_pure_result(self, opnum, args, descr): op = ResOperation(opnum, args, None, descr) key = self.optimizer.make_args_key(op) op = self.pure_operations.get(key, None) if op is None: return False return op.getdescr() is descr
def store_final_boxes_in_guard(self, op, pendingfields): assert pendingfields is not None descr = op.getdescr() assert isinstance(descr, compile.ResumeGuardDescr) modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo) try: newboxes = modifier.finish(self, pendingfields) if len(newboxes) > self.metainterp_sd.options.failargs_limit: raise resume.TagOverflow except resume.TagOverflow: raise compile.giveup() descr.store_final_boxes(op, newboxes) # if op.getopnum() == rop.GUARD_VALUE: if self.getvalue(op.getarg(0)) in self.bool_boxes: # Hack: turn guard_value(bool) into guard_true/guard_false. # This is done after the operation is emitted to let # store_final_boxes_in_guard set the guard_opnum field of the # descr to the original rop.GUARD_VALUE. constvalue = op.getarg(1).getint() if constvalue == 0: opnum = rop.GUARD_FALSE elif constvalue == 1: opnum = rop.GUARD_TRUE else: raise AssertionError("uh?") newop = ResOperation(opnum, [op.getarg(0)], op.result, descr) newop.setfailargs(op.getfailargs()) return newop else: # a real GUARD_VALUE. Make it use one counter per value. descr.make_a_counter_per_value(op) return op
def handle_malloc_operation(self, op): opnum = op.getopnum() if opnum == rop.NEW: self.handle_new_fixedsize(op.getdescr(), op) elif opnum == rop.NEW_WITH_VTABLE: classint = op.getarg(0).getint() descr = heaptracker.vtable2descr(self.cpu, classint) self.handle_new_fixedsize(descr, op) if self.gc_ll_descr.fielddescr_vtable is not None: op = ResOperation(rop.SETFIELD_GC, [op.result, ConstInt(classint)], None, descr=self.gc_ll_descr.fielddescr_vtable) self.newops.append(op) elif opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR: descr = op.getdescr() assert isinstance(descr, ArrayDescr) self.handle_new_array(descr, op) elif opnum == rop.NEWSTR: self.handle_new_array(self.gc_ll_descr.str_descr, op, kind=FLAG_STR) elif opnum == rop.NEWUNICODE: self.handle_new_array(self.gc_ll_descr.unicode_descr, op, kind=FLAG_UNICODE) else: raise NotImplementedError(op.getopname())
def next(self): opnum = self._next() if oparity[opnum] == -1: argnum = self._next() else: argnum = oparity[opnum] args = [] for i in range(argnum): args.append(self._untag(self._next())) descr_index = -1 if opwithdescr[opnum]: descr_index = self._next() if descr_index == 0 or rop.is_guard(opnum): descr = None else: if descr_index < self.all_descr_len + 1: descr = self.metainterp_sd.all_descrs[descr_index - 1] else: descr = self.trace._descrs[descr_index - self.all_descr_len - 1] else: descr = None res = ResOperation(opnum, args, descr=descr) if rop.is_guard(opnum): assert isinstance(res, GuardResOp) res.rd_resume_position = descr_index if res.type != 'v': self._cache[self._index] = res self._index += 1 self._count += 1 return res
def do(self, opnum, argboxes, descr=None): self.fakemetainterp._got_exc = None op = ResOperation(opnum, argboxes, descr) result = _execute_arglist(self.cpu, self.fakemetainterp, opnum, argboxes, descr) if result is not None: c_result = wrap_constant(result) op.copy_value_from(c_result) self.loop.operations.append(op) return op
def gen_guard_true(draw, all_ops, framestack): arg = get_arg(draw, all_ops, allow_const=False) res = ResOperation(rop.GUARD_TRUE, [arg]) if draw(strategies.booleans()): s = [] for i in range(10): s.append(get_arg(draw, all_ops, allow_const=False)) boxes = list(set(s)) framestack.append(Frame(JitCode(1), 2, boxes)) res.framestack = framestack[:] return res
def getstrlen(self, op, string_optimizer, mode, create_ops=True): if self.lgtop is not None: return self.lgtop assert not self.is_virtual() if not create_ops: return None lengthop = ResOperation(mode.STRLEN, [op]) lengthop.set_forwarded(self.getlenbound(mode)) self.lgtop = lengthop string_optimizer.emit_operation(lengthop) return lengthop
def optimize_NEW_ARRAY(self, op): sizebox = self.get_constant_box(op.getarg(0)) if sizebox is not None: # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.getarg(0), ConstInt): op = ResOperation(rop.NEW_ARRAY, [sizebox], op.result, descr=op.getdescr()) self.make_varray(op.getdescr(), sizebox.getint(), op.result, op) else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op)
def _optimize_NEWSTR(self, op, mode): length_box = self.get_constant_box(op.getarg(0)) if length_box and length_box.getint() <= MAX_CONST_LEN: # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.getarg(0), ConstInt): op = ResOperation(mode.NEWSTR, [length_box], op.result) vvalue = self.make_vstring_plain(op.result, op, mode) vvalue.setup(length_box.getint()) else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op) self.pure(mode.STRLEN, [op.result], op.getarg(0))
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f = self.non_raising_func_code(builder, r) RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def emit_operations(self, opt): # create trace instructions for the index lhs = self.emit_varops(opt, self.lhs, self.cmp_op.getarg(0)) rhs = self.emit_varops(opt, self.rhs, self.cmp_op.getarg(1)) opnum = self.cmp_op.getopnum() cmp_op = ResOperation(opnum, [lhs, rhs]) opt.emit_operation(cmp_op) # emit that actual guard guard = ResOperation(self.op.getopnum(), [cmp_op], self.op.getdescr()) guard.setfailargs(self.op.getfailargs()[:]) opt.emit_operation(guard) self.setindex(opt.operation_position()-1) self.setoperation(guard) self.setcmp(cmp_op)
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f, exc = self.raising_func_code(builder, r) TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def gen_initialize_tid(self, v_newgcobj, tid): if self.gc_ll_descr.fielddescr_tid is not None: # produce a SETFIELD to initialize the GC header op = ResOperation(rop.SETFIELD_GC, [v_newgcobj, ConstInt(tid)], None, descr=self.gc_ll_descr.fielddescr_tid) self.newops.append(op)
def emit_load_effective_address(self, v_gcptr, v_index, base, itemscale): if self.cpu.supports_load_effective_address: i1 = ResOperation(rop.LOAD_EFFECTIVE_ADDRESS, [v_gcptr, v_index, ConstInt(base), ConstInt(itemscale)]) self.emit_op(i1) return i1 else: if itemscale > 0: v_index = ResOperation(rop.INT_LSHIFT, [v_index, ConstInt(itemscale)]) self.emit_op(v_index) i1b = ResOperation(rop.INT_ADD, [v_gcptr, v_index]) self.emit_op(i1b) i1 = ResOperation(rop.INT_ADD, [i1b, ConstInt(base)]) self.emit_op(i1) return i1
def handle_str_equal_level1(self, v1, v2, resultbox, mode): l2box = v2.getstrlen(None, mode, None) if isinstance(l2box, ConstInt): if l2box.value == 0: lengthbox = v1.getstrlen(self, mode, None) seo = self.optimizer.send_extra_operation seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox)) return True if l2box.value == 1: l1box = v1.getstrlen(None, mode, None) if isinstance(l1box, ConstInt) and l1box.value == 1: # comparing two single chars vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode) vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) seo = self.optimizer.send_extra_operation seo( ResOperation( rop.INT_EQ, [vchar1.force_box(self), vchar2.force_box(self)], resultbox)) return True if isinstance(v1, VStringSliceValue): vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) do = EffectInfo.OS_STREQ_SLICE_CHAR self.generate_modified_call(do, [ v1.vstr.force_box(self), v1.vstart.force_box(self), v1.vlength.force_box(self), vchar.force_box(self) ], resultbox, mode) return True # if v2.is_null(): if v1.is_nonnull(): self.make_constant(resultbox, CONST_0) return True if v1.is_null(): self.make_constant(resultbox, CONST_1) return True op = ResOperation(rop.PTR_EQ, [v1.force_box(self), llhelper.CONST_NULL], resultbox) self.emit_operation(op) return True # return False
def _force_elements(self, op, optforce, descr): self.size = -1 # at this point we have just written the # 'op = CALL_I(..., OS_RAW_MALLOC_VARSIZE_CHAR)'. # Emit now a CHECK_MEMORY_ERROR resop. check_op = ResOperation(rop.CHECK_MEMORY_ERROR, [op]) optforce.emit_extra(check_op) # buffer = self._get_buffer() for i in range(len(buffer.offsets)): # write the value offset = buffer.offsets[i] descr = buffer.descrs[i] itembox = buffer.values[i] setfield_op = ResOperation(rop.RAW_STORE, [op, ConstInt(offset), itembox], descr=descr) optforce.emit_extra(setfield_op)
def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection calldescr, func = cic.callinfo_for_oopspec(oopspecindex) op = ResOperation(rop.CALL, [ConstInt(func)] + args, result, descr=calldescr) self.emit_operation(op)
def compare_short(self, short, expected_short): expected_short = self.parse(expected_short) remap = {} exp = ([ResOperation(rop.LABEL, expected_short.inputargs)] + expected_short.operations) for k, v in zip(short[0].getarglist(), expected_short.inputargs): remap[v] = k equaloplists(short, exp, remap=remap)
def emit_gc_store_or_indexed(self, op, ptr_box, index_box, value_box, itemsize, factor, offset): factor, offset, index_box = \ self._emit_mul_if_factor_offset_not_supported(index_box, factor, offset) # if index_box is None: args = [ptr_box, ConstInt(offset), value_box, ConstInt(itemsize)] newload = ResOperation(rop.GC_STORE, args) else: args = [ptr_box, index_box, value_box, ConstInt(factor), ConstInt(offset), ConstInt(itemsize)] newload = ResOperation(rop.GC_STORE_INDEXED, args) if op is not None: self.replace_op_with(op, newload) else: self.emit_op(newload)
def gen_guard(self, builder, r): if not builder.ptrvars: raise CannotProduceOperation box = r.choice(builder.ptrvars)[0] op = ResOperation(self.opnum, [box]) passing = ((self.opnum == rop.GUARD_NONNULL and getref_base(box)) or (self.opnum == rop.GUARD_ISNULL and not getref_base(box))) return op, passing
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f = self.non_raising_func_code(builder, r) if len(subset) == 0: RES = lltype.Void else: RES = lltype.Signed TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def make_guards(self, box, guards, optimizer): if self.is_constant(): guards.append(ResOperation(rop.GUARD_VALUE, [box, ConstInt(self.upper)])) return if self.has_lower and self.lower > MININT: bound = self.lower op = ResOperation(rop.INT_GE, [box, ConstInt(bound)]) guards.append(op) op = ResOperation(rop.GUARD_TRUE, [op]) guards.append(op) if self.has_upper and self.upper < MAXINT: bound = self.upper op = ResOperation(rop.INT_LE, [box, ConstInt(bound)]) guards.append(op) op = ResOperation(rop.GUARD_TRUE, [op]) guards.append(op)
def exc_handling(guard_op): # operations need to start with correct GUARD_EXCEPTION if guard_op._exc_box is None: op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], BoxPtr()) op.setdescr(self.builder.getfaildescr()) op.setfailargs([]) return op
def import_state(self, targetop, exported_state): if not targetop: # Trace did not start with a label self.inputargs = self.optimizer.loop.inputargs self.short = None self.initial_virtual_state = None return self.inputargs = targetop.getarglist() target_token = targetop.getdescr() assert isinstance(target_token, TargetToken) if not exported_state: # No state exported, construct one without virtuals self.short = None virtual_state = self.get_virtual_state(self.inputargs) self.initial_virtual_state = virtual_state return self.short = target_token.short_preamble[:] self.short_seen = {} self.short_boxes = exported_state.short_boxes self.initial_virtual_state = target_token.virtual_state for box in self.inputargs: preamble_value = exported_state.exported_values[box] value = self.optimizer.getvalue(box) value.import_from(preamble_value, self.optimizer) # Setup the state of the new optimizer by emiting the # short operations and discarding the result self.optimizer.emitting_dissabled = True for op in exported_state.inputarg_setup_ops: self.optimizer.send_extra_operation(op) seen = {} for op in self.short_boxes.operations(): self.ensure_short_op_emitted(op, self.optimizer, seen) if op and op.result: preamble_value = exported_state.exported_values[op.result] value = self.optimizer.getvalue(op.result) if not value.is_virtual() and not value.is_constant(): imp = ValueImporter(self, preamble_value, op) self.optimizer.importable_values[value] = imp newvalue = self.optimizer.getvalue(op.result) newresult = newvalue.get_key_box() # note that emitting here SAME_AS should not happen, but # in case it does, we would prefer to be suboptimal in asm # to a fatal RPython exception. if newresult is not op.result and \ not self.short_boxes.has_producer(newresult) and \ not newvalue.is_constant(): op = ResOperation(rop.SAME_AS, [op.result], newresult) self.optimizer._newoperations.append(op) #if self.optimizer.loop.logops: # debug_print(' Falling back to add extra: ' + # self.optimizer.loop.logops.repr_of_resop(op)) self.optimizer.flush() self.optimizer.emitting_dissabled = False
def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes, memory_manager=None): """Make a LoopToken that corresponds to assembler code that just calls back the interpreter. Used temporarily: a fully compiled version of the code may end up replacing it. """ jitcell_token = make_jitcell_token(jitdriver_sd) nb_red_args = jitdriver_sd.num_red_args assert len(redargtypes) == nb_red_args inputargs = [] for kind in redargtypes: if kind == history.INT: box = InputArgInt() elif kind == history.REF: box = InputArgRef() elif kind == history.FLOAT: box = InputArgFloat() else: raise AssertionError inputargs.append(box) k = jitdriver_sd.portal_runner_adr funcbox = history.ConstInt(heaptracker.adr2int(k)) callargs = [funcbox] + greenboxes + inputargs # jd = jitdriver_sd opnum = OpHelpers.call_for_descr(jd.portal_calldescr) call_op = ResOperation(opnum, callargs, descr=jd.portal_calldescr) if call_op.type != 'v' is not None: finishargs = [call_op] else: finishargs = [] # faildescr = jitdriver_sd.propagate_exc_descr operations = [ call_op, ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=faildescr), ResOperation(rop.FINISH, finishargs, descr=jd.portal_finishtoken) ] operations[1].setfailargs([]) operations = get_deep_immutable_oplist(operations) cpu.compile_loop(inputargs, operations, jitcell_token, log=False) if memory_manager is not None: # for tests memory_manager.keep_loop_alive(jitcell_token) return jitcell_token
def gen_write_barrier(self, v_base): write_barrier_descr = self.gc_ll_descr.write_barrier_descr args = [v_base] self.newops.append( ResOperation(rop.COND_CALL_GC_WB, args, None, descr=write_barrier_descr)) self.write_barrier_applied[v_base] = None
def _int_sub(string_optimizer, box1, box2): if isinstance(box2, ConstInt): if box2.value == 0: return box1 if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() string_optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox
def gen_malloc_nursery_varsize_frame(self, sizebox): """ Generate CALL_MALLOC_NURSERY_VARSIZE_FRAME """ self.emitting_an_operation_that_can_collect() op = ResOperation(rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME, [sizebox]) self.emit_op(op) self.remember_write_barrier(op) return op
def do(self, opnum, argboxes, descr=None): self.fakemetainterp._got_exc = None op = ResOperation(opnum, argboxes, descr) if opnum != rop.ZERO_PTR_FIELD: result = _execute_arglist(self.cpu, self.fakemetainterp, opnum, argboxes, descr) if result is not None: c_result = wrap_constant(result) op.copy_value_from(c_result) else: import ctypes addr = self.cpu.cast_gcref_to_int(argboxes[0].getref_base()) offset = argboxes[1].getint() assert (offset % ctypes.sizeof(ctypes.c_long)) == 0 ptr = ctypes.cast(addr, ctypes.POINTER(ctypes.c_long)) ptr[offset / ctypes.sizeof(ctypes.c_long)] = 0 self.loop.operations.append(op) return op
def create_op(self, opnum, args, result, descr, fail_args): if opnum == ESCAPE_OP.OPNUM: op = ESCAPE_OP(result) op.initarglist(args) assert descr is None return op if opnum == FORCE_SPILL.OPNUM: op = FORCE_SPILL(result) op.initarglist(args) assert descr is None return op else: res = ResOperation(opnum, args, result, descr) if fail_args is not None: res.setfailargs(fail_args) if self._postproces: self._postproces(res) return res
def produce_into(self, builder, r): subset, f = self.non_raising_func_code(builder, r) RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], descr=builder.getfaildescr()) op.setfailargs(builder.subset_of_intvars(r)) op._exc_box = None builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op)
def cpu_simplify_scale(cpu, index_box, factor, offset): # Returns (factor, offset, index_box, [ops]) where index_box is either # a non-constant BoxInt or None. if isinstance(index_box, ConstInt): return 1, index_box.value * factor + offset, None, False else: if factor != 1 and factor not in cpu.load_supported_factors: # the factor is supported by the cpu # x & (x - 1) == 0 is a quick test for power of 2 assert factor > 0 if (factor & (factor - 1)) == 0: index_box = ResOperation(rop.INT_LSHIFT, [index_box, ConstInt(highest_bit(factor))]) else: index_box = ResOperation(rop.INT_MUL, [index_box, ConstInt(factor)]) return 1, offset, index_box, True return factor, offset, index_box, False
def gen_malloc_nursery_varsize_frame(self, sizebox, v_result): """ Generate CALL_MALLOC_NURSERY_VARSIZE_FRAME """ self.emitting_an_operation_that_can_collect() op = ResOperation(rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME, [sizebox], v_result) self.newops.append(op) self.write_barrier_applied[v_result] = None
def _int_sub(string_optimizer, box1, box2): if isinstance(box2, ConstInt): if box2.value == 0: return box1 if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) op = ResOperation(rop.INT_SUB, [box1, box2]) string_optimizer.send_extra_operation(op) return op
def get_operations(self): var = self.var tolist = [] if self.coefficient_mul != 1: args = [var, ConstInt(self.coefficient_mul)] var = ResOperation(rop.INT_MUL, args) tolist.append(var) if self.coefficient_div != 1: assert 0 # should never be the case with handling # of INT_PY_DIV commented out in this file... if self.constant > 0: args = [var, ConstInt(self.constant)] var = ResOperation(rop.INT_ADD, args) tolist.append(var) if self.constant < 0: args = [var, ConstInt(-self.constant)] var = ResOperation(rop.INT_SUB, args) tolist.append(var) return tolist
def optimize_VIRTUAL_REF(self, op): # get some constants vrefinfo = self.optimizer.metainterp_sd.virtualref_info c_cls = vrefinfo.jit_virtual_ref_const_class vref_descr = vrefinfo.descr descr_virtual_token = vrefinfo.descr_virtual_token descr_forced = vrefinfo.descr_forced # # Replace the VIRTUAL_REF operation with a virtual structure of type # 'jit_virtual_ref'. The jit_virtual_ref structure may be forced soon, # but the point is that doing so does not force the original structure. newop = ResOperation(rop.NEW_WITH_VTABLE, [], descr=vref_descr) vrefvalue = self.make_virtual(c_cls, newop, vref_descr) op.set_forwarded(newop) newop.set_forwarded(vrefvalue) token = ResOperation(rop.FORCE_TOKEN, []) vrefvalue.setfield(descr_virtual_token, newop, token) vrefvalue.setfield(descr_forced, newop, CONST_NULL) return self.emit(token)
def convert_old_style_to_targets(loop, jump): newloop = TreeLoop(loop.name) newloop.inputargs = loop.inputargs newloop.operations = [ResOperation(rop.LABEL, loop.inputargs, descr=FakeDescr())] + \ loop.operations if not jump: assert newloop.operations[-1].getopnum() == rop.JUMP newloop.operations[-1] = newloop.operations[-1].copy_and_change( rop.LABEL) return newloop
def gen_malloc_frame(self, frame_info): descrs = self.gc_ll_descr.getframedescrs(self.cpu) if self.gc_ll_descr.kind == 'boehm': ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_depth) if sign: size = -size args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)] size = ResOperation(rop.GC_LOAD_I, args) self.emit_op(size) frame = ResOperation(rop.NEW_ARRAY, [size], descr=descrs.arraydescr) self.handle_new_array(descrs.arraydescr, frame) return self.get_box_replacement(frame) else: # we read size in bytes here, not the length ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_size) if sign: size = -size args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)] size = ResOperation(rop.GC_LOAD_I, args) self.emit_op(size) frame = self.gen_malloc_nursery_varsize_frame(size) self.gen_initialize_tid(frame, descrs.arraydescr.tid) # we need to explicitely zero all the gc fields, because # of the unusal malloc pattern length = self.emit_getfield(ConstInt(frame_info), descr=descrs.jfi_frame_depth, raw=True) self.emit_setfield(frame, self.c_zero, descr=descrs.jf_extra_stack_depth) self.emit_setfield(frame, self.c_null, descr=descrs.jf_savedata) self.emit_setfield(frame, self.c_null, descr=descrs.jf_force_descr) self.emit_setfield(frame, self.c_null, descr=descrs.jf_descr) self.emit_setfield(frame, self.c_null, descr=descrs.jf_guard_exc) self.emit_setfield(frame, self.c_null, descr=descrs.jf_forward) self.gen_initialize_len(frame, length, descrs.arraydescr.lendescr) return self.get_box_replacement(frame)
def optimize(self, ops, bridge_ops, expected, expected_loop=None, inline_short_preamble=True, jump_values=None, bridge_values=None): loop = self.parse(ops) info = self.unroll_and_optimize(loop, None, jump_values=jump_values) jitcell_token = compile.make_jitcell_token(None) mid_label_descr = TargetToken(jitcell_token) mid_label_descr.short_preamble = info.short_preamble mid_label_descr.virtual_state = info.virtual_state start_label_descr = TargetToken(jitcell_token) jitcell_token.target_tokens = [mid_label_descr, start_label_descr] loop.operations[0].setdescr(mid_label_descr) loop.operations[-1].setdescr(mid_label_descr) info.preamble.operations[0].setdescr(start_label_descr) guards = [op for op in loop.operations if op.is_guard()] assert len(guards) == 1, "more than one guard in the loop" bridge = self.parse(bridge_ops) bridge.operations[-1].setdescr(jitcell_token) self.add_guard_future_condition(bridge) trace = oparser.convert_loop_to_trace( bridge, FakeMetaInterpStaticData(self.cpu)) data = compile.BridgeCompileData( trace, self.convert_values(bridge.operations[-1].getarglist(), bridge_values), None, enable_opts=self.enable_opts, inline_short_preamble=inline_short_preamble) bridge_info, ops = self._do_optimize_loop(data) loop.check_consistency(check_descr=False) info.preamble.check_consistency(check_descr=False) bridge.operations = ([ResOperation(rop.LABEL, bridge_info.inputargs)] + ops) bridge.inputargs = bridge_info.inputargs bridge.check_consistency(check_descr=False) expected = self.parse(expected) self.assert_equal(bridge, convert_old_style_to_targets(expected, jump=True)) jump_bridge = bridge.operations[-1] jump_d = jump_bridge.getdescr() jump_args = jump_bridge.getarglist() if loop.operations[0].getdescr() is jump_d: # jump to loop label_args = loop.operations[0].getarglist() else: assert info.preamble.operations[0].getdescr() is jump_d label_args = info.preamble.operations[0].getarglist() assert len(jump_args) == len(label_args) for a, b in zip(jump_args, label_args): assert a.type == b.type
def produce_into(self, builder, r): subset, f, exc = self.raising_func_code(builder, r) TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) while True: _, vtableptr = builder.get_random_structure_type_and_vtable(r) if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(), descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op)
def _emit_mul_if_factor_offset_not_supported(self, index_box, factor, offset): # Returns (factor, offset, index_box) where index_box is either # a non-constant BoxInt or None. if isinstance(index_box, ConstInt): return 1, index_box.value * factor + offset, None else: if factor != 1 and factor not in self.cpu.load_supported_factors: # the factor is supported by the cpu # x & (x - 1) == 0 is a quick test for power of 2 assert factor > 0 if (factor & (factor - 1)) == 0: index_box = ResOperation(rop.INT_LSHIFT, [index_box, ConstInt(highest_bit(factor))]) else: index_box = ResOperation(rop.INT_MUL, [index_box, ConstInt(factor)]) self.emit_op(index_box) factor = 1 return factor, offset, index_box
def _int_add(optstring, box1, box2): if isinstance(box1, ConstInt): if box1.value == 0: return box2 if isinstance(box2, ConstInt): return ConstInt(box1.value + box2.value) elif isinstance(box2, ConstInt) and box2.value == 0: return box1 op = ResOperation(rop.INT_ADD, [box1, box2]) optstring.optimizer.send_extra_operation(op) return op
def _force_elements(self, op, optforce, descr): if self._fields is None: return for i, fielddescr in enumerate(descr.get_all_fielddescrs()): fld = self._fields[i] if fld is not None: subbox = optforce.force_box(fld) setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox], descr=fielddescr) self._fields[i] = None optforce.emit_operation(setfieldop)
def optimize_VIRTUAL_REF(self, op): # get some constants vrefinfo = self.optimizer.metainterp_sd.virtualref_info c_cls = vrefinfo.jit_virtual_ref_const_class vref_descr = vrefinfo.descr descr_virtual_token = vrefinfo.descr_virtual_token descr_forced = vrefinfo.descr_forced # # Replace the VIRTUAL_REF operation with a virtual structure of type # 'jit_virtual_ref'. The jit_virtual_ref structure may be forced soon, # but the point is that doing so does not force the original structure. newop = ResOperation(rop.NEW_WITH_VTABLE, [], descr=vref_descr) vrefvalue = self.make_virtual(c_cls, newop, vref_descr) op.set_forwarded(newop) newop.set_forwarded(vrefvalue) token = ResOperation(rop.FORCE_TOKEN, []) self.emit_operation(token) vrefvalue.setfield(descr_virtual_token, newop, token) vrefvalue.setfield(descr_forced, newop, self.optimizer.cpu.ts.CONST_NULLREF)
def produce_into(self, builder, r): subset, f, exc = self.raising_func_code(builder, r) TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) while True: _, vtableptr = builder.get_random_structure_type_and_vtable(r) if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [other_box], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op)
def _really_force(self, optforce): if self.mode is mode_string: s = self.get_constant_string_spec(mode_string) if s is not None: c_s = get_const_ptr_for_string(s) self.make_constant(c_s) return else: s = self.get_constant_string_spec(mode_unicode) if s is not None: c_s = get_const_ptr_for_unicode(s) self.make_constant(c_s) return assert self.source_op is not None self.box = box = self.source_op.result lengthbox = self.getstrlen(optforce, self.mode, None) op = ResOperation(self.mode.NEWSTR, [lengthbox], box) if not we_are_translated(): op.name = 'FORCE' optforce.emit_operation(op) self.initialize_forced_string(optforce, box, CONST_0, self.mode)
def parse_loop(self, ops, add_label=True): loop = self.parse(ops, postprocess=self.postprocess) loop.operations = filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) token = JitCellToken() if add_label: label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) else: label = loop.operations[0] label.setdescr(TargetToken(token)) jump = loop.operations[-1] loop = VectorLoop(label, loop.operations[0:-1], jump) loop.jump.setdescr(token) class Optimizer(object): metainterp_sd = FakeMetaInterpStaticData(self.cpu) jitdriver_sd = FakeJitDriverStaticData() opt = Optimizer() opt.jitdriver_sd.vec = True for op in loop.operations: if op.is_guard() and not op.getdescr(): descr = invent_fail_descr_for_op(op.getopnum(), opt) op.setdescr(descr) return loop
def test_opcount_filling_guard(self): descr = ArrayDescr(0,4, None, 'S') vec = ResOperation(rop.VEC_RAW_LOAD_I, ['a','i'], descr=descr) vec.count = 4 pack = Pack([Node(ResOperation(rop.GUARD_TRUE, [vec]), 0), Node(ResOperation(rop.GUARD_TRUE, [vec]), 1), Node(ResOperation(rop.GUARD_TRUE, [vec]), 2), Node(ResOperation(rop.GUARD_TRUE, [vec]), 3), Node(ResOperation(rop.GUARD_TRUE, [vec]), 4), Node(ResOperation(rop.GUARD_TRUE, [vec]), 5), ]) assert pack.pack_load(16) == 24-16 assert pack.pack_load(8) == 24-8 assert pack.pack_load(32) == 24-32 assert pack.opcount_filling_vector_register(16) == 4 ops, newops = pack.slice_operations(16) assert len(ops) == 4 assert len(newops) == 2 assert pack.opcount_filling_vector_register(8) == 2 ops, newops = pack.slice_operations(8) assert len(ops) == 2 assert len(newops) == 4
def record(self, opnum, argboxes, value, descr=None): op = ResOperation(opnum, argboxes, descr) if value is None: assert op.type == 'v' elif isinstance(value, bool): assert op.type == 'i' op.setint(int(value)) elif lltype.typeOf(value) == lltype.Signed: assert op.type == 'i' op.setint(value) elif lltype.typeOf(value) is longlong.FLOATSTORAGE: assert op.type == 'f' op.setfloatstorage(value) else: assert lltype.typeOf(value) == llmemory.GCREF assert op.type == 'r' op.setref_base(value) self.operations.append(op) return op
def remove_tested_failarg(self, op): opnum = op.getopnum() if not (opnum == rop.GUARD_TRUE or opnum == rop.GUARD_FALSE): return if op.getarg(0).is_vector(): return try: i = op.getfailargs().index(op.getarg(0)) except ValueError: return # The checked value is also in the failargs. The front-end # tries not to produce it, but doesn't always succeed (and # it's hard to test all cases). Rewrite it away. value = int(opnum == rop.GUARD_FALSE) op1 = ResOperation(rop.SAME_AS_I, [ConstInt(value)]) op1.setint(value) self.emit_op(op1) lst = op.getfailargs()[:] lst[i] = op1 newop = op.copy_and_change(opnum) newop.setfailargs(lst) self._changed_op = op self._changed_op_to = newop
def exc_handling(guard_op): # operations need to start with correct GUARD_EXCEPTION if guard_op._exc_box is None: op = ResOperation(rop.GUARD_NO_EXCEPTION, []) else: op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box]) op.setdescr(self.builder.getfaildescr()) op.setfailargs([]) return op
def handle_malloc_operation(self, op): opnum = op.getopnum() if opnum == rop.NEW: self.handle_new_fixedsize(op.getdescr(), op) elif opnum == rop.NEW_WITH_VTABLE: descr = op.getdescr() self.handle_new_fixedsize(descr, op) if self.gc_ll_descr.fielddescr_vtable is not None: op = ResOperation(rop.SETFIELD_GC, [op, ConstInt(descr.get_vtable())], descr=self.gc_ll_descr.fielddescr_vtable) self.emit_op(op) elif opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR: descr = op.getdescr() assert isinstance(descr, ArrayDescr) self.handle_new_array(descr, op) elif opnum == rop.NEWSTR: self.handle_new_array(self.gc_ll_descr.str_descr, op, kind=FLAG_STR) elif opnum == rop.NEWUNICODE: self.handle_new_array(self.gc_ll_descr.unicode_descr, op, kind=FLAG_UNICODE) else: raise NotImplementedError(op.getopname())
def compile_simple_loop(metainterp, greenkey, start, inputargs, ops, jumpargs, enable_opts): from rpython.jit.metainterp.optimizeopt import optimize_trace jitdriver_sd = metainterp.jitdriver_sd metainterp_sd = metainterp.staticdata jitcell_token = make_jitcell_token(jitdriver_sd) label = ResOperation(rop.LABEL, inputargs[:], descr=jitcell_token) jump_op = ResOperation(rop.JUMP, jumpargs[:], descr=jitcell_token) call_pure_results = metainterp.call_pure_results data = SimpleCompileData(label, ops + [jump_op], call_pure_results=call_pure_results, enable_opts=enable_opts) try: loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) except InvalidLoop: return None loop = create_empty_loop(metainterp) loop.original_jitcell_token = jitcell_token loop.inputargs = loop_info.inputargs if loop_info.quasi_immutable_deps: loop.quasi_immutable_deps = loop_info.quasi_immutable_deps jump_op = ops[-1] target_token = TargetToken(jitcell_token) target_token.original_jitcell_token = jitcell_token label = ResOperation(rop.LABEL, loop_info.inputargs[:], descr=target_token) jump_op.setdescr(target_token) loop.operations = [label] + ops if not we_are_translated(): loop.check_consistency() jitcell_token.target_tokens = [target_token] send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", inputargs, metainterp.box_names_memo) record_loop_or_bridge(metainterp_sd, loop) return target_token
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) original_intvars = builder.intvars[:] builder.fakemetainterp.ovf_flag = False super(AbstractOvfOperation, self).produce_into(builder, r) if builder.fakemetainterp.ovf_flag: # overflow detected op = ResOperation(rop.GUARD_OVERFLOW, []) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including # the result, and then remove it from builder.intvars. fail_subset = builder.subset_of_intvars(r) builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, []) op.setdescr(builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)