diff --git a/cfrontend/Cil2Csyntax.ml b/cfrontend/Cil2Csyntax.ml index e5690aac3b85e08c6045ae46aa8c0f565f367b14..822f6cb045e41b5bc7e07d5a944b64ab5daa8787 100644 --- a/cfrontend/Cil2Csyntax.ml +++ b/cfrontend/Cil2Csyntax.ml @@ -201,11 +201,12 @@ and eval_cast ty v = | TPtr(_, _), CWStr s -> v (* tolerance? *) | _, _ -> raise NotConst -(** Handler for #pragma directives -- - overriden in machine-dependent CPragmas module *) - -let process_pragma = ref (fun (a: Cil.attribute) -> false) +(** Hooks -- overriden in machine-dependent CPragmas module *) +let process_pragma_hook = ref (fun (a: Cil.attribute) -> false) +let define_variable_hook = ref (fun (id: ident) (v: Cil.varinfo) -> ()) +let define_function_hook = ref (fun (id: ident) (v: Cil.varinfo) -> ()) +let define_stringlit_hook = ref (fun (id: ident) (v: Cil.varinfo) -> ()) (** The parameter to the translation functor: it specifies the translation for integer and float types. *) @@ -296,6 +297,7 @@ let name_for_string_literal s = v.vstorage <- Static; v.vreferenced <- true; Hashtbl.add varinfo_atom id v; + !define_stringlit_hook id v; Hashtbl.add stringTable s id; id @@ -1012,6 +1014,7 @@ let convertGFun fdec = current_function := None; let id = intern_string v.vname in Hashtbl.add varinfo_atom id v; + !define_function_hook id v; Datatypes.Coq_pair (id, Internal { fn_return=ret; fn_params=args; fn_vars=varList; fn_body=s }) @@ -1144,6 +1147,7 @@ let convertGVar v i = updateLoc(v.vdecl); let id = intern_string v.vname in Hashtbl.add varinfo_atom id v; + !define_variable_hook id v; Datatypes.Coq_pair (Datatypes.Coq_pair(id, convertInitInfo v.vtype i), convertTyp v.vtype) @@ -1214,7 +1218,7 @@ let rec processGlobals = function unsupported "inline assembly" | GPragma (Attr(name, _) as attr, loc) -> updateLoc(loc); - if not (!process_pragma attr) then + if not (!process_pragma_hook attr) then warning ("#pragma `" ^ name ^ "' directive ignored"); processGlobals l | GText _ -> processGlobals l (* comments are ignored *) @@ -1264,16 +1268,16 @@ let atom_is_static a = with Not_found -> false +let var_is_readonly v = + let a = typeAttrs v.vtype in + if hasAttribute "volatile" a then false else + if hasAttribute "const" a then true else + match Cil.unrollType v.vtype with + | TArray(ty, _, _) -> + let a' = typeAttrs ty in + hasAttribute "const" a' && not (hasAttribute "volatile" a') + | _ -> false + let atom_is_readonly a = - try - let v = Hashtbl.find varinfo_atom a in - let a = typeAttrs v.vtype in - if hasAttribute "volatile" a then false else - if hasAttribute "const" a then true else - match Cil.unrollType v.vtype with - | TArray(ty, _, _) -> - let a' = typeAttrs ty in - hasAttribute "const" a' && not (hasAttribute "volatile" a') - | _ -> false - with Not_found -> - false + try var_is_readonly (Hashtbl.find varinfo_atom a) + with Not_found -> false diff --git a/driver/Clflags.ml b/driver/Clflags.ml index c6f6e8fe2820347c326e39975b8f89933ac0da3a..ddcfaac43a994492f985faf4c7fd775ce5b7ef7f 100644 --- a/driver/Clflags.ml +++ b/driver/Clflags.ml @@ -24,3 +24,9 @@ let option_E = ref false let option_S = ref false let option_c = ref false let option_v = ref false +let option_small_data = + ref (if Configuration.arch = "powerpc" + && Configuration.variant = "eabi" + && Configuration.system = "diab" + then 8 else 0) +let option_small_const = ref (!option_small_data) diff --git a/driver/Driver.ml b/driver/Driver.ml index b818680481f4bdfe74aebdd4f796c84125297189..aed0221919eeec6ed0bce785c6f879f78c56cf46 100644 --- a/driver/Driver.ml +++ b/driver/Driver.ml @@ -247,10 +247,6 @@ let process_cminor_file sourcename = (* Command-line parsing *) -let starts_with s1 s2 = - String.length s1 >= String.length s2 && - String.sub s1 0 (String.length s2) = s2 - let usage_string = "ccomp [options] <source files> Recognized source files: @@ -269,6 +265,8 @@ Preprocessing options: Compilation options: -flonglong Treat 'long long' as 'long' and 'long double' as 'double' -fmadd Use fused multiply-add and multiply-sub instructions + -fsmall-data <n> Set maximal size <n> for allocation in small data area + -fsmall-const <n> Set maximal size <n> for allocation in small constant area -dcil Save CIL-processed source in <file>.cil.c -dclight Save generated Clight in <file>.light.c -dasm Save generated assembly in <file>.s @@ -281,86 +279,88 @@ General options: -v Print external commands before invoking them " -let rec parse_cmdline i = - if i < Array.length Sys.argv then begin - let s = Sys.argv.(i) in - if starts_with s "-I" || starts_with s "-D" || starts_with s "-U" - then begin - prepro_options := s :: !prepro_options; - parse_cmdline (i + 1) - end else - if starts_with s "-l" || starts_with s "-L" then begin - linker_options := s :: !linker_options; - parse_cmdline (i + 1) - end else - if s = "-o" && i + 1 < Array.length Sys.argv then begin - exe_name := Sys.argv.(i + 1); - parse_cmdline (i + 2) - end else - if s = "-stdlib" && i + 1 < Array.length Sys.argv then begin - stdlib_path := Sys.argv.(i + 1); - parse_cmdline (i + 2) - end else - if s = "-flonglong" then begin - option_flonglong := true; - parse_cmdline (i + 1) - end else - if s = "-fmadd" then begin - option_fmadd := true; - parse_cmdline (i + 1) - end else - if s = "-dcil" then begin - option_dcil := true; - parse_cmdline (i + 1) - end else - if s = "-dclight" then begin - option_dclight := true; - parse_cmdline (i + 1) - end else - if s = "-dasm" then begin - option_dasm := true; - parse_cmdline (i + 1) - end else - if s = "-E" then begin - option_E := true; - parse_cmdline (i + 1) - end else - if s = "-S" then begin - option_S := true; - parse_cmdline (i + 1) - end else - if s = "-c" then begin - option_c := true; - parse_cmdline (i + 1) - end else - if s = "-v" then begin - option_v := true; - parse_cmdline (i + 1) - end else - if Filename.check_suffix s ".c" then begin +type action = + | Set of bool ref + | Self of (string -> unit) + | String of (string -> unit) + | Integer of (int -> unit) + +let rec find_action s = function + | [] -> None + | (re, act) :: rem -> + if Str.string_match re s 0 then Some act else find_action s rem + +let parse_cmdline spec usage = + let acts = List.map (fun (pat, act) -> (Str.regexp pat, act)) spec in + let error () = + eprintf "Usage: %s" usage; + exit 2 in + let rec parse i = + if i < Array.length Sys.argv then begin + let s = Sys.argv.(i) in + match find_action s acts with + | None -> + if s <> "-help" && s <> "--help" + then eprintf "Unknown argument `%s'\n" s; + error () + | Some(Set r) -> + r := true; parse (i+1) + | Some(Self fn) -> + fn s; parse (i+1) + | Some(String fn) -> + if i + 1 < Array.length Sys.argv then begin + fn Sys.argv.(i+1); parse (i+2) + end else begin + eprintf "Option `%s' expects an argument\n" s; error() + end + | Some(Integer fn) -> + if i + 1 < Array.length Sys.argv then begin + let n = + try + int_of_string Sys.argv.(i+1) + with Failure _ -> + eprintf "Argument to option `%s' must be an integer\n" s; + error() + in + fn n; parse (i+2) + end else begin + eprintf "Option `%s' expects an argument\n" s; error() + end + end + in parse 1 + +let cmdline_actions = [ + "-[IDU].", Self(fun s -> prepro_options := s :: !prepro_options); + "-[lL].", Self(fun s -> linker_options := s :: !linker_options); + "-o$", String(fun s -> exe_name := s); + "-stdlib$", String(fun s -> stdlib_path := s); + "-flonglong$", Set option_flonglong; + "-fmadd$", Set option_fmadd; + "-fsmall-data$", Integer(fun n -> option_small_data := n); + "-fsmall-const$", Integer(fun n -> option_small_const := n); + "-dcil$", Set option_dcil; + "-dclight$", Set option_dclight; + "-dasm$", Set option_dasm; + "-E$", Set option_E; + "-S$", Set option_S; + "-c$", Set option_c; + "-v$", Set option_v; + ".*\\.c$", Self (fun s -> let objfile = process_c_file s in - linker_options := objfile :: !linker_options; - parse_cmdline (i + 1) - end else - if Filename.check_suffix s ".cm" then begin + linker_options := objfile :: !linker_options); + ".*\\.cm$", Self (fun s -> let objfile = process_cminor_file s in - linker_options := objfile :: !linker_options; - parse_cmdline (i + 1) - end else - if Filename.check_suffix s ".o" || Filename.check_suffix s ".a" then begin - linker_options := s :: !linker_options; - parse_cmdline (i + 1) - end else begin - eprintf "Unknown argument `%s'\n" s; - eprintf "Usage: %s" usage_string; - exit 2 - end - end + linker_options := objfile :: !linker_options); + ".*\\.[oa]$", Self (fun s -> + linker_options := s :: !linker_options) +] let _ = Cil.initCIL(); CPragmas.initialize(); - parse_cmdline 1; - if not (!option_c || !option_S || !option_E) then begin + parse_cmdline cmdline_actions usage_string; + if !linker_options <> [] + && not (!option_c || !option_S || !option_E) + then begin linker !exe_name !linker_options end diff --git a/powerpc/PrintAsm.ml b/powerpc/PrintAsm.ml index d9c6531472afa601a92f50bb5bd7e9856dcd03c3..50a847442daa5f77253b3aa719a344c98055d785 100644 --- a/powerpc/PrintAsm.ml +++ b/powerpc/PrintAsm.ml @@ -175,26 +175,23 @@ let section oc name = (* Names of sections *) -let (text, data, const_data, sdata, float_literal) = +let (text, data, const_data, float_literal) = match target with | MacOS -> (".text", ".data", ".const", - ".data", (* unused *) ".const_data") | Linux -> (".text", ".data", ".rodata", - ".data", (* unused *) ".section .rodata.cst8,\"aM\",@progbits,8") | Diab -> (".text", ".data", - ".data", (* or: .rodata? *) - ".sdata", (* to check *) - ".data") (* or: .rodata? *) + ".text", + ".text") (* Encoding masks for rlwinm instructions *) @@ -496,7 +493,7 @@ let print_function oc name code = Hashtbl.clear current_function_labels; section oc (match CPragmas.section_for_atom name true with - | Some s -> ".section\t" ^ s + | Some s -> s | None -> text); fprintf oc " .align 2\n"; if not (Cil2Csyntax.atom_is_static name) then @@ -713,14 +710,11 @@ let print_var oc (Coq_pair(Coq_pair(name, init_data), _)) = match init_data with [Init_space _] -> false | _ -> true in let sec = match CPragmas.section_for_atom name init with - | Some s -> ".section\t" ^ s + | Some s -> s | None -> - if CPragmas.atom_is_small_data name (coqint_of_camlint 0l) then - sdata - else if Cil2Csyntax.atom_is_readonly name then - const_data - else - data + if Cil2Csyntax.atom_is_readonly name + then const_data + else data in section oc sec; fprintf oc " .align 3\n"; diff --git a/powerpc/eabi/CPragmas.ml b/powerpc/eabi/CPragmas.ml index 9d2eb8a4b953427b9808f08050d11f23c4a4bdae..d4b79b5257e95e8d8fc6e7ad6cb76cdff19c38f6 100644 --- a/powerpc/eabi/CPragmas.ml +++ b/powerpc/eabi/CPragmas.ml @@ -22,31 +22,72 @@ open Camlcoq type section_info = { sec_name_init: string; sec_name_uninit: string; + sec_acc_mode: string; sec_near_access: bool } +let default_section_info = { + sec_name_init = ".data"; + sec_name_uninit = ".data"; (* COMM? *) + sec_acc_mode = "RW"; + sec_near_access = false +} + let section_table : (string, section_info) Hashtbl.t = Hashtbl.create 17 -let use_section_table : (AST.ident, section_info) Hashtbl.t = - Hashtbl.create 51 +(* Built-in sections *) + +let _ = + let rodata = + if Configuration.system = "linux" then ".rodata" else ".text" in + List.iter (fun (n, si) -> Hashtbl.add section_table n si) [ + "CODE", {sec_name_init = ".text"; + sec_name_uninit = ".text"; + sec_acc_mode = "RX"; + sec_near_access = false}; + "DATA", {sec_name_init = ".data"; + sec_name_uninit = ".data"; (* COMM? *) + sec_acc_mode = "RW"; + sec_near_access = false}; + "SDATA", {sec_name_init = ".sdata"; + sec_name_uninit = ".sbss"; + sec_acc_mode = "RW"; + sec_near_access = true}; + "CONST", {sec_name_init = rodata; + sec_name_uninit = rodata; + sec_acc_mode = "R"; + sec_near_access = false}; + "SCONST",{sec_name_init = ".sdata2"; + sec_name_uninit = ".sdata2"; + sec_acc_mode = "R"; + sec_near_access = true}; + "STRING",{sec_name_init = rodata; + sec_name_uninit = rodata; + sec_acc_mode = "R"; + sec_near_access = false} + ] let process_section_pragma classname istring ustring addrmode accmode = - let is_near = (addrmode = "near-absolute") || (addrmode = "near-data") in - let is_writable = String.contains accmode 'W' - and is_executable = String.contains accmode 'X' in - let sec_type = - match is_writable, is_executable with - | true, true -> 'm' (* text+data *) - | true, false -> 'd' (* data *) - | false, true -> 'c' (* text *) - | false, false -> 'r' (* const *) - in - let info = - { sec_name_init = sprintf "%s,,%c" istring sec_type; - sec_name_uninit = sprintf "%s,,%c" ustring sec_type; - sec_near_access = is_near } in - Hashtbl.add section_table classname info + let old_si = + try Hashtbl.find section_table classname + with Not_found -> default_section_info in + let si = + { sec_name_init = + if istring = "" then old_si.sec_name_init else istring; + sec_name_uninit = + if ustring = "" then old_si.sec_name_uninit else ustring; + sec_acc_mode = + if accmode = "" then old_si.sec_acc_mode else accmode; + sec_near_access = + if addrmode = "" + then old_si.sec_near_access + else (addrmode = "near-code") || (addrmode = "near-data") } in + Hashtbl.add section_table classname si + + +let use_section_table : (AST.ident, section_info) Hashtbl.t = + Hashtbl.create 51 let process_use_section_pragma classname id = try @@ -55,18 +96,42 @@ let process_use_section_pragma classname id = with Not_found -> Cil2Csyntax.error (sprintf "unknown section name `%s'" classname) +let default_use_section id classname = + if not (Hashtbl.mem use_section_table id) then begin + let info = + try Hashtbl.find section_table classname + with Not_found -> assert false in + Hashtbl.add use_section_table id info + end + +let define_function id v = + default_use_section id "CODE" + +let define_stringlit id v = + default_use_section id "STRING" + +let define_variable id v = + let sz = Cil.bitsSizeOf v.vtype / 8 in + let sect = + if Cil2Csyntax.var_is_readonly v then + if sz <= !Clflags.option_small_const then "SCONST" else "CONST" + else + if sz <= !Clflags.option_small_data then "SDATA" else "DATA" in + default_use_section id sect + (* CIL does not parse the "section" and "use_section" pragmas, which have irregular syntax, so we parse them using regexps *) let re_start_pragma_section = Str.regexp "section\\b" -let re_pragma_section = Str.regexp - "section[ \t]+\ - \\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+\ - \"\\([^\"]*\\)\"[ \t]+\ - \"\\([^\"]*\\)\"[ \t]+\ - \\([a-z-]+\\)[ \t]+\ - \\([A-Z]+\\)" +let re_pragma_section = Str.regexp( + "section[ \t]+" +^ "\\([A-Za-z_][A-Za-z_0-9]*\\)[ \t]+" (* class_name *) +^ "\\(\"[^\"]*\"\\)?[ \t]*" (* istring *) +^ "\\(\"[^\"]*\"\\)?[ \t]*" (* ustring *) +^ "\\(standard\\|near-absolute\\|far-absolute\\|near-data\\|far-data\\|near-code\\|far-code\\)?[ \t]*" (* addressing mode *) +^ "\\([RWXON]*\\)" (* access mode *) +) let re_start_pragma_use_section = Str.regexp "use_section\\b" @@ -101,34 +166,51 @@ let process_pragma (Attr(name, _)) = false let initialize () = - Cil2Csyntax.process_pragma := process_pragma + Cil2Csyntax.process_pragma_hook := process_pragma; + Cil2Csyntax.define_variable_hook := define_variable; + Cil2Csyntax.define_function_hook := define_function; + Cil2Csyntax.define_stringlit_hook := define_stringlit (* PowerPC-specific: say if an atom is in a small data area *) let atom_is_small_data a ofs = - match Configuration.system with - | "diab" -> - begin try - let v = Hashtbl.find Cil2Csyntax.varinfo_atom a in - let sz = Cil.bitsSizeOf v.vtype / 8 in - let ofs = camlint_of_coqint ofs in - if ofs >= 0l && ofs < Int32.of_int sz then begin - try (Hashtbl.find use_section_table a).sec_near_access - with Not_found -> sz <= 8 - end else - false + begin try + let v = Hashtbl.find Cil2Csyntax.varinfo_atom a in + let sz = Cil.bitsSizeOf v.vtype / 8 in + let ofs = camlint_of_coqint ofs in + if ofs >= 0l && ofs < Int32.of_int sz then begin + try + (Hashtbl.find use_section_table a).sec_near_access with Not_found -> - false - end - | _ -> + if Cil2Csyntax.var_is_readonly v + then sz <= !Clflags.option_small_const + else sz <= !Clflags.option_small_data + end else false + with Not_found -> + false + end (* PowerPC-specific: determine section to use for a particular symbol *) let section_for_atom a init = try let sinfo = Hashtbl.find use_section_table a in - Some(if init then sinfo.sec_name_init else sinfo.sec_name_uninit) - with Not_found -> - None - + let sname = + if init then sinfo.sec_name_init else sinfo.sec_name_uninit in + if not (String.contains sname '\"') then + Some sname + else begin + (* The following is Diab-specific... *) + let accmode = sinfo.sec_acc_mode in + let is_writable = String.contains accmode 'W' + and is_executable = String.contains accmode 'X' in + let stype = + match is_writable, is_executable with + | true, true -> 'm' (* text+data *) + | true, false -> 'd' (* data *) + | false, true -> 'c' (* text *) + | false, false -> 'r' (* const *) + in Some(sprintf ".section\t%s,,%c" sname stype) + end + with Not_found -> None