summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2010-08-27 12:42:44 -0700
committerDavid Schleef <ds@schleef.org>2010-08-27 12:42:44 -0700
commite5fc168166aa6917f37f030ff8cc67d61cf5511c (patch)
treea49ab478a9b4c77f9aae76ab35cfe5b084c7ee70
parent28051d83049250561110fd91cf13397ad3cb538f (diff)
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.
-rw-r--r--orc/opcodes.h2
-rw-r--r--orc/orcemulateopcodes.c14
-rw-r--r--orc/orcprogram-c.c36
-rw-r--r--orc/orcrules-sse.c31
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