Handle corner cases of abs(), min() and max()

The abs() function needs to be able to turn -0.0 into 0.0. This proved
to be too clunky (and perhaps impossible) to do with tests and jumps,
so add an %abs/wr opcode to do it using fabs().

The min/max functions need to take special care with the handling
of NaN operands. These matter, so generate the extra code to handle
them.
This commit is contained in:
Stephen Williams 2008-05-06 22:19:59 -07:00
parent 10ab5cf698
commit ca517b5519
5 changed files with 38 additions and 20 deletions

View File

@ -115,18 +115,36 @@ static int draw_binary_real(ivl_expr_t exp)
case 'm': { // min(l,r)
int lab_out = local_count++;
int lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
/* If l is NaN, the go out and accept r as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
/* If l <= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", l, r);
/* At this point we know we want r as the result. */
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
break;
}
case 'M': { // max(l,r)
int lab_out = local_count++;
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", l, r);
int lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_out);
/* If l is NaN, the go out and accept r as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 4;\n", thread_count, lab_r);
/* if l >= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out);
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", thread_count, lab_r, l, r);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
break;
}
@ -439,22 +457,8 @@ static int draw_unary_real(ivl_expr_t exp)
}
if (ivl_expr_opcode(exp) == 'm') { /* abs(sube) */
unsigned lab_positive = local_count++;
unsigned lab_out = local_count++;
int res = allocate_word();
fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0 -- %d = abs(%d)\n",
res, res, sub);
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", sub, res);
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n",
thread_count, lab_positive);
fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub);
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out);
fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n",
thread_count, lab_positive, res, sub);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
clr_word(sub);
return res;
fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub);
return sub;
}
fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));

View File

@ -32,6 +32,7 @@ typedef bool (*vvp_code_fun)(vthread_t thr, vvp_code_t code);
* implementation lives in the vthread.cc file so that they have
* access to the thread context.
*/
extern bool of_ABS_WR(vthread_t thr, vvp_code_t code);
extern bool of_ADD(vthread_t thr, vvp_code_t code);
extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
extern bool of_ADDI(vthread_t thr, vvp_code_t code);

View File

@ -82,6 +82,7 @@ struct opcode_table_s {
};
const static struct opcode_table_s opcode_table[] = {
{ "%abs/wr", of_ABS_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%add/wr", of_ADD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },

View File

@ -19,6 +19,10 @@ the left operand, the right operand, and the base. The left operand is
replaced with the result, which is the same width as the left and
right operands.
* %abs/wr <bit-o>, <bit-i>
This instructure calculate the absolute value of a real value. It uses
the fabs() function in the run-time to do the work.
* %add <bit-l>, <bit-r>, <wid>

View File

@ -401,6 +401,14 @@ void vthread_schedule_list(vthread_t thr)
schedule_vthread(thr, 0);
}
bool of_ABS_WR(vthread_t thr, vvp_code_t cp)
{
unsigned dst = cp->bit_idx[0];
unsigned src = cp->bit_idx[1];
thr->words[dst].w_real = fabs(thr->words[src].w_real);
return true;
}
bool of_AND(vthread_t thr, vvp_code_t cp)
{