target-alpha: Implement fp branch/cmov inline.
The old fcmov implementation had a typo: - tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]); which moved the condition, not the second source, to the destination. But it's also easy to implement the simplified fp comparison inline. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
fe57ca82b0
commit
dbb30fe6ef
|
@ -77,13 +77,6 @@ DEF_HELPER_2(cmpgeq, i64, i64, i64)
|
||||||
DEF_HELPER_2(cmpgle, i64, i64, i64)
|
DEF_HELPER_2(cmpgle, i64, i64, i64)
|
||||||
DEF_HELPER_2(cmpglt, i64, i64, i64)
|
DEF_HELPER_2(cmpglt, i64, i64, i64)
|
||||||
|
|
||||||
DEF_HELPER_1(cmpfeq, i64, i64)
|
|
||||||
DEF_HELPER_1(cmpfne, i64, i64)
|
|
||||||
DEF_HELPER_1(cmpflt, i64, i64)
|
|
||||||
DEF_HELPER_1(cmpfle, i64, i64)
|
|
||||||
DEF_HELPER_1(cmpfgt, i64, i64)
|
|
||||||
DEF_HELPER_1(cmpfge, i64, i64)
|
|
||||||
|
|
||||||
DEF_HELPER_2(cpys, i64, i64, i64)
|
DEF_HELPER_2(cpys, i64, i64, i64)
|
||||||
DEF_HELPER_2(cpysn, i64, i64, i64)
|
DEF_HELPER_2(cpysn, i64, i64, i64)
|
||||||
DEF_HELPER_2(cpyse, i64, i64, i64)
|
DEF_HELPER_2(cpyse, i64, i64, i64)
|
||||||
|
|
|
@ -884,37 +884,6 @@ uint64_t helper_cmpglt(uint64_t a, uint64_t b)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t helper_cmpfeq (uint64_t a)
|
|
||||||
{
|
|
||||||
return !(a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t helper_cmpfne (uint64_t a)
|
|
||||||
{
|
|
||||||
return (a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t helper_cmpflt (uint64_t a)
|
|
||||||
{
|
|
||||||
return (a & 0x8000000000000000ULL) && (a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t helper_cmpfle (uint64_t a)
|
|
||||||
{
|
|
||||||
return (a & 0x8000000000000000ULL) || !(a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t helper_cmpfgt (uint64_t a)
|
|
||||||
{
|
|
||||||
return !(a & 0x8000000000000000ULL) && (a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t helper_cmpfge (uint64_t a)
|
|
||||||
{
|
|
||||||
return !(a & 0x8000000000000000ULL) || !(a & 0x7FFFFFFFFFFFFFFFULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Floating point format conversion */
|
/* Floating point format conversion */
|
||||||
uint64_t helper_cvtts (uint64_t a)
|
uint64_t helper_cvtts (uint64_t a)
|
||||||
{
|
{
|
||||||
|
|
|
@ -294,77 +294,98 @@ static inline void gen_store_mem(DisasContext *ctx,
|
||||||
tcg_temp_free(addr);
|
tcg_temp_free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
static void gen_bcond_pcload(DisasContext *ctx, int32_t disp, int lab_true)
|
||||||
|
{
|
||||||
|
int lab_over = gen_new_label();
|
||||||
|
|
||||||
|
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
||||||
|
tcg_gen_br(lab_over);
|
||||||
|
gen_set_label(lab_true);
|
||||||
|
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp << 2));
|
||||||
|
gen_set_label(lab_over);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
|
||||||
int32_t disp, int mask)
|
int32_t disp, int mask)
|
||||||
{
|
{
|
||||||
int l1, l2;
|
int lab_true = gen_new_label();
|
||||||
|
|
||||||
l1 = gen_new_label();
|
|
||||||
l2 = gen_new_label();
|
|
||||||
if (likely(ra != 31)) {
|
if (likely(ra != 31)) {
|
||||||
if (mask) {
|
if (mask) {
|
||||||
TCGv tmp = tcg_temp_new();
|
TCGv tmp = tcg_temp_new();
|
||||||
tcg_gen_andi_i64(tmp, cpu_ir[ra], 1);
|
tcg_gen_andi_i64(tmp, cpu_ir[ra], 1);
|
||||||
tcg_gen_brcondi_i64(cond, tmp, 0, l1);
|
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
} else
|
} else {
|
||||||
tcg_gen_brcondi_i64(cond, cpu_ir[ra], 0, l1);
|
tcg_gen_brcondi_i64(cond, cpu_ir[ra], 0, lab_true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Very uncommon case - Do not bother to optimize. */
|
/* Very uncommon case - Do not bother to optimize. */
|
||||||
TCGv tmp = tcg_const_i64(0);
|
TCGv tmp = tcg_const_i64(0);
|
||||||
tcg_gen_brcondi_i64(cond, tmp, 0, l1);
|
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
||||||
tcg_temp_free(tmp);
|
tcg_temp_free(tmp);
|
||||||
}
|
}
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
gen_bcond_pcload(ctx, disp, lab_true);
|
||||||
tcg_gen_br(l2);
|
|
||||||
gen_set_label(l1);
|
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp << 2));
|
|
||||||
gen_set_label(l2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_fbcond(DisasContext *ctx, int opc, int ra, int32_t disp)
|
/* Generate a forward TCG branch to LAB_TRUE if RA cmp 0.0.
|
||||||
|
This is complicated by the fact that -0.0 compares the same as +0.0. */
|
||||||
|
|
||||||
|
static void gen_fbcond_internal(TCGCond cond, TCGv src, int lab_true)
|
||||||
{
|
{
|
||||||
int l1, l2;
|
int lab_false = -1;
|
||||||
|
uint64_t mzero = 1ull << 63;
|
||||||
TCGv tmp;
|
TCGv tmp;
|
||||||
TCGv src;
|
|
||||||
|
|
||||||
l1 = gen_new_label();
|
switch (cond) {
|
||||||
l2 = gen_new_label();
|
case TCG_COND_LE:
|
||||||
if (ra != 31) {
|
case TCG_COND_GT:
|
||||||
|
/* For <= or >, the -0.0 value directly compares the way we want. */
|
||||||
|
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TCG_COND_EQ:
|
||||||
|
case TCG_COND_NE:
|
||||||
|
/* For == or !=, we can simply mask off the sign bit and compare. */
|
||||||
|
/* ??? Assume that the temporary is reclaimed at the branch. */
|
||||||
tmp = tcg_temp_new();
|
tmp = tcg_temp_new();
|
||||||
src = cpu_fir[ra];
|
tcg_gen_andi_i64(tmp, src, mzero - 1);
|
||||||
} else {
|
tcg_gen_brcondi_i64(cond, tmp, 0, lab_true);
|
||||||
tmp = tcg_const_i64(0);
|
|
||||||
src = tmp;
|
|
||||||
}
|
|
||||||
switch (opc) {
|
|
||||||
case 0x31: /* FBEQ */
|
|
||||||
gen_helper_cmpfeq(tmp, src);
|
|
||||||
break;
|
break;
|
||||||
case 0x32: /* FBLT */
|
|
||||||
gen_helper_cmpflt(tmp, src);
|
case TCG_COND_GE:
|
||||||
|
/* For >=, emit two branches to the destination. */
|
||||||
|
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
||||||
|
tcg_gen_brcondi_i64(TCG_COND_EQ, src, mzero, lab_true);
|
||||||
break;
|
break;
|
||||||
case 0x33: /* FBLE */
|
|
||||||
gen_helper_cmpfle(tmp, src);
|
case TCG_COND_LT:
|
||||||
break;
|
/* For <, first filter out -0.0 to what will be the fallthru. */
|
||||||
case 0x35: /* FBNE */
|
lab_false = gen_new_label();
|
||||||
gen_helper_cmpfne(tmp, src);
|
tcg_gen_brcondi_i64(TCG_COND_EQ, src, mzero, lab_false);
|
||||||
break;
|
tcg_gen_brcondi_i64(cond, src, 0, lab_true);
|
||||||
case 0x36: /* FBGE */
|
gen_set_label(lab_false);
|
||||||
gen_helper_cmpfge(tmp, src);
|
|
||||||
break;
|
|
||||||
case 0x37: /* FBGT */
|
|
||||||
gen_helper_cmpfgt(tmp, src);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
tcg_gen_brcondi_i64(TCG_COND_NE, tmp, 0, l1);
|
}
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc);
|
|
||||||
tcg_gen_br(l2);
|
static void gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, int32_t disp)
|
||||||
gen_set_label(l1);
|
{
|
||||||
tcg_gen_movi_i64(cpu_pc, ctx->pc + (int64_t)(disp << 2));
|
int lab_true;
|
||||||
gen_set_label(l2);
|
|
||||||
|
if (unlikely(ra == 31)) {
|
||||||
|
/* Very uncommon case, but easier to optimize it to an integer
|
||||||
|
comparison than continuing with the floating point comparison. */
|
||||||
|
gen_bcond(ctx, cond, ra, disp, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lab_true = gen_new_label();
|
||||||
|
gen_fbcond_internal(cond, cpu_fir[ra], lab_true);
|
||||||
|
gen_bcond_pcload(ctx, disp, lab_true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_cmov(TCGCond inv_cond, int ra, int rb, int rc,
|
static inline void gen_cmov(TCGCond inv_cond, int ra, int rb, int rc,
|
||||||
|
@ -399,6 +420,28 @@ static inline void gen_cmov(TCGCond inv_cond, int ra, int rb, int rc,
|
||||||
gen_set_label(l1);
|
gen_set_label(l1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc)
|
||||||
|
{
|
||||||
|
TCGv va = cpu_fir[ra];
|
||||||
|
int l1;
|
||||||
|
|
||||||
|
if (unlikely(rc == 31))
|
||||||
|
return;
|
||||||
|
if (unlikely(ra == 31)) {
|
||||||
|
/* ??? Assume that the temporary is reclaimed at the branch. */
|
||||||
|
va = tcg_const_i64(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
l1 = gen_new_label();
|
||||||
|
gen_fbcond_internal(inv_cond, va, l1);
|
||||||
|
|
||||||
|
if (rb != 31)
|
||||||
|
tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]);
|
||||||
|
else
|
||||||
|
tcg_gen_movi_i64(cpu_fir[rc], 0);
|
||||||
|
gen_set_label(l1);
|
||||||
|
}
|
||||||
|
|
||||||
#define FARITH2(name) \
|
#define FARITH2(name) \
|
||||||
static inline void glue(gen_f, name)(int rb, int rc) \
|
static inline void glue(gen_f, name)(int rb, int rc) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -482,38 +525,6 @@ FARITH3(cpys)
|
||||||
FARITH3(cpysn)
|
FARITH3(cpysn)
|
||||||
FARITH3(cpyse)
|
FARITH3(cpyse)
|
||||||
|
|
||||||
#define FCMOV(name) \
|
|
||||||
static inline void glue(gen_f, name)(int ra, int rb, int rc) \
|
|
||||||
{ \
|
|
||||||
int l1; \
|
|
||||||
TCGv tmp; \
|
|
||||||
\
|
|
||||||
if (unlikely(rc == 31)) \
|
|
||||||
return; \
|
|
||||||
\
|
|
||||||
l1 = gen_new_label(); \
|
|
||||||
tmp = tcg_temp_new(); \
|
|
||||||
if (ra != 31) { \
|
|
||||||
tmp = tcg_temp_new(); \
|
|
||||||
gen_helper_ ## name (tmp, cpu_fir[ra]); \
|
|
||||||
} else { \
|
|
||||||
tmp = tcg_const_i64(0); \
|
|
||||||
gen_helper_ ## name (tmp, tmp); \
|
|
||||||
} \
|
|
||||||
tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1); \
|
|
||||||
if (rb != 31) \
|
|
||||||
tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]); \
|
|
||||||
else \
|
|
||||||
tcg_gen_movi_i64(cpu_fir[rc], 0); \
|
|
||||||
gen_set_label(l1); \
|
|
||||||
}
|
|
||||||
FCMOV(cmpfeq)
|
|
||||||
FCMOV(cmpfne)
|
|
||||||
FCMOV(cmpflt)
|
|
||||||
FCMOV(cmpfge)
|
|
||||||
FCMOV(cmpfle)
|
|
||||||
FCMOV(cmpfgt)
|
|
||||||
|
|
||||||
static inline uint64_t zapnot_mask(uint8_t lit)
|
static inline uint64_t zapnot_mask(uint8_t lit)
|
||||||
{
|
{
|
||||||
uint64_t mask = 0;
|
uint64_t mask = 0;
|
||||||
|
@ -1871,27 +1882,27 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
break;
|
break;
|
||||||
case 0x02A:
|
case 0x02A:
|
||||||
/* FCMOVEQ */
|
/* FCMOVEQ */
|
||||||
gen_fcmpfeq(ra, rb, rc);
|
gen_fcmov(TCG_COND_NE, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x02B:
|
case 0x02B:
|
||||||
/* FCMOVNE */
|
/* FCMOVNE */
|
||||||
gen_fcmpfne(ra, rb, rc);
|
gen_fcmov(TCG_COND_EQ, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x02C:
|
case 0x02C:
|
||||||
/* FCMOVLT */
|
/* FCMOVLT */
|
||||||
gen_fcmpflt(ra, rb, rc);
|
gen_fcmov(TCG_COND_GE, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x02D:
|
case 0x02D:
|
||||||
/* FCMOVGE */
|
/* FCMOVGE */
|
||||||
gen_fcmpfge(ra, rb, rc);
|
gen_fcmov(TCG_COND_LT, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x02E:
|
case 0x02E:
|
||||||
/* FCMOVLE */
|
/* FCMOVLE */
|
||||||
gen_fcmpfle(ra, rb, rc);
|
gen_fcmov(TCG_COND_GT, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x02F:
|
case 0x02F:
|
||||||
/* FCMOVGT */
|
/* FCMOVGT */
|
||||||
gen_fcmpfgt(ra, rb, rc);
|
gen_fcmov(TCG_COND_LE, ra, rb, rc);
|
||||||
break;
|
break;
|
||||||
case 0x030:
|
case 0x030:
|
||||||
/* CVTQL */
|
/* CVTQL */
|
||||||
|
@ -2482,9 +2493,15 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
case 0x31: /* FBEQ */
|
case 0x31: /* FBEQ */
|
||||||
|
gen_fbcond(ctx, TCG_COND_EQ, ra, disp21);
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
case 0x32: /* FBLT */
|
case 0x32: /* FBLT */
|
||||||
|
gen_fbcond(ctx, TCG_COND_LT, ra, disp21);
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
case 0x33: /* FBLE */
|
case 0x33: /* FBLE */
|
||||||
gen_fbcond(ctx, opc, ra, disp21);
|
gen_fbcond(ctx, TCG_COND_LE, ra, disp21);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
case 0x34:
|
case 0x34:
|
||||||
|
@ -2495,9 +2512,15 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
case 0x35: /* FBNE */
|
case 0x35: /* FBNE */
|
||||||
|
gen_fbcond(ctx, TCG_COND_NE, ra, disp21);
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
case 0x36: /* FBGE */
|
case 0x36: /* FBGE */
|
||||||
|
gen_fbcond(ctx, TCG_COND_GE, ra, disp21);
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
case 0x37: /* FBGT */
|
case 0x37: /* FBGT */
|
||||||
gen_fbcond(ctx, opc, ra, disp21);
|
gen_fbcond(ctx, TCG_COND_GT, ra, disp21);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
case 0x38:
|
case 0x38:
|
||||||
|
|
Loading…
Reference in a new issue