@@ -45,6 +45,7 @@
#define TCG_CT_CONST_ANDI 0x1000
#define TCG_CT_CONST_ORI 0x2000
#define TCG_CT_CONST_XORI 0x4000
+#define TCG_CT_CONST_CMPI 0x8000
/* Several places within the instruction set 0 means "no register"
rather than TCG_REG_R0. */
@@ -131,6 +132,7 @@ typedef enum S390Opcode {
RRE_LLGHR = 0xb985,
RRE_LRVR = 0xb91f,
RRE_LRVGR = 0xb90f,
+ RRE_LTGR = 0xb902,
RRE_MSGR = 0xb90c,
RRE_MSR = 0xb252,
RRE_NGR = 0xb980,
@@ -146,6 +148,7 @@ typedef enum S390Opcode {
RR_DR = 0x1d,
RR_LCR = 0x13,
RR_LR = 0x18,
+ RR_LTR = 0x12,
RR_NR = 0x14,
RR_OR = 0x16,
RR_SR = 0x1b,
@@ -248,9 +251,6 @@ static const int tcg_target_call_oarg_regs[] = {
TCG_REG_R3,
};
-/* signed/unsigned is handled by using COMPARE and COMPARE LOGICAL,
- respectively */
-
#define S390_CC_EQ 8
#define S390_CC_LT 4
#define S390_CC_GT 2
@@ -258,19 +258,37 @@ static const int tcg_target_call_oarg_regs[] = {
#define S390_CC_NE (S390_CC_LT | S390_CC_GT)
#define S390_CC_LE (S390_CC_LT | S390_CC_EQ)
#define S390_CC_GE (S390_CC_GT | S390_CC_EQ)
+#define S390_CC_NEVER 0
#define S390_CC_ALWAYS 15
+/* Condition codes that result from a COMPARE and COMPARE LOGICAL. */
static const uint8_t tcg_cond_to_s390_cond[10] = {
[TCG_COND_EQ] = S390_CC_EQ,
+ [TCG_COND_NE] = S390_CC_NE,
[TCG_COND_LT] = S390_CC_LT,
- [TCG_COND_LTU] = S390_CC_LT,
[TCG_COND_LE] = S390_CC_LE,
- [TCG_COND_LEU] = S390_CC_LE,
[TCG_COND_GT] = S390_CC_GT,
- [TCG_COND_GTU] = S390_CC_GT,
[TCG_COND_GE] = S390_CC_GE,
+ [TCG_COND_LTU] = S390_CC_LT,
+ [TCG_COND_LEU] = S390_CC_LE,
+ [TCG_COND_GTU] = S390_CC_GT,
[TCG_COND_GEU] = S390_CC_GE,
+};
+
+/* Condition codes that result from a LOAD AND TEST. Here, we have no
+ unsigned instruction variation, however since the test is vs zero we
+ can re-map the outcomes appropriately. */
+static const uint8_t tcg_cond_to_ltr_cond[10] = {
+ [TCG_COND_EQ] = S390_CC_EQ,
[TCG_COND_NE] = S390_CC_NE,
+ [TCG_COND_LT] = S390_CC_LT,
+ [TCG_COND_LE] = S390_CC_LE,
+ [TCG_COND_GT] = S390_CC_GT,
+ [TCG_COND_GE] = S390_CC_GE,
+ [TCG_COND_LTU] = S390_CC_NEVER,
+ [TCG_COND_LEU] = S390_CC_EQ,
+ [TCG_COND_GTU] = S390_CC_NE,
+ [TCG_COND_GEU] = S390_CC_ALWAYS,
};
#ifdef CONFIG_SOFTMMU
@@ -387,6 +405,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
ct->ct &= ~TCG_CT_REG;
ct->ct |= TCG_CT_CONST_XORI;
break;
+ case 'C':
+ ct->ct &= ~TCG_CT_REG;
+ ct->ct |= TCG_CT_CONST_CMPI;
+ break;
default:
break;
}
@@ -507,6 +529,13 @@ static int tcg_match_xori(int ct, tcg_target_long val)
return 1;
}
+/* Imediates to be used with comparisons. */
+
+static int tcg_match_cmpi(int ct, tcg_target_long val)
+{
+ return (val == 0);
+}
+
/* Test if a constant matches the constraint. */
static int tcg_target_const_match(tcg_target_long val,
const TCGArgConstraint *arg_ct)
@@ -552,6 +581,8 @@ static int tcg_target_const_match(tcg_target_long val,
return tcg_match_ori(ct, val);
} else if (ct & TCG_CT_CONST_XORI) {
return tcg_match_xori(ct, val);
+ } else if (ct & TCG_CT_CONST_CMPI) {
+ return tcg_match_cmpi(ct, val);
}
return 0;
@@ -1050,39 +1081,48 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val)
}
}
-static void tgen32_cmp(TCGContext *s, TCGCond c, TCGReg r1, TCGReg r2)
-{
- if (c > TCG_COND_GT) {
- /* unsigned */
- tcg_out_insn(s, RR, CLR, r1, r2);
- } else {
- /* signed */
- tcg_out_insn(s, RR, CR, r1, r2);
- }
-}
-
-static void tgen64_cmp(TCGContext *s, TCGCond c, TCGReg r1, TCGReg r2)
+static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
+ TCGArg c2, int c2const)
{
- if (c > TCG_COND_GT) {
- /* unsigned */
- tcg_out_insn(s, RRE, CLGR, r1, r2);
+ if (c2const) {
+ if (c2 == 0) {
+ if (type == TCG_TYPE_I32) {
+ tcg_out_insn(s, RR, LTR, r1, r1);
+ } else {
+ tcg_out_insn(s, RRE, LTGR, r1, r1);
+ }
+ return tcg_cond_to_ltr_cond[c];
+ } else {
+ tcg_abort();
+ }
} else {
- /* signed */
- tcg_out_insn(s, RRE, CGR, r1, r2);
+ if (c > TCG_COND_GT) {
+ /* 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 {
+ tcg_out_insn(s, RRE, CGR, r1, c2);
+ }
+ }
}
+ return tcg_cond_to_s390_cond[c];
}
static void tgen_setcond(TCGContext *s, TCGType type, TCGCond c,
- TCGReg dest, TCGReg r1, TCGReg r2)
+ TCGReg dest, TCGReg r1, TCGArg c2, int c2const)
{
- if (type == TCG_TYPE_I32) {
- tgen32_cmp(s, c, r1, r2);
- } else {
- tgen64_cmp(s, c, r1, r2);
- }
+ int cc = tgen_cmp(s, type, c, r1, c2, c2const);
+
/* Emit: r1 = 1; if (cc) goto over; r1 = 0; over: */
tcg_out_movi(s, type, dest, 1);
- tcg_out_insn(s, RI, BRC, tcg_cond_to_s390_cond[c], (4 + 4) >> 1);
+ tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1);
tcg_out_movi(s, type, dest, 0);
}
@@ -1115,6 +1155,13 @@ static void tgen_branch(TCGContext *s, int cc, int labelno)
}
}
+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);
+ tgen_branch(s, cc, labelno);
+}
+
static void tgen_calli(TCGContext *s, tcg_target_long dest)
{
tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1;
@@ -1755,20 +1802,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tgen_branch(s, S390_CC_ALWAYS, args[0]);
break;
- case INDEX_op_brcond_i64:
- tgen64_cmp(s, args[2], args[0], args[1]);
- goto do_brcond;
case INDEX_op_brcond_i32:
- tgen32_cmp(s, args[2], args[0], args[1]);
- do_brcond:
- tgen_branch(s, tcg_cond_to_s390_cond[args[2]], args[3]);
+ tgen_brcond(s, TCG_TYPE_I32, args[2], args[0],
+ args[1], const_args[1], args[3]);
+ break;
+ case INDEX_op_brcond_i64:
+ tgen_brcond(s, TCG_TYPE_I64, args[2], args[0],
+ args[1], const_args[1], args[3]);
break;
case INDEX_op_setcond_i32:
- tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2]);
+ tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1],
+ args[2], const_args[2]);
break;
case INDEX_op_setcond_i64:
- tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2]);
+ tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1],
+ args[2], const_args[2]);
break;
case INDEX_op_qemu_ld8u:
@@ -1880,8 +1929,8 @@ static const TCGTargetOpDef s390_op_defs[] = {
{ INDEX_op_bswap16_i32, { "r", "r" } },
{ INDEX_op_bswap32_i32, { "r", "r" } },
- { INDEX_op_brcond_i32, { "r", "r" } },
- { INDEX_op_setcond_i32, { "r", "r", "r" } },
+ { INDEX_op_brcond_i32, { "r", "rWC" } },
+ { INDEX_op_setcond_i32, { "r", "r", "rWC" } },
{ INDEX_op_qemu_ld8u, { "r", "L" } },
{ INDEX_op_qemu_ld8s, { "r", "L" } },
@@ -1945,8 +1994,8 @@ static const TCGTargetOpDef s390_op_defs[] = {
{ INDEX_op_bswap32_i64, { "r", "r" } },
{ INDEX_op_bswap64_i64, { "r", "r" } },
- { INDEX_op_brcond_i64, { "r", "r" } },
- { INDEX_op_setcond_i64, { "r", "r", "r" } },
+ { INDEX_op_brcond_i64, { "r", "rC" } },
+ { INDEX_op_setcond_i64, { "r", "r", "rC" } },
#endif
{ -1 },
This instruction is always available, and nicely eliminates the constant load for comparisons against zero. Signed-off-by: Richard Henderson <rth@twiddle.net> --- tcg/s390/tcg-target.c | 133 +++++++++++++++++++++++++++++++++--------------- 1 files changed, 91 insertions(+), 42 deletions(-)