diff options
author | Richard Henderson <rth@twiddle.net> | 2017-06-16 15:33:28 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2017-09-06 07:24:41 -0700 |
commit | 7af525af01b9615c4f4df5da2e8a50f2fe00b023 (patch) | |
tree | 2d284ddff20cf18d5110e24c2f2e5c2cc3dce54c /tcg/s390 | |
parent | c2097136ad6e3f476fd177fc3d2e48fa6bffacfd (diff) | |
download | qemu-7af525af01b9615c4f4df5da2e8a50f2fe00b023.zip qemu-7af525af01b9615c4f4df5da2e8a50f2fe00b023.tar.gz qemu-7af525af01b9615c4f4df5da2e8a50f2fe00b023.tar.bz2 |
tcg/s390: Use load-on-condition-2 facility
This allows LOAD HALFWORD IMMEDIATE ON CONDITION,
eliminating one insn in some common cases.
Acked-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'tcg/s390')
-rw-r--r-- | tcg/s390/tcg-target.h | 1 | ||||
-rw-r--r-- | tcg/s390/tcg-target.inc.c | 79 |
2 files changed, 63 insertions, 17 deletions
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index f7619a9..bedda5e 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -59,6 +59,7 @@ typedef enum TCGReg { #define FACILITY_LOAD_ON_COND (1ULL << (63 - 45)) #define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND #define FACILITY_DISTINCT_OPS FACILITY_LOAD_ON_COND +#define FACILITY_LOAD_ON_COND2 (1ULL << (63 - 53)) extern uint64_t s390_facilities; diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index a80b07d..0de968f 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -122,6 +122,7 @@ typedef enum S390Opcode { RIE_CLGIJ = 0xec7d, RIE_CLRJ = 0xec77, RIE_CRJ = 0xec76, + RIE_LOCGHI = 0xec46, RIE_RISBG = 0xec55, RRE_AGR = 0xb908, @@ -495,6 +496,13 @@ static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2) tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff)); } +static void tcg_out_insn_RIE(TCGContext *s, S390Opcode op, TCGReg r1, + int i2, int m3) +{ + tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3); + tcg_out32(s, (i2 << 16) | (op & 0xff)); +} + static void tcg_out_insn_RIL(TCGContext *s, S390Opcode op, TCGReg r1, int i2) { tcg_out16(s, op | (r1 << 4)); @@ -1063,7 +1071,20 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg c1, TCGArg c2, int c2const) { int cc; + bool have_loc; + /* With LOC2, we can always emit the minimum 3 insns. */ + if (s390_facilities & FACILITY_LOAD_ON_COND2) { + /* Emit: d = 0, d = (cc ? 1 : d). */ + cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + tcg_out_insn(s, RIE, LOCGHI, dest, 1, cc); + return; + } + + have_loc = (s390_facilities & FACILITY_LOAD_ON_COND) != 0; + + /* For HAVE_LOC, only the path through do_greater is smaller. */ switch (cond) { case TCG_COND_GTU: case TCG_COND_GT: @@ -1076,6 +1097,9 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, return; case TCG_COND_GEU: + if (have_loc) { + goto do_loc; + } do_geu: /* We need "real" carry semantics, so use SUBTRACT LOGICAL instead of COMPARE LOGICAL. This may need an extra move. */ @@ -1105,10 +1129,17 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, return; case TCG_COND_LEU: + if (have_loc) { + goto do_loc; + } + /* fallthru */ case TCG_COND_LTU: case TCG_COND_LT: /* Swap operands so that we can use GEU/GTU/GT. */ if (c2const) { + if (have_loc) { + goto do_loc; + } tcg_out_movi(s, type, TCG_TMP0, c2); c2 = c1; c2const = 0; @@ -1133,6 +1164,9 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, break; case TCG_COND_EQ: + if (have_loc) { + goto do_loc; + } /* X == 0 is X <= 0 is 0 >= X. */ if (c2const && c2 == 0) { tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0); @@ -1148,33 +1182,39 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, } cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); - if (s390_facilities & FACILITY_LOAD_ON_COND) { - /* Emit: d = 0, t = 1, d = (cc ? t : d). */ - tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); - tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc); - } else { - /* Emit: d = 1; if (cc) goto over; d = 0; over: */ - tcg_out_movi(s, type, dest, 1); - tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_movi(s, type, dest, 0); - } + /* Emit: d = 1; if (cc) goto over; d = 0; over: */ + tcg_out_movi(s, type, dest, 1); + tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); + tcg_out_movi(s, type, dest, 0); + return; + + do_loc: + cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); + /* Emit: d = 0, t = 1, d = (cc ? t : d). */ + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); + tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc); } static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, - TCGReg c1, TCGArg c2, int c2const, TCGReg r3) + TCGReg c1, TCGArg c2, int c2const, + TCGArg v3, int v3const) { int cc; if (s390_facilities & FACILITY_LOAD_ON_COND) { cc = tgen_cmp(s, type, c, c1, c2, c2const, false); - tcg_out_insn(s, RRF, LOCGR, dest, r3, cc); + if (v3const) { + tcg_out_insn(s, RIE, LOCGHI, dest, v3, cc); + } else { + tcg_out_insn(s, RRF, LOCGR, dest, v3, cc); + } } else { c = tcg_invert_cond(c); cc = tgen_cmp(s, type, c, c1, c2, c2const, false); /* Emit: if (cc) goto over; dest = r3; over: */ tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_insn(s, RRE, LGR, dest, r3); + tcg_out_insn(s, RRE, LGR, dest, v3); } } @@ -1937,7 +1977,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], - args[2], const_args[2], args[3]); + args[2], const_args[2], args[3], const_args[3]); break; case INDEX_op_qemu_ld_i32: @@ -2170,7 +2210,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], - args[2], const_args[2], args[3]); + args[2], const_args[2], args[3], const_args[3]); break; OP_32_64(deposit): @@ -2391,7 +2431,12 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) = { .args_ct_str = { "r", "r", "rZ", "r", "0" } }; static const TCGTargetOpDef movc_c = { .args_ct_str = { "r", "r", "rC", "r", "0" } }; - return (s390_facilities & FACILITY_EXT_IMM ? &movc_c : &movc_z); + static const TCGTargetOpDef movc_l + = { .args_ct_str = { "r", "r", "rC", "rI", "0" } }; + return (s390_facilities & FACILITY_EXT_IMM + ? (s390_facilities & FACILITY_LOAD_ON_COND2 + ? &movc_l : &movc_c) + : &movc_z); } case INDEX_op_div2_i32: case INDEX_op_div2_i64: |