Skip to content

Commit 2575d4f

Browse files
committed
Verilog: typechecking for relations
Relations are special-cased in 1800-2017 11.8.2. If both operands are signed, both are sign-extended to the max width. Otherwise, both are zero-extended to the max width. In particular, signed operands are then _not_ sign extended, which a typecast would do.
1 parent 03d9ee4 commit 2575d4f

File tree

11 files changed

+123
-29
lines changed

11 files changed

+123
-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: 110 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,84 @@ 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 : to_bitvector_type(expr.type()).get_width();
2194+
2195+
// first make unsigned
2196+
typet tmp_type;
2197+
2198+
if(type.id() == ID_unsignedbv)
2199+
tmp_type = unsignedbv_typet{old_width};
2200+
else if(type.id() == ID_verilog_unsignedbv)
2201+
tmp_type = verilog_unsignedbv_typet{old_width};
2202+
else
2203+
PRECONDITION(false);
2204+
2205+
return typecast_exprt::conditional_cast(
2206+
typecast_exprt::conditional_cast(expr, tmp_type), type);
2207+
}
2208+
2209+
/*******************************************************************\
2210+
2211+
Function: verilog_typecheck_exprt::typecheck_relation
2212+
2213+
Inputs:
2214+
2215+
Outputs:
2216+
2217+
Purpose:
2218+
2219+
\*******************************************************************/
2220+
2221+
void verilog_typecheck_exprt::typecheck_relation(binary_exprt &expr)
2222+
{
2223+
auto &lhs = expr.lhs();
2224+
auto &rhs = expr.rhs();
2225+
2226+
// Relations are special-cased in 1800-2017 11.8.2.
2227+
const typet new_type =
2228+
max_type(enum_decay(lhs.type()), enum_decay(rhs.type()));
2229+
2230+
if(new_type.is_nil())
2231+
{
2232+
throw errort().with_location(expr.source_location())
2233+
<< "expected operands of compatible type but got:\n"
2234+
<< " " << to_string(lhs.type()) << '\n'
2235+
<< " " << to_string(rhs.type());
2236+
}
2237+
2238+
// If both operands are signed, both are sign-extended to the max width.
2239+
// Otherwise, both are zero-extended to the max width.
2240+
// In particular, signed operands are then _not_ sign extended,
2241+
// which a typecast would do.
2242+
if(new_type.id() == ID_verilog_unsignedbv || new_type.id() == ID_unsignedbv)
2243+
{
2244+
// zero extend both operands
2245+
lhs = zero_extend(lhs, new_type);
2246+
rhs = zero_extend(rhs, new_type);
2247+
}
2248+
else
2249+
{
2250+
// convert
2251+
implicit_typecast(lhs, new_type);
2252+
implicit_typecast(rhs, new_type);
2253+
}
2254+
}
2255+
2256+
/*******************************************************************\
2257+
21662258
Function: verilog_typecheck_exprt::max_type
21672259
21682260
Inputs:
@@ -2561,7 +2653,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
25612653
Forall_operands(it, expr)
25622654
convert_expr(*it);
25632655

2564-
tc_binary_expr(expr);
2656+
typecheck_relation(expr);
25652657

25662658
return std::move(expr);
25672659
}
@@ -2573,7 +2665,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
25732665
Forall_operands(it, expr)
25742666
convert_expr(*it);
25752667

2576-
tc_binary_expr(expr);
2668+
typecheck_relation(expr);
25772669

25782670
// This returns 'x' if either of the operands contains x or z.
25792671
if(
@@ -2610,7 +2702,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
26102702
Forall_operands(it, expr)
26112703
convert_expr(*it);
26122704

2613-
tc_binary_expr(expr);
2705+
typecheck_relation(expr);
26142706

26152707
return std::move(expr);
26162708
}
@@ -2622,7 +2714,7 @@ exprt verilog_typecheck_exprt::convert_binary_expr(binary_exprt expr)
26222714
Forall_operands(it, expr)
26232715
convert_expr(*it);
26242716

2625-
tc_binary_expr(expr);
2717+
typecheck_relation(expr);
26262718
no_bool_ops(expr);
26272719

26282720
return std::move(expr);

0 commit comments

Comments
 (0)