aboutsummaryrefslogtreecommitdiffstats
path: root/cfrontend/C2Clight.ml
diff options
context:
space:
mode:
authorxleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-08-18 09:10:05 +0000
committerxleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-08-18 09:10:05 +0000
commit790c187f338303d3b9a47cd3e08ba34d8cc75191 (patch)
treeb20182164c17198eecaf5b4a9be93ebb340a9553 /cfrontend/C2Clight.ml
parenta15858a0a8fcea82db02fe8c9bd2ed912210419f (diff)
downloadcompcert-790c187f338303d3b9a47cd3e08ba34d8cc75191.tar.gz
compcert-790c187f338303d3b9a47cd3e08ba34d8cc75191.zip
Renamed C2Clight into C2C
git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1468 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
Diffstat (limited to 'cfrontend/C2Clight.ml')
-rw-r--r--cfrontend/C2Clight.ml922
1 files changed, 0 insertions, 922 deletions
diff --git a/cfrontend/C2Clight.ml b/cfrontend/C2Clight.ml
deleted file mode 100644
index f62099a4..00000000
--- a/cfrontend/C2Clight.ml
+++ /dev/null
@@ -1,922 +0,0 @@
-open Printf
-
-open Cparser
-open Cparser.C
-open Cparser.Env
-open Cparser.Builtins
-
-open Camlcoq
-open AST
-open Values
-open Csyntax
-
-(** Record the declarations of global variables and associate them
- with the corresponding atom. *)
-
-let decl_atom : (AST.ident, Env.t * C.decl) Hashtbl.t = Hashtbl.create 103
-
-(** Hooks -- overriden in machine-dependent CPragmas module *)
-
-let process_pragma_hook = ref (fun (s: string) -> false)
-
-(** ** Error handling *)
-
-let currentLocation = ref Cutil.no_loc
-
-let updateLoc l = currentLocation := l
-
-let numErrors = ref 0
-
-let error msg =
- incr numErrors;
- eprintf "%aError: %s\n" Cutil.printloc !currentLocation msg
-
-let unsupported msg =
- incr numErrors;
- eprintf "%aUnsupported feature: %s\n" Cutil.printloc !currentLocation msg
-
-let warning msg =
- eprintf "%aWarning: %s\n" Cutil.printloc !currentLocation msg
-
-
-(** ** The builtin environment *)
-
-let builtins_generic = {
- typedefs = [
- (* keeps GCC-specific headers happy, harmless for others *)
- "__builtin_va_list", C.TPtr(C.TVoid [], [])
- ];
- functions = [
- (* Floating-point absolute value *)
- "__builtin_fabs",
- (TFloat(FDouble, []), [TFloat(FDouble, [])], false);
- (* The volatile read/volatile write functions *)
- "__builtin_volatile_read_int8unsigned",
- (TInt(IUChar, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_int8signed",
- (TInt(ISChar, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_int16unsigned",
- (TInt(IUShort, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_int16signed",
- (TInt(IShort, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_int32",
- (TInt(IInt, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_float32",
- (TFloat(FFloat, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_float64",
- (TFloat(FDouble, []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_read_pointer",
- (TPtr(TVoid [], []), [TPtr(TVoid [], [])], false);
- "__builtin_volatile_write_int8unsigned",
- (TVoid [], [TPtr(TVoid [], []); TInt(IUChar, [])], false);
- "__builtin_volatile_write_int8signed",
- (TVoid [], [TPtr(TVoid [], []); TInt(ISChar, [])], false);
- "__builtin_volatile_write_int16unsigned",
- (TVoid [], [TPtr(TVoid [], []); TInt(IUShort, [])], false);
- "__builtin_volatile_write_int16signed",
- (TVoid [], [TPtr(TVoid [], []); TInt(IShort, [])], false);
- "__builtin_volatile_write_int32",
- (TVoid [], [TPtr(TVoid [], []); TInt(IInt, [])], false);
- "__builtin_volatile_write_float32",
- (TVoid [], [TPtr(TVoid [], []); TFloat(FFloat, [])], false);
- "__builtin_volatile_write_float64",
- (TVoid [], [TPtr(TVoid [], []); TFloat(FDouble, [])], false);
- "__builtin_volatile_write_pointer",
- (TVoid [], [TPtr(TVoid [], []); TPtr(TVoid [], [])], false);
- (* Block copy *)
- "__builtin_memcpy",
- (TVoid [],
- [TPtr(TVoid [], []);
- TPtr(TVoid [AConst], []);
- TInt(Cutil.size_t_ikind, [])],
- false);
- "__builtin_memcpy_words",
- (TVoid [],
- [TPtr(TVoid [], []);
- TPtr(TVoid [AConst], []);
- TInt(Cutil.size_t_ikind, [])],
- false)
- ]
-}
-
-(* Add processor-dependent builtins *)
-
-let builtins =
- { typedefs = builtins_generic.typedefs @ CBuiltins.builtins.typedefs;
- functions = builtins_generic.functions @ CBuiltins.builtins.functions }
-
-(** ** Functions used to handle string literals *)
-
-let stringNum = ref 0 (* number of next global for string literals *)
-let stringTable = Hashtbl.create 47
-
-let name_for_string_literal env s =
- try
- Hashtbl.find stringTable s
- with Not_found ->
- incr stringNum;
- let name = Printf.sprintf "__stringlit_%d" !stringNum in
- let id = intern_string name in
- Hashtbl.add decl_atom id
- (env, (C.Storage_static,
- Env.fresh_ident name,
- C.TPtr(C.TInt(C.IChar,[C.AConst]),[]),
- None));
- Sections.define_stringlit id;
- Hashtbl.add stringTable s id;
- id
-
-let typeStringLiteral s =
- Tarray(Tint(I8, Unsigned), z_of_camlint(Int32.of_int(String.length s + 1)))
-
-let global_for_string s id =
- let init = ref [] in
- let add_char c =
- init :=
- AST.Init_int8(coqint_of_camlint(Int32.of_int(Char.code c)))
- :: !init in
- add_char '\000';
- for i = String.length s - 1 downto 0 do add_char s.[i] done;
- Datatypes.Coq_pair(id,
- {gvar_info = typeStringLiteral s; gvar_init = !init;
- gvar_readonly = true; gvar_volatile = false})
-
-let globals_for_strings globs =
- Hashtbl.fold
- (fun s id l -> global_for_string s id :: l)
- stringTable globs
-
-(** ** Handling of stubs for variadic functions *)
-
-let stub_function_table = Hashtbl.create 47
-
-let register_stub_function name tres targs =
- let rec letters_of_type = function
- | Tnil -> []
- | Tcons(Tfloat _, tl) -> "f" :: letters_of_type tl
- | Tcons(_, tl) -> "i" :: letters_of_type tl in
- let stub_name =
- name ^ "$" ^ String.concat "" (letters_of_type targs) in
- try
- (stub_name, Hashtbl.find stub_function_table stub_name)
- with Not_found ->
- let rec types_of_types = function
- | Tnil -> Tnil
- | Tcons(Tfloat _, tl) -> Tcons(Tfloat F64, types_of_types tl)
- | Tcons(_, tl) -> Tcons(Tpointer Tvoid, types_of_types tl) in
- let stub_type = Tfunction (types_of_types targs, tres) in
- Hashtbl.add stub_function_table stub_name stub_type;
- (stub_name, stub_type)
-
-let declare_stub_function stub_name stub_type =
- match stub_type with
- | Tfunction(targs, tres) ->
- Datatypes.Coq_pair(intern_string stub_name,
- External({ ef_id = intern_string stub_name;
- ef_sig = signature_of_type targs tres;
- ef_inline = false },
- targs, tres))
- | _ -> assert false
-
-let declare_stub_functions k =
- Hashtbl.fold (fun n i k -> declare_stub_function n i :: k)
- stub_function_table k
-
-(** ** Translation functions *)
-
-(** Constants *)
-
-let convertInt n = coqint_of_camlint(Int64.to_int32 n)
-
-(** Types *)
-
-let convertIkind = function
- | C.IBool -> unsupported "'_Bool' type"; (Unsigned, I8)
- | C.IChar -> (Unsigned, I8)
- | C.ISChar -> (Signed, I8)
- | C.IUChar -> (Unsigned, I8)
- | C.IInt -> (Signed, I32)
- | C.IUInt -> (Unsigned, I32)
- | C.IShort -> (Signed, I16)
- | C.IUShort -> (Unsigned, I16)
- | C.ILong -> (Signed, I32)
- | C.IULong -> (Unsigned, I32)
- | C.ILongLong ->
- if not !Clflags.option_flonglong then unsupported "'long long' type";
- (Signed, I32)
- | C.IULongLong ->
- if not !Clflags.option_flonglong then unsupported "'unsigned long long' type";
- (Unsigned, I32)
-
-let convertFkind = function
- | C.FFloat -> F32
- | C.FDouble -> F64
- | C.FLongDouble ->
- if not !Clflags.option_flonglong then unsupported "'long double' type";
- F64
-
-let convertTyp env t =
-
- let rec convertTyp seen t =
- match Cutil.unroll env t with
- | C.TVoid a -> Tvoid
- | C.TInt(ik, a) ->
- let (sg, sz) = convertIkind ik in Tint(sz, sg)
- | C.TFloat(fk, a) ->
- Tfloat(convertFkind fk)
- | C.TPtr(C.TStruct(id, _), _) when List.mem id seen ->
- Tcomp_ptr(intern_string ("struct " ^ id.name))
- | C.TPtr(C.TUnion(id, _), _) when List.mem id seen ->
- Tcomp_ptr(intern_string ("union " ^ id.name))
- | C.TPtr(ty, a) ->
- Tpointer(convertTyp seen ty)
- | C.TArray(ty, None, a) ->
- (* Cparser verified that the type ty[] occurs only in
- contexts that are safe for Clight, so just treat as ty[0]. *)
- (* warning "array type of unspecified size"; *)
- Tarray(convertTyp seen ty, coqint_of_camlint 0l)
- | C.TArray(ty, Some sz, a) ->
- Tarray(convertTyp seen ty, convertInt sz)
- | C.TFun(tres, targs, va, a) ->
- if va then unsupported "variadic function type";
- if Cutil.is_composite_type env tres then
- unsupported "return type is a struct or union";
- Tfunction(begin match targs with
- | None -> warning "un-prototyped function type"; Tnil
- | Some tl -> convertParams seen tl
- end,
- convertTyp seen tres)
- | C.TNamed _ ->
- assert false
- | C.TStruct(id, a) ->
- let flds =
- try
- convertFields (id :: seen) (Env.find_struct env id)
- with Env.Error e ->
- error (Env.error_message e); Fnil in
- Tstruct(intern_string("struct " ^ id.name), flds)
- | C.TUnion(id, a) ->
- let flds =
- try
- convertFields (id :: seen) (Env.find_union env id)
- with Env.Error e ->
- error (Env.error_message e); Fnil in
- Tunion(intern_string("union " ^ id.name), flds)
-
- and convertParams seen = function
- | [] -> Tnil
- | (id, ty) :: rem ->
- if Cutil.is_composite_type env ty then
- unsupported "function parameter of struct or union type";
- Tcons(convertTyp seen ty, convertParams seen rem)
-
- and convertFields seen ci =
- convertFieldList seen ci.Env.ci_members
-
- and convertFieldList seen = function
- | [] -> Fnil
- | f :: fl ->
- if f.fld_bitfield <> None then
- unsupported "bit field in struct or union";
- Fcons(intern_string f.fld_name, convertTyp seen f.fld_typ,
- convertFieldList seen fl)
-
- in convertTyp [] t
-
-let rec convertTypList env = function
- | [] -> Tnil
- | t1 :: tl -> Tcons(convertTyp env t1, convertTypList env tl)
-
-let rec projFunType env ty =
- match Cutil.unroll env ty with
- | TFun(res, args, vararg, attr) -> Some(res, vararg)
- | TPtr(ty', attr) -> projFunType env ty'
- | _ -> None
-
-(* Handling of volatile *)
-
-let is_volatile_access env e =
- List.mem C.AVolatile (Cutil.attributes_of_type env e.etyp)
- && Cutil.is_lvalue env e
-
-let volatile_fun_suffix_type ty =
- match ty with
- | Tint(I8, Unsigned) -> ("int8unsigned", ty)
- | Tint(I8, Signed) -> ("int8signed", ty)
- | Tint(I16, Unsigned) -> ("int16unsigned", ty)
- | Tint(I16, Signed) -> ("int16signed", ty)
- | Tint(I32, _) -> ("int32", Tint(I32, Signed))
- | Tfloat F32 -> ("float32", ty)
- | Tfloat F64 -> ("float64", ty)
- | Tpointer _ | Tarray _ | Tfunction _ | Tcomp_ptr _ ->
- ("pointer", Tpointer Tvoid)
- | _ ->
- unsupported "operation on volatile struct or union"; ("", Tvoid)
-
-let volatile_read_fun ty =
- let (suffix, ty') = volatile_fun_suffix_type ty in
- let funty = Tfunction(Tcons(Tpointer Tvoid, Tnil), ty') in
- Evalof(Evar(intern_string ("__builtin_volatile_read_" ^ suffix), funty), funty)
-
-let volatile_write_fun ty =
- let (suffix, ty') = volatile_fun_suffix_type ty in
- let funty = Tfunction(Tcons(Tpointer Tvoid, Tcons(ty', Tnil)), Tvoid) in
- Evalof(Evar(intern_string ("__builtin_volatile_write_" ^ suffix), funty), funty)
-
-(** Expressions *)
-
-let ezero = Eval(Vint(coqint_of_camlint 0l), Tint(I32, Signed))
-
-let rec convertExpr env e =
- let ty = convertTyp env e.etyp in
- match e.edesc with
- | C.EVar _
- | C.EUnop((C.Oderef|C.Odot _|C.Oarrow _), _)
- | C.EBinop(C.Oindex, _, _, _) ->
- let l = convertLvalue env e in
- if is_volatile_access env e then
- Ecall(volatile_read_fun (typeof l),
- Econs(Eaddrof(l, Tpointer(typeof l)), Enil),
- ty)
- else
- Evalof(l, ty)
-
- | C.EConst(C.CInt(i, _, _)) ->
- Eval(Vint(convertInt i), ty)
- | C.EConst(C.CFloat(f, _, _)) ->
- Eval(Vfloat(f), ty)
- | C.EConst(C.CStr s) ->
- let ty = typeStringLiteral s in
- Evalof(Evar(name_for_string_literal env s, ty), ty)
- | C.EConst(C.CWStr s) ->
- unsupported "wide string literal"; ezero
- | C.EConst(C.CEnum(id, i)) ->
- Eval(Vint(convertInt i), ty)
- | C.ESizeof ty1 ->
- Esizeof(convertTyp env ty1, ty)
-
- | C.EUnop(C.Ominus, e1) ->
- Eunop(Oneg, convertExpr env e1, ty)
- | C.EUnop(C.Oplus, e1) ->
- convertExpr env e1
- | C.EUnop(C.Olognot, e1) ->
- Eunop(Onotbool, convertExpr env e1, ty)
- | C.EUnop(C.Onot, e1) ->
- Eunop(Onotint, convertExpr env e1, ty)
- | C.EUnop(C.Oaddrof, e1) ->
- Eaddrof(convertLvalue env e1, ty)
- | C.EUnop(C.Opreincr, e1) ->
- coq_Epreincr Incr (convertLvalue env e1) ty
- | C.EUnop(C.Opredecr, e1) ->
- coq_Epreincr Decr (convertLvalue env e1) ty
- | C.EUnop(C.Opostincr, e1) ->
- Epostincr(Incr, convertLvalue env e1, ty)
- | C.EUnop(C.Opostdecr, e1) ->
- Epostincr(Decr, convertLvalue env e1, ty)
-
- | C.EBinop((C.Oadd|C.Osub|C.Omul|C.Odiv|C.Omod|C.Oand|C.Oor|C.Oxor|
- C.Oshl|C.Oshr|C.Oeq|C.One|C.Olt|C.Ogt|C.Ole|C.Oge) as op,
- e1, e2, _) ->
- let op' =
- match op with
- | C.Oadd -> Oadd
- | C.Osub -> Osub
- | C.Omul -> Omul
- | C.Odiv -> Odiv
- | C.Omod -> Omod
- | C.Oand -> Oand
- | C.Oor -> Oor
- | C.Oxor -> Oxor
- | C.Oshl -> Oshl
- | C.Oshr -> Oshr
- | C.Oeq -> Oeq
- | C.One -> One
- | C.Olt -> Olt
- | C.Ogt -> Ogt
- | C.Ole -> Ole
- | C.Oge -> Oge
- | _ -> assert false in
- Ebinop(op', convertExpr env e1, convertExpr env e2, ty)
- | C.EBinop(C.Oassign, e1, e2, _) ->
- let e1' = convertLvalue env e1 in
- let e2' = convertExpr env e2 in
- if Cutil.is_composite_type env e1.etyp then
- unsupported "assignment between structs or between unions";
- if is_volatile_access env e1 then
- Ecall(volatile_write_fun (typeof e1'),
- Econs(Eaddrof(e1', Tpointer(typeof e1')), Econs(e2', Enil)),
- Tvoid) (* typing issue here *)
- else
- Eassign(e1', e2', ty)
- | C.EBinop((C.Oadd_assign|C.Osub_assign|C.Omul_assign|C.Odiv_assign|
- C.Omod_assign|C.Oand_assign|C.Oor_assign|C.Oxor_assign|
- C.Oshl_assign|C.Oshr_assign) as op,
- e1, e2, tyres) ->
- let tyres = convertTyp env tyres in
- let op' =
- match op with
- | C.Oadd_assign -> Oadd
- | C.Osub_assign -> Osub
- | C.Omul_assign -> Omul
- | C.Odiv_assign -> Odiv
- | C.Omod_assign -> Omod
- | C.Oand_assign -> Oand
- | C.Oor_assign -> Oor
- | C.Oxor_assign -> Oxor
- | C.Oshl_assign -> Oshl
- | C.Oshr_assign -> Oshr
- | _ -> assert false in
- let e1' = convertLvalue env e1 in
- let e2' = convertExpr env e2 in
- if is_volatile_access env e1 then
- (error "assign-op to volatile not supported"; ezero)
- else
- Eassignop(op', e1', e2', tyres, ty)
- | C.EBinop(C.Ocomma, e1, e2, _) ->
- Ecomma(convertExpr env e1, convertExpr env e2, ty)
- | C.EBinop(C.Ologand, e1, e2, _) ->
- coq_Eseqand (convertExpr env e1) (convertExpr env e2) ty
- | C.EBinop(C.Ologor, e1, e2, _) ->
- coq_Eseqor (convertExpr env e1) (convertExpr env e2) ty
-
- | C.EConditional(e1, e2, e3) ->
- Econdition(convertExpr env e1, convertExpr env e2, convertExpr env e3, ty)
- | C.ECast(ty1, e1) ->
- Ecast(convertExpr env e1, convertTyp env ty1)
- | C.ECall(fn, args) ->
- match projFunType env fn.etyp with
- | None ->
- error "wrong type for function part of a call"; ezero
- | Some(res, false) ->
- (* Non-variadic function *)
- Ecall(convertExpr env fn, convertExprList env args, ty)
- | Some(res, true) ->
- (* Variadic function: generate a call to a stub function with
- the appropriate number and types of arguments. Works only if
- the function expression e is a global variable. *)
- let fun_name =
- match fn with
- | {edesc = C.EVar id} when !Clflags.option_fvararg_calls ->
- (*warning "emulating call to variadic function"; *)
- id.name
- | _ ->
- unsupported "call to variadic function";
- "<error>" in
- let targs = convertTypList env (List.map (fun e -> e.etyp) args) in
- let tres = convertTyp env res in
- let (stub_fun_name, stub_fun_typ) =
- register_stub_function fun_name tres targs in
- Ecall(Evalof(Evar(intern_string stub_fun_name, stub_fun_typ),
- stub_fun_typ),
- convertExprList env args, ty)
-
-and convertLvalue env e =
- let ty = convertTyp env e.etyp in
- match e.edesc with
- | C.EVar id ->
- Evar(intern_string id.name, ty)
- | C.EUnop(C.Oderef, e1) ->
- Ederef(convertExpr env e1, ty)
- | C.EUnop(C.Odot id, e1) ->
- Efield(convertLvalue env e1, intern_string id, ty)
- | C.EUnop(C.Oarrow id, e1) ->
- let e1' = convertExpr env e1 in
- let ty1 =
- match typeof e1' with
- | Tpointer t -> t
- | _ -> error ("wrong type for ->" ^ id ^ " access"); Tvoid in
- Efield(Ederef(e1', ty1), intern_string id, ty)
- | C.EBinop(C.Oindex, e1, e2, _) ->
- coq_Eindex (convertExpr env e1) (convertExpr env e2) ty
- | _ ->
- error "illegal l-value"; ezero
-
-and convertExprList env el =
- match el with
- | [] -> Enil
- | e1 :: el' -> Econs(convertExpr env e1, convertExprList env el')
-
-(* Separate the cases of a switch statement body *)
-
-type switchlabel =
- | Case of C.exp
- | Default
-
-type switchbody =
- | Label of switchlabel
- | Stmt of C.stmt
-
-let rec flattenSwitch = function
- | {sdesc = C.Sseq(s1, s2)} ->
- flattenSwitch s1 @ flattenSwitch s2
- | {sdesc = C.Slabeled(C.Scase e, s1)} ->
- Label(Case e) :: flattenSwitch s1
- | {sdesc = C.Slabeled(C.Sdefault, s1)} ->
- Label Default :: flattenSwitch s1
- | s ->
- [Stmt s]
-
-let rec groupSwitch = function
- | [] ->
- (Cutil.sskip, [])
- | Label case :: rem ->
- let (fst, cases) = groupSwitch rem in
- (Cutil.sskip, (case, fst) :: cases)
- | Stmt s :: rem ->
- let (fst, cases) = groupSwitch rem in
- (Cutil.sseq s.sloc s fst, cases)
-
-(* Statement *)
-
-let rec convertStmt env s =
- updateLoc s.sloc;
- match s.sdesc with
- | C.Sskip ->
- Sskip
- | C.Sdo e ->
- Sdo(convertExpr env e)
- | C.Sseq(s1, s2) ->
- Ssequence(convertStmt env s1, convertStmt env s2)
- | C.Sif(e, s1, s2) ->
- Sifthenelse(convertExpr env e, convertStmt env s1, convertStmt env s2)
- | C.Swhile(e, s1) ->
- Swhile(convertExpr env e, convertStmt env s1)
- | C.Sdowhile(s1, e) ->
- Sdowhile(convertExpr env e, convertStmt env s1)
- | C.Sfor(s1, e, s2, s3) ->
- Sfor(convertStmt env s1, convertExpr env e, convertStmt env s2,
- convertStmt env s3)
- | C.Sbreak ->
- Sbreak
- | C.Scontinue ->
- Scontinue
- | C.Sswitch(e, s1) ->
- let (init, cases) = groupSwitch (flattenSwitch s1) in
- if cases = [] then
- unsupported "ill-formed 'switch' statement";
- if init.sdesc <> C.Sskip then
- warning "ignored code at beginning of 'switch'";
- Sswitch(convertExpr env e, convertSwitch env cases)
- | C.Slabeled(C.Slabel lbl, s1) ->
- Slabel(intern_string lbl, convertStmt env s1)
- | C.Slabeled(C.Scase _, _) ->
- unsupported "'case' outside of 'switch'"; Sskip
- | C.Slabeled(C.Sdefault, _) ->
- unsupported "'default' outside of 'switch'"; Sskip
- | C.Sgoto lbl ->
- Sgoto(intern_string lbl)
- | C.Sreturn None ->
- Sreturn None
- | C.Sreturn(Some e) ->
- Sreturn(Some(convertExpr env e))
- | C.Sblock _ ->
- unsupported "nested blocks"; Sskip
- | C.Sdecl _ ->
- unsupported "inner declarations"; Sskip
-
-and convertSwitch env = function
- | [] ->
- LSdefault Sskip
- | [Default, s] ->
- LSdefault (convertStmt env s)
- | (Default, s) :: _ ->
- updateLoc s.sloc;
- unsupported "'default' case must occur last";
- LSdefault Sskip
- | (Case e, s) :: rem ->
- updateLoc s.sloc;
- let v =
- match Ceval.integer_expr env e with
- | None -> unsupported "'case' label is not a compile-time integer"; 0L
- | Some v -> v in
- LScase(convertInt v,
- convertStmt env s,
- convertSwitch env rem)
-
-(** Function definitions *)
-
-let convertFundef env fd =
- if Cutil.is_composite_type env fd.fd_ret then
- unsupported "function returning a struct or union";
- let ret =
- convertTyp env fd.fd_ret in
- let params =
- List.map
- (fun (id, ty) ->
- if Cutil.is_composite_type env ty then
- unsupported "function parameter of struct or union type";
- Datatypes.Coq_pair(intern_string id.name, convertTyp env ty))
- fd.fd_params in
- let vars =
- List.map
- (fun (sto, id, ty, init) ->
- if sto = Storage_extern || sto = Storage_static then
- unsupported "'static' or 'extern' local variable";
- if init <> None then
- unsupported "initialized local variable";
- Datatypes.Coq_pair(intern_string id.name, convertTyp env ty))
- fd.fd_locals in
- let body' = convertStmt env fd.fd_body in
- let id' = intern_string fd.fd_name.name in
- let decl =
- (fd.fd_storage, fd.fd_name, Cutil.fundef_typ fd, None) in
- Hashtbl.add decl_atom id' (env, decl);
- Sections.define_function id';
- Datatypes.Coq_pair(id',
- Internal {fn_return = ret; fn_params = params;
- fn_vars = vars; fn_body = body'})
-
-(** External function declaration *)
-
-let noninlined_builtin_functions = [
- "__builtin_memcpy";
- "__builtin_memcpy_words"
-]
-
-let convertFundecl env (sto, id, ty, optinit) =
- let (args, res) =
- match convertTyp env ty with
- | Tfunction(args, res) -> (args, res)
- | _ -> assert false in
- let id' = intern_string id.name in
- let ef =
- { ef_id = id';
- ef_sig = signature_of_type args res;
- ef_inline = List.mem_assoc id.name builtins.functions
- && not (List.mem id.name noninlined_builtin_functions) } in
- Datatypes.Coq_pair(id', External(ef, args, res))
-
-(** Initializers *)
-
-let init_data_of_string s =
- let id = ref [] in
- let enter_char c =
- let n = coqint_of_camlint(Int32.of_int(Char.code c)) in
- id := Init_int8 n :: !id in
- enter_char '\000';
- for i = String.length s - 1 downto 0 do enter_char s.[i] done;
- !id
-
-let convertInit env ty init =
-
- let k = ref []
- and pos = ref 0 in
- let emit size datum =
- k := datum :: !k;
- pos := !pos + size in
- let emit_space size =
- emit size (Init_space (z_of_camlint (Int32.of_int size))) in
- let align size =
- let n = !pos land (size - 1) in
- if n > 0 then emit_space (size - n) in
- let check_align size =
- assert (!pos land (size - 1) = 0) in
-
- let rec reduceInitExpr = function
- | { edesc = C.EVar id; etyp = ty } ->
- begin match Cutil.unroll env ty with
- | C.TArray _ | C.TFun _ -> Some id
- | _ -> None
- end
- | {edesc = C.EUnop(C.Oaddrof, {edesc = C.EVar id})} -> Some id
- | {edesc = C.ECast(ty, e)} -> reduceInitExpr e
- | _ -> None in
-
- let rec cvtInit ty = function
- | Init_single e ->
- begin match reduceInitExpr e with
- | Some id ->
- check_align 4;
- emit 4 (Init_addrof(intern_string id.name, coqint_of_camlint 0l))
- | None ->
- match Ceval.constant_expr env ty e with
- | Some(C.CInt(v, ik, _)) ->
- begin match convertIkind ik with
- | (_, I8) ->
- emit 1 (Init_int8(convertInt v))
- | (_, I16) ->
- check_align 2;
- emit 2 (Init_int16(convertInt v))
- | (_, I32) ->
- check_align 4;
- emit 4 (Init_int32(convertInt v))
- end
- | Some(C.CFloat(v, fk, _)) ->
- begin match convertFkind fk with
- | F32 ->
- check_align 4;
- emit 4 (Init_float32 v)
- | F64 ->
- check_align 8;
- emit 8 (Init_float64 v)
- end
- | Some(C.CStr s) ->
- check_align 4;
- let id = name_for_string_literal env s in
- emit 4 (Init_addrof(id, coqint_of_camlint 0l))
- | Some(C.CWStr _) ->
- unsupported "wide character strings"
- | Some(C.CEnum _) ->
- error "enum tag after constant folding"
- | None ->
- Format.printf "%a@." Cprint.exp (0, e);
- error "initializer is not a compile-time constant"
- end
- | Init_array il ->
- let ty_elt =
- match Cutil.unroll env ty with
- | C.TArray(t, _, _) -> t
- | _ -> error "array type expected in initializer"; C.TVoid [] in
- List.iter (cvtInit ty_elt) il
- | Init_struct(_, flds) ->
- cvtPadToSizeof ty (fun () -> List.iter cvtFieldInit flds)
- | Init_union(_, fld, i) ->
- cvtPadToSizeof ty (fun () -> cvtFieldInit (fld,i))
-
- and cvtFieldInit (fld, i) =
- let ty' = convertTyp env fld.fld_typ in
- let al = Int32.to_int (camlint_of_z (Csyntax.alignof ty')) in
- align al;
- cvtInit fld.fld_typ i
-
- and cvtPadToSizeof ty fn =
- let ty' = convertTyp env ty in
- let sz = Int32.to_int (camlint_of_z (Csyntax.sizeof ty')) in
- let pos0 = !pos in
- fn();
- let pos1 = !pos in
- assert (pos1 <= pos0 + sz);
- if pos1 < pos0 + sz then emit_space (pos0 + sz - pos1)
-
- in cvtInit ty init; List.rev !k
-
-(** Global variable *)
-
-let rec type_is_readonly env t =
- let a = Cutil.attributes_of_type env t in
- if List.mem C.AVolatile a then false else
- if List.mem C.AConst a then true else
- match Cutil.unroll env t with
- | C.TArray(t', _, _) -> type_is_readonly env t'
- | _ -> false
-
-let rec type_is_volatile env t =
- let a = Cutil.attributes_of_type env t in
- if List.mem C.AConst a then true else
- match Cutil.unroll env t with
- | C.TArray(t', _, _) -> type_is_volatile env t'
- | _ -> false
-
-let convertGlobvar env (sto, id, ty, optinit as decl) =
- let id' = intern_string id.name in
- let ty' = convertTyp env ty in
- let init' =
- match optinit with
- | None ->
- if sto = C.Storage_extern then [] else [Init_space(Csyntax.sizeof ty')]
- | Some i ->
- convertInit env ty i in
- Hashtbl.add decl_atom id' (env, decl);
- Sections.define_variable id'
- (match Cutil.sizeof env ty with Some sz -> sz | None -> max_int)
- (type_is_readonly env ty);
- Datatypes.Coq_pair(id',
- {gvar_info = ty'; gvar_init = init';
- gvar_readonly = type_is_readonly env ty;
- gvar_volatile = type_is_volatile env ty})
-
-(** Convert a list of global declarations.
- Result is a pair [(funs, vars)] where [funs] are
- the function definitions (internal and external)
- and [vars] the variable declarations. *)
-
-let rec convertGlobdecls env funs vars gl =
- match gl with
- | [] -> (List.rev funs, List.rev vars)
- | g :: gl' ->
- updateLoc g.gloc;
- match g.gdesc with
- | C.Gdecl((sto, id, ty, optinit) as d) ->
- (* Prototyped functions become external declarations.
- Variadic functions are skipped.
- Other types become variable declarations. *)
- begin match Cutil.unroll env ty with
- | TFun(_, Some _, false, _) ->
- convertGlobdecls env (convertFundecl env d :: funs) vars gl'
- | TFun(_, None, false, _) ->
- error "function declaration without prototype";
- convertGlobdecls env funs vars gl'
- | TFun(_, _, true, _) ->
- convertGlobdecls env funs vars gl'
- | _ ->
- convertGlobdecls env funs (convertGlobvar env d :: vars) gl'
- end
- | C.Gfundef fd ->
- convertGlobdecls env (convertFundef env fd :: funs) vars gl'
- | C.Gcompositedecl _ | C.Gcompositedef _
- | C.Gtypedef _ | C.Genumdef _ ->
- (* typedefs are unrolled, structs are expanded inline, and
- enum tags are folded. So we just skip their declarations. *)
- convertGlobdecls env funs vars gl'
- | C.Gpragma s ->
- if not (!process_pragma_hook s) then
- warning ("'#pragma " ^ s ^ "' directive ignored");
- convertGlobdecls env funs vars gl'
-
-(** Build environment of typedefs and structs *)
-
-let rec translEnv env = function
- | [] -> env
- | g :: gl ->
- let env' =
- match g.gdesc with
- | C.Gcompositedecl(su, id) ->
- Env.add_composite env id (Cutil.composite_info_decl env su)
- | C.Gcompositedef(su, id, fld) ->
- Env.add_composite env id (Cutil.composite_info_def env su fld)
- | C.Gtypedef(id, ty) ->
- Env.add_typedef env id ty
- | _ ->
- env in
- translEnv env' gl
-
-(** Eliminate forward declarations of globals that are defined later. *)
-
-module IdentSet = Set.Make(struct type t = C.ident let compare = compare end)
-
-let cleanupGlobals p =
-
- let rec clean defs accu = function
- | [] -> accu
- | g :: gl ->
- updateLoc g.gloc;
- match g.gdesc with
- | C.Gdecl(sto, id, ty, None) ->
- if IdentSet.mem id defs
- then clean defs accu gl
- else clean (IdentSet.add id defs) (g :: accu) gl
- | C.Gdecl(_, id, ty, _) ->
- if IdentSet.mem id defs then
- error ("multiple definitions of " ^ id.name);
- clean (IdentSet.add id defs) (g :: accu) gl
- | C.Gfundef fd ->
- if IdentSet.mem fd.fd_name defs then
- error ("multiple definitions of " ^ fd.fd_name.name);
- clean (IdentSet.add fd.fd_name defs) (g :: accu) gl
- | _ ->
- clean defs (g :: accu) gl
-
- in clean IdentSet.empty [] (List.rev p)
-
-(** Convert a [C.program] into a [Csyntax.program] *)
-
-let convertProgram p =
- numErrors := 0;
- stringNum := 0;
- Hashtbl.clear decl_atom;
- Hashtbl.clear stringTable;
- Hashtbl.clear stub_function_table;
- let p = Builtins.declarations() @ p in
- try
- let (funs1, vars1) =
- convertGlobdecls (translEnv Env.empty p) [] [] (cleanupGlobals p) in
- let funs2 = declare_stub_functions funs1 in
- let vars2 = globals_for_strings vars1 in
- if !numErrors > 0
- then None
- else Some { AST.prog_funct = funs2;
- AST.prog_vars = vars2;
- AST.prog_main = intern_string "main" }
- with Env.Error msg ->
- error (Env.error_message msg); None
-
-(** ** Extracting information about global variables from their atom *)
-
-let atom_is_static a =
- try
- let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
- sto = C.Storage_static
- with Not_found ->
- false
-
-let atom_is_readonly a =
- try
- let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
- type_is_readonly env ty
- with Not_found ->
- false
-
-let atom_sizeof a =
- try
- let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
- Cutil.sizeof env ty
- with Not_found ->
- None
-
-let atom_alignof a =
- try
- let (env, (sto, id, ty, init)) = Hashtbl.find decl_atom a in
- Cutil.alignof env ty
- with Not_found ->
- None
-