From e5fc168166aa6917f37f030ff8cc67d61cf5511c Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 27 Aug 2010 12:42:44 -0700 Subject: [PATCH] Change meaning of convfl/convdl to be saturated Some architectures (powerpc) clamp out-of-range values to the integer range when converting from float to int. Others (x86) maps out-of-range values to 0x80000000. Since we have to choose one, saturating seems like the better choice. --- orc/opcodes.h | 2 -- orc/orcemulateopcodes.c | 14 ++++++++++++-- orc/orcprogram-c.c | 36 ++++++++++++++++++++++++++++++++++++ orc/orcrules-sse.c | 31 +++++++++++++++++++++++++------ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/orc/opcodes.h b/orc/opcodes.h index bdff6a0..821404c 100644 --- a/orc/opcodes.h +++ b/orc/opcodes.h @@ -135,7 +135,6 @@ BINARY_F(minf, "ORC_MINF(ORC_DENORMAL(%s),ORC_DENORMAL(%s))") BINARY_FL(cmpeqf, "(ORC_DENORMAL(%s) == ORC_DENORMAL(%s)) ? (~0) : 0") BINARY_FL(cmpltf, "(ORC_DENORMAL(%s) < ORC_DENORMAL(%s)) ? (~0) : 0") BINARY_FL(cmplef, "(ORC_DENORMAL(%s) <= ORC_DENORMAL(%s)) ? (~0) : 0") -UNARY_FL(convfl, "(int)%s") UNARY_LF(convlf, "%s") BINARY_D(addd, "ORC_DENORMAL_D(ORC_DENORMAL_D(%s) + ORC_DENORMAL_D(%s))") @@ -148,7 +147,6 @@ BINARY_D(mind, "ORC_MIND(ORC_DENORMAL_D(%s),ORC_DENORMAL_D(%s))") BINARY_DQ(cmpeqd, "(ORC_DENORMAL_D(%s) == ORC_DENORMAL_D(%s)) ? (~0ULL) : 0") BINARY_DQ(cmpltd, "(ORC_DENORMAL_D(%s) < ORC_DENORMAL_D(%s)) ? (~0ULL) : 0") BINARY_DQ(cmpled, "(ORC_DENORMAL_D(%s) <= ORC_DENORMAL_D(%s)) ? (~0ULL) : 0") -UNARY_DL(convdl, "(int)%s") UNARY_LD(convld, "%s") UNARY_DF(convdf, "ORC_DENORMAL ((float) %s)") UNARY_FD(convfd, "ORC_DENORMAL (%s)") diff --git a/orc/orcemulateopcodes.c b/orc/orcemulateopcodes.c index 8ea7c55..8a89ca8 100644 --- a/orc/orcemulateopcodes.c +++ b/orc/orcemulateopcodes.c @@ -4102,7 +4102,12 @@ emulate_convfl (OrcOpcodeExecutor *ex, int offset, int n) /* 0: loadl */ var32 = ptr4[i]; /* 1: convfl */ - var33.i = (int)var32.f; + { + int tmp; + tmp = (int)var32.f; + if (tmp == 0x80000000 && !(var32.i&0x80000000)) tmp = 0x7fffffff; + var33.i = tmp; + } /* 2: storel */ ptr0[i] = var33; } @@ -4423,7 +4428,12 @@ emulate_convdl (OrcOpcodeExecutor *ex, int offset, int n) /* 0: loadq */ var32 = ptr4[i]; /* 1: convdl */ - var33.i = (int)var32.f; + { + int tmp; + tmp = var32.f; + if (tmp == 0x80000000 && !(var32.i&0x8000000000000000ULL)) tmp = 0x7fffffff; + var33.i = tmp; + } /* 2: storel */ ptr0[i] = var33; } diff --git a/orc/orcprogram-c.c b/orc/orcprogram-c.c index 42d88b6..690219e 100644 --- a/orc/orcprogram-c.c +++ b/orc/orcprogram-c.c @@ -1001,6 +1001,40 @@ c_rule_divluw (OrcCompiler *p, void *user, OrcInstruction *insn) dest, src2, src1, src2); } +static void +c_rule_convfl (OrcCompiler *p, void *user, OrcInstruction *insn) +{ + char dest[40], src[40], src_i[40]; + + c_get_name_int (dest, p, insn, insn->dest_args[0]); + c_get_name_float (src, p, insn, insn->src_args[0]); + c_get_name_int (src_i, p, insn, insn->src_args[0]); + + ORC_ASM_CODE(p, " {\n"); + ORC_ASM_CODE(p," int tmp;\n"); + ORC_ASM_CODE(p," tmp = (int)%s;\n", src); + ORC_ASM_CODE(p," if (tmp == 0x80000000 && !(%s&0x80000000)) tmp = 0x7fffffff;\n", src_i); + ORC_ASM_CODE(p," %s = tmp;\n", dest); + ORC_ASM_CODE(p, " }\n"); +} + +static void +c_rule_convdl (OrcCompiler *p, void *user, OrcInstruction *insn) +{ + char dest[40], src[40], src_i[40]; + + c_get_name_int (dest, p, insn, insn->dest_args[0]); + c_get_name_float (src, p, insn, insn->src_args[0]); + c_get_name_int (src_i, p, insn, insn->src_args[0]); + + ORC_ASM_CODE(p, " {\n"); + ORC_ASM_CODE(p," int tmp;\n"); + ORC_ASM_CODE(p," tmp = %s;\n", src); + ORC_ASM_CODE(p," if (tmp == 0x80000000 && !(%s&0x8000000000000000ULL)) tmp = 0x7fffffff;\n", src_i); + ORC_ASM_CODE(p," %s = tmp;\n", dest); + ORC_ASM_CODE(p, " }\n"); +} + static OrcTarget c_target = { "c", FALSE, @@ -1098,5 +1132,7 @@ orc_c_init (void) orc_rule_register (rule_set, "splatw3q", c_rule_splatw3q, NULL); orc_rule_register (rule_set, "div255w", c_rule_div255w, NULL); orc_rule_register (rule_set, "divluw", c_rule_divluw, NULL); + orc_rule_register (rule_set, "convfl", c_rule_convfl, NULL); + orc_rule_register (rule_set, "convdl", c_rule_convdl, NULL); } diff --git a/orc/orcrules-sse.c b/orc/orcrules-sse.c index b500d02..ad66827 100644 --- a/orc/orcrules-sse.c +++ b/orc/orcrules-sse.c @@ -2157,17 +2157,36 @@ sse_rule_cmpled (OrcCompiler *p, void *user, OrcInstruction *insn) static void sse_rule_convfl (OrcCompiler *p, void *user, OrcInstruction *insn) { - orc_sse_emit_f30f (p, "cvttps2dq", 0x5b, - p->vars[insn->src_args[0]].alloc, - p->vars[insn->dest_args[0]].alloc); + int src = p->vars[insn->src_args[0]].alloc; + int dest = p->vars[insn->dest_args[0]].alloc; + int tmpc; + int tmp = orc_compiler_get_temp_reg (p); + + tmpc = orc_compiler_get_temp_constant (p, 4, 0x80000000); + orc_sse_emit_movdqa (p, src, tmp); + orc_sse_emit_f30f (p, "cvttps2dq", 0x5b, src, dest); + orc_sse_emit_psrad (p, 31, tmp); + orc_sse_emit_pcmpeqd (p, dest, tmpc); + orc_sse_emit_pandn (p, tmpc, tmp); + orc_sse_emit_paddd (p, tmp, dest); + } static void sse_rule_convdl (OrcCompiler *p, void *user, OrcInstruction *insn) { - orc_sse_emit_660f (p, "cvttpd2dq", 0xe6, - p->vars[insn->src_args[0]].alloc, - p->vars[insn->dest_args[0]].alloc); + int src = p->vars[insn->src_args[0]].alloc; + int dest = p->vars[insn->dest_args[0]].alloc; + int tmpc; + int tmp = orc_compiler_get_temp_reg (p); + + tmpc = orc_compiler_get_temp_constant (p, 4, 0x80000000); + orc_sse_emit_pshufd (p, ORC_SSE_SHUF(3,1,3,1), src, tmp); + orc_sse_emit_660f (p, "cvttpd2dq", 0xe6, src, dest); + orc_sse_emit_psrad (p, 31, tmp); + orc_sse_emit_pcmpeqd (p, dest, tmpc); + orc_sse_emit_pandn (p, tmpc, tmp); + orc_sse_emit_paddd (p, tmp, dest); } static void -- 2.7.4