vlog95: Add support for translating some power expressions as a left shift.

If the left power operator expression is a numeric constant that has a
value 2^n n>0 then we can use a left shift to calculate the result. This
patch adds code to do this. All other power expressions are flagged as a
compilation error.
This commit is contained in:
Cary R 2011-01-18 13:46:18 -08:00 committed by Stephen Williams
parent 5cec7e3870
commit 755d0b59d6
1 changed files with 57 additions and 9 deletions

View File

@ -16,10 +16,57 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
# include <inttypes.h>
# include "config.h"
# include "vlog95_priv.h"
// HERE: Do we need to use wid?
// HERE: Do we need to use wid in these routines? We should probably use
// it to verify that the expressions have the expected width.
/*
* We can convert any 2^n ** <unsigned variable> expression to
* 1 << (n * <unsigned variable>). If the variable is signed then we need
* to add a check for less than zero and for that case return 0.
*/
static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
unsigned wid)
{
int rtype;
int64_t value, scale;
unsigned is_signed_rval = 0;
unsigned expr_wid;
ivl_expr_t lval = ivl_expr_oper1(expr);
ivl_expr_t rval = ivl_expr_oper2(expr);
/* The L-value must be a number. */
if (ivl_expr_type(lval) != IVL_EX_NUMBER) return 0;
/* The L-value must of the form 2^n. */
value = get_int64_from_number(lval, &rtype);
if (rtype) return 0;
expr_wid = ivl_expr_width(lval);
if (value < 2) return 0;
if (value % 2) return 0;
/* Generate the appropriate conversion. */
if (ivl_expr_signed(rval)) {
emit_expr(scope, rval, 0);
fprintf(vlog_out, " < 0 ? %u'h0 : (", expr_wid);
is_signed_rval = 1;
}
scale = value / 2;
fprintf(vlog_out, "%u'h1 << ", expr_wid);
if (scale != 1) {
if (is_signed_rval) {
fprintf(vlog_out, "(%"PRId64, scale);
} else {
fprintf(vlog_out, "(%u'h%"PRIx64,
ivl_expr_width(rval), scale);
}
fprintf(vlog_out, " * ");
}
emit_expr(scope, rval, 0);
if (scale != 1) fprintf(vlog_out, ")");
if (is_signed_rval) fprintf(vlog_out, ")");
return 1;
}
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
@ -97,14 +144,15 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
fprintf(vlog_out, ")");
break;
case 'p':
// HERE: We can convert 2 ** <r-val> to 1 << <r-val>
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, " ** ");
emit_expr(scope, ivl_expr_oper2(expr), 0);
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
"supported.\n",
ivl_expr_file(expr), ivl_expr_lineno(expr));
vlog_errors += 1;
if (! emit_power_as_shift(scope, expr, wid)) {
emit_expr(scope, ivl_expr_oper1(expr), wid);
fprintf(vlog_out, " ** ");
emit_expr(scope, ivl_expr_oper2(expr), 0);
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
"supported.\n",
ivl_expr_file(expr), ivl_expr_lineno(expr));
vlog_errors += 1;
}
break;
default:
emit_expr(scope, ivl_expr_oper1(expr), wid);