1 (* *********************************************************************)
3 (* The Compcert verified compiler *)
5 (* Xavier Leroy, INRIA Paris-Rocquencourt *)
7 (* Copyright Institut National de Recherche en Informatique et en *)
8 (* Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU General Public License as published by *)
10 (* the Free Software Foundation, either version 2 of the License, or *)
11 (* (at your option) any later version. This file is also distributed *)
12 (* under the terms of the INRIA Non-Commercial License Agreement. *)
14 (* *********************************************************************)
16 (* Elimination of bit fields in structs *)
18 (* Assumes: unblocked, simplified code.
19 Preserves: unblocked, simplified code. *)
27 (* Info associated to each bitfield *)
30 { bf_carrier: string; (* name of underlying regular field *)
31 bf_carrier_typ: typ; (* type of underlying regular field *)
32 bf_pos: int; (* start bit *)
33 bf_size: int; (* size in bit *)
34 bf_signed: bool } (* signed or unsigned *)
37 0 <= pos < bitsizeof(int)
38 0 < sz <= bitsizeof(int)
39 0 < pos + sz <= bitsizeof(int)
42 (* Mapping (struct identifier, bitfield name) -> bitfield info *)
45 (Hashtbl.create 57: (ident * string, bitfield_info) Hashtbl.t)
47 (* Packing algorithm -- keep consistent with [Cutil.pack_bitfield]! *)
49 let unsigned_ikind_for_carrier nbits =
50 if nbits <= 8 then IUChar else
51 if nbits <= 8 * !config.sizeof_short then IUShort else
52 if nbits <= 8 * !config.sizeof_int then IUInt else
53 if nbits <= 8 * !config.sizeof_long then IULong else
54 if nbits <= 8 * !config.sizeof_longlong then IULongLong else
57 let pack_bitfields env id ml =
58 let rec pack accu pos = function
62 match m.fld_bitfield with
63 | None -> (pos, accu, ml)
66 (pos, accu, ms) (* bit width 0 means end of pack *)
67 else if pos + n > 8 * !config.sizeof_int then
68 (pos, accu, ml) (* doesn't fit in current word *)
71 match unroll env m.fld_typ with
72 | TInt(ik, _) -> is_signed_ikind ik
73 | _ -> assert false (* should never happen, checked in Elab *) in
74 pack ((m.fld_name, pos, n, signed) :: accu) (pos + n) ms
78 let rec transf_members env id count = function
81 if m.fld_bitfield = None then
82 m :: transf_members env id count ms
84 let (nbits, bitfields, ml') = pack_bitfields env id ml in
85 let carrier = sprintf "__bf%d" count in
86 let carrier_typ = TInt(unsigned_ikind_for_carrier nbits, []) in
88 (fun (name, pos, sz, signed) ->
89 Hashtbl.add bitfield_table
91 {bf_carrier = carrier; bf_carrier_typ = carrier_typ;
92 bf_pos = pos; bf_size = sz; bf_signed = signed})
94 { fld_name = carrier; fld_typ = carrier_typ; fld_bitfield = None}
95 :: transf_members env id (count + 1) ml'
98 let transf_composite env su id ml =
100 | Struct -> transf_members env id 1 ml
103 (* Bitfield manipulation expressions *)
105 let left_shift_count bf =
107 (Int64.of_int (8 * !config.sizeof_int - (bf.bf_pos + bf.bf_size)))
110 let right_shift_count bf =
112 (Int64.of_int (8 * !config.sizeof_int - bf.bf_size))
115 let insertion_mask bf =
118 (Int64.pred (Int64.shift_left 1L bf.bf_size))
120 (* Give the mask an hexadecimal string representation, nicer to read *)
121 {edesc = EConst(CInt(m, IUInt, sprintf "0x%LXU" m)); etyp = TInt(IUInt, [])}
123 (* Extract the value of a bitfield *)
127 unsigned int bitfield_unsigned_extract(unsigned int x, int ofs, int sz)
129 return (x << (BITSIZE_UINT - (ofs + sz))) >> (BITSIZE_UINT - sz);
132 signed int bitfield_signed_extract(unsigned int x, int ofs, int sz)
134 return ((signed int) (x << (BITSIZE_UINT - (ofs + sz))))
135 >> (BITSIZE_UINT - sz);
140 let bitfield_extract bf carrier =
142 {edesc = EBinop(Oshl, carrier, left_shift_count bf, TInt(IUInt, []));
143 etyp = carrier.etyp} in
144 let ty = TInt((if bf.bf_signed then IInt else IUInt), []) in
146 {edesc = ECast(ty, e1); etyp = ty} in
147 {edesc = EBinop(Oshr, e2, right_shift_count bf, e2.etyp);
150 (* Assign a bitfield within a carrier *)
154 unsigned int bitfield_insert(unsigned int x, int ofs, int sz, unsigned int y)
156 unsigned int mask = ((1U << sz) - 1) << ofs;
157 return (x & ~mask) | ((y << ofs) & mask);
162 let bitfield_assign bf carrier newval =
163 let msk = insertion_mask bf in
164 let notmsk = {edesc = EUnop(Onot, msk); etyp = msk.etyp} in
166 {edesc = EBinop(Oshl, newval, intconst (Int64.of_int bf.bf_pos) IUInt,
168 etyp = TInt(IUInt,[])} in
170 {edesc = EBinop(Oand, newval_shifted, msk, TInt(IUInt,[]));
171 etyp = TInt(IUInt,[])}
173 {edesc = EBinop(Oand, carrier, notmsk, TInt(IUInt,[]));
174 etyp = TInt(IUInt,[])} in
175 {edesc = EBinop(Oor, oldval_masked, newval_masked, TInt(IUInt,[]));
176 etyp = TInt(IUInt,[])}
180 let transf_expr env e =
182 let is_bitfield_access ty fieldname =
183 match unroll env ty with
185 (try Some(Hashtbl.find bitfield_table (id, fieldname))
186 with Not_found -> None)
189 let is_bitfield_access_ptr ty fieldname =
190 match unroll env ty with
191 | TPtr(ty', _) -> is_bitfield_access ty' fieldname
200 | EUnop(Odot fieldname, e1) ->
202 begin match is_bitfield_access e1.etyp fieldname with
204 {edesc = EUnop(Odot fieldname, e1'); etyp = e.etyp}
207 {edesc = EUnop(Odot bf.bf_carrier, e1');
208 etyp = bf.bf_carrier_typ}
211 | EUnop(Oarrow fieldname, e1) ->
213 begin match is_bitfield_access_ptr e1.etyp fieldname with
215 {edesc = EUnop(Oarrow fieldname, e1'); etyp = e.etyp}
218 {edesc = EUnop(Oarrow bf.bf_carrier, e1');
219 etyp = bf.bf_carrier_typ}
223 (* Note: simplified expr, so no ++/-- *)
224 {edesc = EUnop(op, texp e1); etyp = e.etyp}
226 | EBinop(Oassign, e1, e2, ty) ->
227 begin match e1.edesc with
228 | EUnop(Odot fieldname, e11) ->
229 let lhs = texp e11 in let rhs = texp e2 in
230 begin match is_bitfield_access e11.etyp fieldname with
232 {edesc = EBinop(Oassign,
233 {edesc = EUnop(Odot fieldname, lhs);
239 {edesc = EUnop(Odot bf.bf_carrier, lhs);
240 etyp = bf.bf_carrier_typ} in
241 {edesc = EBinop(Oassign, carrier,
242 bitfield_assign bf carrier rhs,
246 | EUnop(Oarrow fieldname, e11) ->
247 let lhs = texp e11 in let rhs = texp e2 in
248 begin match is_bitfield_access_ptr e11.etyp fieldname with
250 {edesc = EBinop(Oassign,
251 {edesc = EUnop(Oarrow fieldname, lhs);
257 {edesc = EUnop(Oarrow bf.bf_carrier, lhs);
258 etyp = bf.bf_carrier_typ} in
259 {edesc = EBinop(Oassign, carrier,
260 bitfield_assign bf carrier rhs,
265 {edesc = EBinop(Oassign, texp e1, texp e2, e1.etyp); etyp = e1.etyp}
268 | EBinop(op, e1, e2, ty) ->
269 (* Note: simplified expr assumed, so no assign-op *)
270 {edesc = EBinop(op, texp e1, texp e2, ty); etyp = e.etyp}
271 | EConditional(e1, e2, e3) ->
272 {edesc = EConditional(texp e1, texp e2, texp e3); etyp = e.etyp}
274 {edesc = ECast(ty, texp e1); etyp = e.etyp}
276 {edesc = ECall(texp e1, List.map texp el); etyp = e.etyp}
282 let rec transf_stmt env s =
286 {sdesc = Sdo(transf_expr env e); sloc = s.sloc}
288 {sdesc = Sseq(transf_stmt env s1, transf_stmt env s2); sloc = s.sloc }
290 {sdesc = Sif(transf_expr env e, transf_stmt env s1, transf_stmt env s2);
293 {sdesc = Swhile(transf_expr env e, transf_stmt env s1);
296 {sdesc = Sdowhile(transf_stmt env s1, transf_expr env e);
298 | Sfor(s1, e, s2, s3) ->
299 {sdesc = Sfor(transf_stmt env s1, transf_expr env e, transf_stmt env s2,
305 {sdesc = Sswitch(transf_expr env e, transf_stmt env s1); sloc = s.sloc}
306 | Slabeled(lbl, s) ->
307 {sdesc = Slabeled(lbl, transf_stmt env s); sloc = s.sloc}
310 | Sreturn (Some e) ->
311 {sdesc = Sreturn(Some(transf_expr env e)); sloc = s.sloc}
312 | Sblock _ | Sdecl _ ->
313 assert false (* should not occur in unblocked code *)
317 let transf_fundef env f =
318 { f with fd_body = transf_stmt env f.fd_body }
322 let bitfield_initializer bf i =
325 let m = Int64.pred (Int64.shift_left 1L bf.bf_size) in
327 {edesc = EConst(CInt(m, IUInt, sprintf "0x%LXU" m));
328 etyp = TInt(IUInt, [])} in
330 {edesc = EBinop(Oand, e, e_mask, TInt(IUInt,[]));
331 etyp = TInt(IUInt,[])} in
332 {edesc = EBinop(Oshl, e_and, intconst (Int64.of_int bf.bf_pos) IInt,
334 etyp = TInt(IUInt, [])}
337 let rec pack_bitfield_init id carrier fld_init_list =
338 match fld_init_list with
342 let bf = Hashtbl.find bitfield_table (id, fld.fld_name) in
343 if bf.bf_carrier <> carrier then
346 let (el, rem') = pack_bitfield_init id carrier rem in
347 (bitfield_initializer bf i :: el, rem')
352 let rec or_expr_list = function
356 {edesc = EBinop(Oor, e1, or_expr_list el, TInt(IUInt,[]));
357 etyp = TInt(IUInt,[])}
359 let rec transf_struct_init id fld_init_list =
360 match fld_init_list with
364 let bf = Hashtbl.find bitfield_table (id, fld.fld_name) in
366 pack_bitfield_init id bf.bf_carrier fld_init_list in
367 ({fld_name = bf.bf_carrier; fld_typ = bf.bf_carrier_typ;
368 fld_bitfield = None},
369 Init_single {edesc = ECast(bf.bf_carrier_typ, or_expr_list el);
370 etyp = bf.bf_carrier_typ})
371 :: transf_struct_init id rem'
373 (fld, i) :: transf_struct_init id rem
375 let rec transf_init env i =
377 | Init_single e -> Init_single (transf_expr env e)
378 | Init_array il -> Init_array (List.map (transf_init env) il)
379 | Init_struct(id, fld_init_list) ->
381 List.map (fun (f, i) -> (f, transf_init env i)) fld_init_list in
382 Init_struct(id, transf_struct_init id fld_init_list')
383 | Init_union(id, fld, i) -> Init_union(id, fld, transf_init env i)
385 let transf_decl env (sto, id, ty, init_opt) =
387 match init_opt with None -> None | Some i -> Some(transf_init env i))
393 ~composite:transf_composite
395 ~fundef:transf_fundef