These instructions are available with the general-instructions-extension facility. Use them if available.
Signed-off-by: Richard Henderson <r...@twiddle.net> --- tcg/s390/tcg-target.c | 102 +++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 95 insertions(+), 7 deletions(-) diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 691a3f5..d5c26b8 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -119,6 +119,15 @@ typedef enum S390Opcode { RI_OILH = 0xa50a, RI_OILL = 0xa50b, + RIE_CGIJ = 0xec7c, + RIE_CGRJ = 0xec64, + RIE_CIJ = 0xec7e, + RIE_CLGRJ = 0xec65, + RIE_CLIJ = 0xec7f, + RIE_CLGIJ = 0xec7d, + RIE_CLRJ = 0xec77, + RIE_CRJ = 0xec76, + RRE_AGR = 0xb908, RRE_CGR = 0xb920, RRE_CLGR = 0xb921, @@ -1110,6 +1119,7 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val) static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, TCGArg c2, int c2const) { + _Bool is_unsigned = (c > TCG_COND_GT); if (c2const) { if (c2 == 0) { if (type == TCG_TYPE_I32) { @@ -1119,15 +1129,13 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, } return tcg_cond_to_ltr_cond[c]; } else { - if (c > TCG_COND_GT) { - /* unsigned */ + if (is_unsigned) { if (type == TCG_TYPE_I32) { tcg_out_insn(s, RIL, CLFI, r1, c2); } else { tcg_out_insn(s, RIL, CLGFI, r1, c2); } } else { - /* signed */ if (type == TCG_TYPE_I32) { tcg_out_insn(s, RIL, CFI, r1, c2); } else { @@ -1136,15 +1144,13 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, } } } else { - if (c > TCG_COND_GT) { - /* unsigned */ + if (is_unsigned) { if (type == TCG_TYPE_I32) { tcg_out_insn(s, RR, CLR, r1, c2); } else { tcg_out_insn(s, RRE, CLGR, r1, c2); } } else { - /* signed */ if (type == TCG_TYPE_I32) { tcg_out_insn(s, RR, CR, r1, c2); } else { @@ -1195,10 +1201,92 @@ static void tgen_branch(TCGContext *s, int cc, int labelno) } } +static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc, + TCGReg r1, TCGReg r2, int labelno) +{ + TCGLabel* l = &s->labels[labelno]; + tcg_target_long off; + + if (l->has_value) { + off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1; + } else { + /* We need to keep the offset unchanged for retranslation. */ + off = ((int16_t *)s->code_ptr)[1]; + tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2); + } + + tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2); + tcg_out16(s, off); + tcg_out16(s, cc << 12 | (opc & 0xff)); +} + +static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc, + TCGReg r1, int i2, int labelno) +{ + TCGLabel* l = &s->labels[labelno]; + tcg_target_long off; + + if (l->has_value) { + off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1; + } else { + /* We need to keep the offset unchanged for retranslation. */ + off = ((int16_t *)s->code_ptr)[1]; + tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2); + } + + tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc); + tcg_out16(s, off); + tcg_out16(s, (i2 << 8) | (opc & 0xff)); +} + static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, TCGArg c2, int c2const, int labelno) { - int cc = tgen_cmp(s, type, c, r1, c2, c2const); + int cc; + + if (facilities & FACILITY_GEN_INST_EXT) { + _Bool is_unsigned = (c > TCG_COND_GT); + _Bool in_range; + S390Opcode opc; + + cc = tcg_cond_to_s390_cond[c]; + + if (!c2const) { + opc = (type == TCG_TYPE_I32 + ? (is_unsigned ? RIE_CLRJ : RIE_CRJ) + : (is_unsigned ? RIE_CLGRJ : RIE_CGRJ)); + tgen_compare_branch(s, opc, cc, r1, c2, labelno); + return; + } + + /* COMPARE IMMEDIATE AND BRANCH RELATIVE has an 8-bit immediate field. + If the immediate we've been given does not fit that range, we'll + fall back to separate compare and branch instructions using the + larger comparison range afforded by COMPARE IMMEDIATE. */ + if (type == TCG_TYPE_I32) { + if (is_unsigned) { + opc = RIE_CLIJ; + in_range = (uint32_t)c2 == (uint8_t)c2; + } else { + opc = RIE_CIJ; + in_range = (int32_t)c2 == (int8_t)c2; + } + } else { + if (is_unsigned) { + opc = RIE_CLGIJ; + in_range = (uint64_t)c2 == (uint8_t)c2; + } else { + opc = RIE_CGIJ; + in_range = (int64_t)c2 == (int8_t)c2; + } + } + if (in_range) { + tgen_compare_imm_branch(s, opc, cc, r1, c2, labelno); + return; + } + } + + cc = tgen_cmp(s, type, c, r1, c2, c2const); tgen_branch(s, cc, labelno); } -- 1.7.0.1