Skip to content

Commit a10a654

Browse files
authored
Merge pull request #225 from xbauch/feature/type-cast-range-check
Range check for non-bounded numeric types
2 parents 98fd6aa + 97bcc02 commit a10a654

File tree

7 files changed

+109
-28
lines changed

7 files changed

+109
-28
lines changed

experiments/golden-results/StratoX-summary.txt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Calling function: Process_Declaration
88
Error message: Unknown declaration kind
99
Nkind: N_Freeze_Generic_Entity
1010
--
11-
Occurs: 104 times
11+
Occurs: 105 times
1212
Calling function: Do_Function_Call
1313
Error message: func name not in symbol table
1414
Nkind: N_Function_Call
@@ -23,7 +23,7 @@ Calling function: Do_Type_Definition
2323
Error message: Access type unsupported
2424
Nkind: N_Access_To_Object_Definition
2525
--
26-
Occurs: 42 times
26+
Occurs: 43 times
2727
Calling function: Do_Expression
2828
Error message: Unknown attribute
2929
Nkind: N_Attribute_Reference
@@ -93,6 +93,11 @@ Calling function: Process_Pragma_Declaration
9393
Error message: Unsupported pragma: Global
9494
Nkind: N_Pragma
9595
--
96+
Occurs: 10 times
97+
Calling function: Process_Statement
98+
Error message: Raise statement
99+
Nkind: N_Raise_Statement
100+
--
96101
Occurs: 9 times
97102
Calling function: Process_Declaration
98103
Error message: Unknown declaration kind
@@ -103,11 +108,6 @@ Calling function: Process_Pragma_Declaration
103108
Error message: Unsupported pragma: Elaborate Body
104109
Nkind: N_Pragma
105110
--
106-
Occurs: 9 times
107-
Calling function: Process_Statement
108-
Error message: Raise statement
109-
Nkind: N_Raise_Statement
110-
--
111111
Occurs: 8 times
112112
Calling function: Process_Declaration
113113
Error message: Generic instantiation declaration
@@ -193,6 +193,11 @@ Calling function: Do_Procedure_Call_Statement
193193
Error message: sym id not in symbol table
194194
Nkind: N_Procedure_Call_Statement
195195
--
196+
Occurs: 2 times
197+
Calling function: Do_Function_Call
198+
Error message: function entity not defining identifier
199+
Nkind: N_Function_Call
200+
--
196201
Occurs: 1 times
197202
Calling function: Do_Compilation_Unit
198203
Error message: Unknown tree node
@@ -204,11 +209,6 @@ Error message: Constant Type not in Class_Bitvector_Type
204209
Nkind: N_Integer_Literal
205210
--
206211
Occurs: 1 times
207-
Calling function: Do_Function_Call
208-
Error message: function entity not defining identifier
209-
Nkind: N_Function_Call
210-
--
211-
Occurs: 1 times
212212
Calling function: Do_Itype_Integer_Subtype
213213
Error message: Non-literal bound unsupported
214214
Nkind: N_Defining_Identifier

gnat2goto/driver/range_check.adb

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,56 @@ package body Range_Check is
7272
return All_Bounds_Table.Element (Bound_Index);
7373
end Get_Bound_Type;
7474

75-
function Get_Bound (Bound_Type : Irep; Pos : Bound_Low_Or_High) return Irep
75+
function Get_Bound (N : Node_Id; Bound_Type : Irep; Pos : Bound_Low_Or_High)
76+
return Irep
77+
is
78+
begin
79+
case Kind (Bound_Type) is
80+
when I_Bounded_Signedbv_Type
81+
| I_Bounded_Unsignedbv_Type
82+
| I_Bounded_Floatbv_Type =>
83+
return Get_Bound_Of_Bounded_Type (Bound_Type, Pos);
84+
when I_Unsignedbv_Type =>
85+
-- this case is probably unnecessary:
86+
-- 1: how does one create non-bounded unsigned types anyway
87+
-- 2: CBMC has facilities to check unsigned overflow
88+
declare
89+
Type_Width : constant Integer := Get_Width (Bound_Type);
90+
Bound_Value : constant Uint :=
91+
(if Pos = Bound_Low
92+
then Uint_0
93+
else UI_From_Int (2 ** Type_Width - 1));
94+
begin
95+
return Make_Constant_Expr (Source_Location => No_Location,
96+
I_Type => Bound_Type,
97+
Range_Check => False,
98+
Value =>
99+
Convert_Uint_To_Hex (Bound_Value,
100+
Types.Pos (Type_Width)));
101+
end;
102+
when I_Signedbv_Type =>
103+
declare
104+
Type_Width : constant Integer := Get_Width (Bound_Type);
105+
Bound_Value : constant Uint :=
106+
(if Pos = Bound_Low
107+
then UI_From_Int (-(2 ** (Type_Width - 1)))
108+
else UI_From_Int (2 ** (Type_Width - 1) - 1));
109+
begin
110+
return Make_Constant_Expr (Source_Location => No_Location,
111+
I_Type => Bound_Type,
112+
Range_Check => False,
113+
Value =>
114+
Convert_Uint_To_Hex (Bound_Value,
115+
Types.Pos (Type_Width)));
116+
end;
117+
when others =>
118+
return Report_Unhandled_Node_Irep (N, "Get_Bound",
119+
"Unsupported range type");
120+
end case;
121+
end Get_Bound;
122+
123+
function Get_Bound_Of_Bounded_Type (Bound_Type : Irep;
124+
Pos : Bound_Low_Or_High) return Irep
76125
is
77126
Bound_Index : constant Integer := (if Pos = Bound_Low
78127
then Get_Lower_Bound (Bound_Type)
@@ -93,7 +142,7 @@ package body Range_Check is
93142
when Symb_Bound =>
94143
return Load_Symbol_Bound (Bound_Index);
95144
end case;
96-
end Get_Bound;
145+
end Get_Bound_Of_Bounded_Type;
97146

98147
----------------------------
99148
-- Make_Range_Assert_Expr --
@@ -185,9 +234,9 @@ package body Range_Check is
185234
end Build_Assert_Function;
186235

187236
Lower_Bound : constant Irep :=
188-
Get_Bound (Followed_Bound_Type, Bound_Low);
237+
Get_Bound (N, Followed_Bound_Type, Bound_Low);
189238
Upper_Bound : constant Irep :=
190-
Get_Bound (Followed_Bound_Type, Bound_High);
239+
Get_Bound (N, Followed_Bound_Type, Bound_High);
191240
begin
192241
Append_Argument (Call_Args, Value);
193242
Append_Argument (Call_Args, Lower_Bound);
@@ -230,7 +279,9 @@ package body Range_Check is
230279
pragma Assert (Kind (Bound_Type) in
231280
I_Bounded_Unsignedbv_Type
232281
| I_Bounded_Signedbv_Type
233-
| I_Bounded_Floatbv_Type);
282+
| I_Bounded_Floatbv_Type
283+
| I_Unsignedbv_Type
284+
| I_Signedbv_Type);
234285
-- The compared expressions (value and bound) have to be of the
235286
-- same type
236287
if Get_Width (Bound_Type) > Get_Width (Value_Expr_Type)

gnat2goto/driver/range_check.ads

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,27 @@ package Range_Check is
1919
function Store_Real_Bound (Number : Bound_Type_Real) return Integer;
2020
function Store_Symbol_Bound (Number : Bound_Type_Symbol) return Integer;
2121

22-
function Get_Bound (Bound_Type : Irep; Pos : Bound_Low_Or_High) return Irep
22+
function Get_Bound (N : Node_Id; Bound_Type : Irep; Pos : Bound_Low_Or_High)
23+
return Irep
2324
with Pre => Kind (Bound_Type) in
2425
I_Bounded_Unsignedbv_Type | I_Bounded_Signedbv_Type
25-
| I_Bounded_Floatbv_Type,
26+
| I_Bounded_Floatbv_Type | I_Unsignedbv_Type | I_Signedbv_Type,
27+
2628
Post => Kind (Get_Bound'Result) in Class_Expr;
2729

30+
function Get_Bound_Of_Bounded_Type (Bound_Type : Irep;
31+
Pos : Bound_Low_Or_High) return Irep
32+
with Pre => Kind (Bound_Type) in
33+
I_Bounded_Signedbv_Type
34+
| I_Bounded_Floatbv_Type
35+
| I_Bounded_Unsignedbv_Type,
36+
Post => Kind (Get_Bound_Of_Bounded_Type'Result) in Class_Expr;
37+
2838
function Make_Range_Assert_Expr (N : Node_Id; Value : Irep;
2939
Bounds_Type : Irep) return Irep
3040
with Pre => Kind (Bounds_Type) in
31-
I_Bounded_Signedbv_Type | I_Bounded_Floatbv_Type | I_Symbol_Type;
41+
I_Bounded_Signedbv_Type | I_Bounded_Floatbv_Type | I_Symbol_Type
42+
| I_Unsignedbv_Type | I_Signedbv_Type;
3243

3344
function Make_Range_Expression (Value_Expr : Irep; Lower_Bound : Irep;
3445
Upper_Bound : Irep)

gnat2goto/driver/tree_walk.adb

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,12 +1541,17 @@ package body Tree_Walk is
15411541
begin
15421542
-- TODO: Range expressions for non-bounded types are outside
15431543
-- the scope of this PR
1544-
if Kind (Type_Of_Val) in I_Bounded_Signedbv_Type | I_Bounded_Floatbv_Type
1545-
then
1546-
return Make_Range_Assert_Expr (N, Typecast_Expr, Type_Of_Val);
1547-
else
1548-
return Typecast_Expr;
1549-
end if;
1544+
case Kind (Type_Of_Val) is
1545+
when I_Bounded_Signedbv_Type
1546+
| I_Bounded_Floatbv_Type
1547+
| I_Bounded_Unsignedbv_Type
1548+
| I_Unsignedbv_Type
1549+
| I_Signedbv_Type
1550+
| I_Bounded_Mod_Type =>
1551+
return Make_Range_Assert_Expr (N, Typecast_Expr, Type_Of_Val);
1552+
when others =>
1553+
return Typecast_Expr;
1554+
end case;
15501555
end Do_Qualified_Expression;
15511556

15521557
-----------------------------
@@ -1592,8 +1597,8 @@ package body Tree_Walk is
15921597
Set_Lhs (Assume_And_Yield,
15931598
Make_Assume_Expr (N,
15941599
Make_Range_Expression (Sym_Nondet,
1595-
Get_Bound (Followed_Type, Bound_Low),
1596-
Get_Bound (Followed_Type, Bound_High))));
1600+
Get_Bound (N, Followed_Type, Bound_Low),
1601+
Get_Bound (N, Followed_Type, Bound_High))));
15971602
else
15981603
Set_Lhs (Assume_And_Yield,
15991604
Make_Assume_Expr (N,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
procedure Test is
2+
type Uint_8 is mod 2**8;
3+
Uint_Var : Uint_8 := 5;
4+
Int_Var : Integer;
5+
begin
6+
Int_Var := Integer'(Integer (Uint_Var));
7+
pragma Assert (Int_Var = 5);
8+
end Test;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[assertion.1] Range Check: SUCCESS
2+
[1] file test.adb line 7 assertion: SUCCESS
3+
VERIFICATION SUCCESSFUL
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from test_support import *
2+
3+
prove()

0 commit comments

Comments
 (0)