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:
parent
10ab5cf698
commit
ca517b5519
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue