Skip to content

Commit d3696d6

Browse files
authored
Merge pull request #836 from diffblue/verilog_simplifier
Verilog: extract expression simplifier
2 parents 58088d7 + 47a9745 commit d3696d6

File tree

4 files changed

+181
-107
lines changed

4 files changed

+181
-107
lines changed

src/verilog/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SRC = aval_bval_encoding.cpp \
1818
verilog_preprocessor.cpp \
1919
verilog_preprocessor_lex.yy.cpp \
2020
verilog_preprocessor_tokenizer.cpp \
21+
verilog_simplifier.cpp \
2122
verilog_standard.cpp \
2223
verilog_symbol_table.cpp \
2324
verilog_synthesis.cpp \

src/verilog/verilog_simplifier.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*******************************************************************\
2+
3+
Module: Verilog Expression Simplifier
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "verilog_simplifier.h"
10+
11+
#include <util/arith_tools.h>
12+
#include <util/bitvector_expr.h>
13+
#include <util/mathematical_types.h>
14+
#include <util/simplify_expr.h>
15+
16+
#include <ebmc/ebmc_error.h>
17+
18+
#include "verilog_types.h"
19+
20+
static constant_exprt
21+
countones(const constant_exprt &expr, const namespacet &ns)
22+
{
23+
// lower to popcount and try simplifier
24+
auto simplified =
25+
simplify_expr(popcount_exprt{expr, verilog_int_typet{}.lower()}, ns);
26+
27+
if(!simplified.is_constant())
28+
{
29+
throw ebmc_errort() << "failed to simplify constant $countones";
30+
}
31+
else
32+
return to_constant_expr(simplified);
33+
}
34+
35+
static exprt verilog_simplifier_rec(exprt expr, const namespacet &ns)
36+
{
37+
// Remember the Verilog type.
38+
auto expr_verilog_type = expr.type().get(ID_C_verilog_type);
39+
auto expr_identifier = expr.type().get(ID_C_identifier);
40+
41+
// Remember the source location.
42+
auto location = expr.source_location();
43+
44+
// Do any operands first.
45+
bool operands_are_constant = true;
46+
47+
for(auto &op : expr.operands())
48+
{
49+
// recursive call
50+
op = verilog_simplifier_rec(op, ns);
51+
if(!op.is_constant())
52+
operands_are_constant = false;
53+
}
54+
55+
// Are all operands constants now?
56+
if(!operands_are_constant)
57+
return expr; // give up
58+
59+
auto make_all_ones = [](const typet &type) -> exprt
60+
{
61+
if(type.id() == ID_unsignedbv)
62+
{
63+
return from_integer(
64+
power(2, to_unsignedbv_type(type).get_width()) - 1, type);
65+
}
66+
else if(type.id() == ID_signedbv)
67+
{
68+
return from_integer(-1, type);
69+
}
70+
else if(type.id() == ID_bool)
71+
return true_exprt{};
72+
else
73+
PRECONDITION(false);
74+
};
75+
76+
if(expr.id() == ID_reduction_or)
77+
{
78+
// The simplifier doesn't know how to simplify reduction_or
79+
auto &reduction_or = to_unary_expr(expr);
80+
expr = notequal_exprt(
81+
reduction_or.op(), from_integer(0, reduction_or.op().type()));
82+
}
83+
else if(expr.id() == ID_reduction_nor)
84+
{
85+
// The simplifier doesn't know how to simplify reduction_nor
86+
auto &reduction_nor = to_unary_expr(expr);
87+
expr = equal_exprt(
88+
reduction_nor.op(), from_integer(0, reduction_nor.op().type()));
89+
}
90+
else if(expr.id() == ID_reduction_and)
91+
{
92+
// The simplifier doesn't know how to simplify reduction_and
93+
auto &reduction_and = to_unary_expr(expr);
94+
expr =
95+
equal_exprt{reduction_and.op(), make_all_ones(reduction_and.op().type())};
96+
}
97+
else if(expr.id() == ID_reduction_nand)
98+
{
99+
// The simplifier doesn't know how to simplify reduction_nand
100+
auto &reduction_nand = to_unary_expr(expr);
101+
expr = notequal_exprt{
102+
reduction_nand.op(), make_all_ones(reduction_nand.op().type())};
103+
}
104+
else if(expr.id() == ID_reduction_xor)
105+
{
106+
// The simplifier doesn't know how to simplify reduction_xor
107+
// Lower to countones.
108+
auto &reduction_xor = to_unary_expr(expr);
109+
auto ones = countones(to_constant_expr(reduction_xor.op()), ns);
110+
expr = extractbit_exprt{ones, from_integer(0, natural_typet{})};
111+
}
112+
else if(expr.id() == ID_reduction_xnor)
113+
{
114+
// The simplifier doesn't know how to simplify reduction_xnor
115+
// Lower to countones.
116+
auto &reduction_xnor = to_unary_expr(expr);
117+
auto ones = countones(to_constant_expr(reduction_xnor.op()), ns);
118+
expr = not_exprt{extractbit_exprt{ones, from_integer(0, natural_typet{})}};
119+
}
120+
else if(expr.id() == ID_replication)
121+
{
122+
auto &replication = to_replication_expr(expr);
123+
auto times = numeric_cast_v<std::size_t>(replication.times());
124+
// lower to a concatenation
125+
exprt::operandst ops;
126+
ops.reserve(times);
127+
for(std::size_t i = 0; i < times; i++)
128+
ops.push_back(replication.op());
129+
expr = concatenation_exprt{ops, expr.type()};
130+
}
131+
132+
// We fall back to the simplifier to approximate
133+
// the standard's definition of 'constant expression'.
134+
auto simplified_expr = simplify_expr(expr, ns);
135+
136+
// Restore the Verilog type, if any.
137+
if(expr_verilog_type != irep_idt())
138+
simplified_expr.type().set(ID_C_verilog_type, expr_verilog_type);
139+
140+
if(expr_identifier != irep_idt())
141+
simplified_expr.type().set(ID_C_identifier, expr_identifier);
142+
143+
if(location.is_not_nil())
144+
simplified_expr.add_source_location() = location;
145+
146+
return simplified_expr;
147+
}
148+
149+
exprt verilog_simplifier(exprt expr, const namespacet &ns)
150+
{
151+
return verilog_simplifier_rec(expr, ns);
152+
}

src/verilog/verilog_simplifier.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*******************************************************************\
2+
3+
Module: Verilog Expression Simplifier
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_VERILOG_SIMPLIFIER_H
10+
#define CPROVER_VERILOG_SIMPLIFIER_H
11+
12+
class exprt;
13+
class namespacet;
14+
15+
exprt verilog_simplifier(exprt, const namespacet &);
16+
17+
#endif

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 11 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Author: Daniel Kroening, [email protected]
2525
#include "verilog_bits.h"
2626
#include "verilog_expr.h"
2727
#include "verilog_lowering.h"
28+
#include "verilog_simplifier.h"
2829
#include "verilog_types.h"
2930
#include "vtype.h"
3031

@@ -1383,9 +1384,16 @@ exprt verilog_typecheck_exprt::elaborate_constant_expression(exprt expr)
13831384
{
13841385
// This performs constant-folding on a type-checked expression
13851386
// according to Section 11.2.1 IEEE 1800-2017.
1386-
auto expr_lowered = verilog_lowering(expr);
1387+
auto expr_lowered = verilog_lowering(std::move(expr));
13871388

1388-
return elaborate_constant_expression_rec(expr_lowered);
1389+
// replace constant symbols
1390+
auto expr_replaced =
1391+
elaborate_constant_expression_rec(std::move(expr_lowered));
1392+
1393+
// finally simplify
1394+
auto expr_simplified = verilog_simplifier(std::move(expr_replaced), ns);
1395+
1396+
return expr_simplified;
13891397
}
13901398

13911399
/*******************************************************************\
@@ -1461,117 +1469,13 @@ exprt verilog_typecheck_exprt::elaborate_constant_expression_rec(exprt expr)
14611469
}
14621470
else
14631471
{
1464-
// Remember the Verilog type.
1465-
auto expr_verilog_type = expr.type().get(ID_C_verilog_type);
1466-
auto expr_identifier = expr.type().get(ID_C_identifier);
1467-
1468-
// Remember the source location.
1469-
auto location = expr.source_location();
1470-
14711472
// Do any operands first.
1472-
bool operands_are_constant = true;
1473-
14741473
for(auto &op : expr.operands())
14751474
{
14761475
// recursive call
14771476
op = elaborate_constant_expression_rec(op);
1478-
if(!op.is_constant())
1479-
operands_are_constant = false;
1480-
}
1481-
1482-
// Are all operands constants now?
1483-
if(!operands_are_constant)
1484-
return expr; // give up
1485-
1486-
auto make_all_ones = [](const typet &type) -> exprt
1487-
{
1488-
if(type.id() == ID_unsignedbv)
1489-
{
1490-
return from_integer(
1491-
power(2, to_unsignedbv_type(type).get_width()) - 1, type);
1492-
}
1493-
else if(type.id() == ID_signedbv)
1494-
{
1495-
return from_integer(-1, type);
1496-
}
1497-
else if(type.id() == ID_bool)
1498-
return true_exprt{};
1499-
else
1500-
PRECONDITION(false);
1501-
};
1502-
1503-
if(expr.id() == ID_reduction_or)
1504-
{
1505-
// The simplifier doesn't know how to simplify reduction_or
1506-
auto &reduction_or = to_unary_expr(expr);
1507-
expr = notequal_exprt(
1508-
reduction_or.op(), from_integer(0, reduction_or.op().type()));
1509-
}
1510-
else if(expr.id() == ID_reduction_nor)
1511-
{
1512-
// The simplifier doesn't know how to simplify reduction_nor
1513-
auto &reduction_nor = to_unary_expr(expr);
1514-
expr = equal_exprt(
1515-
reduction_nor.op(), from_integer(0, reduction_nor.op().type()));
1516-
}
1517-
else if(expr.id() == ID_reduction_and)
1518-
{
1519-
// The simplifier doesn't know how to simplify reduction_and
1520-
auto &reduction_and = to_unary_expr(expr);
1521-
expr = equal_exprt{
1522-
reduction_and.op(), make_all_ones(reduction_and.op().type())};
1523-
}
1524-
else if(expr.id() == ID_reduction_nand)
1525-
{
1526-
// The simplifier doesn't know how to simplify reduction_nand
1527-
auto &reduction_nand = to_unary_expr(expr);
1528-
expr = notequal_exprt{
1529-
reduction_nand.op(), make_all_ones(reduction_nand.op().type())};
1530-
}
1531-
else if(expr.id() == ID_reduction_xor)
1532-
{
1533-
// The simplifier doesn't know how to simplify reduction_xor
1534-
// Lower to countones.
1535-
auto &reduction_xor = to_unary_expr(expr);
1536-
auto ones = countones(to_constant_expr(reduction_xor.op()));
1537-
expr = extractbit_exprt{ones, from_integer(0, natural_typet{})};
1538-
}
1539-
else if(expr.id() == ID_reduction_xnor)
1540-
{
1541-
// The simplifier doesn't know how to simplify reduction_xnor
1542-
// Lower to countones.
1543-
auto &reduction_xnor = to_unary_expr(expr);
1544-
auto ones = countones(to_constant_expr(reduction_xnor.op()));
1545-
expr =
1546-
not_exprt{extractbit_exprt{ones, from_integer(0, natural_typet{})}};
15471477
}
1548-
else if(expr.id() == ID_replication)
1549-
{
1550-
auto &replication = to_replication_expr(expr);
1551-
auto times = numeric_cast_v<std::size_t>(replication.times());
1552-
// lower to a concatenation
1553-
exprt::operandst ops;
1554-
ops.reserve(times);
1555-
for(std::size_t i = 0; i < times; i++)
1556-
ops.push_back(replication.op());
1557-
expr = concatenation_exprt{ops, expr.type()};
1558-
}
1559-
1560-
// We fall back to the simplifier to approximate
1561-
// the standard's definition of 'constant expression'.
1562-
auto simplified_expr = simplify_expr(expr, ns);
1563-
1564-
// Restore the Verilog type, if any.
1565-
if(expr_verilog_type != irep_idt())
1566-
simplified_expr.type().set(ID_C_verilog_type, expr_verilog_type);
1567-
1568-
if(expr_identifier != irep_idt())
1569-
simplified_expr.type().set(ID_C_identifier, expr_identifier);
1570-
1571-
if(location.is_not_nil())
1572-
simplified_expr.add_source_location() = location;
1573-
1574-
return simplified_expr;
1478+
return expr;
15751479
}
15761480
}
15771481

0 commit comments

Comments
 (0)