def wrap_constant(value): if lltype.typeOf(value) == lltype.Signed: return ConstInt(value) elif isinstance(value, bool): return ConstInt(int(value)) elif lltype.typeOf(value) == longlong.FLOATSTORAGE: return ConstFloat(value) elif isinstance(value, float): return ConstFloat(longlong.getfloatstorage(value)) else: assert lltype.typeOf(value) == llmemory.GCREF return ConstPtr(value)
def test_ResumeDataLoopMemo_other(): memo = ResumeDataLoopMemo(FakeMetaInterpStaticData()) const = ConstFloat(longlong.getfloatstorage(-1.0)) tagged = memo.getconst(const) index, tagbits = untag(tagged) assert tagbits == TAGCONST assert memo.consts[index - TAG_CONST_OFFSET] is const
def callback(asm): c = ConstFloat(longlong.getfloatstorage(-42.5)) loc = self.xrm.convert_to_imm(c) asm.mov(loc, xmm5) asm.regalloc_push(xmm5) asm.regalloc_pop(xmm0) asm.mc.CVTTSD2SI(eax, xmm0)
def produce_into(self, builder, r): if r.random() < 0.4: UnaryOperation.produce_into(self, builder, r) elif r.random() < 0.75 or not builder.cpu.supports_floats: self.put(builder, [ConstInt(r.random_integer())]) else: self.put(builder, [ConstFloat(r.random_float_storage())])
def produce_into(self, builder, r): if not builder.floatvars: raise CannotProduceOperation k = r.random() if k < 0.18: v_first = ConstFloat(r.random_float_storage()) else: v_first = r.choice(builder.floatvars) if k > 0.82: v_second = ConstFloat(r.random_float_storage()) else: v_second = r.choice(builder.floatvars) if abs(v_first.getfloat()) > 1E100 or abs(v_second.getfloat()) > 1E100: raise CannotProduceOperation # avoid infinities if abs(v_second.getfloat()) < 1E-100: raise CannotProduceOperation # e.g. division by zero error self.put(builder, [v_first, v_second])
def constant_from_op(op): if op.type == 'i': return ConstInt(op.getint()) elif op.type == 'r': return ConstPtr(op.getref_base()) else: assert op.type == 'f' return ConstFloat(op.getfloatstorage())
def constbox(v): if v.type == INT: return ConstInt(getint(v)) if v.type == FLOAT: return ConstFloat(getfloatstorage(v)) if v.type == REF: return ConstPtr(getref_base(v)) assert 0, v.type
def produce_into(self, builder, r): if not builder.floatvars: raise CannotProduceOperation k = r.random() if k < 0.18: v_first = ConstFloat(r.random_float_storage()) else: v_first = r.choice(builder.floatvars) if k > 0.82: v_second = ConstFloat(r.random_float_storage()) else: v_second = r.choice(builder.floatvars) if abs(getfloat(v_first)) > 1E100 or abs(getfloat(v_second)) > 1E100: raise CannotProduceOperation # avoid infinities if abs(getfloat(v_second)) < 1E-100: raise CannotProduceOperation # e.g. division by zero error self.put(builder, [v_first, v_second])
def get_current_constant_fieldvalue(self): struct = self.struct fielddescr = self.fielddescr if self.fielddescr.is_pointer_field(): return ConstPtr(self.cpu.bh_getfield_gc_r(struct, fielddescr)) elif self.fielddescr.is_float_field(): return ConstFloat(self.cpu.bh_getfield_gc_f(struct, fielddescr)) else: return ConstInt(self.cpu.bh_getfield_gc_i(struct, fielddescr))
def accumulate_prepare(self, state): vec_reg_size = state.vec_reg_size for pack in self.packs: if not pack.is_accumulating(): continue if pack.leftmost().is_guard(): # guard breaks dependencies, thus it is an accumulation pack continue for i,node in enumerate(pack.operations): op = node.getoperation() state.accumulation[op] = pack assert isinstance(pack, AccumPack) datatype = pack.getdatatype() bytesize = pack.getbytesize() count = vec_reg_size // bytesize signed = datatype == 'i' oplist = state.invariant_oplist # reset the box to zeros or ones if pack.reduce_init() == 0: vecop = OpHelpers.create_vec(datatype, bytesize, signed, count) oplist.append(vecop) opnum = rop.VEC_INT_XOR if datatype == FLOAT: # see PRECISION loss below raise NotImplementedError vecop = VecOperation(opnum, [vecop, vecop], vecop, count) oplist.append(vecop) elif pack.reduce_init() == 1: # PRECISION loss, because the numbers are accumulated (associative, commutative properties must hold) # you can end up a small number and a huge number that is finally multiplied. giving an # inprecision result, thus this is disabled now raise NotImplementedError # multiply is only supported by floats vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize, signed, count) oplist.append(vecop) else: raise NotImplementedError("cannot handle %s" % pack.operator) # pack the scalar value args = [vecop, pack.getleftmostseed(), ConstInt(0), ConstInt(1)] vecop = OpHelpers.create_vec_pack(datatype, args, bytesize, signed, count) oplist.append(vecop) seed = pack.getleftmostseed() state.accumulation[seed] = pack # rename the variable with the box state.setvector_of_box(seed, 0, vecop) # prevent it from expansion state.renamer.start_renaming(seed, vecop)
def _untag(self, tagged): tag, v = untag(tagged) if tag == TAGBOX: return self._get(v) elif tag == TAGINT: return ConstInt(v + SMALL_INT_START) elif tag == TAGCONSTPTR: return ConstPtr(self.trace._refs[v]) elif tag == TAGCONSTOTHER: if v & 1: return ConstFloat(self.trace._floats[v >> 1]) else: return ConstInt(self.trace._bigints[v >> 1]) else: assert False
def optimize_FLOAT_TRUEDIV(self, op): arg1 = op.getarg(0) arg2 = op.getarg(1) v2 = self.getvalue(arg2) # replace "x / const" by "x * (1/const)" if possible if v2.is_constant(): divisor = v2.box.getfloat() fraction = math.frexp(divisor)[0] # This optimization is valid for powers of two # but not for zeroes, some denormals and NaN: if fraction == 0.5 or fraction == -0.5: reciprocal = 1.0 / divisor rfraction = math.frexp(reciprocal)[0] if rfraction == 0.5 or rfraction == -0.5: c = ConstFloat(longlong.getfloatstorage(reciprocal)) op = op.copy_and_change(rop.FLOAT_MUL, args=[arg1, c]) self.emit_operation(op)
def optimize_FLOAT_TRUEDIV(self, op): arg1 = op.getarg(0) arg2 = op.getarg(1) v2 = get_box_replacement(arg2) # replace "x / const" by "x * (1/const)" if possible newop = op if v2.is_constant(): divisor = v2.getfloat() fraction = math.frexp(divisor)[0] # This optimization is valid for powers of two # but not for zeroes, some denormals and NaN: if fraction == 0.5 or fraction == -0.5: reciprocal = 1.0 / divisor rfraction = math.frexp(reciprocal)[0] if rfraction == 0.5 or rfraction == -0.5: c = ConstFloat(longlong.getfloatstorage(reciprocal)) newop = self.replace_op_with(op, rop.FLOAT_MUL, args=[arg1, c]) return self.emit(newop)
def accumulate_prepare(self, state): vec_reg_size = state.vec_reg_size for pack in self.packs: if not pack.is_accumulating(): continue if pack.leftmost().is_guard(): # guard breaks dependencies, thus it is an accumulation pack continue for i,node in enumerate(pack.operations): op = node.getoperation() state.accumulation[op] = pack assert isinstance(pack, AccumPack) datatype = pack.getdatatype() bytesize = pack.getbytesize() count = vec_reg_size // bytesize signed = datatype == 'i' oplist = state.invariant_oplist # reset the box to zeros or ones if pack.reduce_init() == 0: vecop = OpHelpers.create_vec(datatype, bytesize, signed, count) oplist.append(vecop) vecop = VecOperation(rop.VEC_INT_XOR, [vecop, vecop], vecop, count) oplist.append(vecop) elif pack.reduce_init() == 1: # multiply is only supported by floats vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize, signed, count) oplist.append(vecop) else: raise NotImplementedError("cannot handle %s" % pack.operator) # pack the scalar value args = [vecop, pack.getleftmostseed(), ConstInt(0), ConstInt(1)] vecop = OpHelpers.create_vec_pack(datatype, args, bytesize, signed, count) oplist.append(vecop) seed = pack.getleftmostseed() state.accumulation[seed] = pack # rename the variable with the box state.setvector_of_box(seed, 0, vecop) # prevent it from expansion state.renamer.start_renaming(seed, vecop)
def test_wrap(): def _is(box1, box2): return (box1.__class__ == box2.__class__ and box1.value == box2.value) p = lltype.malloc(lltype.GcStruct('S')) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert _is(wrap(None, 42), BoxInt(42)) assert _is(wrap(None, 42.5), boxfloat(42.5)) assert _is(wrap(None, p), BoxPtr(po)) assert _is(wrap(None, 42, in_const_box=True), ConstInt(42)) assert _is(wrap(None, 42.5, in_const_box=True), constfloat(42.5)) assert _is(wrap(None, p, in_const_box=True), ConstPtr(po)) if longlong.supports_longlong: import sys from rpython.rlib.rarithmetic import r_longlong, r_ulonglong value = r_longlong(-sys.maxint*17) assert _is(wrap(None, value), BoxFloat(value)) assert _is(wrap(None, value, in_const_box=True), ConstFloat(value)) value_unsigned = r_ulonglong(-sys.maxint*17) assert _is(wrap(None, value_unsigned), BoxFloat(value)) sfval = r_singlefloat(42.5) ival = longlong.singlefloat2int(sfval) assert _is(wrap(None, sfval), BoxInt(ival)) assert _is(wrap(None, sfval, in_const_box=True), ConstInt(ival))
def constfloat(x): return ConstFloat(longlong.getfloatstorage(x))
def build_bridge(self): 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 if self.dont_generate_more: return False r = self.r guard_op = self.guard_op fail_args = guard_op.getfailargs() fail_descr = guard_op.getdescr() op = self.should_fail_by if not op.getfailargs(): return False for _fail_box in fail_args: _fail_box.set_forwarded(None) # generate the branch: a sequence of operations that ends in a FINISH subloop = DummyLoop([]) self.subloops.append(subloop) # keep around for debugging if rop.is_guard_exception(guard_op.getopnum()): subloop.operations.append(exc_handling(guard_op)) bridge_builder = self.builder.fork(self.builder.cpu, subloop, op.getfailargs()[:]) self.generate_ops(bridge_builder, r, subloop, op.getfailargs()[:]) # note that 'self.guard_op' now points to the guard that will fail in # this new bridge, while 'guard_op' still points to the guard that # has just failed. if r.random() < 0.1 and self.guard_op is None: # Occasionally, instead of ending in a FINISH, we end in a jump # to another loop. We don't do it, however, if the new bridge's # execution will hit 'self.guard_op', but only if it executes # to the FINISH normally. (There is no point to the extra # complexity, as we might get the same effect by two calls # to build_bridge().) # First make up the other loop... # # New restriction: must have the same argument count and types # as the original loop subset = [] for box in self.loop.inputargs: srcbox = r.choice(fail_args) if srcbox.type != box.type: if box.type == INT: srcbox = ConstInt(r.random_integer()) elif box.type == FLOAT: srcbox = ConstFloat(r.random_float_storage()) else: raise AssertionError(box.type) subset.append(srcbox) # args = [] for x in subset: if x.type == INT: args.append(InputArgInt(getint(x))) elif x.type == FLOAT: args.append(InputArgFloat(getfloatstorage(x))) else: assert 0, x.type rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) # done self.should_fail_by = rl.should_fail_by self.expected = rl.expected assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. jump_op = ResOperation(rop.JUMP, subset, descr=rl.loop._targettoken) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts self.loop._jitcelltoken.record_jump_to(rl.loop._jitcelltoken) self.dont_generate_more = True if r.random() < .05: return False dump(subloop) self.builder.cpu.compile_bridge(fail_descr, fail_args, subloop.operations, self.loop._jitcelltoken) if self.output: bridge_builder.print_loop(self.output, fail_descr, fail_args) return True
def produce_into(self, builder, r): if r.random() < 0.4: UnaryFloatOperation.produce_into(self, builder, r) else: self.put(builder, [ConstFloat(r.random_float_storage())])