Skip to content

Commit 2e283cc

Browse files
authored
Merge pull request #667 from diffblue/typecheck_relation
Verilog: typechecking for relations
2 parents 85dccf8 + 19994d4 commit 2e283cc

File tree

11 files changed

+124
-29
lines changed

11 files changed

+124
-29
lines changed

regression/ebmc/example1/example1.sv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ module main(input a, input b);
1111

1212
my_add adder(a, b, result);
1313

14-
assert final (a+b==result);
14+
assert final (2'(a)+b==result);
1515

1616
endmodule

regression/verilog/SVA/immediate3.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
immediate3.sv
33
--bound 0
4-
^\[full_adder\.assert\.1\] always \{ full_adder\.carry, full_adder\.sum \} == full_adder\.a \+ full_adder\.b \+ full_adder\.c: PROVED up to bound 0$
4+
^\[full_adder\.assert\.1\] always \{ full_adder\.carry, full_adder\.sum \} == \{ 1'b0, full_adder\.a \} \+ full_adder\.b \+ full_adder\.c: PROVED up to bound 0$
55
^EXIT=0$
66
^SIGNAL=0$
77
--

regression/verilog/SVA/immediate3.sv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ module full_adder(input a, b, c, output sum, carry);
44
assign carry = a & b | (a ^ b) & c;
55

66
always @(*)
7-
assert final({carry, sum} == a + b + c);
7+
assert final({carry, sum} == {1'b0, a} + b + c);
88

99
endmodule

regression/verilog/SVA/static_final1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
static_final1.sv
33
--bound 0
4-
^\[full_adder\.p0\] always \{ full_adder\.carry, full_adder\.sum \} == full_adder\.a \+ full_adder\.b \+ full_adder\.c: PROVED up to bound 0$
4+
^\[full_adder\.p0\] always \{ full_adder\.carry, full_adder\.sum \} == \{ 1'b0, full_adder\.a \} \+ full_adder\.b \+ full_adder\.c: PROVED up to bound 0$
55
^EXIT=0$
66
^SIGNAL=0$
77
--

regression/verilog/SVA/static_final1.sv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ module full_adder(input a, b, c, output sum, carry);
55

66
// 1800-2017
77
// 16.4.3 Deferred assertions outside procedural code
8-
p0: assert final ({carry, sum} == a + b + c);
8+
p0: assert final ({carry, sum} == {1'b0, a} + b + c);
99

1010
endmodule

regression/verilog/expressions/concatenation1.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module main(in1, in2);
77
always @in1
88
out = { in2, in1 };
99

10-
always assert property1: out == ((in2<<16)|in1);
10+
always assert property1: out == (({16'b0, in2}<<16)|in1);
1111

1212
always assert property2: {4'b1001,4'b1011}==8'b10011011;
1313

regression/verilog/expressions/equality1.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ equality1.v
99
^\[.*\] always 32'b0000000000000000000000000000000z == 20 === 32'b0000000000000000000000000000000x: PROVED up to bound 0$
1010
^\[.*\] always 32'b0000000000000000000000000000000x != 10 === 32'b0000000000000000000000000000000x: PROVED up to bound 0$
1111
^\[.*\] always 32'b0000000000000000000000000000000z != 20 === 32'b0000000000000000000000000000000x: PROVED up to bound 0$
12-
^\[.*\] always 2'b11 == 2'b11 === 0: REFUTED$
12+
^\[.*\] always 1'sb1 == 2'b11 === 0: PROVED up to bound 0$
1313
^\[.*\] always 2'sb11 == 2'sb11 === 1: PROVED up to bound 0$
14-
^EXIT=10$
14+
^EXIT=0$
1515
^SIGNAL=0$
1616
--
1717
^warning: ignoring

regression/verilog/expressions/equality2.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ equality2.v
1111
^\[.*\] always 32'b0000000000000000000000000000000x === 1 == 0: PROVED up to bound 0$
1212
^\[.*\] always 32'b0000000000000000000000000000000z === 1 == 0: PROVED up to bound 0$
1313
^\[.*\] always 1 === 1 == 1: PROVED up to bound 0$
14-
^\[.*\] always 3'b011 === 3'b111 == 1: REFUTED$
14+
^\[.*\] always 3'b011 === 2'sb11 == 1: PROVED up to bound 0$
1515
^\[.*\] always 3'sb111 === 3'sb111 == 1: PROVED up to bound 0$
16-
^EXIT=10$
16+
^EXIT=0$
1717
^SIGNAL=0$
1818
--
1919
^warning: ignoring

regression/verilog/expressions/replication1.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module main(in);
77
out = { 4 { in } };
88

99
always assert property1:
10-
out==(in | (in<<8) | (in<<16) | (in<<24));
10+
out==({24'b0, in} | (in<<8) | (in<<16) | (in<<24));
1111

1212
// 1-replication
1313
always assert property2:

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 111 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,6 +2118,33 @@ void verilog_typecheck_exprt::convert_range(
21182118

21192119
/*******************************************************************\
21202120
2121+
Function: verilog_typecheck_exprt::enum_decay
2122+
2123+
Inputs:
2124+
2125+
Outputs:
2126+
2127+
Purpose:
2128+
2129+
\*******************************************************************/
2130+
2131+
typet verilog_typecheck_exprt::enum_decay(const typet &type)
2132+
{
2133+
// Verilog enum types decay to their base type when used in relational
2134+
// or arithmetic expressions.
2135+
if(type.get(ID_C_verilog_type) == ID_verilog_enum)
2136+
{
2137+
typet result = type;
2138+
result.remove(ID_C_verilog_type);
2139+
result.remove(ID_C_identifier);
2140+
return result;
2141+
}
2142+
else
2143+
return type;
2144+
}
2145+
2146+
/*******************************************************************\
2147+
21212148
Function: verilog_typecheck_exprt::tc_binary_expr
21222149
21232150
Inputs:
@@ -2132,20 +2159,7 @@ void verilog_typecheck_exprt::tc_binary_expr(
21322159
const exprt &expr,
21332160
exprt &op0, exprt &op1)
21342161
{
2135-
// Verilog enum types decay to their base type when used in relational
2136-
// or arithmetic expressions.
2137-
auto enum_decay = [](const typet &type) {
2138-
if(type.get(ID_C_verilog_type) == ID_verilog_enum)
2139-
{
2140-
typet result = type;
2141-
result.remove(ID_C_verilog_type);
2142-
result.remove(ID_C_identifier);
2143-
return result;
2144-
}
2145-
else
2146-
return type;
2147-
};
2148-
2162+
// follows 1800-2017 11.8.2
21492163
const typet new_type =
21502164
max_type(enum_decay(op0.type()), enum_decay(op1.type()));
21512165

@@ -2163,6 +2177,85 @@ void verilog_typecheck_exprt::tc_binary_expr(
21632177

21642178
/*******************************************************************\
21652179
2180+
Function: zero_extend
2181+
2182+
Inputs:
2183+
2184+
Outputs:
2185+
2186+
Purpose:
2187+
2188+
\*******************************************************************/
2189+
2190+
static exprt zero_extend(const exprt &expr, const typet &type)
2191+
{
2192+
auto old_width = expr.type().id() == ID_bool
2193+
? 1
2194+
: to_bitvector_type(expr.type()).get_width();
2195+
2196+
// first make unsigned
2197+
typet tmp_type;
2198+
2199+
if(type.id() == ID_unsignedbv)
2200+
tmp_type = unsignedbv_typet{old_width};
2201+
else if(type.id() == ID_verilog_unsignedbv)
2202+
tmp_type = verilog_unsignedbv_typet{old_width};
2203+
else
2204+
PRECONDITION(false);
2205+
2206+
return typecast_exprt::conditional_cast(
2207+
typecast_exprt::conditional_cast(expr, tmp_type), type);
2208+
}
2209+
2210+
/*******************************************************************\
2211+
2212+
Function: verilog_typecheck_exprt::typecheck_relation
2213+
2214+
Inputs:
2215+
2216+
Outputs:
2217+
2218+
Purpose:
2219+
2220+
\*******************************************************************/
2221+
2222+
void verilog_typecheck_exprt::typecheck_relation(binary_exprt &expr)
2223+
{
2224+
auto &lhs = expr.lhs();
2225+
auto &rhs = expr.rhs();
2226+
2227+
// Relations are special-cased in 1800-2017 11.8.2.
2228+
const typet new_type =
2229+
max_type(enum_decay(lhs.type()), enum_decay(rhs.type()));
2230+
2231+
if(new_type.is_nil())
2232+
{
2233+
throw errort().with_location(expr.source_location())
2234+
<< "expected operands of compatible type but got:\n"
2235+
<< " " << to_string(lhs.type()) << '\n'
2236+
<< " " << to_string(rhs.type());
2237+
}
2238+
2239+
// If both operands are signed, both are sign-extended to the max width.
2240+
// Otherwise, both are zero-extended to the max width.
2241+
// In particular, signed operands are then _not_ sign extended,
2242+
// which a typecast would do.
2243+
if(new_type.id() == ID_verilog_unsignedbv || new_type.id() == ID_unsignedbv)
2244+
{
2245+
// zero extend both operands
2246+
lhs = zero_extend(lhs, new_type);
2247+
rhs = zero_extend(rhs, new_type);
2248+
}
2249+
else
2250+
{
2251+
// convert
2252+
implicit_typecast(lhs, new_type);
2253+
implicit_typecast(rhs, new_type);
2254+
}
2255+
}
2256+
2257+
/*******************************************************************\
2258+
21662259
Function: verilog_typecheck_exprt::max_type
21672260
21682261
Inputs:
@@ -2585,7 +2678,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
25852678
Forall_operands(it, expr)
25862679
convert_expr(*it);
25872680

2588-
tc_binary_expr(expr);
2681+
typecheck_relation(expr);
25892682

25902683
return std::move(expr);
25912684
}
@@ -2597,7 +2690,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
25972690
Forall_operands(it, expr)
25982691
convert_expr(*it);
25992692

2600-
tc_binary_expr(expr);
2693+
typecheck_relation(expr);
26012694

26022695
// This returns 'x' if either of the operands contains x or z.
26032696
if(
@@ -2648,7 +2741,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
26482741
Forall_operands(it, expr)
26492742
convert_expr(*it);
26502743

2651-
tc_binary_expr(expr);
2744+
typecheck_relation(expr);
26522745

26532746
return std::move(expr);
26542747
}
@@ -2660,7 +2753,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
26602753
Forall_operands(it, expr)
26612754
convert_expr(*it);
26622755

2663-
tc_binary_expr(expr);
2756+
typecheck_relation(expr);
26642757
no_bool_ops(expr);
26652758

26662759
return std::move(expr);

0 commit comments

Comments
 (0)