vvp code generator try to generate condition flags directly.
When generating code for a condition expression, i.e. directly before a %jmp/X statement, try to generate the result into the flag bit without passing through the vec4 stack. For example, the %cmpX/X instructions generate results into the flag bits, so it makes no sense to push these bits into the vec4 stack then pop them back into the flag bit. So try to handle this case.
This commit is contained in:
parent
04bdfbccee
commit
c71ab5869a
|
|
@ -49,7 +49,9 @@ LDFLAGS = @LDFLAGS@
|
|||
|
||||
O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \
|
||||
draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
eval_bool.o eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_bool.o \
|
||||
eval_condit.o \
|
||||
eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_vec4.o \
|
||||
modpath.o stmt_assign.o vector.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
static int draw_condition_fallback(ivl_expr_t expr)
|
||||
{
|
||||
int use_flag = allocate_flag();
|
||||
|
||||
/* Evaluate the condition expression, including optionally
|
||||
reducing it to a single bit. Put the result into a flag bit
|
||||
for use by all the tests. */
|
||||
draw_eval_vec4(expr);
|
||||
if (ivl_expr_width(expr) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
|
||||
return use_flag;
|
||||
}
|
||||
|
||||
static int draw_condition_binary_compare(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_CLASS)
|
||||
&& (ivl_expr_value(re)==IVL_VT_CLASS)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'e': /* == */
|
||||
fprintf(vvp_out, " %%cmp/u;\n");
|
||||
return 4;
|
||||
break;
|
||||
case 'E': /* === */
|
||||
fprintf(vvp_out, " %%cmp/u;\n");
|
||||
return 6;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int draw_condition_binary_le(ivl_expr_t expr)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(expr);
|
||||
ivl_expr_t re = ivl_expr_oper2(expr);
|
||||
ivl_expr_t tmp;
|
||||
|
||||
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
||||
|| (ivl_expr_value(re) == IVL_VT_REAL)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_value(le)==IVL_VT_STRING)
|
||||
&& (ivl_expr_type(re)==IVL_EX_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
if ((ivl_expr_type(le)==IVL_EX_STRING)
|
||||
&& (ivl_expr_value(re)==IVL_VT_STRING)) {
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
|
||||
char use_opcode = ivl_expr_opcode(expr);
|
||||
char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u';
|
||||
|
||||
/* If this is a > or >=, then convert it to < or <= by
|
||||
swapping the operands. Adjust the opcode to match. */
|
||||
switch (use_opcode) {
|
||||
case 'G':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = 'L';
|
||||
break;
|
||||
case '>':
|
||||
tmp = le;
|
||||
le = re;
|
||||
re = tmp;
|
||||
use_opcode = '<';
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTE: I think I would rather the elaborator handle the
|
||||
operand widths. When that happens, take this code out. */
|
||||
|
||||
unsigned use_wid = ivl_expr_width(le);
|
||||
if (ivl_expr_width(re) > use_wid)
|
||||
use_wid = ivl_expr_width(re);
|
||||
|
||||
draw_eval_vec4(le);
|
||||
resize_vec4_wid(le, use_wid);
|
||||
|
||||
if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) {
|
||||
/* Special case: If the right operand can be handled as
|
||||
an immediate operand, then use that instead. */
|
||||
char opcode[8];
|
||||
snprintf(opcode, sizeof opcode, "%%cmpi/%c", s_flag);
|
||||
draw_immediate_vec4(re, opcode);
|
||||
|
||||
} else {
|
||||
draw_eval_vec4(re);
|
||||
resize_vec4_wid(re, use_wid);
|
||||
|
||||
fprintf(vvp_out, " %%cmp/%c;\n", s_flag);
|
||||
}
|
||||
|
||||
switch (use_opcode) {
|
||||
case '<':
|
||||
return 5;
|
||||
case 'L':
|
||||
fprintf(vvp_out, " %%flag_or 5, 4;\n");
|
||||
return 5;
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_condition_binary(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_opcode(expr)) {
|
||||
case 'e': /* == */
|
||||
case 'E': /* === */
|
||||
return draw_condition_binary_compare(expr);
|
||||
case '<':
|
||||
case '>':
|
||||
case 'L': /* <= */
|
||||
case 'G': /* >= */
|
||||
return draw_condition_binary_le(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
|
||||
int draw_eval_condition(ivl_expr_t expr)
|
||||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_BINARY:
|
||||
return draw_condition_binary(expr);
|
||||
default:
|
||||
return draw_condition_fallback(expr);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ void resize_vec4_wid(ivl_expr_t expr, unsigned wid)
|
|||
/*
|
||||
* Test if the draw_immediate_vec4 instruction can be used.
|
||||
*/
|
||||
static int test_immediate_vec4_ok(ivl_expr_t re)
|
||||
int test_immediate_vec4_ok(ivl_expr_t re)
|
||||
{
|
||||
const char*bits;
|
||||
unsigned idx;
|
||||
|
|
@ -62,7 +62,7 @@ static int test_immediate_vec4_ok(ivl_expr_t re)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void draw_immediate_vec4(ivl_expr_t re, const char*opcode)
|
||||
void draw_immediate_vec4(ivl_expr_t re, const char*opcode)
|
||||
{
|
||||
unsigned long val0 = 0;
|
||||
unsigned long valx = 0;
|
||||
|
|
@ -1018,15 +1018,17 @@ static void draw_ternary_vec4(ivl_expr_t expr)
|
|||
unsigned lab_true = local_count++;
|
||||
unsigned lab_out = local_count++;
|
||||
|
||||
int use_flag = allocate_flag();
|
||||
int use_flag = draw_eval_condition(cond);
|
||||
|
||||
/* Evaluate the condition expression, including optionally
|
||||
reducing it to a single bit. Put the result into a flag bit
|
||||
for use by all the tests. */
|
||||
draw_eval_vec4(cond);
|
||||
if (ivl_expr_width(cond) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
/* The condition flag is used after possibly other statements,
|
||||
so we need to put it into a non-common place. Allocate a
|
||||
safe flag bit and move the condition to the flag position. */
|
||||
if (use_flag < 8) {
|
||||
int tmp_flag = allocate_flag();
|
||||
assert(tmp_flag >= 8);
|
||||
fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp_flag, use_flag);
|
||||
use_flag = tmp_flag;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_true, use_flag);
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ int allocate_flag(void)
|
|||
|
||||
void clr_flag(int idx)
|
||||
{
|
||||
if (idx < 8) return;
|
||||
assert(idx < FLAGS_COUNT);
|
||||
int word = idx / 32;
|
||||
uint32_t mask = 1 << (idx%32);
|
||||
|
|
|
|||
|
|
@ -207,6 +207,13 @@ extern const char*draw_input_from_net(ivl_nexus_t nex);
|
|||
*/
|
||||
extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
||||
|
||||
/*
|
||||
* This evaluates an expression as a condition flag and leaves the
|
||||
* result in a flag that is returned. This result may be used as an
|
||||
* operand for conditional jump instructions.
|
||||
*/
|
||||
extern int draw_eval_condition(ivl_expr_t expr);
|
||||
|
||||
|
||||
extern int number_is_unknown(ivl_expr_t ex);
|
||||
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
|
||||
|
|
@ -250,6 +257,11 @@ extern int draw_eval_object(ivl_expr_t ex);
|
|||
extern int show_stmt_assign(ivl_statement_t net);
|
||||
extern void show_stmt_file_line(ivl_statement_t net, const char*desc);
|
||||
|
||||
/*
|
||||
*/
|
||||
extern int test_immediate_vec4_ok(ivl_expr_t expr);
|
||||
extern void draw_immediate_vec4(ivl_expr_t expr, const char*opcode);
|
||||
|
||||
/*
|
||||
* These functions manage word register allocation.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1187,14 +1187,10 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
|
|||
|
||||
show_stmt_file_line(net, "If statement.");
|
||||
|
||||
draw_eval_vec4(expr);
|
||||
|
||||
lab_false = local_count++;
|
||||
lab_out = local_count++;
|
||||
|
||||
int use_flag = allocate_flag();
|
||||
/* The %flag/vec4 pops the vec4 bit and puts it to the flag. */
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
int use_flag = draw_eval_condition(expr);
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
|
||||
thread_count, lab_false, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
|
@ -1324,12 +1320,7 @@ static int show_stmt_do_while(ivl_statement_t net, ivl_scope_t sscope)
|
|||
/* Draw the evaluation of the condition expression, and test
|
||||
the result. If the expression evaluates to true, then
|
||||
branch to the top label. */
|
||||
draw_eval_vec4(ivl_stmt_cond_expr(net));
|
||||
if (ivl_expr_width(ivl_stmt_cond_expr(net)) > 1)
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
|
||||
int use_flag = allocate_flag();
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n",
|
||||
thread_count, top_label, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
|
@ -1673,13 +1664,7 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
|||
/* Draw the evaluation of the condition expression, and test
|
||||
the result. If the expression evaluates to false, then
|
||||
branch to the out label. */
|
||||
draw_eval_vec4(ivl_stmt_cond_expr(net));
|
||||
if (ivl_expr_width(ivl_stmt_cond_expr(net)) > 1) {
|
||||
fprintf(vvp_out, " %%or/r;\n");
|
||||
}
|
||||
|
||||
int use_flag = allocate_flag();
|
||||
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag);
|
||||
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %u;\n",
|
||||
thread_count, out_label, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
|
|
|||
Loading…
Reference in New Issue