Merge pull request #573 from larsclausen/short-circuit-logical-operator

Short circuit logical operator
This commit is contained in:
martinwhitaker 2021-12-31 09:16:35 +00:00 committed by GitHub
commit 18cc3b91a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 44 deletions

View File

@ -811,6 +811,36 @@ NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const
const NetEConst*lc = dynamic_cast<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(r);
// If the left side is constant and the right side is short circuited
// replace the expression with a constant
if (rc == 0 && lc != 0) {
verinum v = lc->value();
verinum::V res = verinum::Vx;
switch (op_) {
case 'a': // Logical AND (&&)
if (v.is_zero())
res = verinum::V0;
break;
case 'o': // Logical OR (||)
if (! v.is_zero() && v.is_defined())
res = verinum::V1;
break;
case 'q': // Logical implication (->)
if (v.is_zero())
res = verinum::V1;
break;
default:
break;
}
if (res != verinum::Vx) {
NetEConst*tmp = new NetEConst(verinum(res, 1));
ivl_assert(*this, tmp);
eval_debug(this, tmp, false);
return tmp;
}
}
if (lc == 0 || rc == 0) return 0;
verinum::V lv = verinum::V0;

View File

@ -278,22 +278,39 @@ static int draw_condition_binary_le(ivl_expr_t expr)
static int draw_condition_binary_lor(ivl_expr_t expr)
{
unsigned label_out = local_count++;
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
int lx = draw_eval_condition(le);
int tmp_flag = lx;
/* Short circuit right hand side if necessary */
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %d;\n", thread_count, label_out, lx);
if (lx < 8) {
int tmp = allocate_flag();
fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp, lx);
lx = tmp;
tmp_flag = allocate_flag();
fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp_flag, lx);
}
int rx = draw_eval_condition(re);
fprintf(vvp_out, " %%flag_or %d, %d;\n", rx, lx);
clr_flag(lx);
return rx;
/*
* The flag needs to be in the same position regardless of whether the
* right side is short-cicuited or not.
*/
if (lx == tmp_flag) {
fprintf(vvp_out, " %%flag_or %d, %d;\n", lx, rx);
} else {
fprintf(vvp_out, " %%flag_or %d, %d;\n", rx, tmp_flag);
if (lx != rx)
fprintf(vvp_out, " %%flag_mov %d, %d;\n", lx, rx);
clr_flag(tmp_flag);
}
fprintf(vvp_out, "T_%u.%u;\n", thread_count, label_out);
clr_flag(rx);
return lx;
}
static int draw_condition_binary(ivl_expr_t expr)

View File

@ -432,25 +432,45 @@ static void draw_binary_vec4_lequiv(ivl_expr_t expr)
assert(ivl_expr_width(expr) == 1);
}
static void draw_binary_vec4_land(ivl_expr_t expr)
static void draw_binary_vec4_logical(ivl_expr_t expr, char op)
{
const char *opcode;
const char *jmp_type;
switch (op) {
case 'a':
opcode = "and";
jmp_type = "0";
break;
case 'o':
opcode = "or";
jmp_type = "1";
break;
default:
assert(0);
break;
}
unsigned label_out = local_count++;
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
/* Push the left expression. Reduce it to a single bit if
necessary. */
draw_eval_vec4(le);
if (ivl_expr_width(le) > 1)
fprintf(vvp_out, " %%or/r;\n");
/* Now push the right expression. Again, reduce to a single
bit if necessary. */
/* Evaluate the left expression as a conditon and skip the right expression
* if the left is false. */
int flag = draw_eval_condition(le);
fprintf(vvp_out, " %%flag_get/vec4 %d;\n", flag);
fprintf(vvp_out, " %%jmp/%s T_%u.%u, %d;\n", jmp_type, thread_count,
label_out, flag);
clr_flag(flag);
/* Now push the right expression. Reduce to a single bit if necessary. */
draw_eval_vec4(re);
if (ivl_expr_width(re) > 1)
fprintf(vvp_out, " %%or/r;\n");
fprintf(vvp_out, " %%and;\n");
fprintf(vvp_out, " %%%s;\n", opcode);
fprintf(vvp_out, "T_%u.%u;\n", thread_count, label_out);
if (ivl_expr_width(expr) > 1)
fprintf(vvp_out, " %%pad/u %u;\n", ivl_expr_width(expr));
}
@ -632,29 +652,6 @@ static void draw_binary_vec4_le(ivl_expr_t expr)
}
}
static void draw_binary_vec4_lor(ivl_expr_t expr)
{
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
/* Push the left expression. Reduce it to a single bit if
necessary. */
draw_eval_vec4(le);
if (ivl_expr_width(le) > 1)
fprintf(vvp_out, " %%or/r;\n");
/* Now push the right expression. Again, reduce to a single
bit if necessary. */
draw_eval_vec4(re);
if (ivl_expr_width(re) > 1)
fprintf(vvp_out, " %%or/r;\n");
fprintf(vvp_out, " %%or;\n");
if (ivl_expr_width(expr) > 1)
fprintf(vvp_out, " %%pad/u %u;\n", ivl_expr_width(expr));
}
static void draw_binary_vec4_lrs(ivl_expr_t expr)
{
ivl_expr_t le = ivl_expr_oper1(expr);
@ -695,7 +692,8 @@ static void draw_binary_vec4(ivl_expr_t expr)
{
switch (ivl_expr_opcode(expr)) {
case 'a': /* Logical && */
draw_binary_vec4_land(expr);
case 'o': /* || (logical or) */
draw_binary_vec4_logical(expr, ivl_expr_opcode(expr));
break;
case '+':
@ -738,10 +736,6 @@ static void draw_binary_vec4(ivl_expr_t expr)
draw_binary_vec4_lrs(expr);
break;
case 'o': /* || (logical or) */
draw_binary_vec4_lor(expr);
break;
case 'q': /* -> (logical implication) */
draw_binary_vec4_limpl(expr);
break;