Skip to content

Commit 2fa9bb5

Browse files
committed
cparser: lower implicit local array tails to counted loops
1 parent 6721d7e commit 2fa9bb5

1 file changed

Lines changed: 82 additions & 15 deletions

File tree

‎cparser/Unblock.ml‎

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
open C
2323
open Cutil
2424

25-
(* Convert an initializer to a list of assignment expressions. *)
25+
(* Convert an initializer to a list of assignment expressions.
26+
Used for compound literals, where initialization is embedded in an
27+
expression at the appropriate sequence point. *)
2628

27-
let rec local_initializer env path init k =
29+
let rec local_initializer_expr env path init k =
2830
match init with
2931
| Init_single e ->
3032
{ edesc = EBinop(Oassign, path, e, path.etyp); etyp = path.etyp } :: k
@@ -42,7 +44,7 @@ let rec local_initializer env path init k =
4244
match il with
4345
| [] -> (default_init env ty_elt, [])
4446
| i1 :: il' -> (i1, il') in
45-
local_initializer env
47+
local_initializer_expr env
4648
{ edesc = EBinop(Oindex, path, intconst pos IInt, TPtr(ty_elt, []));
4749
etyp = ty_elt }
4850
i1
@@ -51,27 +53,92 @@ let rec local_initializer env path init k =
5153
array_init 0L il
5254
| Init_struct(id, fil) ->
5355
let field_init (fld, i) k =
54-
local_initializer env
56+
local_initializer_expr env
5557
{ edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
5658
i k in
5759
List.fold_right field_init fil k
5860
| Init_union(id, fld, i) ->
59-
local_initializer env
61+
local_initializer_expr env
6062
{ edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
6163
i k
6264

63-
(* Prepend assignments to the given statement. *)
64-
65-
let add_inits_stmt loc inits s =
66-
List.fold_right
67-
(fun e s -> sseq loc {sdesc = Sdo e; sloc = loc} s)
68-
inits s
69-
7065
(* Record new variables to be locally or globally defined *)
7166

7267
let local_variables = ref ([]: decl list)
7368
let global_variables = ref ([]: decl list)
7469

70+
let new_local name ty =
71+
let id = Env.fresh_ident name in
72+
local_variables :=
73+
(Storage_default, id, ty, None) :: !local_variables;
74+
{ edesc = EVar id; etyp = ty }
75+
76+
(* Convert a declaration initializer to assignment statements. The explicitly
77+
supplied outer array prefix is traversed directly. A nonempty implicit
78+
array tail is initialized by a typed counted loop, so the generated AST
79+
does not grow with the number of omitted elements. *)
80+
81+
let rec local_initializer_stmt env loc path init k =
82+
match init with
83+
| Init_single e ->
84+
sseq loc (sassign loc path e) k
85+
| Init_array il ->
86+
let (ty_elt, sz) =
87+
match unroll env path.etyp with
88+
| TArray(ty_elt, Some sz, _) -> (ty_elt, sz)
89+
(* We accept empty array initializer for flexible array members, which
90+
has size zero *)
91+
| TArray(ty_elt, None, _) when il = [] -> (ty_elt, 0L)
92+
| _ ->
93+
Diagnostics.fatal_error Diagnostics.no_loc
94+
"wrong type for array initializer" in
95+
let array_elt index =
96+
{ edesc = EBinop(Oindex, path, index, TPtr(ty_elt, []));
97+
etyp = ty_elt } in
98+
let array_default_init pos =
99+
let index_kind = size_t_ikind () in
100+
let index_type = TInt(index_kind, []) in
101+
let index = new_local "__init_index" index_type in
102+
let init_index = sassign loc index (intconst pos index_kind) in
103+
let test_index =
104+
{ edesc = EBinop(Olt, index, intconst sz index_kind, index_type);
105+
etyp = TInt(IInt, []) } in
106+
let incr_index =
107+
{ sdesc = Sdo { edesc = EUnop(Opreincr, index);
108+
etyp = index_type };
109+
sloc = loc } in
110+
let body =
111+
local_initializer_stmt env loc
112+
(array_elt index)
113+
(default_init env ty_elt)
114+
sskip in
115+
let loop =
116+
{ sdesc = Sfor(init_index, test_index, incr_index, body);
117+
sloc = loc } in
118+
sseq loc loop k in
119+
let rec array_init pos il =
120+
if pos >= sz then k else begin
121+
match il with
122+
| i1 :: il' ->
123+
local_initializer_stmt env loc
124+
(array_elt (intconst pos IInt))
125+
i1
126+
(array_init (Int64.succ pos) il')
127+
| [] ->
128+
array_default_init pos
129+
end in
130+
array_init 0L il
131+
| Init_struct(id, fil) ->
132+
let field_init (fld, i) k =
133+
local_initializer_stmt env loc
134+
{ edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
135+
i k in
136+
List.fold_right field_init fil k
137+
| Init_union(id, fld, i) ->
138+
local_initializer_stmt env loc
139+
{ edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
140+
i k
141+
75142
(* Note: "const int x = y - 1;" is legal, but we turn it into
76143
"const int x; x = y - 1;", which is not. Therefore, remove
77144
top-level 'const' attribute. Also remove it on element type of
@@ -94,7 +161,7 @@ let process_compound_literal islocal env ty init =
94161
let e = {edesc = EVar id; etyp = ty'} in
95162
local_variables :=
96163
(Storage_default, id, ty', None) :: !local_variables;
97-
(local_initializer env e init [], e)
164+
(local_initializer_expr env e init [], e)
98165
end else begin
99166
global_variables :=
100167
(Storage_static, id, ty, Some init) :: !global_variables;
@@ -253,8 +320,8 @@ let process_decl loc env ctx (sto, id, ty, optinit) k =
253320
k
254321
| Some init ->
255322
let init' = expand_init true env init in
256-
let l = local_initializer env { edesc = EVar id; etyp = ty' } init' [] in
257-
add_inits_stmt loc l k
323+
local_initializer_stmt env loc
324+
{ edesc = EVar id; etyp = ty' } init' k
258325

259326
(* Simplification of blocks within a statement *)
260327

0 commit comments

Comments
 (0)