class FloatOpAssembler(object): _mixin_ = True emit_float_add = gen_emit_rr_rp('ADBR', 'ADB') emit_float_sub = gen_emit_rr_rp('SDBR', 'SDB') emit_float_mul = gen_emit_rr_rp('MDBR', 'MDB') emit_float_truediv = gen_emit_rr_rp('DDBR', 'DDB') # Support for NaNs: S390X sets condition code to 0x3 (unordered) # whenever any operand is nan. # in the case float_le,float_ge the overflow bit is not set of # the initial condition! # e.g. guard_true(nan <= x): jumps 1100 inv => 0011, bit 3 set # e.g. guard_false(nan <= x): does not jump 1100, bit 3 not set # e.g. guard_true(nan >= nan): jumps 1010 inv => 0101, bit 3 set emit_float_lt = gen_emit_cmp_op(c.LT, fp=True) emit_float_le = gen_emit_cmp_op(c.FLE, fp=True) emit_float_eq = gen_emit_cmp_op(c.EQ, fp=True) emit_float_ne = gen_emit_cmp_op(c.NE, fp=True) emit_float_gt = gen_emit_cmp_op(c.GT, fp=True) emit_float_ge = gen_emit_cmp_op(c.FGE, fp=True) def emit_float_neg(self, op, arglocs, regalloc): l0, = arglocs self.mc.LCDBR(l0, l0) def emit_float_abs(self, op, arglocs, regalloc): l0, = arglocs self.mc.LPDBR(l0, l0) def emit_cast_float_to_int(self, op, arglocs, regalloc): f0, r0 = arglocs self.mc.CGDBR(r0, c.FP_TOWARDS_ZERO, f0) def emit_cast_int_to_float(self, op, arglocs, regalloc): r0, f0 = arglocs self.mc.CDGBR(f0, r0) def emit_convert_float_bytes_to_longlong(self, op, arglocs, regalloc): l0, res = arglocs self.mc.LGDR(res, l0) def emit_convert_longlong_bytes_to_float(self, op, arglocs, regalloc): l0, res = arglocs self.mc.LDGR(res, l0)
class IntOpAssembler(object): _mixin_ = True emit_int_add = gen_emit_rr_rh_ri_rp('AGR', 'AGHI', 'AGFI', 'AG') emit_int_add_ovf = emit_int_add emit_nursery_ptr_increment = emit_int_add def emit_int_sub(self, op, arglocs, regalloc): res, l0, l1 = arglocs self.mc.SGRK(res, l0, l1) emit_int_sub_ovf = emit_int_sub emit_int_mul = gen_emit_rr_rh_ri_rp('MSGR', 'MGHI', 'MSGFI', 'MSG') def emit_int_mul_ovf(self, op, arglocs, regalloc): lr, lq, l1 = arglocs if l1.is_in_pool(): self.mc.LG(r.SCRATCH, l1) l1 = r.SCRATCH elif l1.is_imm(): self.mc.LGFI(r.SCRATCH, l1) l1 = r.SCRATCH else: # we are not allowed to modify l1 if it is not a scratch # register, thus copy it here! self.mc.LGR(r.SCRATCH, l1) l1 = r.SCRATCH mc = self.mc # check left neg jmp_lq_lt_0 = mc.get_relative_pos() mc.reserve_cond_jump() # CGIJ lq < 0 +-----------+ jmp_l1_ge_0 = mc.get_relative_pos() # | mc.reserve_cond_jump() # CGIJ l1 >= 0 -----------|-> (both same sign) jmp_lq_pos_l1_neg = mc.get_relative_pos() # | mc.reserve_cond_jump(short=True) # BCR any -----|-> (xor negative) jmp_l1_neg_lq_neg = mc.get_relative_pos() # | mc.reserve_cond_jump() # <-----------------------+ # CGIJ l1 < 0 -> (both same_sign) # (xor negative) label_xor_neg = mc.get_relative_pos() mc.LPGR(lq, lq) mc.LPGR(l1, l1) mc.MLGR(lr, l1) mc.LGHI(r.SCRATCH, l.imm(-1)) mc.RISBG(r.SCRATCH, r.SCRATCH, l.imm(0), l.imm(0x80 | 0), l.imm(0)) # is the value greater than 2**63 ? then an overflow occured jmp_xor_lq_overflow = mc.get_relative_pos() mc.reserve_cond_jump() # CLGRJ lq > 0x8000 ... 00 -> (label_overflow) jmp_xor_lr_overflow = mc.get_relative_pos() mc.reserve_cond_jump() # CLGIJ lr > 0 -> (label_overflow) mc.LCGR(lq, lq) # complement the value mc.XGR(r.SCRATCH, r.SCRATCH) mc.SPM(r.SCRATCH ) # 0x80 ... 00 clears the condition code and program mask jmp_no_overflow_xor_neg = mc.get_relative_pos() mc.reserve_cond_jump(short=True) # both are positive/negative label_both_same_sign = mc.get_relative_pos() mc.LPGR(lq, lq) mc.LPGR(l1, l1) mc.MLGR(lr, l1) mc.LGHI(r.SCRATCH, l.imm(-1)) # 0xff -> shift 0 -> 0xff set MSB on pos 0 to zero -> 7f mc.RISBG(r.SCRATCH, r.SCRATCH, l.imm(1), l.imm(0x80 | 63), l.imm(0)) jmp_lq_overflow = mc.get_relative_pos() mc.reserve_cond_jump() # CLGRJ lq > 0x7fff ... ff -> (label_overflow) jmp_lr_overflow = mc.get_relative_pos() mc.reserve_cond_jump() # CLGIJ lr > 0 -> (label_overflow) jmp_neither_lqlr_overflow = mc.get_relative_pos() mc.reserve_cond_jump(short=True) # BRC any -> (label_end) # set overflow! label_overflow = mc.get_relative_pos() # set bit 34 & 35 -> indicates overflow mc.XGR(r.SCRATCH, r.SCRATCH) mc.OILH(r.SCRATCH, l.imm(0x3000)) # sets OF mc.SPM(r.SCRATCH) # no overflow happended label_end = mc.get_relative_pos() # patch patch patch!!! # jmp_lq_lt_0 pos = jmp_lq_lt_0 omc = OverwritingBuilder(self.mc, pos, 1) omc.CGIJ(lq, l.imm(0), c.LT, l.imm(jmp_l1_neg_lq_neg - pos)) omc.overwrite() # jmp_l1_ge_0 pos = jmp_l1_ge_0 omc = OverwritingBuilder(self.mc, pos, 1) omc.CGIJ(l1, l.imm(0), c.GE, l.imm(label_both_same_sign - pos)) omc.overwrite() # jmp_lq_pos_l1_neg pos = jmp_lq_pos_l1_neg omc = OverwritingBuilder(self.mc, pos, 1) omc.BRC(c.ANY, l.imm(label_xor_neg - pos)) omc.overwrite() # jmp_l1_neg_lq_neg pos = jmp_l1_neg_lq_neg omc = OverwritingBuilder(self.mc, pos, 1) omc.CGIJ(l1, l.imm(0), c.LT, l.imm(label_both_same_sign - pos)) omc.overwrite() # patch jmp_xor_lq_overflow pos = jmp_xor_lq_overflow omc = OverwritingBuilder(self.mc, pos, 1) omc.CLGRJ(lq, r.SCRATCH, c.GT, l.imm(label_overflow - pos)) omc.overwrite() # patch jmp_xor_lr_overflow pos = jmp_xor_lr_overflow omc = OverwritingBuilder(self.mc, pos, 1) omc.CLGIJ(lr, l.imm(0), c.GT, l.imm(label_overflow - pos)) omc.overwrite() # patch jmp_no_overflow_xor_neg omc = OverwritingBuilder(self.mc, jmp_no_overflow_xor_neg, 1) omc.BRC(c.ANY, l.imm(label_end - jmp_no_overflow_xor_neg)) omc.overwrite() # patch jmp_lq_overflow omc = OverwritingBuilder(self.mc, jmp_lq_overflow, 1) omc.CLGRJ(lq, r.SCRATCH, c.GT, l.imm(label_overflow - jmp_lq_overflow)) omc.overwrite() # patch jmp_lr_overflow omc = OverwritingBuilder(self.mc, jmp_lr_overflow, 1) omc.CLGIJ(lr, l.imm(0), c.GT, l.imm(label_overflow - jmp_lr_overflow)) omc.overwrite() # patch jmp_neither_lqlr_overflow omc = OverwritingBuilder(self.mc, jmp_neither_lqlr_overflow, 1) omc.BRC(c.ANY, l.imm(label_end - jmp_neither_lqlr_overflow)) omc.overwrite() emit_int_floordiv = gen_emit_div_mod('DSGR', 'DSG') emit_uint_floordiv = gen_emit_div_mod('DLGR', 'DLG') # NOTE division sets one register with the modulo value, thus # the regalloc ensures the right register survives. emit_int_mod = gen_emit_div_mod('DSGR', 'DSG') def emit_int_invert(self, op, arglocs, regalloc): l0, = arglocs assert not l0.is_imm() self.mc.LGHI(r.SCRATCH, l.imm(-1)) self.mc.XGR(l0, r.SCRATCH) def emit_int_neg(self, op, arglocs, regalloc): l0, = arglocs self.mc.LCGR(l0, l0) def emit_int_signext(self, op, arglocs, regalloc): l0, = arglocs extend_from = op.getarg(1).getint() if extend_from == 1: self.mc.LGBR(l0, l0) elif extend_from == 2: self.mc.LGHR(l0, l0) elif extend_from == 4: self.mc.LGFR(l0, l0) else: raise AssertionError(extend_from) def emit_int_force_ge_zero(self, op, arglocs, resloc): l0, = arglocs off = self.mc.CGIJ_byte_count + self.mc.LGHI_byte_count self.mc.CGIJ(l0, l.imm(0), c.GE, l.imm(off)) self.mc.LGHI(l0, l.imm(0)) def emit_int_is_zero(self, op, arglocs, regalloc): l0, res = arglocs self.mc.CGHI(l0, l.imm(0)) self.flush_cc(c.EQ, res) def emit_int_is_true(self, op, arglocs, regalloc): l0, res = arglocs self.mc.CGHI(l0, l.imm(0)) self.flush_cc(c.NE, res) emit_int_and = gen_emit_rr_rp("NGR", "NG") emit_int_or = gen_emit_rr_rp("OGR", "OG") emit_int_xor = gen_emit_rr_rp("XGR", "XG") emit_int_rshift = gen_emit_shift("SRAG") emit_int_lshift = gen_emit_shift("SLLG") emit_uint_rshift = gen_emit_shift("SRLG") emit_int_le = gen_emit_cmp_op(c.LE) emit_int_lt = gen_emit_cmp_op(c.LT) emit_int_gt = gen_emit_cmp_op(c.GT) emit_int_ge = gen_emit_cmp_op(c.GE) emit_int_eq = gen_emit_cmp_op(c.EQ) emit_int_ne = gen_emit_cmp_op(c.NE) emit_ptr_eq = emit_int_eq emit_ptr_ne = emit_int_ne emit_instance_ptr_eq = emit_ptr_eq emit_instance_ptr_ne = emit_ptr_ne emit_uint_le = gen_emit_cmp_op(c.LE, signed=False) emit_uint_lt = gen_emit_cmp_op(c.LT, signed=False) emit_uint_gt = gen_emit_cmp_op(c.GT, signed=False) emit_uint_ge = gen_emit_cmp_op(c.GE, signed=False)