1 (* Based on the prototype --- expect some obsolete definitions to be present *)
12 open Extracted.BitVector
14 (* Integer conversion *)
16 let rec convertIntNat n =
17 if n = 0 then Extracted.Nat.O else Extracted.Nat.S (convertIntNat (n-1))
19 let rec convertInt64Nat n =
20 if n = Int64.zero then Extracted.Nat.O else Extracted.Nat.S (convertInt64Nat (Int64.pred n))
22 let convertBool = function
23 | true -> Extracted.Bool.True
24 | false -> Extracted.Bool.False
26 let rec convertIntBV len n =
29 | _ -> let l = len -1 in VCons (convertIntNat l, convertBool (Int64.logand n (Int64.shift_left Int64.one l) <> Int64.zero), convertIntBV l n)
32 convertIntBV (match sz with I8 -> 8 | I16 -> 16 | I32 -> 32) n
34 (** Extract the type part of a type-annotated Clight expression. *)
36 let typeof e = match e with Expr(_,te) -> te
38 (** Natural alignment of a type, in bytes. *)
39 let rec alignof = function
47 | Tarray (t',n) -> alignof t'
48 | Tfunction (_,_) -> 1
49 | Tstruct (_,fld) -> alignof_fields fld
50 | Tunion (_,fld) -> alignof_fields fld
52 and alignof_fields = function
54 | Fcons (id,t, f') -> max (alignof t) (alignof_fields f')
56 (** Size of a type, in bytes. *)
59 ((n + amount - 1) / amount) * amount
64 | Extracted.Nat.O -> i
65 | Extracted.Nat.S m -> aux m (i+1)
77 | Tarray (t',n) -> sizeof t' * max 1 (int_of_nat n)
78 | Tfunction (_,_) -> 1
79 | Tstruct (_,fld) -> align (max 1 (sizeof_struct fld 0)) (alignof t)
80 | Tunion (_,fld) -> align (max 1 (sizeof_union fld)) (alignof t)
82 and sizeof_struct fld pos =
85 | Fcons (id,t, fld') -> sizeof_struct fld' (align pos (alignof t) + sizeof t)
86 and sizeof_union = function
88 | Fcons (id,t, fld') -> max (sizeof t) (sizeof_union fld')
90 (** Record the declarations of global variables and associate them
91 with the corresponding atom. *)
93 let decl_atom : (ident, Env.t * C.decl) Hashtbl.t = Hashtbl.create 103
95 (** Hooks -- overriden in machine-dependent CPragmas module *)
97 let process_pragma_hook = ref (fun (s: string) -> false)
98 let define_variable_hook = ref (fun (id: ident) (d: C.decl) -> ())
99 let define_function_hook = ref (fun (id: ident) (d: C.decl) -> ())
100 let define_stringlit_hook = ref (fun (id: ident) -> ())
102 (** ** Error handling *)
104 let currentLocation = ref Cutil.no_loc
106 let updateLoc l = currentLocation := l
108 let numErrors = ref 0
112 eprintf "%aError: %s\n" Cutil.printloc !currentLocation msg
114 let unsupported msg =
116 eprintf "%aUnsupported feature: %s\n" Cutil.printloc !currentLocation msg
119 eprintf "%aWarning: %s\n" Cutil.printloc !currentLocation msg
121 (** ** Identifier creation *)
123 (* Rather than use the Matita name generators which have to be threaded
124 throughout definitions, we'll use an imperative generator here. *)
126 let idGenerator = ref (Extracted.Identifiers.new_universe Extracted.PreIdentifiers.SymbolTag)
127 let idTable = Hashtbl.create 47
128 let symTable = Hashtbl.create 47
131 Hashtbl.find idTable s
133 let { Extracted.Types.fst = id; Extracted.Types.snd = g} = Extracted.Identifiers.fresh Extracted.PreIdentifiers.SymbolTag !idGenerator in
135 Hashtbl.add idTable s id;
136 Hashtbl.add symTable id s;
139 (** ** Functions used to handle string literals *)
141 let stringNum = ref 0 (* number of next global for string literals *)
142 let stringTable = Hashtbl.create 47
144 let name_for_string_literal env s =
146 Hashtbl.find stringTable s
149 let name = Printf.sprintf "__stringlit_%d" !stringNum in
150 let id = make_id name in
151 Hashtbl.add decl_atom id
152 (env, (C.Storage_static,
153 Env.fresh_ident name,
154 C.TPtr(C.TInt(C.IChar,[C.AConst]),[]),
156 !define_stringlit_hook id;
157 Hashtbl.add stringTable s id;
160 let typeStringLiteral s =
161 Tarray(Tint(I8, Unsigned), convertIntNat (String.length s + 1))
163 let global_for_string s id =
167 Init_int8(convertInt I8 (Int64.of_int (Char.code c)))
170 for i = String.length s - 1 downto 0 do add_char s.[i] done;
171 ((id, !init), typeStringLiteral s)
173 let globals_for_strings globs =
175 (fun s id l -> global_for_string s id :: l)
178 (** ** Handling of stubs for variadic functions *)
180 let stub_function_table = Hashtbl.create 47
182 let register_stub_function name tres targs =
183 let rec letters_of_type = function
185 (*| Tfloat(_)::tl -> "f" :: letters_of_type tl*)
186 | Tcons (_, tl) -> "i" :: letters_of_type tl in
187 let stub_name = make_id
188 (name ^ "$" ^ String.concat "" (letters_of_type targs)) in
190 (stub_name, Hashtbl.find stub_function_table stub_name)
192 let rec types_of_types = function
194 (*| Tfloat(_)::tl -> Tfloat(F64)::(types_of_types tl)*)
195 | Tcons (_,tl) -> Tcons (Tpointer(Tvoid), types_of_types tl) in
196 let stub_type = Tfunction (types_of_types targs, tres) in
197 Hashtbl.add stub_function_table stub_name stub_type;
198 (stub_name, stub_type)
200 let declare_stub_function stub_name stub_type =
202 | Tfunction(targs, tres) ->
204 CL_External(stub_name, targs, tres))
207 let declare_stub_functions k =
209 (fun n i k -> declare_stub_function n i :: k)
210 stub_function_table k
212 (** ** Translation functions *)
220 let convertIkind = function
221 | C.IBool -> unsupported "'_Bool' type"; (Unsigned, I8)
222 | C.IChar -> (Unsigned, I8)
223 | C.ISChar -> (Signed, I8)
224 | C.IUChar -> (Unsigned, I8)
225 | C.IInt -> (Signed, I32)
226 | C.IUInt -> (Unsigned, I32)
227 | C.IShort -> (Signed, I16)
228 | C.IUShort -> (Unsigned, I16)
229 | C.ILong -> (Signed, I32)
230 | C.IULong -> (Unsigned, I32)
232 (*if not !ClightFlags.option_flonglong then*) unsupported "'long long' type";
235 (*if not !ClightFlags.option_flonglong then*) unsupported "'unsigned long long' type";
239 let convertFkind = function
243 if not !ClightFlags.option_flonglong then unsupported "'long double' type";
247 let convertTyp env t =
249 let rec convertTyp seen t =
250 match Cutil.unroll env t with
253 let (sg, sz) = convertIkind ik in Tint(sz, sg)
254 | C.TFloat(fk, a) -> unsupported "float type"; Tvoid
255 (*Tfloat(convertFkind fk)*)
256 | C.TPtr(C.TStruct(id, _), _) when List.mem id seen ->
257 Tcomp_ptr(make_id ("struct " ^ id.name))
258 | C.TPtr(C.TUnion(id, _), _) when List.mem id seen ->
259 Tcomp_ptr(make_id ("union " ^ id.name))
261 Tpointer(convertTyp seen ty)
262 | C.TArray(ty, None, a) ->
263 (* Cparser verified that the type ty[] occurs only in
264 contexts that are safe for Clight, so just treat as ty[0]. *)
265 (* warning "array type of unspecified size"; *)
266 Tarray(convertTyp seen ty, Extracted.Nat.O)
267 | C.TArray(ty, Some sz, a) ->
268 Tarray(convertTyp seen ty, convertInt64Nat sz )
269 | C.TFun(tres, targs, va, a) ->
270 if va then unsupported "variadic function type";
271 if Cutil.is_composite_type env tres then
272 unsupported "return type is a struct or union";
273 Tfunction(begin match targs with
274 | None -> warning "un-prototyped function type"; Tnil
275 | Some tl -> convertParams seen tl
277 convertTyp seen tres)
280 | C.TStruct(id, a) ->
283 convertFields (id :: seen) (Env.find_struct env id)
285 error (Env.error_message e); Fnil in
286 Tstruct(make_id ("struct " ^ id.name), flds)
290 convertFields (id :: seen) (Env.find_union env id)
292 error (Env.error_message e); Fnil in
293 Tunion(make_id ("union " ^ id.name), flds)
295 and convertParams seen = function
298 if Cutil.is_composite_type env ty then
299 unsupported "function parameter of struct or union type";
300 Tcons (convertTyp seen ty, convertParams seen rem)
302 and convertFields seen ci =
303 convertFieldList seen ci.Env.ci_members
305 and convertFieldList seen = function
308 if f.fld_bitfield <> None then
309 unsupported "bit field in struct or union";
310 Fcons (make_id f.fld_name, convertTyp seen f.fld_typ,
311 convertFieldList seen fl)
315 let rec convertTypList env = function
317 | t1 :: tl -> Tcons (convertTyp env t1, convertTypList env tl)
321 let ezero = Expr(Econst_int(I32, zero (convertIntNat 32)), Tint(I32, Signed))
323 let is_pointer = function
327 let rec convertExpr env e =
328 let ty = convertTyp env e.etyp in
330 | C.EConst(C.CInt(i, _, _)) when i = Int64.zero && is_pointer ty ->
331 Expr(Ecast (ty, Expr (Econst_int (I8,zero (convertIntNat 8)), Tint (I8, Unsigned))), ty)
332 | C.EConst(C.CInt(i, k, _)) ->
333 let (_,sz) = convertIkind k in
334 Expr(Econst_int(sz, convertInt sz i), ty)
335 | C.EConst(C.CFloat(f, _, _)) -> unsupported "float constant"; ezero
336 (*Expr(Econst_float f, ty)*)
337 | C.EConst(C.CStr s) ->
338 Expr(Evar(name_for_string_literal env s), typeStringLiteral s)
339 | C.EConst(C.CWStr s) ->
340 unsupported "wide string literal"; ezero
341 | C.EConst(C.CEnum(id, i)) ->
342 let sz = match ty with Tint (sz, _) -> sz | _ -> I32 in
343 Expr(Econst_int(sz, convertInt sz i), ty)
346 Expr(Esizeof(convertTyp env ty1), ty)
348 Expr(Evar(make_id id.name), ty)
350 | C.EUnop(C.Oderef, e1) ->
351 Expr(Ederef(convertExpr env e1), ty)
352 | C.EUnop(C.Oaddrof, e1) ->
353 Expr(Eaddrof(convertExpr env e1), ty)
354 | C.EUnop(C.Odot id, e1) ->
355 Expr(Efield(convertExpr env e1, make_id id), ty)
356 | C.EUnop(C.Oarrow id, e1) ->
357 let e1' = convertExpr env e1 in
359 match typeof e1' with
361 | _ -> error ("wrong type for ->" ^ id ^ " access"); Tvoid in
362 Expr(Efield(Expr(Ederef(convertExpr env e1), ty1),
364 | C.EUnop(C.Oplus, e1) ->
366 | C.EUnop(C.Ominus, e1) ->
367 Expr(Eunop(Oneg, convertExpr env e1), ty)
368 | C.EUnop(C.Olognot, e1) ->
369 Expr(Eunop(Onotbool, convertExpr env e1), ty)
370 | C.EUnop(C.Onot, e1) ->
371 Expr(Eunop(Onotint, convertExpr env e1), ty)
373 unsupported "pre/post increment/decrement operator"; ezero
375 | C.EBinop(C.Oindex, e1, e2, _) ->
376 Expr(Ederef(Expr(Ebinop(Oadd, convertExpr env e1, convertExpr env e2),
378 | C.EBinop(C.Ologand, e1, e2, _) ->
379 Expr(Eandbool(convertExpr env e1, convertExpr env e2), ty)
380 | C.EBinop(C.Ologor, e1, e2, _) ->
381 Expr(Eorbool(convertExpr env e1, convertExpr env e2), ty)
382 | C.EBinop(op, e1, e2, _) ->
401 | C.Ocomma -> unsupported "sequence operator"; Oadd
402 | _ -> unsupported "assignment operator"; Oadd in
403 Expr(Ebinop(op', convertExpr env e1, convertExpr env e2), ty)
404 | C.EConditional(e1, e2, e3) ->
405 Expr(Econdition(convertExpr env e1, convertExpr env e2, convertExpr env e3), ty)
406 | C.ECast(ty1, e1) ->
407 Expr(Ecast(convertTyp env ty1, convertExpr env e1), ty)
409 unsupported "function call within expression"; ezero
413 let rec projFunType env ty =
414 match Cutil.unroll env ty with
415 | TFun(res, args, vararg, attr) -> Some(res, vararg)
416 | TPtr(ty', attr) -> projFunType env ty'
419 let rec convertList l =
421 | [] -> Extracted.List.Nil
422 | h::t -> Extracted.List.Cons (h,convertList t)
424 let convertFuncall env lhs fn args =
425 match projFunType env fn.etyp with
427 error "wrong type for function part of a call"; Sskip
428 | Some(res, false) ->
429 (* Non-variadic function *)
430 Scall(lhs, convertExpr env fn, convertList (List.map (convertExpr env) args))
432 (* Variadic function: generate a call to a stub function with
433 the appropriate number and types of arguments. Works only if
434 the function expression e is a global variable. *)
437 | {edesc = C.EVar id} when false (* FIXME? !ClightFlags.option_fvararg_calls *)->
438 (*warning "emulating call to variadic function"; *)
441 unsupported "call to variadic function";
443 let targs = convertTypList env (List.map (fun e -> e.etyp) args) in
444 let tres = convertTyp env res in
445 let (stub_fun_name, stub_fun_typ) =
446 register_stub_function fun_name tres targs in
448 Expr(Evar(stub_fun_name), stub_fun_typ),
449 convertList (List.map (convertExpr env) args))
451 (* Handling of volatile *)
453 let is_volatile_access env e =
454 List.mem C.AVolatile (Cutil.attributes_of_type env e.etyp)
455 && Cutil.is_lvalue env e
457 let volatile_fun_suffix_type ty =
459 | Tint(I8, Unsigned) -> ("int8unsigned", ty)
460 | Tint(I8, Signed) -> ("int8signed", ty)
461 | Tint(I16, Unsigned) -> ("int16unsigned", ty)
462 | Tint(I16, Signed) -> ("int16signed", ty)
463 | Tint(I32, _) -> ("int32", Tint(I32, Signed))
464 (*| Tfloat F32 -> ("float32", ty)
465 | Tfloat F64 -> ("float64", ty)*)
466 | Tpointer _ | Tarray _ | Tfunction _ | Tcomp_ptr _ ->
467 ("pointer", Tpointer Tvoid)
469 unsupported "operation on volatile struct or union"; ("", Tvoid)
471 let volatile_read_fun ty =
472 let (suffix, ty') = volatile_fun_suffix_type ty in
473 Expr(Evar(make_id ("__builtin_volatile_read_" ^ suffix)),
474 Tfunction(Tcons (Tpointer Tvoid, Tnil), ty'))
476 let volatile_write_fun ty =
477 let (suffix, ty') = volatile_fun_suffix_type ty in
478 Expr(Evar(make_id ("__builtin_volatile_write_" ^ suffix)),
479 Tfunction(Tcons (Tpointer Tvoid, Tcons (ty', Tnil)), Tvoid))
481 (* Toplevel expression, argument of an Sdo *)
483 let convertTopExpr env e =
485 | C.EBinop(C.Oassign, lhs, {edesc = C.ECall(fn, args)}, _) ->
486 convertFuncall env (Extracted.Types.Some (convertExpr env lhs)) fn args
487 | C.EBinop(C.Oassign, lhs, rhs, _) ->
488 if Cutil.is_composite_type env lhs.etyp then
489 unsupported "assignment between structs or between unions";
490 let lhs' = convertExpr env lhs
491 and rhs' = convertExpr env rhs in
492 begin match (is_volatile_access env lhs, is_volatile_access env rhs) with
493 | true, true -> (* should not happen *)
494 unsupported "volatile-to-volatile assignment";
496 | false, true -> (* volatile read *)
497 Scall(Extracted.Types.Some lhs',
498 volatile_read_fun (typeof rhs'),
499 convertList [ Expr (Eaddrof rhs', Tpointer (typeof rhs')) ])
500 | true, false -> (* volatile write *)
501 Scall(Extracted.Types.None,
502 volatile_write_fun (typeof lhs'),
503 convertList [ Expr(Eaddrof lhs', Tpointer (typeof lhs')); rhs' ])
504 | false, false -> (* regular assignment *)
505 Sassign(convertExpr env lhs, convertExpr env rhs)
507 | C.ECall(fn, args) ->
508 convertFuncall env Extracted.Types.None fn args
510 unsupported "illegal toplevel expression"; Sskip
512 (* Separate the cases of a switch statement body *)
519 | Label of switchlabel
522 let rec flattenSwitch = function
523 | {sdesc = C.Sseq(s1, s2)} ->
524 flattenSwitch s1 @ flattenSwitch s2
525 | {sdesc = C.Slabeled(C.Scase e, s1)} ->
526 Label(Case e) :: flattenSwitch s1
527 | {sdesc = C.Slabeled(C.Sdefault, s1)} ->
528 Label Default :: flattenSwitch s1
532 let rec groupSwitch = function
535 | Label case :: rem ->
536 let (fst, cases) = groupSwitch rem in
537 (Cutil.sskip, (case, fst) :: cases)
539 let (fst, cases) = groupSwitch rem in
540 (Cutil.sseq s.sloc s fst, cases)
544 let rec convertStmt env s =
552 Ssequence(convertStmt env s1, convertStmt env s2)
553 | C.Sif(e, s1, s2) ->
554 Sifthenelse(convertExpr env e, convertStmt env s1, convertStmt env s2)
556 Swhile(convertExpr env e, convertStmt env s1)
557 | C.Sdowhile(s1, e) ->
558 Sdowhile(convertExpr env e, convertStmt env s1)
559 | C.Sfor(s1, e, s2, s3) ->
560 Sfor(convertStmt env s1, convertExpr env e, convertStmt env s2,
566 | C.Sswitch(e, s1) ->
567 let (init, cases) = groupSwitch (flattenSwitch s1) in
569 unsupported "ill-formed 'switch' statement";
570 if init.sdesc <> C.Sskip then
571 warning "ignored code at beginning of 'switch'";
572 let e' = convertExpr env e in
573 let sz = match typeof e' with Tint(sz,_) -> sz | _ -> I32 in
574 Sswitch(e', convertSwitch env sz cases)
575 | C.Slabeled(C.Slabel lbl, s1) ->
576 Slabel(make_id lbl, convertStmt env s1)
577 | C.Slabeled(C.Scase _, _) ->
578 unsupported "'case' outside of 'switch'"; Sskip
579 | C.Slabeled(C.Sdefault, _) ->
580 unsupported "'default' outside of 'switch'"; Sskip
584 Sreturn Extracted.Types.None
585 | C.Sreturn(Some e) ->
586 Sreturn(Extracted.Types.Some(convertExpr env e))
588 unsupported "nested blocks"; Sskip
590 unsupported "inner declarations"; Sskip
592 and convertSwitch env sz = function
596 LSdefault (convertStmt env s)
597 | (Default, s) :: _ ->
599 unsupported "'default' case must occur last";
601 | (Case e, s) :: rem ->
604 match Ceval.integer_expr env e with
605 | None -> unsupported "'case' label is not a compile-time integer"; 0L
610 convertSwitch env sz rem)
612 (** Function definitions *)
614 let convertProd (x,y) = {Extracted.Types.fst = x; Extracted.Types.snd = y}
616 let convertFundef env fd =
617 if Cutil.is_composite_type env fd.fd_ret then
618 unsupported "function returning a struct or union";
620 convertTyp env fd.fd_ret in
624 if Cutil.is_composite_type env ty then
625 unsupported "function parameter of struct or union type";
626 convertProd (make_id id.name, convertTyp env ty))
630 (fun (sto, id, ty, init) ->
631 if sto = Storage_extern || sto = Storage_static then
632 unsupported "'static' or 'extern' local variable";
634 unsupported "initialized local variable";
635 convertProd (make_id id.name, convertTyp env ty))
637 let body' = convertStmt env fd.fd_body in
638 let id' = make_id fd.fd_name.name in
640 (fd.fd_storage, fd.fd_name, Cutil.fundef_typ fd, None) in
641 Hashtbl.add decl_atom id' (env, decl);
642 !define_function_hook id' decl;
644 CL_Internal {fn_return = ret; fn_params = convertList params;
645 fn_vars = convertList vars; fn_body = body'})
647 (** External function declaration *)
649 let convertFundecl env (sto, id, ty, optinit) =
650 match convertTyp env ty with
651 | Tfunction(args, res) ->
652 let id' = make_id id.name in
653 (id', CL_External(id', args, res))
659 let init_data_of_string s =
662 let n = convertInt I8 (Int64.of_int (Char.code c)) in
663 id := Init_int8 n :: !id in
665 for i = String.length s - 1 downto 0 do enter_char s.[i] done;
668 let convertInit env ty init =
672 let emit size datum =
674 pos := !pos + size in
675 let emit_space size =
676 emit size (Init_space (convertIntNat size)) in
678 let n = !pos land (size - 1) in
679 if n > 0 then emit_space (size - n) in
680 let check_align size =
681 assert (!pos land (size - 1) = 0) in
683 let rec reduceInitExpr = function
684 | { edesc = C.EVar id; etyp = ty } ->
685 begin match Cutil.unroll env ty with
686 | C.TArray _ | C.TFun _ -> Some id
689 | {edesc = C.EUnop(C.Oaddrof, {edesc = C.EVar id})} -> Some id
690 | {edesc = C.ECast(ty, e)} -> reduceInitExpr e
693 let rec cvtInit ty = function
695 begin match reduceInitExpr e with
698 emit 4 (Init_addrof(make_id id.name, convertIntNat 0))
700 match Ceval.constant_expr env ty e with
701 | Some(C.CInt(v, ik, _)) ->
704 (* The only integer constant that is a pointer is zero *)
707 begin match convertIkind ik with
709 emit 1 (Init_int8(convertInt I8 v))
712 emit 2 (Init_int16(convertInt I16 v))
715 emit 4 (Init_int32(convertInt I32 v))
718 | Some(C.CFloat(v, fk, _)) ->
720 (*begin match convertFkind fk with
723 emit 4 (Init_float32 v)
726 emit 8 (Init_float64 v)
730 let id = name_for_string_literal env s in
731 emit 4 (Init_addrof(id, convertIntNat 0))
733 unsupported "wide character strings"
735 error "enum tag after constant folding"
737 error "initializer is not a compile-time constant"
741 match Cutil.unroll env ty with
742 | C.TArray(t, _, _) -> t
743 | _ -> error "array type expected in initializer"; C.TVoid [] in
744 List.iter (cvtInit ty_elt) il
745 | Init_struct(_, flds) ->
746 cvtPadToSizeof ty (fun () -> List.iter cvtFieldInit flds)
747 | Init_union(_, fld, i) ->
748 cvtPadToSizeof ty (fun () -> cvtFieldInit (fld,i))
750 and cvtFieldInit (fld, i) =
751 let ty' = convertTyp env fld.fld_typ in
752 let al = alignof ty' in
754 cvtInit fld.fld_typ i
756 and cvtPadToSizeof ty fn =
757 let ty' = convertTyp env ty in
758 let sz = sizeof ty' in
762 assert (pos1 <= pos0 + sz);
763 if pos1 < pos0 + sz then emit_space (pos0 + sz - pos1)
765 in cvtInit ty init; List.rev !k
767 (** Global variable *)
769 let convertGlobvar env (sto, id, ty, optinit as decl) =
770 let id' = make_id id.name in
771 let ty' = convertTyp env ty in
775 if sto = C.Storage_extern then [] else [Init_space(convertIntNat (sizeof ty'))]
777 convertInit env ty i in
778 Hashtbl.add decl_atom id' (env, decl);
779 !define_variable_hook id' decl;
782 (** Convert a list of global declarations.
783 Result is a pair [(funs, vars)] where [funs] are
784 the function definitions (internal and external)
785 and [vars] the variable declarations. *)
787 let rec convertGlobdecls env funs vars gl =
789 | [] -> (List.rev funs, List.rev vars)
793 | C.Gdecl((sto, id, ty, optinit) as d) ->
794 (* Prototyped functions become external declarations.
795 Variadic functions are skipped.
796 Other types become variable declarations. *)
797 begin match Cutil.unroll env ty with
798 | TFun(_, Some _, false, _) ->
799 convertGlobdecls env (convertFundecl env d :: funs) vars gl'
800 | TFun(_, None, false, _) ->
801 error "function declaration without prototype";
802 convertGlobdecls env funs vars gl'
803 | TFun(_, _, true, _) ->
804 convertGlobdecls env funs vars gl'
806 convertGlobdecls env funs (convertGlobvar env d :: vars) gl'
809 convertGlobdecls env (convertFundef env fd :: funs) vars gl'
810 | C.Gcompositedecl _ | C.Gcompositedef _
811 | C.Gtypedef _ | C.Genumdef _ ->
812 (* typedefs are unrolled, structs are expanded inline, and
813 enum tags are folded. So we just skip their declarations. *)
814 convertGlobdecls env funs vars gl'
816 if not (!process_pragma_hook s) then
817 warning ("'#pragma " ^ s ^ "' directive ignored");
818 convertGlobdecls env funs vars gl'
820 (** Build environment of typedefs and structs *)
822 let rec translEnv env = function
827 | C.Gcompositedecl(su, id) ->
828 Env.add_composite env id (Cutil.composite_info_decl env su)
829 | C.Gcompositedef(su, id, fld) ->
830 Env.add_composite env id (Cutil.composite_info_def env su fld)
831 | C.Gtypedef(id, ty) ->
832 Env.add_typedef env id ty
837 (** Eliminate forward declarations of globals that are defined later. *)
839 module IdentSet = Set.Make(struct type t = C.ident let compare = compare end)
841 let cleanupGlobals p =
843 let rec clean defs accu = function
848 | C.Gdecl(sto, id, ty, None) ->
849 if IdentSet.mem id defs
850 then clean defs accu gl
851 else clean (IdentSet.add id defs) (g :: accu) gl
852 | C.Gdecl(_, id, ty, _) ->
853 if IdentSet.mem id defs then
854 error ("multiple definitions of " ^ id.name);
855 clean (IdentSet.add id defs) (g :: accu) gl
857 if IdentSet.mem fd.fd_name defs then
858 error ("multiple definitions of " ^ fd.fd_name.name);
859 clean (IdentSet.add fd.fd_name defs) (g :: accu) gl
861 clean defs (g :: accu) gl
863 in clean IdentSet.empty [] (List.rev p)
865 (** Convert a [C.program] into a [Csyntax.program] *)
867 let convertCLVar ((x,y),z) =
868 {Extracted.Types.fst = {Extracted.Types.fst = x; Extracted.Types.snd = XData};
869 Extracted.Types.snd = {Extracted.Types.fst = convertList y; Extracted.Types.snd = z}}
871 let convertProgram (p:C.program) : clight_program option =
873 idGenerator := Extracted.Identifiers.new_universe Extracted.PreIdentifiers.SymbolTag;
875 Hashtbl.clear decl_atom;
876 Hashtbl.clear idTable;
877 Hashtbl.clear stringTable;
878 Hashtbl.clear stub_function_table;
879 (* Hack: externals are problematic for Cerco. TODO *)
880 let p = (* Builtins.declarations() @ *) p in
883 convertGlobdecls (translEnv Env.empty p) [] [] (cleanupGlobals p) in
884 let funs2 = declare_stub_functions funs1 in
885 let main = make_id "main" in
886 let vars2 = globals_for_strings vars1 in
889 else Some { prog_funct = convertList (List.map convertProd funs2);
890 prog_vars = convertList (List.map convertCLVar vars2);
892 with Env.Error msg ->
893 error (Env.error_message msg); None
895 (** ** Extracting information about global variables from their atom *)
897 let rec type_is_readonly env t =
898 let a = Cutil.attributes_of_type env t in
899 if List.mem C.AVolatile a then false else
900 if List.mem C.AConst a then true else
901 match Cutil.unroll env t with
902 | C.TArray(t', _, _) -> type_is_readonly env t'
905 let atom_is_static a =
907 let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
908 sto = C.Storage_static
912 let atom_is_readonly a =
914 let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
915 type_is_readonly env ty
921 let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
928 let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
933 (** ** The builtin environment *)
937 let builtins_generic = {
939 (* keeps GCC-specific headers happy, harmless for others *)
940 "__builtin_va_list", C.TPtr(C.TVoid [], [])
943 (* The volatile read/volatile write functions *)
944 "__builtin_volatile_read_int8unsigned",
945 (TInt(IUChar, []), [TPtr(TVoid [], [])], false);
946 "__builtin_volatile_read_int8signed",
947 (TInt(ISChar, []), [TPtr(TVoid [], [])], false);
948 "__builtin_volatile_read_int16unsigned",
949 (TInt(IUShort, []), [TPtr(TVoid [], [])], false);
950 "__builtin_volatile_read_int16signed",
951 (TInt(IShort, []), [TPtr(TVoid [], [])], false);
952 "__builtin_volatile_read_int32",
953 (TInt(IInt, []), [TPtr(TVoid [], [])], false);
954 "__builtin_volatile_read_float32",
955 (TFloat(FFloat, []), [TPtr(TVoid [], [])], false);
956 "__builtin_volatile_read_float64",
957 (TFloat(FDouble, []), [TPtr(TVoid [], [])], false);
958 "__builtin_volatile_read_pointer",
959 (TPtr(TVoid [], []), [TPtr(TVoid [], [])], false);
960 "__builtin_volatile_write_int8unsigned",
961 (TVoid [], [TPtr(TVoid [], []); TInt(IUChar, [])], false);
962 "__builtin_volatile_write_int8signed",
963 (TVoid [], [TPtr(TVoid [], []); TInt(ISChar, [])], false);
964 "__builtin_volatile_write_int16unsigned",
965 (TVoid [], [TPtr(TVoid [], []); TInt(IUShort, [])], false);
966 "__builtin_volatile_write_int16signed",
967 (TVoid [], [TPtr(TVoid [], []); TInt(IShort, [])], false);
968 "__builtin_volatile_write_int32",
969 (TVoid [], [TPtr(TVoid [], []); TInt(IInt, [])], false);
970 "__builtin_volatile_write_float32",
971 (TVoid [], [TPtr(TVoid [], []); TFloat(FFloat, [])], false);
972 "__builtin_volatile_write_float64",
973 (TVoid [], [TPtr(TVoid [], []); TFloat(FDouble, [])], false);
974 "__builtin_volatile_write_pointer",
975 (TVoid [], [TPtr(TVoid [], []); TPtr(TVoid [], [])], false)
979 (* Add processor-dependent builtins *)
982 { typedefs = builtins_generic.typedefs @ CBuiltins.builtins.typedefs;
983 functions = builtins_generic.functions @ CBuiltins.builtins.functions