aboutsummaryrefslogtreecommitdiffstats
path: root/cil/src/cil.ml
diff options
context:
space:
mode:
authorxleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-03-03 10:25:25 +0000
committerxleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-03-03 10:25:25 +0000
commit93d89c2b5e8497365be152fb53cb6cd4c5764d34 (patch)
tree0de8d05bbd0eeaeb5e4b85395f8dd576984b6a9e /cil/src/cil.ml
parent891377ce1962cdb31357d6580d6546ec22df2b4f (diff)
downloadcompcert-93d89c2b5e8497365be152fb53cb6cd4c5764d34.tar.gz
compcert-93d89c2b5e8497365be152fb53cb6cd4c5764d34.zip
Getting rid of CIL
git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1270 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
Diffstat (limited to 'cil/src/cil.ml')
-rw-r--r--cil/src/cil.ml6427
1 files changed, 0 insertions, 6427 deletions
diff --git a/cil/src/cil.ml b/cil/src/cil.ml
deleted file mode 100644
index 2c4e12a7..00000000
--- a/cil/src/cil.ml
+++ /dev/null
@@ -1,6427 +0,0 @@
-(* MODIF: Loop constructor replaced by 3 constructors: While, DoWhile, For. *)
-(* MODIF: useLogicalOperators flag set to true by default. *)
-
-(*
- *
- * Copyright (c) 2001-2003,
- * George C. Necula <necula@cs.berkeley.edu>
- * Scott McPeak <smcpeak@cs.berkeley.edu>
- * Wes Weimer <weimer@cs.berkeley.edu>
- * Ben Liblit <liblit@cs.berkeley.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. The names of the contributors may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *)
-
-open Escape
-open Pretty
-open Trace (* sm: 'trace' function *)
-module E = Errormsg
-module H = Hashtbl
-module IH = Inthash
-
-(*
- * CIL: An intermediate language for analyzing C progams.
- *
- * Version Tue Dec 12 15:21:52 PST 2000
- * Scott McPeak, George Necula, Wes Weimer
- *
- *)
-
-(* The module Cilversion is generated automatically by Makefile from
- * information in configure.in *)
-let cilVersion = Cilversion.cilVersion
-let cilVersionMajor = Cilversion.cilVersionMajor
-let cilVersionMinor = Cilversion.cilVersionMinor
-let cilVersionRevision = Cilversion.cilVersionRev
-
-(* A few globals that control the interpretation of C source *)
-let msvcMode = ref false (* Whether the pretty printer should
- * print output for the MS VC
- * compiler. Default is GCC *)
-
-let useLogicalOperators = ref (*false*) true
-
-
-module M = Machdep
-(* Cil.initCil will set this to the current machine description.
- Makefile.cil generates the file obj/@ARCHOS@/machdep.ml,
- which contains the descriptions of gcc and msvc. *)
-let theMachine : M.mach ref = ref M.gcc
-
-
-let lowerConstants: bool ref = ref true
- (** Do lower constants (default true) *)
-let insertImplicitCasts: bool ref = ref true
- (** Do insert implicit casts (default true) *)
-
-
-let little_endian = ref true
-let char_is_unsigned = ref false
-let underscore_name = ref false
-
-type lineDirectiveStyle =
- | LineComment
- | LinePreprocessorInput
- | LinePreprocessorOutput
-
-let lineDirectiveStyle = ref (Some LinePreprocessorInput)
-
-let print_CIL_Input = ref false
-
-let printCilAsIs = ref false
-
-let lineLength = ref 80
-
-(* sm: return the string 's' if we're printing output for gcc, suppres
- * it if we're printing for CIL to parse back in. the purpose is to
- * hide things from gcc that it complains about, but still be able
- * to do lossless transformations when CIL is the consumer *)
-let forgcc (s: string) : string =
- if (!print_CIL_Input) then "" else s
-
-
-let debugConstFold = false
-
-(** The Abstract Syntax of CIL *)
-
-
-(** The top-level representation of a CIL source file. Its main contents is
- the list of global declarations and definitions. *)
-type file =
- { mutable fileName: string; (** The complete file name *)
- mutable globals: global list; (** List of globals as they will appear
- in the printed file *)
- mutable globinit: fundec option;
- (** An optional global initializer function. This is a function where
- * you can put stuff that must be executed before the program is
- * started. This function, is conceptually at the end of the file,
- * although it is not part of the globals list. Use {!Cil.getGlobInit}
- * to create/get one. *)
- mutable globinitcalled: bool;
- (** Whether the global initialization function is called in main. This
- should always be false if there is no global initializer. When
- you create a global initialization CIL will try to insert code in
- main to call it. *)
- }
-
-and comment = location * string
-
-(** The main type for representing global declarations and definitions. A list
- of these form a CIL file. The order of globals in the file is generally
- important. *)
-and global =
- | GType of typeinfo * location
- (** A typedef. All uses of type names (through the [TNamed] constructor)
- must be preceeded in the file by a definition of the name. The string
- is the defined name and always not-empty. *)
-
- | GCompTag of compinfo * location
- (** Defines a struct/union tag with some fields. There must be one of
- these for each struct/union tag that you use (through the [TComp]
- constructor) since this is the only context in which the fields are
- printed. Consequently nested structure tag definitions must be
- broken into individual definitions with the innermost structure
- defined first. *)
-
- | GCompTagDecl of compinfo * location
- (** Declares a struct/union tag. Use as a forward declaration. This is
- * printed without the fields. *)
-
- | GEnumTag of enuminfo * location
- (** Declares an enumeration tag with some fields. There must be one of
- these for each enumeration tag that you use (through the [TEnum]
- constructor) since this is the only context in which the items are
- printed. *)
-
- | GEnumTagDecl of enuminfo * location
- (** Declares an enumeration tag. Use as a forward declaration. This is
- * printed without the items. *)
-
- | GVarDecl of varinfo * location
- (** A variable declaration (not a definition). If the variable has a
- function type then this is a prototype. There can be several
- declarations and at most one definition for a given variable. If both
- forms appear then they must share the same varinfo structure. A
- prototype shares the varinfo with the fundec of the definition. Either
- has storage Extern or there must be a definition in this file *)
-
- | GVar of varinfo * initinfo * location
- (** A variable definition. Can have an initializer. The initializer is
- * updateable so that you can change it without requiring to recreate
- * the list of globals. There can be at most one definition for a
- * variable in an entire program. Cannot have storage Extern or function
- * type. *)
-
-
- | GFun of fundec * location
- (** A function definition. *)
-
- | GAsm of string * location (** Global asm statement. These ones
- can contain only a template *)
- | GPragma of attribute * location (** Pragmas at top level. Use the same
- syntax as attributes *)
- | GText of string (** Some text (printed verbatim) at
- top level. E.g., this way you can
- put comments in the output. *)
-
-
-(** The various types available. Every type is associated with a list of
- * attributes, which are always kept in sorted order. Use {!Cil.addAttribute}
- * and {!Cil.addAttributes} to construct list of attributes. If you want to
- * inspect a type, you should use {!Cil.unrollType} to see through the uses
- * of named types. *)
-and typ =
- TVoid of attributes (** Void type *)
- | TInt of ikind * attributes (** An integer type. The kind specifies
- the sign and width. *)
- | TFloat of fkind * attributes (** A floating-point type. The kind
- specifies the precision. *)
-
- | TPtr of typ * attributes
- (** Pointer type. *)
-
- | TArray of typ * exp option * attributes
- (** Array type. It indicates the base type and the array length. *)
-
- | TFun of typ * (string * typ * attributes) list option * bool * attributes
- (** Function type. Indicates the type of the result, the name, type
- * and name attributes of the formal arguments ([None] if no
- * arguments were specified, as in a function whose definition or
- * prototype we have not seen; [Some \[\]] means void). Use
- * {!Cil.argsToList} to obtain a list of arguments. The boolean
- * indicates if it is a variable-argument function. If this is the
- * type of a varinfo for which we have a function declaration then
- * the information for the formals must match that in the
- * function's sformals. *)
-
- | TNamed of typeinfo * attributes
- (* The use of a named type. All uses of the same type name must
- * share the typeinfo. Each such type name must be preceeded
- * in the file by a [GType] global. This is printed as just the
- * type name. The actual referred type is not printed here and is
- * carried only to simplify processing. To see through a sequence
- * of named type references, use {!Cil.unrollType}. The attributes
- * are in addition to those given when the type name was defined. *)
-
- | TComp of compinfo * attributes
- (** A reference to a struct or a union type. All references to the
- same struct or union must share the same compinfo among them and
- with a [GCompTag] global that preceeds all uses (except maybe
- those that are pointers to the composite type). The attributes
- given are those pertaining to this use of the type and are in
- addition to the attributes that were given at the definition of
- the type and which are stored in the compinfo. *)
-
- | TEnum of enuminfo * attributes
- (** A reference to an enumeration type. All such references must
- share the enuminfo among them and with a [GEnumTag] global that
- preceeds all uses. The attributes refer to this use of the
- enumeration and are in addition to the attributes of the
- enumeration itself, which are stored inside the enuminfo *)
-
-
-
- | TBuiltin_va_list of attributes
- (** This is the same as the gcc's type with the same name *)
-
-(** Various kinds of integers *)
-and ikind =
- IChar (** [char] *)
- | ISChar (** [signed char] *)
- | IUChar (** [unsigned char] *)
- | IInt (** [int] *)
- | IUInt (** [unsigned int] *)
- | IShort (** [short] *)
- | IUShort (** [unsigned short] *)
- | ILong (** [long] *)
- | IULong (** [unsigned long] *)
- | ILongLong (** [long long] (or [_int64] on Microsoft Visual C) *)
- | IULongLong (** [unsigned long long] (or [unsigned _int64] on Microsoft
- Visual C) *)
-
-(** Various kinds of floating-point numbers*)
-and fkind =
- FFloat (** [float] *)
- | FDouble (** [double] *)
- | FLongDouble (** [long double] *)
-
-(** An attribute has a name and some optional parameters *)
-and attribute = Attr of string * attrparam list
-
-(** Attributes are lists sorted by the attribute name *)
-and attributes = attribute list
-
-(** The type of parameters in attributes *)
-and attrparam =
- | AInt of int (** An integer constant *)
- | AStr of string (** A string constant *)
- | ACons of string * attrparam list (** Constructed attributes. These
- are printed [foo(a1,a2,...,an)].
- The list of parameters can be
- empty and in that case the
- parentheses are not printed. *)
- | ASizeOf of typ (** A way to talk about types *)
- | ASizeOfE of attrparam
- | ASizeOfS of typsig (** Replacement for ASizeOf in type
- signatures. Only used for
- attributes inside typsigs.*)
- | AAlignOf of typ
- | AAlignOfE of attrparam
- | AAlignOfS of typsig
- | AUnOp of unop * attrparam
- | ABinOp of binop * attrparam * attrparam
- | ADot of attrparam * string (** a.foo **)
-
-
-(** Information about a composite type (a struct or a union). Use
- {!Cil.mkCompInfo}
- to create non-recursive or (potentially) recursive versions of this. Make
- sure you have a [GCompTag] for each one of these. *)
-and compinfo = {
- mutable cstruct: bool; (** True if struct, False if union *)
- mutable cname: string; (** The name. Always non-empty. Use
- * {!Cil.compFullName} to get the
- * full name of a comp (along with
- * the struct or union) *)
- mutable ckey: int; (** A unique integer constructed from
- * the name. Use {!Hashtbl.hash} on
- * the string returned by
- * {!Cil.compFullName}. All compinfo
- * for a given key are shared. *)
- mutable cfields: fieldinfo list; (** Information about the fields *)
- mutable cattr: attributes; (** The attributes that are defined at
- the same time as the composite
- type *)
- mutable cdefined: bool; (** Whether this is a defined
- * compinfo. *)
- mutable creferenced: bool; (** True if used. Initially set to
- * false *)
- }
-
-(** Information about a struct/union field *)
-and fieldinfo = {
- mutable fcomp: compinfo; (** The compinfo of the host. Note
- that this must be shared with the
- host since there can be only one
- compinfo for a given id *)
- mutable fname: string; (** The name of the field. Might be
- * the value of
- * {!Cil.missingFieldName} in which
- * case it must be a bitfield and is
- * not printed and it does not
- * participate in initialization *)
- mutable ftype: typ; (** The type *)
- mutable fbitfield: int option; (** If a bitfield then ftype should be
- an integer type *)
- mutable fattr: attributes; (** The attributes for this field
- * (not for its type) *)
- mutable floc: location; (** The location where this field
- * is defined *)
-}
-
-
-
-(** Information about an enumeration. This is shared by all references to an
- enumeration. Make sure you have a [GEnumTag] for each of of these. *)
-and enuminfo = {
- mutable ename: string; (** The name. Always non-empty *)
- mutable eitems: (string * exp * location) list; (** Items with names
- and values. This list
- should be
- non-empty. The item
- values must be
- compile-time
- constants. *)
- mutable eattr: attributes; (** Attributes *)
- mutable ereferenced: bool; (** True if used. Initially set to false*)
-}
-
-(** Information about a defined type *)
-and typeinfo = {
- mutable tname: string;
- (** The name. Can be empty only in a [GType] when introducing a composite
- * or enumeration tag. If empty cannot be refered to from the file *)
- mutable ttype: typ;
- (** The actual type. *)
- mutable treferenced: bool;
- (** True if used. Initially set to false*)
-}
-
-
-(** Information about a variable. These structures are shared by all
- * references to the variable. So, you can change the name easily, for
- * example. Use one of the {!Cil.makeLocalVar}, {!Cil.makeTempVar} or
- * {!Cil.makeGlobalVar} to create instances of this data structure. *)
-and varinfo = {
- mutable vname: string; (** The name of the variable. Cannot
- * be empty. *)
- mutable vtype: typ; (** The declared type of the
- * variable. *)
- mutable vattr: attributes; (** A list of attributes associated
- * with the variable. *)
- mutable vstorage: storage; (** The storage-class *)
- (* The other fields are not used in varinfo when they appear in the formal
- * argument list in a [TFun] type *)
-
-
- mutable vglob: bool; (** True if this is a global variable*)
-
- (** Whether this varinfo is for an inline function. *)
- mutable vinline: bool;
-
- mutable vdecl: location; (** Location of variable declaration *)
-
- mutable vid: int; (** A unique integer identifier. *)
- mutable vaddrof: bool; (** True if the address of this
- variable is taken. CIL will set
- * these flags when it parses C, but
- * you should make sure to set the
- * flag whenever your transformation
- * create [AddrOf] expression. *)
-
- mutable vreferenced: bool; (** True if this variable is ever
- referenced. This is computed by
- [removeUnusedVars]. It is safe to
- just initialize this to False *)
-}
-
-(** Storage-class information *)
-and storage =
- NoStorage | (** The default storage. Nothing is
- * printed *)
- Static |
- Register |
- Extern
-
-
-(** Expressions (Side-effect free)*)
-and exp =
- Const of constant (** Constant *)
- | Lval of lval (** Lvalue *)
- | SizeOf of typ (** sizeof(<type>). Has [unsigned
- * int] type (ISO 6.5.3.4). This is
- * not turned into a constant because
- * some transformations might want to
- * change types *)
-
- | SizeOfE of exp (** sizeof(<expression>) *)
- | SizeOfStr of string
- (** sizeof(string_literal). We separate this case out because this is the
- * only instance in which a string literal should not be treated as
- * having type pointer to character. *)
-
- | AlignOf of typ (** Has [unsigned int] type *)
- | AlignOfE of exp
-
-
- | UnOp of unop * exp * typ (** Unary operation. Includes
- the type of the result *)
-
- | BinOp of binop * exp * exp * typ
- (** Binary operation. Includes the
- type of the result. The arithemtic
- conversions are made explicit
- for the arguments *)
- | CastE of typ * exp (** Use {!Cil.mkCast} to make casts *)
-
- | AddrOf of lval (** Always use {!Cil.mkAddrOf} to
- * construct one of these. Apply to an
- * lvalue of type [T] yields an
- * expression of type [TPtr(T)] *)
-
- | StartOf of lval (** There is no C correspondent for this. C has
- * implicit coercions from an array to the address
- * of the first element. [StartOf] is used in CIL to
- * simplify type checking and is just an explicit
- * form of the above mentioned implicit conversion.
- * It is not printed. Given an lval of type
- * [TArray(T)] produces an expression of type
- * [TPtr(T)]. *)
-
-
-(** Literal constants *)
-and constant =
- | CInt64 of int64 * ikind * string option
- (** Integer constant. Give the ikind (see ISO9899 6.1.3.2)
- * and the textual representation, if available. Use
- * {!Cil.integer} or {!Cil.kinteger} to create these. Watch
- * out for integers that cannot be represented on 64 bits.
- * OCAML does not give Overflow exceptions. *)
- | CStr of string (** String constant (of pointer type) *)
- | CWStr of int64 list (** Wide string constant (of type "wchar_t *") *)
- | CChr of char (** Character constant. This has type int, so use
- * charConstToInt to read the value in case
- * sign-extension is needed. *)
- | CReal of float * fkind * string option (** Floating point constant. Give
- the fkind (see ISO 6.4.4.2) and
- also the textual representation,
- if available *)
- | CEnum of exp * string * enuminfo
- (** An enumeration constant with the given value, name, from the given
- * enuminfo. This is not used if {!Cil.lowerEnum} is false (default).
- * Use {!Cillower.lowerEnumVisitor} to replace these with integer
- * constants. *)
-
-(** Unary operators *)
-and unop =
- Neg (** Unary minus *)
- | BNot (** Bitwise complement (~) *)
- | LNot (** Logical Not (!) *)
-
-(** Binary operations *)
-and binop =
- PlusA (** arithmetic + *)
- | PlusPI (** pointer + integer *)
- | IndexPI (** pointer + integer but only when
- * it arises from an expression
- * [e\[i\]] when [e] is a pointer and
- * not an array. This is semantically
- * the same as PlusPI but CCured uses
- * this as a hint that the integer is
- * probably positive. *)
- | MinusA (** arithmetic - *)
- | MinusPI (** pointer - integer *)
- | MinusPP (** pointer - pointer *)
- | Mult (** * *)
- | Div (** / *)
- | Mod (** % *)
- | Shiftlt (** shift left *)
- | Shiftrt (** shift right *)
-
- | Lt (** < (arithmetic comparison) *)
- | Gt (** > (arithmetic comparison) *)
- | Le (** <= (arithmetic comparison) *)
- | Ge (** > (arithmetic comparison) *)
- | Eq (** == (arithmetic comparison) *)
- | Ne (** != (arithmetic comparison) *)
- | BAnd (** bitwise and *)
- | BXor (** exclusive-or *)
- | BOr (** inclusive-or *)
-
- | LAnd (** logical and *)
- | LOr (** logical or *)
-
-
-
-
-(** An lvalue denotes the contents of a range of memory addresses. This range
- * is denoted as a host object along with an offset within the object. The
- * host object can be of two kinds: a local or global variable, or an object
- * whose address is in a pointer expression. We distinguish the two cases so
- * that we can tell quickly whether we are accessing some component of a
- * variable directly or we are accessing a memory location through a pointer.*)
-and lval =
- lhost * offset
-
-(** The host part of an {!Cil.lval}. *)
-and lhost =
- | Var of varinfo
- (** The host is a variable. *)
-
- | Mem of exp
- (** The host is an object of type [T] when the expression has pointer
- * [TPtr(T)]. *)
-
-
-(** The offset part of an {!Cil.lval}. Each offset can be applied to certain
- * kinds of lvalues and its effect is that it advances the starting address
- * of the lvalue and changes the denoted type, essentially focussing to some
- * smaller lvalue that is contained in the original one. *)
-and offset =
- | NoOffset (** No offset. Can be applied to any lvalue and does
- * not change either the starting address or the type.
- * This is used when the lval consists of just a host
- * or as a terminator in a list of other kinds of
- * offsets. *)
-
- | Field of fieldinfo * offset
- (** A field offset. Can be applied only to an lvalue
- * that denotes a structure or a union that contains
- * the mentioned field. This advances the offset to the
- * beginning of the mentioned field and changes the
- * type to the type of the mentioned field. *)
-
- | Index of exp * offset
- (** An array index offset. Can be applied only to an
- * lvalue that denotes an array. This advances the
- * starting address of the lval to the beginning of the
- * mentioned array element and changes the denoted type
- * to be the type of the array element *)
-
-
-
-(* The following equivalences hold *)
-(* Mem(AddrOf(Mem a, aoff)), off = Mem a, aoff + off *)
-(* Mem(AddrOf(Var v, aoff)), off = Var v, aoff + off *)
-(* AddrOf (Mem a, NoOffset) = a *)
-
-(** Initializers for global variables. You can create an initializer with
- * {!Cil.makeZeroInit}. *)
-and init =
- | SingleInit of exp (** A single initializer *)
- | CompoundInit of typ * (offset * init) list
- (** Used only for initializers of structures, unions and arrays.
- * The offsets are all of the form [Field(f, NoOffset)] or
- * [Index(i, NoOffset)] and specify the field or the index being
- * initialized. For structures all fields
- * must have an initializer (except the unnamed bitfields), in
- * the proper order. This is necessary since the offsets are not
- * printed. For arrays the list must contain a prefix of the
- * initializers; the rest are 0-initialized.
- * For unions there must be exactly one initializer. If
- * the initializer is not for the first field then a field
- * designator is printed, so you better be on GCC since MSVC does
- * not understand this. You can scan an initializer list with
- * {!Cil.foldLeftCompound}. *)
-
-(** We want to be able to update an initializer in a global variable, so we
- * define it as a mutable field *)
-and initinfo = {
- mutable init : init option;
- }
-
-
-(** Function definitions. *)
-and fundec =
- { mutable svar: varinfo;
- (** Holds the name and type as a variable, so we can refer to it
- * easily from the program. All references to this function either
- * in a function call or in a prototype must point to the same
- * varinfo. *)
- mutable sformals: varinfo list;
- (** Formals. These must be shared with the formals that appear in the
- * type of the function. Use {!Cil.setFormals} or
- * {!Cil.setFunctionType} to set these
- * formals and ensure that they are reflected in the function type.
- * Do not make copies of these because the body refers to them. *)
- mutable slocals: varinfo list;
- (** Locals. Does not include the sformals. Do not make copies of
- * these because the body refers to them. *)
- mutable smaxid: int; (** Max local id. Starts at 0. *)
- mutable sbody: block; (** The function body. *)
- mutable smaxstmtid: int option; (** max id of a (reachable) statement
- * in this function, if we have
- * computed it. range = 0 ...
- * (smaxstmtid-1). This is computed by
- * {!Cil.computeCFGInfo}. *)
- mutable sallstmts: stmt list; (** After you call {!Cil.computeCFGInfo}
- * this field is set to contain all
- * statements in the function *)
- }
-
-
-(** A block is a sequence of statements with the control falling through from
- one element to the next *)
-and block =
- { mutable battrs: attributes; (** Attributes for the block *)
- mutable bstmts: stmt list; (** The statements comprising the block*)
- }
-
-
-(** Statements.
- The statement is the structural unit in the control flow graph. Use mkStmt
- to make a statement and then fill in the fields. *)
-and stmt = {
- mutable labels: label list; (** Whether the statement starts with
- some labels, case statements or
- default statement *)
- mutable skind: stmtkind; (** The kind of statement *)
-
- (* Now some additional control flow information. Initially this is not
- * filled in. *)
- mutable sid: int; (** A number (>= 0) that is unique
- in a function. *)
- mutable succs: stmt list; (** The successor statements. They can
- always be computed from the skind
- and the context in which this
- statement appears *)
- mutable preds: stmt list; (** The inverse of the succs function*)
- }
-
-(** Labels *)
-and label =
- Label of string * location * bool
- (** A real label. If the bool is "true", the label is from the
- * input source program. If the bool is "false", the label was
- * created by CIL or some other transformation *)
- | Case of exp * location (** A case statement *)
- | Default of location (** A default statement *)
-
-
-
-(* The various kinds of statements *)
-and stmtkind =
- | Instr of instr list (** A group of instructions that do not
- contain control flow. Control
- implicitly falls through. *)
- | Return of exp option * location (** The return statement. This is a
- leaf in the CFG. *)
-
- | Goto of stmt ref * location (** A goto statement. Appears from
- actual goto's in the code. *)
- | Break of location (** A break to the end of the nearest
- enclosing loop or Switch *)
- | Continue of location (** A continue to the start of the
- nearest enclosing loop *)
- | If of exp * block * block * location (** A conditional.
- Two successors, the "then" and
- the "else" branches. Both
- branches fall-through to the
- successor of the If statement *)
- | Switch of exp * block * (stmt list) * location
- (** A switch statement. The block
- contains within all of the cases.
- We also have direct pointers to the
- statements that implement the
- cases. Which cases they implement
- you can get from the labels of the
- statement *)
-
-(*
- | Loop of block * location * (stmt option) * (stmt option)
- (** A [while(1)] loop. The
- * termination test is implemented
- * in the body of a loop using a
- * [Break] statement. If
- * prepareCFG has been called, the
- * first stmt option will point to
- * the stmt containing the
- * continue label for this loop
- * and the second will point to
- * the stmt containing the break
- * label for this loop. *)
-*)
- | While of exp * block * location (** A while loop. *)
- | DoWhile of exp * block * location (** A do...while loop. *)
- | For of block * exp * block * block * location (** A for loop. *)
-
- | Block of block (** Just a block of statements. Use it
- as a way to keep some attributes
- local *)
- (** On MSVC we support structured exception handling. This is what you
- * might expect. Control can get into the finally block either from the
- * end of the body block, or if an exception is thrown. The location
- * corresponds to the try keyword. *)
- | TryFinally of block * block * location
-
- (** On MSVC we support structured exception handling. The try/except
- * statement is a bit tricky:
- __try { blk }
- __except (e) {
- handler
- }
-
- The argument to __except must be an expression. However, we keep a
- list of instructions AND an expression in case you need to make
- function calls. We'll print those as a comma expression. The control
- can get to the __except expression only if an exception is thrown.
- After that, depending on the value of the expression the control
- goes to the handler, propagates the exception, or retries the
- exception !!! The location corresponds to the try keyword.
- *)
- | TryExcept of block * (instr list * exp) * block * location
-
-
-(** Instructions. They may cause effects directly but may not have control
- flow.*)
-and instr =
- Set of lval * exp * location (** An assignment. A cast is present
- if the exp has different type
- from lval *)
- | Call of lval option * exp * exp list * location
- (** optional: result is an lval. A cast might be
- necessary if the declared result type of the
- function is not the same as that of the
- destination. If the function is declared then
- casts are inserted for those arguments that
- correspond to declared formals. (The actual
- number of arguments might be smaller or larger
- than the declared number of arguments. C allows
- this.) If the type of the result variable is not
- the same as the declared type of the function
- result then an implicit cast exists. *)
-
- (* See the GCC specification for the meaning of ASM.
- * If the source is MS VC then only the templates
- * are used *)
- (* sm: I've added a notes.txt file which contains more
- * information on interpreting Asm instructions *)
- | Asm of attributes * (* Really only const and volatile can appear
- * here *)
- string list * (* templates (CR-separated) *)
- (string * lval) list * (* outputs must be lvals with
- * constraints. I would like these
- * to be actually variables, but I
- * run into some trouble with ASMs
- * in the Linux sources *)
- (string * exp) list * (* inputs with constraints *)
- string list * (* register clobbers *)
- location
- (** An inline assembly instruction. The arguments are (1) a list of
- attributes (only const and volatile can appear here and only for
- GCC), (2) templates (CR-separated), (3) a list of
- outputs, each of which is an lvalue with a constraint, (4) a list
- of input expressions along with constraints, (5) clobbered
- registers, and (5) location information *)
-
-
-
-(** Describes a location in a source file *)
-and location = {
- line: int; (** The line number. -1 means "do not know" *)
- file: string; (** The name of the source file*)
- byte: int; (** The byte position in the source file *)
-}
-
-(* Type signatures. Two types are identical iff they have identical
- * signatures *)
-and typsig =
- TSArray of typsig * int64 option * attribute list
- | TSPtr of typsig * attribute list
- | TSComp of bool * string * attribute list
- | TSFun of typsig * typsig list * bool * attribute list
- | TSEnum of string * attribute list
- | TSBase of typ
-
-
-
-(** To be able to add/remove features easily, each feature should be package
- * as an interface with the following interface. These features should be *)
-type featureDescr = {
- fd_enabled: bool ref;
- (** The enable flag. Set to default value *)
-
- fd_name: string;
- (** This is used to construct an option "--doxxx" and "--dontxxx" that
- * enable and disable the feature *)
-
- fd_description: string;
- (* A longer name that can be used to document the new options *)
-
- fd_extraopt: (string * Arg.spec * string) list;
- (** Additional command line options *)
-
- fd_doit: (file -> unit);
- (** This performs the transformation *)
-
- fd_post_check: bool;
- (* Whether to perform a CIL consistency checking after this stage, if
- * checking is enabled (--check is passed to cilly) *)
-}
-
-let locUnknown = { line = -1;
- file = "";
- byte = -1;}
-
-(* A reference to the current location *)
-let currentLoc : location ref = ref locUnknown
-
-(* A reference to the current global being visited *)
-let currentGlobal: global ref = ref (GText "dummy")
-
-
-let compareLoc (a: location) (b: location) : int =
- let namecmp = compare a.file b.file in
- if namecmp != 0
- then namecmp
- else
- let linecmp = a.line - b.line in
- if linecmp != 0
- then linecmp
- else a.byte - b.byte
-
-let argsToList : (string * typ * attributes) list option
- -> (string * typ * attributes) list
- = function
- None -> []
- | Some al -> al
-
-
-(* A hack to allow forward reference of d_exp *)
-let pd_exp : (unit -> exp -> doc) ref =
- ref (fun _ -> E.s (E.bug "pd_exp not initialized"))
-
-(** Different visiting actions. 'a will be instantiated with [exp], [instr],
- etc. *)
-type 'a visitAction =
- SkipChildren (** Do not visit the children. Return
- the node as it is. *)
- | DoChildren (** Continue with the children of this
- node. Rebuild the node on return
- if any of the children changes
- (use == test) *)
- | ChangeTo of 'a (** Replace the expression with the
- given one *)
- | ChangeDoChildrenPost of 'a * ('a -> 'a) (** First consider that the entire
- exp is replaced by the first
- parameter. Then continue with
- the children. On return rebuild
- the node if any of the children
- has changed and then apply the
- function on the node *)
-
-
-
-(* sm/gn: cil visitor interface for traversing Cil trees. *)
-(* Use visitCilStmt and/or visitCilFile to use this. *)
-(* Some of the nodes are changed in place if the children are changed. Use
- * one of Change... actions if you want to copy the node *)
-
-(** A visitor interface for traversing CIL trees. Create instantiations of
- * this type by specializing the class {!Cil.nopCilVisitor}. *)
-class type cilVisitor = object
-
- method vvdec: varinfo -> varinfo visitAction
- (** Invoked for each variable declaration. The subtrees to be traversed
- * are those corresponding to the type and attributes of the variable.
- * Note that variable declarations are all the [GVar], [GVarDecl], [GFun],
- * all the [varinfo] in formals of function types, and the formals and
- * locals for function definitions. This means that the list of formals
- * in a function definition will be traversed twice, once as part of the
- * function type and second as part of the formals in a function
- * definition. *)
-
- method vvrbl: varinfo -> varinfo visitAction
- (** Invoked on each variable use. Here only the [SkipChildren] and
- * [ChangeTo] actions make sense since there are no subtrees. Note that
- * the type and attributes of the variable are not traversed for a
- * variable use *)
-
- method vexpr: exp -> exp visitAction
- (** Invoked on each expression occurence. The subtrees are the
- * subexpressions, the types (for a [Cast] or [SizeOf] expression) or the
- * variable use. *)
-
- method vlval: lval -> lval visitAction
- (** Invoked on each lvalue occurence *)
-
- method voffs: offset -> offset visitAction
- (** Invoked on each offset occurrence that is *not* as part
- * of an initializer list specification, i.e. in an lval or
- * recursively inside an offset. *)
-
- method vinitoffs: offset -> offset visitAction
- (** Invoked on each offset appearing in the list of a
- * CompoundInit initializer. *)
-
- method vinst: instr -> instr list visitAction
- (** Invoked on each instruction occurrence. The [ChangeTo] action can
- * replace this instruction with a list of instructions *)
-
- method vstmt: stmt -> stmt visitAction
- (** Control-flow statement. *)
-
- method vblock: block -> block visitAction (** Block. Replaced in
- place. *)
- method vfunc: fundec -> fundec visitAction (** Function definition.
- Replaced in place. *)
- method vglob: global -> global list visitAction (** Global (vars, types,
- etc.) *)
- method vinit: init -> init visitAction (** Initializers for globals *)
- method vtype: typ -> typ visitAction (** Use of some type. Note
- * that for structure/union
- * and enumeration types the
- * definition of the
- * composite type is not
- * visited. Use [vglob] to
- * visit it. *)
- method vattr: attribute -> attribute list visitAction
- (** Attribute. Each attribute can be replaced by a list *)
- method vattrparam: attrparam -> attrparam visitAction
- (** Attribute parameters. *)
-
- (** Add here instructions while visiting to queue them to
- * preceede the current statement or instruction being processed *)
- method queueInstr: instr list -> unit
-
- (** Gets the queue of instructions and resets the queue *)
- method unqueueInstr: unit -> instr list
-
-end
-
-(* the default visitor does nothing at each node, but does *)
-(* not stop; hence they return true *)
-class nopCilVisitor : cilVisitor = object
- method vvrbl (v:varinfo) = DoChildren (* variable *)
- method vvdec (v:varinfo) = DoChildren (* variable
- * declaration *)
- method vexpr (e:exp) = DoChildren (* expression *)
- method vlval (l:lval) = DoChildren (* lval (base is 1st
- * field) *)
- method voffs (o:offset) = DoChildren (* lval or recursive offset *)
- method vinitoffs (o:offset) = DoChildren (* initializer offset *)
- method vinst (i:instr) = DoChildren (* imperative instruction *)
- method vstmt (s:stmt) = DoChildren (* constrol-flow statement *)
- method vblock (b: block) = DoChildren
- method vfunc (f:fundec) = DoChildren (* function definition *)
- method vglob (g:global) = DoChildren (* global (vars, types, etc.) *)
- method vinit (i:init) = DoChildren (* global initializers *)
- method vtype (t:typ) = DoChildren (* use of some type *)
- method vattr (a: attribute) = DoChildren
- method vattrparam (a: attrparam) = DoChildren
-
- val mutable instrQueue = []
-
- method queueInstr (il: instr list) =
- List.iter (fun i -> instrQueue <- i :: instrQueue) il
-
- method unqueueInstr () =
- let res = List.rev instrQueue in
- instrQueue <- [];
- res
-
-end
-
-let assertEmptyQueue vis =
- if vis#unqueueInstr () <> [] then
- (* Either a visitor inserted an instruction somewhere that it shouldn't
- have (i.e. at the top level rather than inside of a statement), or
- there's a bug in the visitor engine. *)
- E.s (E.bug "Visitor's instruction queue is not empty.\n You should only use queueInstr inside a function body!");
- ()
-
-
-let lu = locUnknown
-
-(* sm: utility *)
-let startsWith (prefix: string) (s: string) : bool =
-(
- let prefixLen = (String.length prefix) in
- (String.length s) >= prefixLen &&
- (String.sub s 0 prefixLen) = prefix
-)
-
-
-let get_instrLoc (inst : instr) =
- match inst with
- Set(_, _, loc) -> loc
- | Call(_, _, _, loc) -> loc
- | Asm(_, _, _, _, _, loc) -> loc
-let get_globalLoc (g : global) =
- match g with
- | GFun(_,l) -> (l)
- | GType(_,l) -> (l)
- | GEnumTag(_,l) -> (l)
- | GEnumTagDecl(_,l) -> (l)
- | GCompTag(_,l) -> (l)
- | GCompTagDecl(_,l) -> (l)
- | GVarDecl(_,l) -> (l)
- | GVar(_,_,l) -> (l)
- | GAsm(_,l) -> (l)
- | GPragma(_,l) -> (l)
- | GText(_) -> locUnknown
-
-let rec get_stmtLoc (statement : stmtkind) =
- match statement with
- Instr([]) -> lu
- | Instr(hd::tl) -> get_instrLoc(hd)
- | Return(_, loc) -> loc
- | Goto(_, loc) -> loc
- | Break(loc) -> loc
- | Continue(loc) -> loc
- | If(_, _, _, loc) -> loc
- | Switch (_, _, _, loc) -> loc
-(*
- | Loop (_, loc, _, _) -> loc
-*)
- | While (_, _, loc) -> loc
- | DoWhile (_, _, loc) -> loc
- | For (_, _, _, _, loc) -> loc
- | Block b -> if b.bstmts == [] then lu
- else get_stmtLoc ((List.hd b.bstmts).skind)
- | TryFinally (_, _, l) -> l
- | TryExcept (_, _, _, l) -> l
-
-
-(* The next variable identifier to use. Counts up *)
-let nextGlobalVID = ref 1
-
-(* The next compindo identifier to use. Counts up. *)
-let nextCompinfoKey = ref 1
-
-(* Some error reporting functions *)
-let d_loc (_: unit) (loc: location) : doc =
- text loc.file ++ chr ':' ++ num loc.line
-
-let d_thisloc (_: unit) : doc = d_loc () !currentLoc
-
-let error (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- E.hadErrors := true;
- ignore (eprintf "@!%t: Error: %a@!"
- d_thisloc insert d);
- nil
- in
- Pretty.gprintf f fmt
-
-let unimp (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- E.hadErrors := true;
- ignore (eprintf "@!%t: Unimplemented: %a@!"
- d_thisloc insert d);
- nil
- in
- Pretty.gprintf f fmt
-
-let bug (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- E.hadErrors := true;
- ignore (eprintf "@!%t: Bug: %a@!"
- d_thisloc insert d);
- E.showContext ();
- nil
- in
- Pretty.gprintf f fmt
-
-let errorLoc (loc: location) (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- E.hadErrors := true;
- ignore (eprintf "@!%a: Error: %a@!"
- d_loc loc insert d);
- E.showContext ();
- nil
- in
- Pretty.gprintf f fmt
-
-let warn (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- ignore (eprintf "@!%t: Warning: %a@!"
- d_thisloc insert d);
- nil
- in
- Pretty.gprintf f fmt
-
-
-let warnOpt (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- if !E.warnFlag then
- ignore (eprintf "@!%t: Warning: %a@!"
- d_thisloc insert d);
- nil
- in
- Pretty.gprintf f fmt
-
-let warnContext (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- ignore (eprintf "@!%t: Warning: %a@!"
- d_thisloc insert d);
- E.showContext ();
- nil
- in
- Pretty.gprintf f fmt
-
-let warnContextOpt (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- if !E.warnFlag then
- ignore (eprintf "@!%t: Warning: %a@!"
- d_thisloc insert d);
- E.showContext ();
- nil
- in
- Pretty.gprintf f fmt
-
-let warnLoc (loc: location) (fmt : ('a,unit,doc) format) : 'a =
- let f d =
- ignore (eprintf "@!%a: Warning: %a@!"
- d_loc loc insert d);
- E.showContext ();
- nil
- in
- Pretty.gprintf f fmt
-
-
-
-(* Construct an integer. Use only for values that fit on 31 bits.
- For larger values, use kinteger *)
-let integer (i: int) = Const (CInt64(Int64.of_int i, IInt, None))
-
-let zero = integer 0
-let one = integer 1
-let mone = integer (-1)
-
-(** Given the character c in a (CChr c), sign-extend it to 32 bits.
- (This is the official way of interpreting character constants, according to
- ISO C 6.4.4.4.10, which says that character constants are chars cast to ints)
- Returns CInt64(sign-extened c, IInt, None) *)
-let charConstToInt (c: char) : constant =
- let c' = Char.code c in
- let value =
- if c' < 128
- then Int64.of_int c'
- else Int64.of_int (c' - 256)
- in
- CInt64(value, IInt, None)
-
-
-let rec isInteger = function
- | Const(CInt64 (n,_,_)) -> Some n
- | Const(CChr c) -> isInteger (Const (charConstToInt c)) (* sign-extend *)
- | Const(CEnum(v, s, ei)) -> isInteger v
- | CastE(_, e) -> isInteger e
- | _ -> None
-
-
-
-let rec isZero (e: exp) : bool = isInteger e = Some Int64.zero
-
-let voidType = TVoid([])
-let intType = TInt(IInt,[])
-let uintType = TInt(IUInt,[])
-let longType = TInt(ILong,[])
-let ulongType = TInt(IULong,[])
-let charType = TInt(IChar, [])
-
-let charPtrType = TPtr(charType,[])
-let charConstPtrType = TPtr(TInt(IChar, [Attr("const", [])]),[])
-let stringLiteralType = ref charPtrType
-
-let voidPtrType = TPtr(voidType, [])
-let intPtrType = TPtr(intType, [])
-let uintPtrType = TPtr(uintType, [])
-
-let doubleType = TFloat(FDouble, [])
-
-
-(* An integer type that fits pointers. Initialized by initCIL *)
-let upointType = ref voidType
-
-(* An integer type that fits wchar_t. Initialized by initCIL *)
-let wcharKind = ref IChar
-let wcharType = ref voidType
-
-
-(* An integer type that is the type of sizeof. Initialized by initCIL *)
-let typeOfSizeOf = ref voidType
-let kindOfSizeOf = ref IUInt
-
-let initCIL_called = ref false
-
-(** Returns true if and only if the given integer type is signed. *)
-let isSigned = function
- | IUChar
- | IUShort
- | IUInt
- | IULong
- | IULongLong ->
- false
- | ISChar
- | IShort
- | IInt
- | ILong
- | ILongLong ->
- true
- | IChar ->
- not !theMachine.M.char_is_unsigned
-
-let mkStmt (sk: stmtkind) : stmt =
- { skind = sk;
- labels = [];
- sid = -1; succs = []; preds = [] }
-
-let mkBlock (slst: stmt list) : block =
- { battrs = []; bstmts = slst; }
-
-let mkEmptyStmt () = mkStmt (Instr [])
-let mkStmtOneInstr (i: instr) = mkStmt (Instr [i])
-
-let dummyInstr = (Asm([], ["dummy statement!!"], [], [], [], lu))
-let dummyStmt = mkStmt (Instr [dummyInstr])
-
-let compactStmts (b: stmt list) : stmt list =
- (* Try to compress statements. Scan the list of statements and remember
- * the last instrunction statement encountered, along with a Clist of
- * instructions in it. *)
- let rec compress (lastinstrstmt: stmt) (* Might be dummStmt *)
- (lastinstrs: instr Clist.clist)
- (body: stmt list) =
- let finishLast (tail: stmt list) : stmt list =
- if lastinstrstmt == dummyStmt then tail
- else begin
- lastinstrstmt.skind <- Instr (Clist.toList lastinstrs);
- lastinstrstmt :: tail
- end
- in
- match body with
- [] -> finishLast []
- | ({skind=Instr il} as s) :: rest ->
- let ils = Clist.fromList il in
- if lastinstrstmt != dummyStmt && s.labels == [] then
- compress lastinstrstmt (Clist.append lastinstrs ils) rest
- else
- finishLast (compress s ils rest)
-
- | s :: rest ->
- let res = s :: compress dummyStmt Clist.empty rest in
- finishLast res
- in
- compress dummyStmt Clist.empty b
-
-
-(** Construct sorted lists of attributes ***)
-let rec addAttribute (Attr(an, _) as a: attribute) (al: attributes) =
- let rec insertSorted = function
- [] -> [a]
- | ((Attr(an0, _) as a0) :: rest) as l ->
- if an < an0 then a :: l
- else if Util.equals a a0 then l (* Do not add if already in there *)
- else a0 :: insertSorted rest (* Make sure we see all attributes with
- * this name *)
- in
- insertSorted al
-
-(** The second attribute list is sorted *)
-and addAttributes al0 (al: attributes) : attributes =
- if al0 == [] then al else
- List.fold_left (fun acc a -> addAttribute a acc) al al0
-
-and dropAttribute (an: string) (al: attributes) =
- List.filter (fun (Attr(an', _)) -> an <> an') al
-
-and dropAttributes (anl: string list) (al: attributes) =
- List.fold_left (fun acc an -> dropAttribute an acc) al anl
-
-and filterAttributes (s: string) (al: attribute list) : attribute list =
- List.filter (fun (Attr(an, _)) -> an = s) al
-
-(* sm: *)
-let hasAttribute s al =
- (filterAttributes s al <> [])
-
-
-type attributeClass =
- AttrName of bool
- (* Attribute of a name. If argument is true and we are on MSVC then
- * the attribute is printed using __declspec as part of the storage
- * specifier *)
- | AttrFunType of bool
- (* Attribute of a function type. If argument is true and we are on
- * MSVC then the attribute is printed just before the function name *)
-
- | AttrType (* Attribute of a type *)
-
-(* This table contains the mapping of predefined attributes to classes.
- * Extend this table with more attributes as you need. This table is used to
- * determine how to associate attributes with names or type during cabs2cil
- * conversion *)
-let attributeHash: (string, attributeClass) H.t =
- let table = H.create 13 in
- List.iter (fun a -> H.add table a (AttrName false))
- [ "section"; "constructor"; "destructor"; "unused"; "used"; "weak";
- "no_instrument_function"; "alias"; "no_check_memory_usage";
- "exception"; "model"; (* "restrict"; *)
- "aconst"; "__asm__" (* Gcc uses this to specifiy the name to be used in
- * assembly for a global *)];
-
- (* Now come the MSVC declspec attributes *)
- List.iter (fun a -> H.add table a (AttrName true))
- [ "thread"; "naked"; "dllimport"; "dllexport";
- "selectany"; "allocate"; "nothrow"; "novtable"; "property"; "noreturn";
- "uuid"; "align" ];
-
- List.iter (fun a -> H.add table a (AttrFunType false))
- [ "format"; "regparm"; "longcall";
- "noinline"; "always_inline"; ];
-
- List.iter (fun a -> H.add table a (AttrFunType true))
- [ "stdcall";"cdecl"; "fastcall" ];
-
- List.iter (fun a -> H.add table a AttrType)
- [ "const"; "volatile"; "restrict"; "mode" ];
- table
-
-
-(* Partition the attributes into classes *)
-let partitionAttributes
- ~(default:attributeClass)
- (attrs: attribute list) :
- attribute list * attribute list * attribute list =
- let rec loop (n,f,t) = function
- [] -> n, f, t
- | (Attr(an, _) as a) :: rest ->
- match (try H.find attributeHash an with Not_found -> default) with
- AttrName _ -> loop (addAttribute a n, f, t) rest
- | AttrFunType _ ->
- loop (n, addAttribute a f, t) rest
- | AttrType -> loop (n, f, addAttribute a t) rest
- in
- loop ([], [], []) attrs
-
-
-(* Get the full name of a comp *)
-let compFullName comp =
- (if comp.cstruct then "struct " else "union ") ^ comp.cname
-
-
-let missingFieldName = "___missing_field_name"
-
-(** Creates a a (potentially recursive) composite type. Make sure you add a
- * GTag for it to the file! **)
-let mkCompInfo
- (isstruct: bool)
- (n: string)
- (* fspec is a function that when given a forward
- * representation of the structure type constructs the type of
- * the fields. The function can ignore this argument if not
- * constructing a recursive type. *)
- (mkfspec: compinfo -> (string * typ * int option * attribute list *
- location) list)
- (a: attribute list) : compinfo =
-
- (* make an new name for anonymous structs *)
- if n = "" then
- E.s (E.bug "mkCompInfo: missing structure name\n");
- (* Make a new self cell and a forward reference *)
- let comp =
- { cstruct = isstruct; cname = ""; ckey = 0; cfields = [];
- cattr = a; creferenced = false;
- (* Make this compinfo undefined by default *)
- cdefined = false; }
- in
- comp.cname <- n;
- comp.ckey <- !nextCompinfoKey;
- incr nextCompinfoKey;
- let flds =
- List.map (fun (fn, ft, fb, fa, fl) ->
- { fcomp = comp;
- ftype = ft;
- fname = fn;
- fbitfield = fb;
- fattr = fa;
- floc = fl}) (mkfspec comp) in
- comp.cfields <- flds;
- if flds <> [] then comp.cdefined <- true;
- comp
-
-(** Make a copy of a compinfo, changing the name and the key *)
-let copyCompInfo (ci: compinfo) (n: string) : compinfo =
- let ci' = {ci with cname = n;
- ckey = !nextCompinfoKey; } in
- incr nextCompinfoKey;
- (* Copy the fields and set the new pointers to parents *)
- ci'.cfields <- List.map (fun f -> {f with fcomp = ci'}) ci'.cfields;
- ci'
-
-(**** Utility functions ******)
-
-let rec typeAttrs = function
- TVoid a -> a
- | TInt (_, a) -> a
- | TFloat (_, a) -> a
- | TNamed (t, a) -> addAttributes a (typeAttrs t.ttype)
- | TPtr (_, a) -> a
- | TArray (_, _, a) -> a
- | TComp (comp, a) -> addAttributes comp.cattr a
- | TEnum (enum, a) -> addAttributes enum.eattr a
- | TFun (_, _, _, a) -> a
- | TBuiltin_va_list a -> a
-
-
-let setTypeAttrs t a =
- match t with
- TVoid _ -> TVoid a
- | TInt (i, _) -> TInt (i, a)
- | TFloat (f, _) -> TFloat (f, a)
- | TNamed (t, _) -> TNamed(t, a)
- | TPtr (t', _) -> TPtr(t', a)
- | TArray (t', l, _) -> TArray(t', l, a)
- | TComp (comp, _) -> TComp (comp, a)
- | TEnum (enum, _) -> TEnum (enum, a)
- | TFun (r, args, v, _) -> TFun(r,args,v,a)
- | TBuiltin_va_list _ -> TBuiltin_va_list a
-
-
-let typeAddAttributes a0 t =
-begin
- match a0 with
- | [] ->
- (* no attributes, keep same type *)
- t
- | _ ->
- (* anything else: add a0 to existing attributes *)
- let add (a: attributes) = addAttributes a0 a in
- match t with
- TVoid a -> TVoid (add a)
- | TInt (ik, a) -> TInt (ik, add a)
- | TFloat (fk, a) -> TFloat (fk, add a)
- | TEnum (enum, a) -> TEnum (enum, add a)
- | TPtr (t, a) -> TPtr (t, add a)
- | TArray (t, l, a) -> TArray (t, l, add a)
- | TFun (t, args, isva, a) -> TFun(t, args, isva, add a)
- | TComp (comp, a) -> TComp (comp, add a)
- | TNamed (t, a) -> TNamed (t, add a)
- | TBuiltin_va_list a -> TBuiltin_va_list (add a)
-end
-
-let typeRemoveAttributes (anl: string list) t =
- let drop (al: attributes) = dropAttributes anl al in
- match t with
- TVoid a -> TVoid (drop a)
- | TInt (ik, a) -> TInt (ik, drop a)
- | TFloat (fk, a) -> TFloat (fk, drop a)
- | TEnum (enum, a) -> TEnum (enum, drop a)
- | TPtr (t, a) -> TPtr (t, drop a)
- | TArray (t, l, a) -> TArray (t, l, drop a)
- | TFun (t, args, isva, a) -> TFun(t, args, isva, drop a)
- | TComp (comp, a) -> TComp (comp, drop a)
- | TNamed (t, a) -> TNamed (t, drop a)
- | TBuiltin_va_list a -> TBuiltin_va_list (drop a)
-
-let unrollType (t: typ) : typ =
- let rec withAttrs (al: attributes) (t: typ) : typ =
- match t with
- TNamed (r, a') -> withAttrs (addAttributes al a') r.ttype
- | x -> typeAddAttributes al x
- in
- withAttrs [] t
-
-let rec unrollTypeDeep (t: typ) : typ =
- let rec withAttrs (al: attributes) (t: typ) : typ =
- match t with
- TNamed (r, a') -> withAttrs (addAttributes al a') r.ttype
- | TPtr(t, a') -> TPtr(unrollTypeDeep t, addAttributes al a')
- | TArray(t, l, a') -> TArray(unrollTypeDeep t, l, addAttributes al a')
- | TFun(rt, args, isva, a') ->
- TFun (unrollTypeDeep rt,
- (match args with
- None -> None
- | Some argl ->
- Some (List.map (fun (an,at,aa) ->
- (an, unrollTypeDeep at, aa)) argl)),
- isva,
- addAttributes al a')
- | x -> typeAddAttributes al x
- in
- withAttrs [] t
-
-let isVoidType t =
- match unrollType t with
- TVoid _ -> true
- | _ -> false
-let isVoidPtrType t =
- match unrollType t with
- TPtr(tau,_) when isVoidType tau -> true
- | _ -> false
-
-let var vi : lval = (Var vi, NoOffset)
-(* let assign vi e = Instrs(Set (var vi, e), lu) *)
-
-let mkString s = Const(CStr s)
-
-
-let mkWhile ~(guard:exp) ~(body: stmt list) : stmt list =
- (* Do it like this so that the pretty printer recognizes it *)
-(*
- [ mkStmt (Loop (mkBlock (mkStmt (If(guard,
- mkBlock [ mkEmptyStmt () ],
- mkBlock [ mkStmt (Break lu)], lu)) ::
- body), lu, None, None)) ]
-*)
- [ mkStmt (While (guard, mkBlock body, lu)) ]
-
-
-
-let mkFor ~(start: stmt list) ~(guard: exp) ~(next: stmt list)
- ~(body: stmt list) : stmt list =
- (start @
- (mkWhile guard (body @ next)))
-
-
-let mkForIncr ~(iter : varinfo) ~(first: exp) ~stopat:(past: exp) ~(incr: exp)
- ~(body: stmt list) : stmt list =
- (* See what kind of operator we need *)
- let compop, nextop =
- match unrollType iter.vtype with
- TPtr _ -> Lt, PlusPI
- | _ -> Lt, PlusA
- in
- mkFor
- [ mkStmt (Instr [(Set (var iter, first, lu))]) ]
- (BinOp(compop, Lval(var iter), past, intType))
- [ mkStmt (Instr [(Set (var iter,
- (BinOp(nextop, Lval(var iter), incr, iter.vtype)),
- lu))])]
- body
-
-
-let rec stripCasts (e: exp) =
- match e with CastE(_, e') -> stripCasts e' | _ -> e
-
-
-
-(* the name of the C function we call to get ccgr ASTs
-external parse : string -> file = "cil_main"
-*)
-(*
- Pretty Printing
- *)
-
-let d_ikind () = function
- IChar -> text "char"
- | ISChar -> text "signed char"
- | IUChar -> text "unsigned char"
- | IInt -> text "int"
- | IUInt -> text "unsigned int"
- | IShort -> text "short"
- | IUShort -> text "unsigned short"
- | ILong -> text "long"
- | IULong -> text "unsigned long"
- | ILongLong ->
- if !msvcMode then text "__int64" else text "long long"
- | IULongLong ->
- if !msvcMode then text "unsigned __int64"
- else text "unsigned long long"
-
-let d_fkind () = function
- FFloat -> text "float"
- | FDouble -> text "double"
- | FLongDouble -> text "long double"
-
-let d_storage () = function
- NoStorage -> nil
- | Static -> text "static "
- | Extern -> text "extern "
- | Register -> text "register "
-
-(* sm: need this value below *)
-let mostNeg32BitInt : int64 = (Int64.of_string "-0x80000000")
-let mostNeg64BitInt : int64 = (Int64.of_string "-0x8000000000000000")
-
-(* constant *)
-let d_const () c =
- match c with
- CInt64(_, _, Some s) -> text s (* Always print the text if there is one *)
- | CInt64(i, ik, None) ->
- (** We must make sure to capture the type of the constant. For some
- * constants this is done with a suffix, for others with a cast prefix.*)
- let suffix : string =
- match ik with
- IUInt -> "U"
- | ILong -> "L"
- | IULong -> "UL"
- | ILongLong -> if !msvcMode then "L" else "LL"
- | IULongLong -> if !msvcMode then "UL" else "ULL"
- | _ -> ""
- in
- let prefix : string =
- if suffix <> "" then ""
- else if ik = IInt then ""
- else "(" ^ (sprint !lineLength (d_ikind () ik)) ^ ")"
- in
- (* Watch out here for negative integers that we should be printing as
- * large positive ones *)
- if i < Int64.zero
- && (match ik with
- IUInt | IULong | IULongLong | IUChar | IUShort -> true | _ -> false) then
- let high = Int64.shift_right i 32 in
- if ik <> IULongLong && ik <> ILongLong && high = Int64.of_int (-1) then
- (* Print only the low order 32 bits *)
- text (prefix ^ "0x" ^
- (Int64.format "%x"
- (Int64.logand i (Int64.shift_right_logical high 32))
- ^ suffix))
- else
- text (prefix ^ "0x" ^ Int64.format "%x" i ^ suffix)
- else (
- if (i = mostNeg32BitInt) then
- (* sm: quirk here: if you print -2147483648 then this is two tokens *)
- (* in C, and the second one is too large to represent in a signed *)
- (* int.. so we do what's done in limits.h, and print (-2147483467-1); *)
- (* in gcc this avoids a warning, but it might avoid a real problem *)
- (* on another compiler or a 64-bit architecture *)
- text (prefix ^ "(-0x7FFFFFFF-1)")
- else if (i = mostNeg64BitInt) then
- (* The same is true of the largest 64-bit negative. *)
- text (prefix ^ "(-0x7FFFFFFFFFFFFFFF-1)")
- else
- text (prefix ^ (Int64.to_string i ^ suffix))
- )
-
- | CStr(s) -> text ("\"" ^ escape_string s ^ "\"")
- | CWStr(s) ->
- (* text ("L\"" ^ escape_string s ^ "\"") *)
- (List.fold_left (fun acc elt ->
- acc ++
- if (elt >= Int64.zero &&
- elt <= (Int64.of_int 255)) then
- text (escape_char (Char.chr (Int64.to_int elt)))
- else
- ( text (Printf.sprintf "\\x%LX\"" elt) ++ break ++
- (text "\""))
- ) (text "L\"") s ) ++ text "\""
- (* we cannot print L"\xabcd" "feedme" as L"\xabcdfeedme" --
- * the former has 7 wide characters and the later has 3. *)
-
- | CChr(c) -> text ("'" ^ escape_char c ^ "'")
- | CReal(_, _, Some s) -> text s
- | CReal(f, _, None) -> text (string_of_float f)
- | CEnum(_, s, ei) -> text s
-
-
-(* Parentheses level. An expression "a op b" is printed parenthesized if its
- * parentheses level is >= that that of its context. Identifiers have the
- * lowest level and weakly binding operators (e.g. |) have the largest level.
- * The correctness criterion is that a smaller level MUST correspond to a
- * stronger precedence!
- *)
-let derefStarLevel = 20
-let indexLevel = 20
-let arrowLevel = 20
-let addrOfLevel = 30
-let additiveLevel = 60
-let comparativeLevel = 70
-let bitwiseLevel = 75
-let getParenthLevel = function
- | BinOp((LAnd | LOr), _,_,_) -> 80
- (* Bit operations. *)
- | BinOp((BOr|BXor|BAnd),_,_,_) -> bitwiseLevel (* 75 *)
-
- (* Comparisons *)
- | BinOp((Eq|Ne|Gt|Lt|Ge|Le),_,_,_) ->
- comparativeLevel (* 70 *)
- (* Additive. Shifts can have higher
- * level than + or - but I want
- * parentheses around them *)
- | BinOp((MinusA|MinusPP|MinusPI|PlusA|
- PlusPI|IndexPI|Shiftlt|Shiftrt),_,_,_)
- -> additiveLevel (* 60 *)
-
- (* Multiplicative *)
- | BinOp((Div|Mod|Mult),_,_,_) -> 40
-
- (* Unary *)
- | CastE(_,_) -> 30
- | AddrOf(_) -> 30
- | StartOf(_) -> 30
- | UnOp((Neg|BNot|LNot),_,_) -> 30
-
- (* Lvals *)
- | Lval(Mem _ , _) -> 20
- | Lval(Var _, (Field _|Index _)) -> 20
- | SizeOf _ | SizeOfE _ | SizeOfStr _ -> 20
- | AlignOf _ | AlignOfE _ -> 20
-
- | Lval(Var _, NoOffset) -> 0 (* Plain variables *)
- | Const _ -> 0 (* Constants *)
-
-
-
-(* Separate out the storage-modifier name attributes *)
-let separateStorageModifiers (al: attribute list) =
- let isstoragemod (Attr(an, _): attribute) : bool =
- try
- match H.find attributeHash an with
- AttrName issm -> issm
- | _ -> E.s (E.bug "separateStorageModifier: %s is not a name attribute" an)
- with Not_found -> false
- in
- let stom, rest = List.partition isstoragemod al in
- if not !msvcMode then
- stom, rest
- else
- (* Put back the declspec. Put it without the leading __ since these will
- * be added later *)
- let stom' =
- List.map (fun (Attr(an, args)) ->
- Attr("declspec", [ACons(an, args)])) stom in
- stom', rest
-
-
-let isIntegralType t =
- match unrollType t with
- (TInt _ | TEnum _) -> true
- | _ -> false
-
-let isArithmeticType t =
- match unrollType t with
- (TInt _ | TEnum _ | TFloat _) -> true
- | _ -> false
-
-
-let isPointerType t =
- match unrollType t with
- TPtr _ -> true
- | _ -> false
-
-let isFunctionType t =
- match unrollType t with
- TFun _ -> true
- | _ -> false
-
-(**** Compute the type of an expression ****)
-let rec typeOf (e: exp) : typ =
- match e with
- | Const(CInt64 (_, ik, _)) -> TInt(ik, [])
-
- (* Character constants have type int. ISO/IEC 9899:1999 (E),
- * section 6.4.4.4 [Character constants], paragraph 10, if you
- * don't believe me. *)
- | Const(CChr _) -> intType
-
- (* The type of a string is a pointer to characters ! The only case when
- * you would want it to be an array is as an argument to sizeof, but we
- * have SizeOfStr for that *)
- | Const(CStr s) -> !stringLiteralType
-
- | Const(CWStr s) -> TPtr(!wcharType,[])
-
- | Const(CReal (_, fk, _)) -> TFloat(fk, [])
-
- | Const(CEnum(_, _, ei)) -> TEnum(ei, [])
-
- | Lval(lv) -> typeOfLval lv
- | SizeOf _ | SizeOfE _ | SizeOfStr _ -> !typeOfSizeOf
- | AlignOf _ | AlignOfE _ -> !typeOfSizeOf
- | UnOp (_, _, t) -> t
- | BinOp (_, _, _, t) -> t
- | CastE (t, _) -> t
- | AddrOf (lv) -> TPtr(typeOfLval lv, [])
- | StartOf (lv) -> begin
- match unrollType (typeOfLval lv) with
- TArray (t,_, _) -> TPtr(t, [])
- | _ -> E.s (E.bug "typeOf: StartOf on a non-array")
- end
-
-and typeOfInit (i: init) : typ =
- match i with
- SingleInit e -> typeOf e
- | CompoundInit (t, _) -> t
-
-and typeOfLval = function
- Var vi, off -> typeOffset vi.vtype off
- | Mem addr, off -> begin
- match unrollType (typeOf addr) with
- TPtr (t, _) -> typeOffset t off
- | _ -> E.s (bug "typeOfLval: Mem on a non-pointer")
- end
-
-and typeOffset basetyp =
- let blendAttributes baseAttrs =
- let (_, _, contageous) =
- partitionAttributes ~default:(AttrName false) baseAttrs in
- typeAddAttributes contageous
- in
- function
- NoOffset -> basetyp
- | Index (_, o) -> begin
- match unrollType basetyp with
- TArray (t, _, baseAttrs) ->
- let elementType = typeOffset t o in
- blendAttributes baseAttrs elementType
- | t -> E.s (E.bug "typeOffset: Index on a non-array")
- end
- | Field (fi, o) ->
- match unrollType basetyp with
- TComp (_, baseAttrs) ->
- let fieldType = typeOffset fi.ftype o in
- blendAttributes baseAttrs fieldType
- | _ -> E.s (bug "typeOffset: Field on a non-compound")
-
-
-(**
- **
- ** MACHINE DEPENDENT PART
- **
- **)
-exception SizeOfError of string * typ
-
-
-(* Get the minimum aligment in bytes for a given type *)
-let rec alignOf_int = function
- | TInt((IChar|ISChar|IUChar), _) -> 1
- | TInt((IShort|IUShort), _) -> !theMachine.M.alignof_short
- | TInt((IInt|IUInt), _) -> !theMachine.M.alignof_int
- | TInt((ILong|IULong), _) -> !theMachine.M.alignof_long
- | TInt((ILongLong|IULongLong), _) -> !theMachine.M.alignof_longlong
- | TEnum _ -> !theMachine.M.alignof_enum
- | TFloat(FFloat, _) -> !theMachine.M.alignof_float
- | TFloat(FDouble, _) -> !theMachine.M.alignof_double
- | TFloat(FLongDouble, _) -> !theMachine.M.alignof_longdouble
- | TNamed (t, _) -> alignOf_int t.ttype
- | TArray (t, _, _) -> alignOf_int t
- | TPtr _ | TBuiltin_va_list _ -> !theMachine.M.alignof_ptr
-
- (* For composite types get the maximum alignment of any field inside *)
- | TComp (c, _) ->
- (* On GCC the zero-width fields do not contribute to the alignment. On
- * MSVC only those zero-width that _do_ appear after other
- * bitfields contribute to the alignment. So we drop those that
- * do not occur after othe bitfields *)
- let rec dropZeros (afterbitfield: bool) = function
- | f :: rest when f.fbitfield = Some 0 && not afterbitfield ->
- dropZeros afterbitfield rest
- | f :: rest -> f :: dropZeros (f.fbitfield <> None) rest
- | [] -> []
- in
- let fields = dropZeros false c.cfields in
- List.fold_left
- (fun sofar f ->
- (* Bitfields with zero width do not contribute to the alignment in
- * GCC *)
- if not !msvcMode && f.fbitfield = Some 0 then sofar else
- max sofar (alignOf_int f.ftype)) 1 fields
- (* These are some error cases *)
- | TFun _ when not !msvcMode -> !theMachine.M.alignof_fun
-
- | TFun _ as t -> raise (SizeOfError ("function", t))
- | TVoid _ as t -> raise (SizeOfError ("void", t))
-
-
-let bitsSizeOfInt (ik: ikind): int =
- match ik with
- | IChar | ISChar | IUChar -> 8
- | IInt | IUInt -> 8 * !theMachine.M.sizeof_int
- | IShort | IUShort -> 8 * !theMachine.M.sizeof_short
- | ILong | IULong -> 8 * !theMachine.M.sizeof_long
- | ILongLong | IULongLong -> 8 * !theMachine.M.sizeof_longlong
-
-(* Represents an integer as for a given kind.
- Returns a flag saying whether the value was changed
- during truncation (because it was too large to fit in k). *)
-let truncateInteger64 (k: ikind) (i: int64) : int64 * bool =
- let nrBits = bitsSizeOfInt k in
- let signed = isSigned k in
- if nrBits = 64 then
- i, false
- else begin
- let i1 = Int64.shift_left i (64 - nrBits) in
- let i2 =
- if signed then Int64.shift_right i1 (64 - nrBits)
- else Int64.shift_right_logical i1 (64 - nrBits)
- in
- let truncated =
- if i2 = i then false
- else
- (* Examine the bits that we chopped off. If they are all zero, then
- * any difference between i2 and i is due to a simple sign-extension.
- * e.g. casting the constant 0x80000000 to int makes it
- * 0xffffffff80000000.
- * Suppress the truncation warning in this case. *)
- let chopped = Int64.shift_right_logical i (64 - nrBits)
- in chopped <> Int64.zero
- in
- i2, truncated
- end
-
-(* Construct an integer constant with possible truncation *)
-let kinteger64 (k: ikind) (i: int64) : exp =
- let i', truncated = truncateInteger64 k i in
- if truncated then
- ignore (warnOpt "Truncating integer %s to %s\n"
- (Int64.format "0x%x" i) (Int64.format "0x%x" i'));
- Const (CInt64(i', k, None))
-
-(* Construct an integer of a given kind. *)
-let kinteger (k: ikind) (i: int) = kinteger64 k (Int64.of_int i)
-
-
-type offsetAcc =
- { oaFirstFree: int; (* The first free bit *)
- oaLastFieldStart: int; (* Where the previous field started *)
- oaLastFieldWidth: int; (* The width of the previous field. Might not
- * be same as FirstFree - FieldStart because
- * of internal padding *)
- oaPrevBitPack: (int * ikind * int) option; (* If the previous fields
- * were packed bitfields,
- * the bit where packing
- * has started, the ikind
- * of the bitfield and the
- * width of the ikind *)
- }
-
-
-(* GCC version *)
-(* Does not use the sofar.oaPrevBitPack *)
-let rec offsetOfFieldAcc_GCC (fi: fieldinfo)
- (sofar: offsetAcc) : offsetAcc =
- (* field type *)
- let ftype = unrollType fi.ftype in
- let ftypeAlign = 8 * alignOf_int ftype in
- let ftypeBits = bitsSizeOf ftype in
-(*
- if fi.fcomp.cname = "comp2468" ||
- fi.fcomp.cname = "comp2469" ||
- fi.fcomp.cname = "comp2470" ||
- fi.fcomp.cname = "comp2471" ||
- fi.fcomp.cname = "comp2472" ||
- fi.fcomp.cname = "comp2473" ||
- fi.fcomp.cname = "comp2474" ||
- fi.fcomp.cname = "comp2475" ||
- fi.fcomp.cname = "comp2476" ||
- fi.fcomp.cname = "comp2477" ||
- fi.fcomp.cname = "comp2478" then
-
- ignore (E.log "offsetOfFieldAcc_GCC(%s of %s:%a%a,firstFree=%d,pack=%a)\n"
- fi.fname fi.fcomp.cname
- d_type ftype
- insert
- (match fi.fbitfield with
- None -> nil
- | Some wdthis -> dprintf ":%d" wdthis)
- sofar.oaFirstFree
- insert
- (match sofar.oaPrevBitPack with
- None -> text "None"
- | Some (packstart, _, wdpack) ->
- dprintf "Some(packstart=%d,wd=%d)"
- packstart wdpack));
-*)
- match ftype, fi.fbitfield with
- (* A width of 0 means that we must end the current packing. It seems that
- * GCC pads only up to the alignment boundary for the type of this field.
- * *)
- | _, Some 0 ->
- let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
- { oaFirstFree = firstFree;
- oaLastFieldStart = firstFree;
- oaLastFieldWidth = 0;
- oaPrevBitPack = None }
-
- (* A bitfield cannot span more alignment boundaries of its type than the
- * type itself *)
- | _, Some wdthis
- when (sofar.oaFirstFree + wdthis + ftypeAlign - 1) / ftypeAlign
- - sofar.oaFirstFree / ftypeAlign > ftypeBits / ftypeAlign ->
- let start = addTrailing sofar.oaFirstFree ftypeAlign in
- { oaFirstFree = start + wdthis;
- oaLastFieldStart = start;
- oaLastFieldWidth = wdthis;
- oaPrevBitPack = None }
-
- (* Try a simple method. Just put the field down *)
- | _, Some wdthis ->
- { oaFirstFree = sofar.oaFirstFree + wdthis;
- oaLastFieldStart = sofar.oaFirstFree;
- oaLastFieldWidth = wdthis;
- oaPrevBitPack = None
- }
-
- (* Non-bitfield *)
- | _, None ->
- (* Align this field *)
- let newStart = addTrailing sofar.oaFirstFree ftypeAlign in
- { oaFirstFree = newStart + ftypeBits;
- oaLastFieldStart = newStart;
- oaLastFieldWidth = ftypeBits;
- oaPrevBitPack = None;
- }
-
-(* MSVC version *)
-and offsetOfFieldAcc_MSVC (fi: fieldinfo)
- (sofar: offsetAcc) : offsetAcc =
- (* field type *)
- let ftype = unrollType fi.ftype in
- let ftypeAlign = 8 * alignOf_int ftype in
- let ftypeBits = bitsSizeOf ftype in
-(*
- ignore (E.log "offsetOfFieldAcc_MSVC(%s of %s:%a%a,firstFree=%d, pack=%a)\n"
- fi.fname fi.fcomp.cname
- d_type ftype
- insert
- (match fi.fbitfield with
- None -> nil
- | Some wdthis -> dprintf ":%d" wdthis)
- sofar.oaFirstFree
- insert
- (match sofar.oaPrevBitPack with
- None -> text "None"
- | Some (prevpack, _, wdpack) -> dprintf "Some(prev=%d,wd=%d)"
- prevpack wdpack));
-*)
- match ftype, fi.fbitfield, sofar.oaPrevBitPack with
- (* Ignore zero-width bitfields that come after non-bitfields *)
- | TInt (ikthis, _), Some 0, None ->
- let firstFree = sofar.oaFirstFree in
- { oaFirstFree = firstFree;
- oaLastFieldStart = firstFree;
- oaLastFieldWidth = 0;
- oaPrevBitPack = None }
-
- (* If we are in a bitpack and we see a bitfield for a type with the
- * different width than the pack, then we finish the pack and retry *)
- | _, Some _, Some (packstart, _, wdpack) when wdpack != ftypeBits ->
- let firstFree =
- if sofar.oaFirstFree = packstart then packstart else
- packstart + wdpack
- in
- offsetOfFieldAcc_MSVC fi
- { oaFirstFree = addTrailing firstFree ftypeAlign;
- oaLastFieldStart = sofar.oaLastFieldStart;
- oaLastFieldWidth = sofar.oaLastFieldWidth;
- oaPrevBitPack = None }
-
- (* A width of 0 means that we must end the current packing. *)
- | TInt (ikthis, _), Some 0, Some (packstart, _, wdpack) ->
- let firstFree =
- if sofar.oaFirstFree = packstart then packstart else
- packstart + wdpack
- in
- let firstFree = addTrailing firstFree ftypeAlign in
- { oaFirstFree = firstFree;
- oaLastFieldStart = firstFree;
- oaLastFieldWidth = 0;
- oaPrevBitPack = Some (firstFree, ikthis, ftypeBits) }
-
- (* Check for a bitfield that fits in the current pack after some other
- * bitfields *)
- | TInt(ikthis, _), Some wdthis, Some (packstart, ikprev, wdpack)
- when packstart + wdpack >= sofar.oaFirstFree + wdthis ->
- { oaFirstFree = sofar.oaFirstFree + wdthis;
- oaLastFieldStart = sofar.oaFirstFree;
- oaLastFieldWidth = wdthis;
- oaPrevBitPack = sofar.oaPrevBitPack
- }
-
-
- | _, _, Some (packstart, _, wdpack) -> (* Finish up the bitfield pack and
- * restart. *)
- let firstFree =
- if sofar.oaFirstFree = packstart then packstart else
- packstart + wdpack
- in
- offsetOfFieldAcc_MSVC fi
- { oaFirstFree = addTrailing firstFree ftypeAlign;
- oaLastFieldStart = sofar.oaLastFieldStart;
- oaLastFieldWidth = sofar.oaLastFieldWidth;
- oaPrevBitPack = None }
-
- (* No active bitfield pack. But we are seeing a bitfield. *)
- | TInt(ikthis, _), Some wdthis, None ->
- let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
- { oaFirstFree = firstFree + wdthis;
- oaLastFieldStart = firstFree;
- oaLastFieldWidth = wdthis;
- oaPrevBitPack = Some (firstFree, ikthis, ftypeBits); }
-
- (* No active bitfield pack. Non-bitfield *)
- | _, None, None ->
- (* Align this field *)
- let firstFree = addTrailing sofar.oaFirstFree ftypeAlign in
- { oaFirstFree = firstFree + ftypeBits;
- oaLastFieldStart = firstFree;
- oaLastFieldWidth = ftypeBits;
- oaPrevBitPack = None;
- }
-
- | _, Some _, None -> E.s (E.bug "offsetAcc")
-
-
-and offsetOfFieldAcc ~(fi: fieldinfo)
- ~(sofar: offsetAcc) : offsetAcc =
- if !msvcMode then offsetOfFieldAcc_MSVC fi sofar
- else offsetOfFieldAcc_GCC fi sofar
-
-(* The size of a type, in bits. If struct or array then trailing padding is
- * added *)
-and bitsSizeOf t =
- if not !initCIL_called then
- E.s (E.error "You did not call Cil.initCIL before using the CIL library");
- match t with
- | TInt (ik,_) -> bitsSizeOfInt ik
- | TFloat(FDouble, _) -> 8 * !theMachine.M.sizeof_double
- | TFloat(FLongDouble, _) -> 8 * !theMachine.M.sizeof_longdouble
- | TFloat _ -> 8 * !theMachine.M.sizeof_float
- | TEnum _ -> 8 * !theMachine.M.sizeof_enum
- | TPtr _ -> 8 * !theMachine.M.sizeof_ptr
- | TBuiltin_va_list _ -> 8 * !theMachine.M.sizeof_ptr
- | TNamed (t, _) -> bitsSizeOf t.ttype
- | TComp (comp, _) when comp.cfields == [] -> begin
- (* Empty structs are allowed in msvc mode *)
- if not comp.cdefined && not !msvcMode then
- raise (SizeOfError ("abstract type", t)) (*abstract type*)
- else
- 0
- end
-
- | TComp (comp, _) when comp.cstruct -> (* Struct *)
- (* Go and get the last offset *)
- let startAcc =
- { oaFirstFree = 0;
- oaLastFieldStart = 0;
- oaLastFieldWidth = 0;
- oaPrevBitPack = None;
- } in
- let lastoff =
- List.fold_left (fun acc fi -> offsetOfFieldAcc ~fi ~sofar:acc)
- startAcc comp.cfields
- in
- if !msvcMode && lastoff.oaFirstFree = 0 && comp.cfields <> [] then
- (* On MSVC if we have just a zero-width bitfields then the length
- * is 32 and is not padded *)
- 32
- else
- addTrailing lastoff.oaFirstFree (8 * alignOf_int t)
-
- | TComp (comp, _) -> (* when not comp.cstruct *)
- (* Get the maximum of all fields *)
- let startAcc =
- { oaFirstFree = 0;
- oaLastFieldStart = 0;
- oaLastFieldWidth = 0;
- oaPrevBitPack = None;
- } in
- let max =
- List.fold_left (fun acc fi ->
- let lastoff = offsetOfFieldAcc ~fi ~sofar:startAcc in
- if lastoff.oaFirstFree > acc then
- lastoff.oaFirstFree else acc) 0 comp.cfields in
- (* Add trailing by simulating adding an extra field *)
- addTrailing max (8 * alignOf_int t)
-
- | TArray(t, Some len, _) -> begin
- match constFold true len with
- Const(CInt64(l,_,_)) ->
- addTrailing ((bitsSizeOf t) * (Int64.to_int l)) (8 * alignOf_int t)
- | _ -> raise (SizeOfError ("array non-constant length", t))
- end
-
-
- | TVoid _ -> 8 * !theMachine.M.sizeof_void
- | TFun _ when not !msvcMode -> (* On GCC the size of a function is defined *)
- 8 * !theMachine.M.sizeof_fun
-
- | TArray (_, None, _) -> (* it seems that on GCC the size of such an
- * array is 0 *)
- 0
-
- | TFun _ -> raise (SizeOfError ("function", t))
-
-
-and addTrailing nrbits roundto =
- (nrbits + roundto - 1) land (lnot (roundto - 1))
-
-and sizeOf t =
- try
- integer ((bitsSizeOf t) lsr 3)
- with SizeOfError _ -> SizeOf(t)
-
-
-and bitsOffset (baset: typ) (off: offset) : int * int =
- let rec loopOff (baset: typ) (width: int) (start: int) = function
- NoOffset -> start, width
- | Index(e, off) -> begin
- let ei =
- match isInteger e with
- Some i64 -> Int64.to_int i64
- | None -> raise (SizeOfError ("index not constant", baset))
- in
- let bt =
- match unrollType baset with
- TArray(bt, _, _) -> bt
- | _ -> E.s (E.bug "bitsOffset: Index on a non-array")
- in
- let bitsbt = bitsSizeOf bt in
- loopOff bt bitsbt (start + ei * bitsbt) off
- end
- | Field(f, off) when not f.fcomp.cstruct ->
- (* All union fields start at offset 0 *)
- loopOff f.ftype (bitsSizeOf f.ftype) start off
-
- | Field(f, off) ->
- (* Construct a list of fields preceeding and including this one *)
- let prevflds =
- let rec loop = function
- [] -> E.s (E.bug "bitsOffset: Cannot find field %s in %s\n"
- f.fname f.fcomp.cname)
- | fi' :: _ when fi' == f -> [fi']
- | fi' :: rest -> fi' :: loop rest
- in
- loop f.fcomp.cfields
- in
- let lastoff =
- List.fold_left (fun acc fi' -> offsetOfFieldAcc ~fi:fi' ~sofar:acc)
- { oaFirstFree = 0; (* Start at 0 because each struct is done
- * separately *)
- oaLastFieldStart = 0;
- oaLastFieldWidth = 0;
- oaPrevBitPack = None } prevflds
- in
- (* ignore (E.log "Field %s of %s: start=%d, lastFieldStart=%d\n"
- f.fname f.fcomp.cname start lastoff.oaLastFieldStart); *)
- loopOff f.ftype lastoff.oaLastFieldWidth
- (start + lastoff.oaLastFieldStart) off
- in
- loopOff baset (bitsSizeOf baset) 0 off
-
-
-
-
-(*** Constant folding. If machdep is true then fold even sizeof operations ***)
-and constFold (machdep: bool) (e: exp) : exp =
- match e with
- BinOp(bop, e1, e2, tres) -> constFoldBinOp machdep bop e1 e2 tres
- | UnOp(unop, e1, tres) -> begin
- try
- let tk =
- match unrollType tres with
- TInt(ik, _) -> ik
- | TEnum _ -> IInt
- | _ -> raise Not_found (* probably a float *)
- in
- match constFold machdep e1 with
- Const(CInt64(i,ik,_)) -> begin
- match unop with
- Neg -> kinteger64 tk (Int64.neg i)
- | BNot -> kinteger64 tk (Int64.lognot i)
- | LNot -> if i = Int64.zero then one else zero
- end
- | e1c -> UnOp(unop, e1c, tres)
- with Not_found -> e
- end
- (* Characters are integers *)
- | Const(CChr c) -> Const(charConstToInt c)
- | Const(CEnum (v, _, _)) -> constFold machdep v
- | SizeOf t when machdep -> begin
- try
- let bs = bitsSizeOf t in
- kinteger !kindOfSizeOf (bs / 8)
- with SizeOfError _ -> e
- end
- | SizeOfE e when machdep -> constFold machdep (SizeOf (typeOf e))
- | SizeOfStr s when machdep -> kinteger !kindOfSizeOf (1 + String.length s)
- | AlignOf t when machdep -> kinteger !kindOfSizeOf (alignOf_int t)
- | AlignOfE e when machdep -> begin
- (* The alignmetn of an expression is not always the alignment of its
- * type. I know that for strings this is not true *)
- match e with
- Const (CStr _) when not !msvcMode ->
- kinteger !kindOfSizeOf !theMachine.M.alignof_str
- (* For an array, it is the alignment of the array ! *)
- | _ -> constFold machdep (AlignOf (typeOf e))
- end
-
- | CastE(it,
- AddrOf (Mem (CastE(TPtr(bt, _), z)), off))
- when machdep && isZero z -> begin
- try
- let start, width = bitsOffset bt off in
- if start mod 8 <> 0 then
- E.s (error "Using offset of bitfield\n");
- constFold machdep (CastE(it, (integer (start / 8))))
- with SizeOfError _ -> e
- end
-
-
- | CastE (t, e) -> begin
- match constFold machdep e, unrollType t with
- (* Might truncate silently *)
- Const(CInt64(i,k,_)), TInt(nk,_) ->
- let i', _ = truncateInteger64 nk i in
- Const(CInt64(i', nk, None))
- | e', _ -> CastE (t, e')
- end
-
- | _ -> e
-
-and constFoldBinOp (machdep: bool) bop e1 e2 tres =
- let e1' = constFold machdep e1 in
- let e2' = constFold machdep e2 in
- if isIntegralType tres then begin
- let newe =
- let rec mkInt = function
- Const(CChr c) -> Const(charConstToInt c)
- | Const(CEnum (v, s, ei)) -> mkInt v
- | CastE(TInt (ik, ta), e) -> begin
- match mkInt e with
- Const(CInt64(i, _, _)) ->
- let i', _ = truncateInteger64 ik i in
- Const(CInt64(i', ik, None))
-
- | e' -> CastE(TInt(ik, ta), e')
- end
- | e -> e
- in
- let tk =
- match unrollType tres with
- TInt(ik, _) -> ik
- | TEnum _ -> IInt
- | _ -> E.s (bug "constFoldBinOp")
- in
- (* See if the result is unsigned *)
- let isunsigned typ = not (isSigned typ) in
- let ge (unsigned: bool) (i1: int64) (i2: int64) : bool =
- if unsigned then
- let l1 = Int64.shift_right_logical i1 1 in
- let l2 = Int64.shift_right_logical i2 1 in (* Both positive now *)
- (l1 > l2) || (l1 = l2 &&
- Int64.logand i1 Int64.one >= Int64.logand i2 Int64.one)
- else i1 >= i2
- in
- let shiftInBounds i2 =
- (* We only try to fold shifts if the second arg is positive and
- less than 64. Otherwise, the semantics are processor-dependent,
- so let the compiler sort it out. *)
- i2 >= Int64.zero && i2 < (Int64.of_int 64)
- in
- (* Assume that the necessary promotions have been done *)
- match bop, mkInt e1', mkInt e2' with
- | PlusA, Const(CInt64(z,_,_)), e2'' when z = Int64.zero -> e2''
- | PlusA, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
- | PlusPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
- | IndexPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
- | MinusPI, e1'', Const(CInt64(z,_,_)) when z = Int64.zero -> e1''
- | PlusA, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.add i1 i2)
- | MinusA, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.sub i1 i2)
- | Mult, Const(CInt64(i1,ik1,_)), Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.mul i1 i2)
- | Mult, Const(CInt64(0L,_,_)), _ -> zero
- | Mult, Const(CInt64(1L,_,_)), e2'' -> e2''
- | Mult, _, Const(CInt64(0L,_,_)) -> zero
- | Mult, e1'', Const(CInt64(1L,_,_)) -> e1''
- | Div, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 -> begin
- try kinteger64 tk (Int64.div i1 i2)
- with Division_by_zero -> BinOp(bop, e1', e2', tres)
- end
- | Div, e1'', Const(CInt64(1L,_,_)) -> e1''
-
- | Mod, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 -> begin
- try kinteger64 tk (Int64.rem i1 i2)
- with Division_by_zero -> BinOp(bop, e1', e2', tres)
- end
- | BAnd, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.logand i1 i2)
- | BAnd, Const(CInt64(0L,_,_)), _ -> zero
- | BAnd, _, Const(CInt64(0L,_,_)) -> zero
- | BOr, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.logor i1 i2)
- | BOr, _, _ when isZero e1' -> e2'
- | BOr, _, _ when isZero e2' -> e1'
- | BXor, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- kinteger64 tk (Int64.logxor i1 i2)
-
- | Shiftlt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,_,_)) when shiftInBounds i2 ->
- kinteger64 tk (Int64.shift_left i1 (Int64.to_int i2))
- | Shiftlt, Const(CInt64(0L,_,_)), _ -> zero
- | Shiftlt, e1'', Const(CInt64(0L,_,_)) -> e1''
-
- | Shiftrt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,_,_)) when shiftInBounds i2 ->
- if isunsigned ik1 then
- kinteger64 tk (Int64.shift_right_logical i1 (Int64.to_int i2))
- else
- kinteger64 tk (Int64.shift_right i1 (Int64.to_int i2))
- | Shiftrt, Const(CInt64(0L,_,_)), _ -> zero
- | Shiftrt, e1'', Const(CInt64(0L,_,_)) -> e1''
-
- | Eq, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if i1 = i2 then 1 else 0)
- | Ne, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if i1 <> i2 then 1 else 0)
- | Le, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if ge (isunsigned ik1) i2 i1 then 1 else 0)
-
- | Ge, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if ge (isunsigned ik1) i1 i2 then 1 else 0)
-
- | Lt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if i1 <> i2 && ge (isunsigned ik1) i2 i1 then 1 else 0)
-
- | Gt, Const(CInt64(i1,ik1,_)),Const(CInt64(i2,ik2,_)) when ik1 = ik2 ->
- integer (if i1 <> i2 && ge (isunsigned ik1) i1 i2 then 1 else 0)
- | LAnd, _, _ when isZero e1' || isZero e2' -> zero
- | LOr, _, _ when isZero e1' -> e2'
- | LOr, _, _ when isZero e2' -> e1'
- | _ -> BinOp(bop, e1', e2', tres)
- in
- if debugConstFold then
- ignore (E.log "Folded %a to %a\n"
- (!pd_exp) (BinOp(bop, e1', e2', tres)) (!pd_exp) newe);
- newe
- end else
- BinOp(bop, e1', e2', tres)
-
-
-
-let parseInt (str: string) : exp =
- let hasSuffix str =
- let l = String.length str in
- fun s ->
- let ls = String.length s in
- l >= ls && s = String.uppercase (String.sub str (l - ls) ls)
- in
- let l = String.length str in
- (* See if it is octal or hex *)
- let octalhex = (l >= 1 && String.get str 0 = '0') in
- (* The length of the suffix and a list of possible kinds. See ISO
- * 6.4.4.1 *)
- let hasSuffix = hasSuffix str in
- let suffixlen, kinds =
- if hasSuffix "ULL" || hasSuffix "LLU" then
- 3, [IULongLong]
- else if hasSuffix "LL" then
- 2, if octalhex then [ILongLong; IULongLong] else [ILongLong]
- else if hasSuffix "UL" || hasSuffix "LU" then
- 2, [IULong; IULongLong]
- else if hasSuffix "L" then
- 1, if octalhex then [ILong; IULong; ILongLong; IULongLong]
- else [ILong; ILongLong]
- else if hasSuffix "U" then
- 1, [IUInt; IULong; IULongLong]
- else if (!msvcMode && hasSuffix "UI64") then
- 4, [IULongLong]
- else if (!msvcMode && hasSuffix "I64") then
- 3, [ILongLong]
- else
- 0, if octalhex || true (* !!! This is against the ISO but it
- * is what GCC and MSVC do !!! *)
- then [IInt; IUInt; ILong; IULong; ILongLong; IULongLong]
- else [IInt; ILong; IUInt; ILongLong]
- in
- (* Convert to integer. To prevent overflow we do the arithmetic
- * on Int64 and we take care of overflow. We work only with
- * positive integers since the lexer takes care of the sign *)
- let rec toInt (base: int64) (acc: int64) (idx: int) : int64 =
- let doAcc (what: int) =
- let acc' =
- Int64.add (Int64.mul base acc) (Int64.of_int what) in
- if acc < Int64.zero || (* We clearly overflow since base >= 2
- * *)
- (acc' > Int64.zero && acc' < acc) then
- E.s (unimp "Cannot represent on 64 bits the integer %s\n"
- str)
- else
- toInt base acc' (idx + 1)
- in
- if idx >= l - suffixlen then begin
- acc
- end else
- let ch = String.get str idx in
- if ch >= '0' && ch <= '9' then
- doAcc (Char.code ch - Char.code '0')
- else if ch >= 'a' && ch <= 'f' then
- doAcc (10 + Char.code ch - Char.code 'a')
- else if ch >= 'A' && ch <= 'F' then
- doAcc (10 + Char.code ch - Char.code 'A')
- else
- E.s (bug "Invalid integer constant: %s (char %c at idx=%d)"
- str ch idx)
- in
- try
- let i =
- if octalhex then
- if l >= 2 &&
- (let c = String.get str 1 in c = 'x' || c = 'X') then
- toInt (Int64.of_int 16) Int64.zero 2
- else
- toInt (Int64.of_int 8) Int64.zero 1
- else
- toInt (Int64.of_int 10) Int64.zero 0
- in
- (* Construct an integer of the first kinds that fits. i must be
- * POSITIVE *)
- let res =
- let rec loop = function
- | ((IInt | ILong) as k) :: _
- when i < Int64.shift_left (Int64.of_int 1) 31 ->
- kinteger64 k i
- | ((IUInt | IULong) as k) :: _
- when i < Int64.shift_left (Int64.of_int 1) 32
- -> kinteger64 k i
- | (ILongLong as k) :: _
- when i <= Int64.sub (Int64.shift_left
- (Int64.of_int 1) 63)
- (Int64.of_int 1)
- ->
- kinteger64 k i
- | (IULongLong as k) :: _ -> kinteger64 k i
- | _ :: rest -> loop rest
- | [] -> E.s (E.unimp "Cannot represent the integer %s\n"
- (Int64.to_string i))
- in
- loop kinds
- in
- res
- with e -> begin
- ignore (E.log "int_of_string %s (%s)\n" str
- (Printexc.to_string e));
- zero
- end
-
-
-
-let d_unop () u =
- match u with
- Neg -> text "-"
- | BNot -> text "~"
- | LNot -> text "!"
-
-let d_binop () b =
- match b with
- PlusA | PlusPI | IndexPI -> text "+"
- | MinusA | MinusPP | MinusPI -> text "-"
- | Mult -> text "*"
- | Div -> text "/"
- | Mod -> text "%"
- | Shiftlt -> text "<<"
- | Shiftrt -> text ">>"
- | Lt -> text "<"
- | Gt -> text ">"
- | Le -> text "<="
- | Ge -> text ">="
- | Eq -> text "=="
- | Ne -> text "!="
- | BAnd -> text "&"
- | BXor -> text "^"
- | BOr -> text "|"
- | LAnd -> text "&&"
- | LOr -> text "||"
-
-let invalidStmt = mkStmt (Instr [])
-
-(** Construct a hash with the builtins *)
-let gccBuiltins : (string, typ * typ list * bool) H.t =
- let h = H.create 17 in
- (* See if we have builtin_va_list *)
- let hasbva = M.gccHas__builtin_va_list in
- let ulongLongType = TInt(IULongLong, []) in
- let floatType = TFloat(FFloat, []) in
- let longDoubleType = TFloat (FLongDouble, []) in
- let voidConstPtrType = TPtr(TVoid [Attr ("const", [])], []) in
- let sizeType = uintType in
-
- H.add h "__builtin___fprintf_chk" (intType, [ voidPtrType; intType; charConstPtrType ], true) (* first argument is really FILE*, not void*, but we don't want to build in the definition for FILE *);
- H.add h "__builtin___memcpy_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
- H.add h "__builtin___memmove_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
- H.add h "__builtin___mempcpy_chk" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType; sizeType ], false);
- H.add h "__builtin___memset_chk" (voidPtrType, [ voidPtrType; intType; sizeType; sizeType ], false);
- H.add h "__builtin___printf_chk" (intType, [ intType; charConstPtrType ], true);
- H.add h "__builtin___snprintf_chk" (intType, [ charPtrType; sizeType; intType; sizeType; charConstPtrType ], true);
- H.add h "__builtin___sprintf_chk" (intType, [ charPtrType; intType; sizeType; charConstPtrType ], true);
- H.add h "__builtin___stpcpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin___strcat_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin___strcpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin___strncat_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType; sizeType ], false);
- H.add h "__builtin___strncpy_chk" (charPtrType, [ charPtrType; charConstPtrType; sizeType; sizeType ], false);
- H.add h "__builtin___vfprintf_chk" (intType, [ voidPtrType; intType; charConstPtrType; TBuiltin_va_list [] ], false) (* first argument is really FILE*, not void*, but we don't want to build in the definition for FILE *);
- H.add h "__builtin___vprintf_chk" (intType, [ intType; charConstPtrType; TBuiltin_va_list [] ], false);
- H.add h "__builtin___vsnprintf_chk" (intType, [ charPtrType; sizeType; intType; sizeType; charConstPtrType; TBuiltin_va_list [] ], false);
- H.add h "__builtin___vsprintf_chk" (intType, [ charPtrType; intType; sizeType; charConstPtrType; TBuiltin_va_list [] ], false);
-
- H.add h "__builtin_acos" (doubleType, [ doubleType ], false);
- H.add h "__builtin_acosf" (floatType, [ floatType ], false);
- H.add h "__builtin_acosl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_alloca" (voidPtrType, [ uintType ], false);
-
- H.add h "__builtin_asin" (doubleType, [ doubleType ], false);
- H.add h "__builtin_asinf" (floatType, [ floatType ], false);
- H.add h "__builtin_asinl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_atan" (doubleType, [ doubleType ], false);
- H.add h "__builtin_atanf" (floatType, [ floatType ], false);
- H.add h "__builtin_atanl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_atan2" (doubleType, [ doubleType; doubleType ], false);
- H.add h "__builtin_atan2f" (floatType, [ floatType; floatType ], false);
- H.add h "__builtin_atan2l" (longDoubleType, [ longDoubleType;
- longDoubleType ], false);
-
- H.add h "__builtin_ceil" (doubleType, [ doubleType ], false);
- H.add h "__builtin_ceilf" (floatType, [ floatType ], false);
- H.add h "__builtin_ceill" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_cos" (doubleType, [ doubleType ], false);
- H.add h "__builtin_cosf" (floatType, [ floatType ], false);
- H.add h "__builtin_cosl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_cosh" (doubleType, [ doubleType ], false);
- H.add h "__builtin_coshf" (floatType, [ floatType ], false);
- H.add h "__builtin_coshl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_clz" (intType, [ uintType ], false);
- H.add h "__builtin_clzl" (intType, [ ulongType ], false);
- H.add h "__builtin_clzll" (intType, [ ulongLongType ], false);
- H.add h "__builtin_constant_p" (intType, [ intType ], false);
- H.add h "__builtin_ctz" (intType, [ uintType ], false);
- H.add h "__builtin_ctzl" (intType, [ ulongType ], false);
- H.add h "__builtin_ctzll" (intType, [ ulongLongType ], false);
-
- H.add h "__builtin_exp" (doubleType, [ doubleType ], false);
- H.add h "__builtin_expf" (floatType, [ floatType ], false);
- H.add h "__builtin_expl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_expect" (longType, [ longType; longType ], false);
-
- H.add h "__builtin_fabs" (doubleType, [ doubleType ], false);
- H.add h "__builtin_fabsf" (floatType, [ floatType ], false);
- H.add h "__builtin_fabsl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_ffs" (intType, [ uintType ], false);
- H.add h "__builtin_ffsl" (intType, [ ulongType ], false);
- H.add h "__builtin_ffsll" (intType, [ ulongLongType ], false);
- H.add h "__builtin_frame_address" (voidPtrType, [ uintType ], false);
-
- H.add h "__builtin_floor" (doubleType, [ doubleType ], false);
- H.add h "__builtin_floorf" (floatType, [ floatType ], false);
- H.add h "__builtin_floorl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_huge_val" (doubleType, [], false);
- H.add h "__builtin_huge_valf" (floatType, [], false);
- H.add h "__builtin_huge_vall" (longDoubleType, [], false);
- H.add h "__builtin_inf" (doubleType, [], false);
- H.add h "__builtin_inff" (floatType, [], false);
- H.add h "__builtin_infl" (longDoubleType, [], false);
- H.add h "__builtin_memcpy" (voidPtrType, [ voidPtrType; voidConstPtrType; uintType ], false);
- H.add h "__builtin_mempcpy" (voidPtrType, [ voidPtrType; voidConstPtrType; sizeType ], false);
-
- H.add h "__builtin_fmod" (doubleType, [ doubleType ], false);
- H.add h "__builtin_fmodf" (floatType, [ floatType ], false);
- H.add h "__builtin_fmodl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_frexp" (doubleType, [ doubleType; intPtrType ], false);
- H.add h "__builtin_frexpf" (floatType, [ floatType; intPtrType ], false);
- H.add h "__builtin_frexpl" (longDoubleType, [ longDoubleType;
- intPtrType ], false);
-
- H.add h "__builtin_ldexp" (doubleType, [ doubleType; intType ], false);
- H.add h "__builtin_ldexpf" (floatType, [ floatType; intType ], false);
- H.add h "__builtin_ldexpl" (longDoubleType, [ longDoubleType;
- intType ], false);
-
- H.add h "__builtin_log" (doubleType, [ doubleType ], false);
- H.add h "__builtin_logf" (floatType, [ floatType ], false);
- H.add h "__builtin_logl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_log10" (doubleType, [ doubleType ], false);
- H.add h "__builtin_log10f" (floatType, [ floatType ], false);
- H.add h "__builtin_log10l" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_modff" (floatType, [ floatType;
- TPtr(floatType,[]) ], false);
- H.add h "__builtin_modfl" (longDoubleType, [ longDoubleType;
- TPtr(longDoubleType, []) ],
- false);
-
- H.add h "__builtin_nan" (doubleType, [ charConstPtrType ], false);
- H.add h "__builtin_nanf" (floatType, [ charConstPtrType ], false);
- H.add h "__builtin_nanl" (longDoubleType, [ charConstPtrType ], false);
- H.add h "__builtin_nans" (doubleType, [ charConstPtrType ], false);
- H.add h "__builtin_nansf" (floatType, [ charConstPtrType ], false);
- H.add h "__builtin_nansl" (longDoubleType, [ charConstPtrType ], false);
- H.add h "__builtin_next_arg" ((if hasbva then TBuiltin_va_list [] else voidPtrType), [], false) (* When we parse builtin_next_arg we drop the second argument *);
- H.add h "__builtin_object_size" (sizeType, [ voidPtrType; intType ], false);
-
- H.add h "__builtin_parity" (intType, [ uintType ], false);
- H.add h "__builtin_parityl" (intType, [ ulongType ], false);
- H.add h "__builtin_parityll" (intType, [ ulongLongType ], false);
-
- H.add h "__builtin_popcount" (intType, [ uintType ], false);
- H.add h "__builtin_popcountl" (intType, [ ulongType ], false);
- H.add h "__builtin_popcountll" (intType, [ ulongLongType ], false);
-
- H.add h "__builtin_powi" (doubleType, [ doubleType; intType ], false);
- H.add h "__builtin_powif" (floatType, [ floatType; intType ], false);
- H.add h "__builtin_powil" (longDoubleType, [ longDoubleType; intType ], false);
- H.add h "__builtin_prefetch" (voidType, [ voidConstPtrType ], true);
- H.add h "__builtin_return" (voidType, [ voidConstPtrType ], false);
- H.add h "__builtin_return_address" (voidPtrType, [ uintType ], false);
-
- H.add h "__builtin_sin" (doubleType, [ doubleType ], false);
- H.add h "__builtin_sinf" (floatType, [ floatType ], false);
- H.add h "__builtin_sinl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_sinh" (doubleType, [ doubleType ], false);
- H.add h "__builtin_sinhf" (floatType, [ floatType ], false);
- H.add h "__builtin_sinhl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_sqrt" (doubleType, [ doubleType ], false);
- H.add h "__builtin_sqrtf" (floatType, [ floatType ], false);
- H.add h "__builtin_sqrtl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_stpcpy" (charPtrType, [ charPtrType; charConstPtrType ], false);
- H.add h "__builtin_strchr" (charPtrType, [ charPtrType; charType ], false);
- H.add h "__builtin_strcmp" (intType, [ charConstPtrType; charConstPtrType ], false);
- H.add h "__builtin_strcpy" (charPtrType, [ charPtrType; charConstPtrType ], false);
- H.add h "__builtin_strcspn" (uintType, [ charConstPtrType; charConstPtrType ], false);
- H.add h "__builtin_strncat" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin_strncmp" (intType, [ charConstPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin_strncpy" (charPtrType, [ charPtrType; charConstPtrType; sizeType ], false);
- H.add h "__builtin_strspn" (intType, [ charConstPtrType; charConstPtrType ], false);
- H.add h "__builtin_strpbrk" (charPtrType, [ charConstPtrType; charConstPtrType ], false);
- (* When we parse builtin_types_compatible_p, we change its interface *)
- H.add h "__builtin_types_compatible_p"
- (intType, [ uintType; (* Sizeof the type *)
- uintType (* Sizeof the type *) ],
- false);
- H.add h "__builtin_tan" (doubleType, [ doubleType ], false);
- H.add h "__builtin_tanf" (floatType, [ floatType ], false);
- H.add h "__builtin_tanl" (longDoubleType, [ longDoubleType ], false);
-
- H.add h "__builtin_tanh" (doubleType, [ doubleType ], false);
- H.add h "__builtin_tanhf" (floatType, [ floatType ], false);
- H.add h "__builtin_tanhl" (longDoubleType, [ longDoubleType ], false);
-
-
- if hasbva then begin
- H.add h "__builtin_va_end" (voidType, [ TBuiltin_va_list [] ], false);
- H.add h "__builtin_varargs_start"
- (voidType, [ TBuiltin_va_list [] ], false);
- H.add h "__builtin_va_start" (voidType, [ TBuiltin_va_list [] ], false);
- (* When we parse builtin_stdarg_start, we drop the second argument *)
- H.add h "__builtin_stdarg_start" (voidType, [ TBuiltin_va_list []; ],
- false);
- (* When we parse builtin_va_arg we change its interface *)
- H.add h "__builtin_va_arg" (voidType, [ TBuiltin_va_list [];
- uintType; (* Sizeof the type *)
- voidPtrType; (* Ptr to res *) ],
- false);
- H.add h "__builtin_va_copy" (voidType, [ TBuiltin_va_list [];
- TBuiltin_va_list [] ],
- false);
- end;
- h
-
-(** Construct a hash with the builtins *)
-let msvcBuiltins : (string, typ * typ list * bool) H.t =
- (* These are empty for now but can be added to depending on the application*)
- let h = H.create 17 in
- (** Take a number of wide string literals *)
- H.add h "__annotation" (voidType, [ ], true);
- h
-
-
-
-let pTypeSig : (typ -> typsig) ref =
- ref (fun _ -> E.s (E.bug "pTypeSig not initialized"))
-
-
-(** A printer interface for CIL trees. Create instantiations of
- * this type by specializing the class {!Cil.defaultCilPrinter}. *)
-class type cilPrinter = object
- method pVDecl: unit -> varinfo -> doc
- (** Invoked for each variable declaration. Note that variable
- * declarations are all the [GVar], [GVarDecl], [GFun], all the [varinfo]
- * in formals of function types, and the formals and locals for function
- * definitions. *)
-
- method pVar: varinfo -> doc
- (** Invoked on each variable use. *)
-
- method pLval: unit -> lval -> doc
- (** Invoked on each lvalue occurence *)
-
- method pOffset: doc -> offset -> doc
- (** Invoked on each offset occurence. The second argument is the base. *)
-
- method pInstr: unit -> instr -> doc
- (** Invoked on each instruction occurrence. *)
-
- method pStmt: unit -> stmt -> doc
- (** Control-flow statement. This is used by
- * {!Cil.printGlobal} and by {!Cil.dumpGlobal}. *)
-
- method dStmt: out_channel -> int -> stmt -> unit
- (** Dump a control-flow statement to a file with a given indentation. This is used by
- * {!Cil.dumpGlobal}. *)
-
- method dBlock: out_channel -> int -> block -> unit
- (** Dump a control-flow block to a file with a given indentation. This is
- * used by {!Cil.dumpGlobal}. *)
-
- method pBlock: unit -> block -> Pretty.doc
- (** Print a block. *)
-
- method pGlobal: unit -> global -> doc
- (** Global (vars, types, etc.). This can be slow and is used only by
- * {!Cil.printGlobal} but by {!Cil.dumpGlobal} for everything else except
- * [GVar] and [GFun]. *)
-
- method dGlobal: out_channel -> global -> unit
- (** Dump a global to a file. This is used by {!Cil.dumpGlobal}. *)
-
- method pFieldDecl: unit -> fieldinfo -> doc
- (** A field declaration *)
-
- method pType: doc option -> unit -> typ -> doc
- (* Use of some type in some declaration. The first argument is used to print
- * the declared element, or is None if we are just printing a type with no
- * name being decalred. Note that for structure/union and enumeration types
- * the definition of the composite type is not visited. Use [vglob] to
- * visit it. *)
-
- method pAttr: attribute -> doc * bool
- (** Attribute. Also return an indication whether this attribute must be
- * printed inside the __attribute__ list or not. *)
-
- method pAttrParam: unit -> attrparam -> doc
- (** Attribute paramter *)
-
- method pAttrs: unit -> attributes -> doc
- (** Attribute lists *)
-
- method pLabel: unit -> label -> doc
- (** Label *)
-
- method pLineDirective: ?forcefile:bool -> location -> Pretty.doc
- (** Print a line-number. This is assumed to come always on an empty line.
- * If the forcefile argument is present and is true then the file name
- * will be printed always. Otherwise the file name is printed only if it
- * is different from the last time time this function is called. The last
- * file name is stored in a private field inside the cilPrinter object. *)
-
- method pStmtKind : stmt -> unit -> stmtkind -> Pretty.doc
- (** Print a statement kind. The code to be printed is given in the
- * {!Cil.stmtkind} argument. The initial {!Cil.stmt} argument
- * records the statement which follows the one being printed;
- * {!Cil.defaultCilPrinterClass} uses this information to prettify
- * statement printing in certain special cases. *)
-
- method pExp: unit -> exp -> doc
- (** Print expressions *)
-
- method pInit: unit -> init -> doc
- (** Print initializers. This can be slow and is used by
- * {!Cil.printGlobal} but not by {!Cil.dumpGlobal}. *)
-
- method dInit: out_channel -> int -> init -> unit
- (** Dump a global to a file with a given indentation. This is used by
- * {!Cil.dumpGlobal}. *)
-end
-
-
-class defaultCilPrinterClass : cilPrinter = object (self)
- val mutable currentFormals : varinfo list = []
- method private getLastNamedArgument (s: string) : exp =
- match List.rev currentFormals with
- f :: _ -> Lval (var f)
- | [] ->
- E.s (warn "Cannot find the last named argument when priting call to %s\n" s)
-
- (*** VARIABLES ***)
- (* variable use *)
- method pVar (v:varinfo) = text v.vname
-
- (* variable declaration *)
- method pVDecl () (v:varinfo) =
- let stom, rest = separateStorageModifiers v.vattr in
- (* First the storage modifiers *)
- text (if v.vinline then "__inline " else "")
- ++ d_storage () v.vstorage
- ++ (self#pAttrs () stom)
- ++ (self#pType (Some (text v.vname)) () v.vtype)
- ++ text " "
- ++ self#pAttrs () rest
-
- (*** L-VALUES ***)
- method pLval () (lv:lval) = (* lval (base is 1st field) *)
- match lv with
- Var vi, o -> self#pOffset (self#pVar vi) o
- | Mem e, Field(fi, o) ->
- self#pOffset
- ((self#pExpPrec arrowLevel () e) ++ text ("->" ^ fi.fname)) o
- | Mem e, o ->
- self#pOffset
- (text "(*" ++ self#pExpPrec derefStarLevel () e ++ text ")") o
-
- (** Offsets **)
- method pOffset (base: doc) = function
- | NoOffset -> base
- | Field (fi, o) ->
- self#pOffset (base ++ text "." ++ text fi.fname) o
- | Index (e, o) ->
- self#pOffset (base ++ text "[" ++ self#pExp () e ++ text "]") o
-
- method private pLvalPrec (contextprec: int) () lv =
- if getParenthLevel (Lval(lv)) >= contextprec then
- text "(" ++ self#pLval () lv ++ text ")"
- else
- self#pLval () lv
-
- (*** EXPRESSIONS ***)
- method pExp () (e: exp) : doc =
- let level = getParenthLevel e in
- match e with
- Const(c) -> d_const () c
- | Lval(l) -> self#pLval () l
- | UnOp(u,e1,_) ->
- (d_unop () u) ++ chr ' ' ++ (self#pExpPrec level () e1)
-
- | BinOp(b,e1,e2,_) ->
- align
- ++ (self#pExpPrec level () e1)
- ++ chr ' '
- ++ (d_binop () b)
- ++ chr ' '
- ++ (self#pExpPrec level () e2)
- ++ unalign
-
- | CastE(t,e) ->
- text "("
- ++ self#pType None () t
- ++ text ")"
- ++ self#pExpPrec level () e
-
- | SizeOf (t) ->
- text "sizeof(" ++ self#pType None () t ++ chr ')'
- | SizeOfE (e) ->
- text "sizeof(" ++ self#pExp () e ++ chr ')'
-
- | SizeOfStr s ->
- text "sizeof(" ++ d_const () (CStr s) ++ chr ')'
-
- | AlignOf (t) ->
- text "__alignof__(" ++ self#pType None () t ++ chr ')'
- | AlignOfE (e) ->
- text "__alignof__(" ++ self#pExp () e ++ chr ')'
- | AddrOf(lv) ->
- text "& " ++ (self#pLvalPrec addrOfLevel () lv)
-
- | StartOf(lv) -> self#pLval () lv
-
- method private pExpPrec (contextprec: int) () (e: exp) =
- let thisLevel = getParenthLevel e in
- let needParens =
- if thisLevel >= contextprec then
- true
- else if contextprec == bitwiseLevel then
- (* quiet down some GCC warnings *)
- thisLevel == additiveLevel || thisLevel == comparativeLevel
- else
- false
- in
- if needParens then
- chr '(' ++ self#pExp () e ++ chr ')'
- else
- self#pExp () e
-
- method pInit () = function
- SingleInit e -> self#pExp () e
- | CompoundInit (t, initl) ->
- (* We do not print the type of the Compound *)
-(*
- let dinit e = d_init () e in
- dprintf "{@[%a@]}"
- (docList ~sep:(chr ',' ++ break) dinit) initl
-*)
- let printDesignator =
- if not !msvcMode then begin
- (* Print only for union when we do not initialize the first field *)
- match unrollType t, initl with
- TComp(ci, _), [(Field(f, NoOffset), _)] ->
- if not (ci.cstruct) && ci.cfields != [] &&
- (List.hd ci.cfields) != f then
- true
- else
- false
- | _ -> false
- end else
- false
- in
- let d_oneInit = function
- Field(f, NoOffset), i ->
- (if printDesignator then
- text ("." ^ f.fname ^ " = ")
- else nil) ++ self#pInit () i
- | Index(e, NoOffset), i ->
- (if printDesignator then
- text "[" ++ self#pExp () e ++ text "] = " else nil) ++
- self#pInit () i
- | _ -> E.s (unimp "Trying to print malformed initializer")
- in
- chr '{' ++ (align
- ++ ((docList ~sep:(chr ',' ++ break) d_oneInit) () initl)
- ++ unalign)
- ++ chr '}'
-(*
- | ArrayInit (_, _, il) ->
- chr '{' ++ (align
- ++ ((docList (chr ',' ++ break) (self#pInit ())) () il)
- ++ unalign)
- ++ chr '}'
-*)
- (* dump initializers to a file. *)
- method dInit (out: out_channel) (ind: int) (i: init) =
- (* Dump an array *)
- let dumpArray (bt: typ) (il: 'a list) (getelem: 'a -> init) =
- let onALine = (* How many elements on a line *)
- match unrollType bt with TComp _ | TArray _ -> 1 | _ -> 4
- in
- let rec outputElements (isfirst: bool) (room_on_line: int) = function
- [] -> output_string out "}"
- | (i: 'a) :: rest ->
- if not isfirst then output_string out ", ";
- let new_room_on_line =
- if room_on_line == 0 then begin
- output_string out "\n"; output_string out (String.make ind ' ');
- onALine - 1
- end else
- room_on_line - 1
- in
- self#dInit out (ind + 2) (getelem i);
- outputElements false new_room_on_line rest
- in
- output_string out "{ ";
- outputElements true onALine il
- in
- match i with
- SingleInit e ->
- fprint out !lineLength (indent ind (self#pExp () e))
- | CompoundInit (t, initl) -> begin
- match unrollType t with
- TArray(bt, _, _) ->
- dumpArray bt initl (fun (_, i) -> i)
- | _ ->
- (* Now a structure or a union *)
- fprint out !lineLength (indent ind (self#pInit () i))
- end
-(*
- | ArrayInit (bt, len, initl) -> begin
- (* If the base type does not contain structs then use the pInit
- match unrollType bt with
- TComp _ | TArray _ ->
- dumpArray bt initl (fun x -> x)
- | _ -> *)
- fprint out !lineLength (indent ind (self#pInit () i))
- end
-*)
-
- (** What terminator to print after an instruction. sometimes we want to
- * print sequences of instructions separated by comma *)
- val mutable printInstrTerminator = ";"
-
- (*** INSTRUCTIONS ****)
- method pInstr () (i:instr) = (* imperative instruction *)
- match i with
- | Set(lv,e,l) -> begin
- (* Be nice to some special cases *)
- match e with
- BinOp((PlusA|PlusPI|IndexPI),Lval(lv'), Const(CInt64(one,_,_)),_)
- when Util.equals lv lv' && one = Int64.one && not !printCilAsIs ->
- self#pLineDirective l
- ++ self#pLval () lv
- ++ text (" ++" ^ printInstrTerminator)
-
- | BinOp((MinusA|MinusPI),Lval(lv'),
- Const(CInt64(one,_,_)), _)
- when Util.equals lv lv' && one = Int64.one && not !printCilAsIs ->
- self#pLineDirective l
- ++ self#pLval () lv
- ++ text (" --" ^ printInstrTerminator)
-
- | BinOp((PlusA|PlusPI|IndexPI),Lval(lv'),Const(CInt64(mone,_,_)),_)
- when Util.equals lv lv' && mone = Int64.minus_one
- && not !printCilAsIs ->
- self#pLineDirective l
- ++ self#pLval () lv
- ++ text (" --" ^ printInstrTerminator)
-
- | BinOp((PlusA|PlusPI|IndexPI|MinusA|MinusPP|MinusPI|BAnd|BOr|BXor|
- Mult|Div|Mod|Shiftlt|Shiftrt) as bop,
- Lval(lv'),e,_) when Util.equals lv lv' ->
- self#pLineDirective l
- ++ self#pLval () lv
- ++ text " " ++ d_binop () bop
- ++ text "= "
- ++ self#pExp () e
- ++ text printInstrTerminator
-
- | _ ->
- self#pLineDirective l
- ++ self#pLval () lv
- ++ text " = "
- ++ self#pExp () e
- ++ text printInstrTerminator
-
- end
- (* In cabs2cil we have turned the call to builtin_va_arg into a
- * three-argument call: the last argument is the address of the
- * destination *)
- | Call(None, Lval(Var vi, NoOffset), [dest; SizeOf t; adest], l)
- when vi.vname = "__builtin_va_arg" && not !printCilAsIs ->
- let destlv = match stripCasts adest with
- AddrOf destlv -> destlv
- | _ -> E.s (E.error "Encountered unexpected call to %s\n" vi.vname)
- in
- self#pLineDirective l
- ++ self#pLval () destlv ++ text " = "
-
- (* Now the function name *)
- ++ text "__builtin_va_arg"
- ++ text "(" ++ (align
- (* Now the arguments *)
- ++ self#pExp () dest
- ++ chr ',' ++ break
- ++ self#pType None () t
- ++ unalign)
- ++ text (")" ^ printInstrTerminator)
-
- (* In cabs2cil we have dropped the last argument in the call to
- * __builtin_stdarg_start. *)
- | Call(None, Lval(Var vi, NoOffset), [marker], l)
- when vi.vname = "__builtin_stdarg_start" && not !printCilAsIs -> begin
- let last = self#getLastNamedArgument vi.vname in
- self#pInstr () (Call(None,Lval(Var vi,NoOffset),[marker; last],l))
- end
-
- (* In cabs2cil we have dropped the last argument in the call to
- * __builtin_next_arg. *)
- | Call(res, Lval(Var vi, NoOffset), [ ], l)
- when vi.vname = "__builtin_next_arg" && not !printCilAsIs -> begin
- let last = self#getLastNamedArgument vi.vname in
- self#pInstr () (Call(res,Lval(Var vi,NoOffset),[last],l))
- end
-
- (* In cparser we have turned the call to
- * __builtin_types_compatible_p(t1, t2) into
- * __builtin_types_compatible_p(sizeof t1, sizeof t2), so that we can
- * represent the types as expressions.
- * Remove the sizeofs when printing. *)
- | Call(dest, Lval(Var vi, NoOffset), [SizeOf t1; SizeOf t2], l)
- when vi.vname = "__builtin_types_compatible_p" && not !printCilAsIs ->
- self#pLineDirective l
- (* Print the destination *)
- ++ (match dest with
- None -> nil
- | Some lv -> self#pLval () lv ++ text " = ")
- (* Now the call itself *)
- ++ dprintf "%s(%a, %a)" vi.vname
- (self#pType None) t1 (self#pType None) t2
- ++ text printInstrTerminator
- | Call(_, Lval(Var vi, NoOffset), _, l)
- when vi.vname = "__builtin_types_compatible_p" && not !printCilAsIs ->
- E.s (bug "__builtin_types_compatible_p: cabs2cil should have added sizeof to the arguments.")
-
- | Call(dest,e,args,l) ->
- self#pLineDirective l
- ++ (match dest with
- None -> nil
- | Some lv ->
- self#pLval () lv ++ text " = " ++
- (* Maybe we need to print a cast *)
- (let destt = typeOfLval lv in
- match unrollType (typeOf e) with
- TFun (rt, _, _, _)
- when not (Util.equals (!pTypeSig rt)
- (!pTypeSig destt)) ->
- text "(" ++ self#pType None () destt ++ text ")"
- | _ -> nil))
- (* Now the function name *)
- ++ (let ed = self#pExp () e in
- match e with
- Lval(Var _, _) -> ed
- | _ -> text "(" ++ ed ++ text ")")
- ++ text "(" ++
- (align
- (* Now the arguments *)
- ++ (docList ~sep:(chr ',' ++ break)
- (self#pExp ()) () args)
- ++ unalign)
- ++ text (")" ^ printInstrTerminator)
-
- | Asm(attrs, tmpls, outs, ins, clobs, l) ->
- if !msvcMode then
- self#pLineDirective l
- ++ text "__asm {"
- ++ (align
- ++ (docList ~sep:line text () tmpls)
- ++ unalign)
- ++ text ("}" ^ printInstrTerminator)
- else
- self#pLineDirective l
- ++ text ("__asm__ ")
- ++ self#pAttrs () attrs
- ++ text " ("
- ++ (align
- ++ (docList ~sep:line
- (fun x -> text ("\"" ^ escape_string x ^ "\""))
- () tmpls)
- ++
- (if outs = [] && ins = [] && clobs = [] then
- chr ':'
- else
- (text ": "
- ++ (docList ~sep:(chr ',' ++ break)
- (fun (c, lv) ->
- text ("\"" ^ escape_string c ^ "\" (")
- ++ self#pLval () lv
- ++ text ")") () outs)))
- ++
- (if ins = [] && clobs = [] then
- nil
- else
- (text ": "
- ++ (docList ~sep:(chr ',' ++ break)
- (fun (c, e) ->
- text ("\"" ^ escape_string c ^ "\" (")
- ++ self#pExp () e
- ++ text ")") () ins)))
- ++
- (if clobs = [] then nil
- else
- (text ": "
- ++ (docList ~sep:(chr ',' ++ break)
- (fun c -> text ("\"" ^ escape_string c ^ "\""))
- ()
- clobs)))
- ++ unalign)
- ++ text (")" ^ printInstrTerminator)
-
-
- (**** STATEMENTS ****)
- method pStmt () (s:stmt) = (* control-flow statement *)
- self#pStmtNext invalidStmt () s
-
- method dStmt (out: out_channel) (ind: int) (s:stmt) : unit =
- fprint out !lineLength (indent ind (self#pStmt () s))
-
- method dBlock (out: out_channel) (ind: int) (b:block) : unit =
- fprint out !lineLength (indent ind (align ++ self#pBlock () b))
-
- method private pStmtNext (next: stmt) () (s: stmt) =
- (* print the labels *)
- ((docList ~sep:line (fun l -> self#pLabel () l)) () s.labels)
- (* print the statement itself. If the labels are non-empty and the
- * statement is empty, print a semicolon *)
- ++
- (if s.skind = Instr [] && s.labels <> [] then
- text ";"
- else
- (if s.labels <> [] then line else nil)
- ++ self#pStmtKind next () s.skind)
-
- method private pLabel () = function
- Label (s, _, true) -> text (s ^ ": ")
- | Label (s, _, false) -> text (s ^ ": /* CIL Label */ ")
- | Case (e, _) -> text "case " ++ self#pExp () e ++ text ": "
- | Default _ -> text "default: "
-
- (* The pBlock will put the unalign itself *)
- method pBlock () (blk: block) =
- let rec dofirst () = function
- [] -> nil
- | [x] -> self#pStmtNext invalidStmt () x
- | x :: rest -> dorest nil x rest
- and dorest acc prev = function
- [] -> acc ++ (self#pStmtNext invalidStmt () prev)
- | x :: rest ->
- dorest (acc ++ (self#pStmtNext x () prev) ++ line)
- x rest
- in
- (* Let the host of the block decide on the alignment. The d_block will
- * pop the alignment as well *)
- text "{"
- ++
- (if blk.battrs <> [] then
- self#pAttrsGen true blk.battrs
- else nil)
- ++ line
- ++ (dofirst () blk.bstmts)
- ++ unalign ++ line ++ text "}"
-
-
- (* Store here the name of the last file printed in a line number. This is
- * private to the object *)
- val mutable lastFileName = ""
- (* Make sure that you only call self#pLineDirective on an empty line *)
- method pLineDirective ?(forcefile=false) l =
- currentLoc := l;
- match !lineDirectiveStyle with
- | Some style when l.line > 0 ->
- let directive =
- match style with
- | LineComment -> text "//#line "
- | LinePreprocessorOutput when not !msvcMode -> chr '#'
- | _ -> text "#line"
- in
- let filename =
- if forcefile || l.file <> lastFileName then
- begin
- lastFileName <- l.file;
- text " \"" ++ text l.file ++ text "\""
- end
- else
- nil
- in
- leftflush ++ directive ++ chr ' ' ++ num l.line ++ filename ++ line
- | _ ->
- nil
-
-
- method private pStmtKind (next: stmt) () = function
- Return(None, l) ->
- self#pLineDirective l
- ++ text "return;"
-
- | Return(Some e, l) ->
- self#pLineDirective l
- ++ text "return ("
- ++ self#pExp () e
- ++ text ");"
-
- | Goto (sref, l) -> begin
- (* Grab one of the labels *)
- let rec pickLabel = function
- [] -> None
- | Label (l, _, _) :: _ -> Some l
- | _ :: rest -> pickLabel rest
- in
- match pickLabel !sref.labels with
- Some l -> text ("goto " ^ l ^ ";")
- | None ->
- ignore (error "Cannot find label for target of goto\n");
- text "goto __invalid_label;"
- end
-
- | Break l ->
- self#pLineDirective l
- ++ text "break;"
-
- | Continue l ->
- self#pLineDirective l
- ++ text "continue;"
-
- | Instr il ->
- align
- ++ (docList ~sep:line (fun i -> self#pInstr () i) () il)
- ++ unalign
-
- | If(be,t,{bstmts=[];battrs=[]},l) when not !printCilAsIs ->
- self#pLineDirective l
- ++ text "if"
- ++ (align
- ++ text " ("
- ++ self#pExp () be
- ++ text ") "
- ++ self#pBlock () t)
-
- | If(be,t,{bstmts=[{skind=Goto(gref,_);labels=[]}];
- battrs=[]},l)
- when !gref == next && not !printCilAsIs ->
- self#pLineDirective l
- ++ text "if"
- ++ (align
- ++ text " ("
- ++ self#pExp () be
- ++ text ") "
- ++ self#pBlock () t)
-
- | If(be,{bstmts=[];battrs=[]},e,l) when not !printCilAsIs ->
- self#pLineDirective l
- ++ text "if"
- ++ (align
- ++ text " ("
- ++ self#pExp () (UnOp(LNot,be,intType))
- ++ text ") "
- ++ self#pBlock () e)
-
- | If(be,{bstmts=[{skind=Goto(gref,_);labels=[]}];
- battrs=[]},e,l)
- when !gref == next && not !printCilAsIs ->
- self#pLineDirective l
- ++ text "if"
- ++ (align
- ++ text " ("
- ++ self#pExp () (UnOp(LNot,be,intType))
- ++ text ") "
- ++ self#pBlock () e)
-
- | If(be,t,e,l) ->
- self#pLineDirective l
- ++ (align
- ++ text "if"
- ++ (align
- ++ text " ("
- ++ self#pExp () be
- ++ text ") "
- ++ self#pBlock () t)
- ++ text " " (* sm: indent next code 2 spaces (was 4) *)
- ++ (align
- ++ text "else "
- ++ self#pBlock () e)
- ++ unalign)
-
- | Switch(e,b,_,l) ->
- self#pLineDirective l
- ++ (align
- ++ text "switch ("
- ++ self#pExp () e
- ++ text ") "
- ++ self#pBlock () b)
-
-(*
- | Loop(b, l, _, _) -> begin
- (* Maybe the first thing is a conditional. Turn it into a WHILE *)
- try
- let term, bodystmts =
- let rec skipEmpty = function
- [] -> []
- | {skind=Instr [];labels=[]} :: rest -> skipEmpty rest
- | x -> x
- in
- (* Bill McCloskey: Do not remove the If if it has labels *)
- match skipEmpty b.bstmts with
- {skind=If(e,tb,fb,_); labels=[]} :: rest
- when not !printCilAsIs -> begin
- match skipEmpty tb.bstmts, skipEmpty fb.bstmts with
- [], {skind=Break _; labels=[]} :: _ -> e, rest
- | {skind=Break _; labels=[]} :: _, []
- -> UnOp(LNot, e, intType), rest
- | _ -> raise Not_found
- end
- | _ -> raise Not_found
- in
- self#pLineDirective l
- ++ text "wh"
- ++ (align
- ++ text "ile ("
- ++ self#pExp () term
- ++ text ") "
- ++ self#pBlock () {bstmts=bodystmts; battrs=b.battrs})
-
- with Not_found ->
- self#pLineDirective l
- ++ text "wh"
- ++ (align
- ++ text "ile (1) "
- ++ self#pBlock () b)
- end
-*)
-
- | While (e, b, l) ->
- self#pLineDirective l
- ++ (align
- ++ text "while ("
- ++ self#pExp () e
- ++ text ") "
- ++ self#pBlock () b)
-
- | DoWhile (e, b, l) ->
- self#pLineDirective l
- ++ (align
- ++ text "do "
- ++ self#pBlock () b
- ++ text " while ("
- ++ self#pExp () e
- ++ text ");")
-
- | For (bInit, e, bIter, b, l) ->
- ignore (E.warn
- "in for loops, the 1st and 3rd expressions are not printed");
- self#pLineDirective l
- ++ (align
- ++ text "for ("
- ++ text "/* ??? */" (* self#pBlock () bInit *)
- ++ text "; "
- ++ self#pExp () e
- ++ text "; "
- ++ text "/* ??? */" (* self#pBlock() bIter *)
- ++ text ") "
- ++ self#pBlock () b)
-
- | Block b -> align ++ self#pBlock () b
-
- | TryFinally (b, h, l) ->
- self#pLineDirective l
- ++ text "__try "
- ++ align
- ++ self#pBlock () b
- ++ text " __fin" ++ align ++ text "ally "
- ++ self#pBlock () h
-
- | TryExcept (b, (il, e), h, l) ->
- self#pLineDirective l
- ++ text "__try "
- ++ align
- ++ self#pBlock () b
- ++ text " __e" ++ align ++ text "xcept(" ++ line
- ++ align
- (* Print the instructions but with a comma at the end, instead of
- * semicolon *)
- ++ (printInstrTerminator <- ",";
- let res =
- (docList ~sep:line (self#pInstr ())
- () il)
- in
- printInstrTerminator <- ";";
- res)
- ++ self#pExp () e
- ++ text ") " ++ unalign
- ++ self#pBlock () h
-
-
- (*** GLOBALS ***)
- method pGlobal () (g:global) : doc = (* global (vars, types, etc.) *)
- match g with
- | GFun (fundec, l) ->
- (* If the function has attributes then print a prototype because
- * GCC cannot accept function attributes in a definition *)
- let oldattr = fundec.svar.vattr in
- (* Always pring the file name before function declarations *)
- let proto =
- if oldattr <> [] then
- (self#pLineDirective l) ++ (self#pVDecl () fundec.svar)
- ++ chr ';' ++ line
- else nil in
- (* Temporarily remove the function attributes *)
- fundec.svar.vattr <- [];
- let body = (self#pLineDirective ~forcefile:true l)
- ++ (self#pFunDecl () fundec) in
- fundec.svar.vattr <- oldattr;
- proto ++ body ++ line
-
- | GType (typ, l) ->
- self#pLineDirective ~forcefile:true l ++
- text "typedef "
- ++ (self#pType (Some (text typ.tname)) () typ.ttype)
- ++ text ";\n"
-
- | GEnumTag (enum, l) ->
- self#pLineDirective l ++
- text "enum" ++ align ++ text (" " ^ enum.ename) ++
- text " {" ++ line
- ++ (docList ~sep:(chr ',' ++ line)
- (fun (n,i, loc) ->
- text (n ^ " = ")
- ++ self#pExp () i)
- () enum.eitems)
- ++ unalign ++ line ++ text "} "
- ++ self#pAttrs () enum.eattr ++ text";\n"
-
- | GEnumTagDecl (enum, l) -> (* This is a declaration of a tag *)
- self#pLineDirective l ++
- text ("enum " ^ enum.ename ^ ";\n")
-
- | GCompTag (comp, l) -> (* This is a definition of a tag *)
- let n = comp.cname in
- let su, su1, su2 =
- if comp.cstruct then "struct", "str", "uct"
- else "union", "uni", "on"
- in
- let sto_mod, rest_attr = separateStorageModifiers comp.cattr in
- self#pLineDirective ~forcefile:true l ++
- text su1 ++ (align ++ text su2 ++ chr ' ' ++ (self#pAttrs () sto_mod)
- ++ text n
- ++ text " {" ++ line
- ++ ((docList ~sep:line (self#pFieldDecl ())) ()
- comp.cfields)
- ++ unalign)
- ++ line ++ text "}" ++
- (self#pAttrs () rest_attr) ++ text ";\n"
-
- | GCompTagDecl (comp, l) -> (* This is a declaration of a tag *)
- self#pLineDirective l ++
- text (compFullName comp) ++ text ";\n"
-
- | GVar (vi, io, l) ->
- self#pLineDirective ~forcefile:true l ++
- self#pVDecl () vi
- ++ chr ' '
- ++ (match io.init with
- None -> nil
- | Some i -> text " = " ++
- (let islong =
- match i with
- CompoundInit (_, il) when List.length il >= 8 -> true
- | _ -> false
- in
- if islong then
- line ++ self#pLineDirective l ++ text " "
- else nil) ++
- (self#pInit () i))
- ++ text ";\n"
-
- (* print global variable 'extern' declarations, and function prototypes *)
- | GVarDecl (vi, l) ->
- self#pLineDirective l ++
- (self#pVDecl () vi)
- ++ text ";\n"
-
- | GAsm (s, l) ->
- self#pLineDirective l ++
- text ("__asm__(\"" ^ escape_string s ^ "\");\n")
-
- | GPragma (Attr(an, args), l) ->
- (* sm: suppress printing pragmas that gcc does not understand *)
- (* assume anything starting with "ccured" is ours *)
- (* also don't print the 'combiner' pragma *)
- (* nor 'cilnoremove' *)
- let suppress =
- not !print_CIL_Input &&
- not !msvcMode &&
- ((startsWith "box" an) ||
- (startsWith "ccured" an) ||
- (an = "merger") ||
- (an = "cilnoremove")) in
- let d =
- match an, args with
- | _, [] ->
- text an
- | "weak", [ACons (symbol, [])] ->
- text "weak " ++ text symbol
- | _ ->
- text (an ^ "(")
- ++ docList ~sep:(chr ',') (self#pAttrParam ()) () args
- ++ text ")"
- in
- self#pLineDirective l
- ++ (if suppress then text "/* " else text "")
- ++ (text "#pragma ")
- ++ d
- ++ (if suppress then text " */\n" else text "\n")
-
- | GText s ->
- if s <> "//" then
- text s ++ text "\n"
- else
- nil
-
-
- method dGlobal (out: out_channel) (g: global) : unit =
- (* For all except functions and variable with initializers, use the
- * pGlobal *)
- match g with
- GFun (fdec, l) ->
- (* If the function has attributes then print a prototype because
- * GCC cannot accept function attributes in a definition *)
- let oldattr = fdec.svar.vattr in
- let proto =
- if oldattr <> [] then
- (self#pLineDirective l) ++ (self#pVDecl () fdec.svar)
- ++ chr ';' ++ line
- else nil in
- fprint out !lineLength
- (proto ++ (self#pLineDirective ~forcefile:true l));
- (* Temporarily remove the function attributes *)
- fdec.svar.vattr <- [];
- fprint out !lineLength (self#pFunDecl () fdec);
- fdec.svar.vattr <- oldattr;
- output_string out "\n"
-
- | GVar (vi, {init = Some i}, l) -> begin
- fprint out !lineLength
- (self#pLineDirective ~forcefile:true l ++
- self#pVDecl () vi
- ++ text " = "
- ++ (let islong =
- match i with
- CompoundInit (_, il) when List.length il >= 8 -> true
- | _ -> false
- in
- if islong then
- line ++ self#pLineDirective l ++ text " "
- else nil));
- self#dInit out 3 i;
- output_string out ";\n"
- end
-
- | g -> fprint out !lineLength (self#pGlobal () g)
-
- method pFieldDecl () fi =
- (self#pType
- (Some (text (if fi.fname = missingFieldName then "" else fi.fname)))
- ()
- fi.ftype)
- ++ text " "
- ++ (match fi.fbitfield with None -> nil
- | Some i -> text ": " ++ num i ++ text " ")
- ++ self#pAttrs () fi.fattr
- ++ text ";"
-
- method private pFunDecl () f =
- self#pVDecl () f.svar
- ++ line
- ++ text "{ "
- ++ (align
- (* locals. *)
- ++ (docList ~sep:line (fun vi -> self#pVDecl () vi ++ text ";")
- () f.slocals)
- ++ line ++ line
- (* the body *)
- ++ ((* remember the declaration *) currentFormals <- f.sformals;
- let body = self#pBlock () f.sbody in
- currentFormals <- [];
- body))
- ++ line
- ++ text "}"
-
- (***** PRINTING DECLARATIONS and TYPES ****)
-
- method pType (nameOpt: doc option) (* Whether we are declaring a name or
- * we are just printing a type *)
- () (t:typ) = (* use of some type *)
- let name = match nameOpt with None -> nil | Some d -> d in
- let printAttributes (a: attributes) =
- let pa = self#pAttrs () a in
- match nameOpt with
- | None when not !print_CIL_Input && not !msvcMode ->
- (* Cannot print the attributes in this case because gcc does not
- * like them here, except if we are printing for CIL, or for MSVC.
- * In fact, for MSVC we MUST print attributes such as __stdcall *)
- if pa = nil then nil else
- text "/*" ++ pa ++ text "*/"
- | _ -> pa
- in
- match t with
- TVoid a ->
- text "void"
- ++ self#pAttrs () a
- ++ text " "
- ++ name
-
- | TInt (ikind,a) ->
- d_ikind () ikind
- ++ self#pAttrs () a
- ++ text " "
- ++ name
-
- | TFloat(fkind, a) ->
- d_fkind () fkind
- ++ self#pAttrs () a
- ++ text " "
- ++ name
-
- | TComp (comp, a) -> (* A reference to a struct *)
- let su = if comp.cstruct then "struct" else "union" in
- text (su ^ " " ^ comp.cname ^ " ")
- ++ self#pAttrs () a
- ++ name
-
- | TEnum (enum, a) ->
- text ("enum " ^ enum.ename ^ " ")
- ++ self#pAttrs () a
- ++ name
- | TPtr (bt, a) ->
- (* Parenthesize the ( * attr name) if a pointer to a function or an
- * array. However, on MSVC the __stdcall modifier must appear right
- * before the pointer constructor "(__stdcall *f)". We push them into
- * the parenthesis. *)
- let (paren: doc option), (bt': typ) =
- match bt with
- TFun(rt, args, isva, fa) when !msvcMode ->
- let an, af', at = partitionAttributes ~default:AttrType fa in
- (* We take the af' and we put them into the parentheses *)
- Some (text "(" ++ printAttributes af'),
- TFun(rt, args, isva, addAttributes an at)
-
- | TFun _ | TArray _ -> Some (text "("), bt
-
- | _ -> None, bt
- in
- let name' = text "*" ++ printAttributes a ++ name in
- let name'' = (* Put the parenthesis *)
- match paren with
- Some p -> p ++ name' ++ text ")"
- | _ -> name'
- in
- self#pType
- (Some name'')
- ()
- bt'
-
- | TArray (elemt, lo, a) ->
- (* ignore the const attribute for arrays *)
- let a' = dropAttributes [ "const" ] a in
- let name' =
- if a' == [] then name else
- if nameOpt == None then printAttributes a' else
- text "(" ++ printAttributes a' ++ name ++ text ")"
- in
- self#pType
- (Some (name'
- ++ text "["
- ++ (match lo with None -> nil | Some e -> self#pExp () e)
- ++ text "]"))
- ()
- elemt
-
- | TFun (restyp, args, isvararg, a) ->
- let name' =
- if a == [] then name else
- if nameOpt == None then printAttributes a else
- text "(" ++ printAttributes a ++ name ++ text ")"
- in
- self#pType
- (Some
- (name'
- ++ text "("
- ++ (align
- ++
- (if args = Some [] && isvararg then
- text "..."
- else
- (if args = None then nil
- else if args = Some [] then text "void"
- else
- let pArg (aname, atype, aattr) =
- let stom, rest = separateStorageModifiers aattr in
- (* First the storage modifiers *)
- (self#pAttrs () stom)
- ++ (self#pType (Some (text aname)) () atype)
- ++ text " "
- ++ self#pAttrs () rest
- in
- (docList ~sep:(chr ',' ++ break) pArg) ()
- (argsToList args))
- ++ (if isvararg then break ++ text ", ..." else nil))
- ++ unalign)
- ++ text ")"))
- ()
- restyp
-
- | TNamed (t, a) ->
- text t.tname ++ self#pAttrs () a ++ text " " ++ name
-
- | TBuiltin_va_list a ->
- text "__builtin_va_list"
- ++ self#pAttrs () a
- ++ text " "
- ++ name
-
-
- (**** PRINTING ATTRIBUTES *********)
- method pAttrs () (a: attributes) =
- self#pAttrsGen false a
-
-
- (* Print one attribute. Return also an indication whether this attribute
- * should be printed inside the __attribute__ list *)
- method pAttr (Attr(an, args): attribute) : doc * bool =
- (* Recognize and take care of some known cases *)
- match an, args with
- "const", [] -> text "const", false
- (* Put the aconst inside the attribute list *)
- | "aconst", [] when not !msvcMode -> text "__const__", true
- | "thread", [] when not !msvcMode -> text "__thread", false
-(*
- | "used", [] when not !msvcMode -> text "__attribute_used__", false
-*)
- | "volatile", [] -> text "volatile", false
- | "restrict", [] -> text "__restrict", false
- | "missingproto", [] -> text "/* missing proto */", false
- | "cdecl", [] when !msvcMode -> text "__cdecl", false
- | "stdcall", [] when !msvcMode -> text "__stdcall", false
- | "fastcall", [] when !msvcMode -> text "__fastcall", false
- | "declspec", args when !msvcMode ->
- text "__declspec("
- ++ docList (self#pAttrParam ()) () args
- ++ text ")", false
- | "w64", [] when !msvcMode -> text "__w64", false
- | "asm", args ->
- text "__asm__("
- ++ docList (self#pAttrParam ()) () args
- ++ text ")", false
- (* we suppress printing mode(__si__) because it triggers an *)
- (* internal compiler error in all current gcc versions *)
- (* sm: I've now encountered a problem with mode(__hi__)... *)
- (* I don't know what's going on, but let's try disabling all "mode"..*)
- | "mode", [ACons(tag,[])] ->
- text "/* mode(" ++ text tag ++ text ") */", false
-
- (* sm: also suppress "format" because we seem to print it in *)
- (* a way gcc does not like *)
- | "format", _ -> text "/* format attribute */", false
-
- (* sm: here's another one I don't want to see gcc warnings about.. *)
- | "mayPointToStack", _ when not !print_CIL_Input
- (* [matth: may be inside another comment.]
- -> text "/*mayPointToStack*/", false
- *)
- -> text "", false
-
- | _ -> (* This is the dafault case *)
- (* Add underscores to the name *)
- let an' = if !msvcMode then "__" ^ an else "__" ^ an ^ "__" in
- if args = [] then
- text an', true
- else
- text (an' ^ "(")
- ++ (docList (self#pAttrParam ()) () args)
- ++ text ")",
- true
-
- method pAttrParam () = function
- | AInt n -> num n
- | AStr s -> text ("\"" ^ escape_string s ^ "\"")
- | ACons(s, []) -> text s
- | ACons(s,al) ->
- text (s ^ "(")
- ++ (docList (self#pAttrParam ()) () al)
- ++ text ")"
- | ASizeOfE a -> text "sizeof(" ++ self#pAttrParam () a ++ text ")"
- | ASizeOf t -> text "sizeof(" ++ self#pType None () t ++ text ")"
- | ASizeOfS ts -> text "sizeof(<typsig>)"
- | AAlignOfE a -> text "__alignof__(" ++ self#pAttrParam () a ++ text ")"
- | AAlignOf t -> text "__alignof__(" ++ self#pType None () t ++ text ")"
- | AAlignOfS ts -> text "__alignof__(<typsig>)"
- | AUnOp(u,a1) ->
- (d_unop () u) ++ text " (" ++ (self#pAttrParam () a1) ++ text ")"
-
- | ABinOp(b,a1,a2) ->
- align
- ++ text "("
- ++ (self#pAttrParam () a1)
- ++ text ") "
- ++ (d_binop () b)
- ++ break
- ++ text " (" ++ (self#pAttrParam () a2) ++ text ") "
- ++ unalign
- | ADot (ap, s) -> (self#pAttrParam () ap) ++ text ("." ^ s)
-
- (* A general way of printing lists of attributes *)
- method private pAttrsGen (block: bool) (a: attributes) =
- (* Scan all the attributes and separate those that must be printed inside
- * the __attribute__ list *)
- let rec loop (in__attr__: doc list) = function
- [] -> begin
- match in__attr__ with
- [] -> nil
- | _ :: _->
- (* sm: added 'forgcc' calls to not comment things out
- * if CIL is the consumer; this is to address a case
- * Daniel ran into where blockattribute(nobox) was being
- * dropped by the merger
- *)
- (if block then
- text (" " ^ (forgcc "/*") ^ " __blockattribute__(")
- else
- text "__attribute__((")
-
- ++ (docList ~sep:(chr ',' ++ break)
- (fun a -> a)) () in__attr__
- ++ text ")"
- ++ (if block then text (forgcc "*/") else text ")")
- end
- | x :: rest ->
- let dx, ina = self#pAttr x in
- if ina then
- loop (dx :: in__attr__) rest
- else
- dx ++ text " " ++ loop in__attr__ rest
- in
- let res = loop [] a in
- if res = nil then
- res
- else
- text " " ++ res ++ text " "
-
-end (* class defaultCilPrinterClass *)
-
-let defaultCilPrinter = new defaultCilPrinterClass
-
-(* Top-level printing functions *)
-let printType (pp: cilPrinter) () (t: typ) : doc =
- pp#pType None () t
-
-let printExp (pp: cilPrinter) () (e: exp) : doc =
- pp#pExp () e
-
-let printLval (pp: cilPrinter) () (lv: lval) : doc =
- pp#pLval () lv
-
-let printGlobal (pp: cilPrinter) () (g: global) : doc =
- pp#pGlobal () g
-
-let dumpGlobal (pp: cilPrinter) (out: out_channel) (g: global) : unit =
- pp#dGlobal out g
-
-let printAttr (pp: cilPrinter) () (a: attribute) : doc =
- let ad, _ = pp#pAttr a in ad
-
-let printAttrs (pp: cilPrinter) () (a: attributes) : doc =
- pp#pAttrs () a
-
-let printInstr (pp: cilPrinter) () (i: instr) : doc =
- pp#pInstr () i
-
-let printStmt (pp: cilPrinter) () (s: stmt) : doc =
- pp#pStmt () s
-
-let printBlock (pp: cilPrinter) () (b: block) : doc =
- (* We must add the alignment ourselves, beucase pBlock will pop it *)
- align ++ pp#pBlock () b
-
-let dumpStmt (pp: cilPrinter) (out: out_channel) (ind: int) (s: stmt) : unit =
- pp#dStmt out ind s
-
-let dumpBlock (pp: cilPrinter) (out: out_channel) (ind: int) (b: block) : unit =
- pp#dBlock out ind b
-
-let printInit (pp: cilPrinter) () (i: init) : doc =
- pp#pInit () i
-
-let dumpInit (pp: cilPrinter) (out: out_channel) (ind: int) (i: init) : unit =
- pp#dInit out ind i
-
-(* Now define some short cuts *)
-let d_exp () e = printExp defaultCilPrinter () e
-let _ = pd_exp := d_exp
-let d_lval () lv = printLval defaultCilPrinter () lv
-let d_offset base () off = defaultCilPrinter#pOffset base off
-let d_init () i = printInit defaultCilPrinter () i
-let d_type () t = printType defaultCilPrinter () t
-let d_global () g = printGlobal defaultCilPrinter () g
-let d_attrlist () a = printAttrs defaultCilPrinter () a
-let d_attr () a = printAttr defaultCilPrinter () a
-let d_attrparam () e = defaultCilPrinter#pAttrParam () e
-let d_label () l = defaultCilPrinter#pLabel () l
-let d_stmt () s = printStmt defaultCilPrinter () s
-let d_block () b = printBlock defaultCilPrinter () b
-let d_instr () i = printInstr defaultCilPrinter () i
-
-let d_shortglobal () = function
- GPragma (Attr(an, _), _) -> dprintf "#pragma %s" an
- | GType (ti, _) -> dprintf "typedef %s" ti.tname
- | GVarDecl (vi, _) -> dprintf "declaration of %s" vi.vname
- | GVar (vi, _, _) -> dprintf "definition of %s" vi.vname
- | GCompTag(ci,_) -> dprintf "definition of %s" (compFullName ci)
- | GCompTagDecl(ci,_) -> dprintf "declaration of %s" (compFullName ci)
- | GEnumTag(ei,_) -> dprintf "definition of enum %s" ei.ename
- | GEnumTagDecl(ei,_) -> dprintf "declaration of enum %s" ei.ename
- | GFun(fd, _) -> dprintf "definition of %s" fd.svar.vname
- | GText _ -> text "GText"
- | GAsm _ -> text "GAsm"
-
-
-(* sm: given an ordinary CIL object printer, yield one which
- * behaves the same, except it never prints #line directives
- * (this is useful for debugging printfs) *)
-let dn_obj (func: unit -> 'a -> doc) : (unit -> 'a -> doc) =
-begin
- (* construct the closure to return *)
- let theFunc () (obj:'a) : doc =
- begin
- let prevStyle = !lineDirectiveStyle in
- lineDirectiveStyle := None;
- let ret = (func () obj) in (* call underlying printer *)
- lineDirectiveStyle := prevStyle;
- ret
- end in
- theFunc
-end
-
-(* now define shortcuts for the non-location-printing versions,
- * with the naming prefix "dn_" *)
-let dn_exp = (dn_obj d_exp)
-let dn_lval = (dn_obj d_lval)
-(* dn_offset is missing because it has a different interface *)
-let dn_init = (dn_obj d_init)
-let dn_type = (dn_obj d_type)
-let dn_global = (dn_obj d_global)
-let dn_attrlist = (dn_obj d_attrlist)
-let dn_attr = (dn_obj d_attr)
-let dn_attrparam = (dn_obj d_attrparam)
-let dn_stmt = (dn_obj d_stmt)
-let dn_instr = (dn_obj d_instr)
-
-
-(* Now define a cilPlainPrinter *)
-class plainCilPrinterClass =
- (* We keep track of the composite types that we have done to avoid
- * recursion *)
- let donecomps : (int, unit) H.t = H.create 13 in
- object (self)
-
- inherit defaultCilPrinterClass as super
-
- (*** PLAIN TYPES ***)
- method pType (dn: doc option) () (t: typ) =
- match dn with
- None -> self#pOnlyType () t
- | Some d -> d ++ text " : " ++ self#pOnlyType () t
-
- method private pOnlyType () = function
- TVoid a -> dprintf "TVoid(@[%a@])" self#pAttrs a
- | TInt(ikind, a) -> dprintf "TInt(@[%a,@?%a@])"
- d_ikind ikind self#pAttrs a
- | TFloat(fkind, a) ->
- dprintf "TFloat(@[%a,@?%a@])" d_fkind fkind self#pAttrs a
- | TNamed (t, a) ->
- dprintf "TNamed(@[%s,@?%a,@?%a@])"
- t.tname self#pOnlyType t.ttype self#pAttrs a
- | TPtr(t, a) -> dprintf "TPtr(@[%a,@?%a@])" self#pOnlyType t self#pAttrs a
- | TArray(t,l,a) ->
- let dl = match l with
- None -> text "None" | Some l -> dprintf "Some(@[%a@])" self#pExp l in
- dprintf "TArray(@[%a,@?%a,@?%a@])"
- self#pOnlyType t insert dl self#pAttrs a
- | TEnum(enum,a) -> dprintf "Enum(%s,@[%a@])" enum.ename self#pAttrs a
- | TFun(tr,args,isva,a) ->
- dprintf "TFun(@[%a,@?%a%s,@?%a@])"
- self#pOnlyType tr
- insert
- (if args = None then text "None"
- else (docList ~sep:(chr ',' ++ break)
- (fun (an,at,aa) ->
- dprintf "%s: %a" an self#pOnlyType at))
- ()
- (argsToList args))
- (if isva then "..." else "") self#pAttrs a
- | TComp (comp, a) ->
- if H.mem donecomps comp.ckey then
- dprintf "TCompLoop(%s %s, _, %a)"
- (if comp.cstruct then "struct" else "union") comp.cname
- self#pAttrs comp.cattr
- else begin
- H.add donecomps comp.ckey (); (* Add it before we do the fields *)
- dprintf "TComp(@[%s %s,@?%a,@?%a,@?%a@])"
- (if comp.cstruct then "struct" else "union") comp.cname
- (docList ~sep:(chr ',' ++ break)
- (fun f -> dprintf "%s : %a" f.fname self#pOnlyType f.ftype))
- comp.cfields
- self#pAttrs comp.cattr
- self#pAttrs a
- end
- | TBuiltin_va_list a ->
- dprintf "TBuiltin_va_list(%a)" self#pAttrs a
-
-
- (* Some plain pretty-printers. Unlike the above these expose all the
- * details of the internal representation *)
- method pExp () = function
- Const(c) ->
- let d_plainconst () c =
- match c with
- CInt64(i, ik, so) ->
- dprintf "Int64(%s,%a,%s)"
- (Int64.format "%d" i)
- d_ikind ik
- (match so with Some s -> s | _ -> "None")
- | CStr(s) ->
- text ("CStr(\"" ^ escape_string s ^ "\")")
- | CWStr(s) ->
- dprintf "CWStr(%a)" d_const c
-
- | CChr(c) -> text ("CChr('" ^ escape_char c ^ "')")
- | CReal(f, fk, so) ->
- dprintf "CReal(%f, %a, %s)"
- f
- d_fkind fk
- (match so with Some s -> s | _ -> "None")
- | CEnum(_, s, _) -> text s
- in
- text "Const(" ++ d_plainconst () c ++ text ")"
-
-
- | Lval(lv) ->
- text "Lval("
- ++ (align
- ++ self#pLval () lv
- ++ unalign)
- ++ text ")"
-
- | CastE(t,e) -> dprintf "CastE(@[%a,@?%a@])" self#pOnlyType t self#pExp e
-
- | UnOp(u,e1,_) ->
- dprintf "UnOp(@[%a,@?%a@])"
- d_unop u self#pExp e1
-
- | BinOp(b,e1,e2,_) ->
- let d_plainbinop () b =
- match b with
- PlusA -> text "PlusA"
- | PlusPI -> text "PlusPI"
- | IndexPI -> text "IndexPI"
- | MinusA -> text "MinusA"
- | MinusPP -> text "MinusPP"
- | MinusPI -> text "MinusPI"
- | _ -> d_binop () b
- in
- dprintf "%a(@[%a,@?%a@])" d_plainbinop b
- self#pExp e1 self#pExp e2
-
- | SizeOf (t) ->
- text "sizeof(" ++ self#pType None () t ++ chr ')'
- | SizeOfE (e) ->
- text "sizeofE(" ++ self#pExp () e ++ chr ')'
- | SizeOfStr (s) ->
- text "sizeofStr(" ++ d_const () (CStr s) ++ chr ')'
- | AlignOf (t) ->
- text "__alignof__(" ++ self#pType None () t ++ chr ')'
- | AlignOfE (e) ->
- text "__alignof__(" ++ self#pExp () e ++ chr ')'
-
- | StartOf lv -> dprintf "StartOf(%a)" self#pLval lv
- | AddrOf (lv) -> dprintf "AddrOf(%a)" self#pLval lv
-
-
-
- method private d_plainoffset () = function
- NoOffset -> text "NoOffset"
- | Field(fi,o) ->
- dprintf "Field(@[%s:%a,@?%a@])"
- fi.fname self#pOnlyType fi.ftype self#d_plainoffset o
- | Index(e, o) ->
- dprintf "Index(@[%a,@?%a@])" self#pExp e self#d_plainoffset o
-
- method pInit () = function
- SingleInit e -> dprintf "SI(%a)" d_exp e
- | CompoundInit (t, initl) ->
- let d_plainoneinit (o, i) =
- self#d_plainoffset () o ++ text " = " ++ self#pInit () i
- in
- dprintf "CI(@[%a,@?%a@])" self#pOnlyType t
- (docList ~sep:(chr ',' ++ break) d_plainoneinit) initl
-(*
- | ArrayInit (t, len, initl) ->
- let idx = ref (- 1) in
- let d_plainoneinit i =
- incr idx;
- text "[" ++ num !idx ++ text "] = " ++ self#pInit () i
- in
- dprintf "AI(@[%a,%d,@?%a@])" self#pOnlyType t len
- (docList ~sep:(chr ',' ++ break) d_plainoneinit) initl
-*)
- method pLval () (lv: lval) =
- match lv with
- | Var vi, o -> dprintf "Var(@[%s,@?%a@])" vi.vname self#d_plainoffset o
- | Mem e, o -> dprintf "Mem(@[%a,@?%a@])" self#pExp e self#d_plainoffset o
-
-
-end
-let plainCilPrinter = new plainCilPrinterClass
-
-(* And now some shortcuts *)
-let d_plainexp () e = plainCilPrinter#pExp () e
-let d_plaintype () t = plainCilPrinter#pType None () t
-let d_plaininit () i = plainCilPrinter#pInit () i
-let d_plainlval () l = plainCilPrinter#pLval () l
-
-(* zra: this allows pretty printers not in cil.ml to
- be exposed to cilmain.ml *)
-let printerForMaincil = ref defaultCilPrinter
-
-let rec d_typsig () = function
- TSArray (ts, eo, al) ->
- dprintf "TSArray(@[%a,@?%a,@?%a@])"
- d_typsig ts
- insert (text (match eo with None -> "None"
- | Some e -> "Some " ^ Int64.to_string e))
- d_attrlist al
- | TSPtr (ts, al) ->
- dprintf "TSPtr(@[%a,@?%a@])"
- d_typsig ts d_attrlist al
- | TSComp (iss, name, al) ->
- dprintf "TSComp(@[%s %s,@?%a@])"
- (if iss then "struct" else "union") name
- d_attrlist al
- | TSFun (rt, args, isva, al) ->
- dprintf "TSFun(@[%a,@?%a,%b,@?%a@])"
- d_typsig rt
- (docList ~sep:(chr ',' ++ break) (d_typsig ())) args isva
- d_attrlist al
- | TSEnum (n, al) ->
- dprintf "TSEnum(@[%s,@?%a@])"
- n d_attrlist al
- | TSBase t -> dprintf "TSBase(%a)" d_type t
-
-
-let newVID () =
- let t = !nextGlobalVID in
- incr nextGlobalVID;
- t
-
- (* Make a varinfo. Used mostly as a helper function below *)
-let makeVarinfo global name typ =
- (* Strip const from type for locals *)
- let vi =
- { vname = name;
- vid = newVID ();
- vglob = global;
- vtype = if global then typ else typeRemoveAttributes ["const"] typ;
- vdecl = lu;
- vinline = false;
- vattr = [];
- vstorage = NoStorage;
- vaddrof = false;
- vreferenced = false; (* sm *)
- } in
- vi
-
-let copyVarinfo (vi: varinfo) (newname: string) : varinfo =
- let vi' = {vi with vname = newname; vid = newVID () } in
- vi'
-
-let makeLocal fdec name typ = (* a helper function *)
- fdec.smaxid <- 1 + fdec.smaxid;
- let vi = makeVarinfo false name typ in
- vi
-
- (* Make a local variable and add it to a function *)
-let makeLocalVar fdec ?(insert = true) name typ =
- let vi = makeLocal fdec name typ in
- if insert then fdec.slocals <- fdec.slocals @ [vi];
- vi
-
-
-let makeTempVar fdec ?(name = "__cil_tmp") typ : varinfo =
- let name = name ^ (string_of_int (1 + fdec.smaxid)) in
- makeLocalVar fdec name typ
-
-
- (* Set the formals and re-create the function name based on the information*)
-let setFormals (f: fundec) (forms: varinfo list) =
- f.sformals <- forms; (* Set the formals *)
- match unrollType f.svar.vtype with
- TFun(rt, _, isva, fa) ->
- f.svar.vtype <-
- TFun(rt,
- Some (List.map (fun a -> (a.vname, a.vtype, a.vattr)) forms),
- isva, fa)
- | _ -> E.s (E.bug "Set formals. %s does not have function type\n"
- f.svar.vname)
-
- (* Set the types of arguments and results as given by the function type
- * passed as the second argument *)
-let setFunctionType (f: fundec) (t: typ) =
- match unrollType t with
- TFun (rt, Some args, va, a) ->
- if List.length f.sformals <> List.length args then
- E.s (E.bug "setFunctionType: number of arguments differs from the number of formals");
- (* Change the function type. *)
- f.svar.vtype <- t;
- (* Change the sformals and we know that indirectly we'll change the
- * function type *)
- List.iter2
- (fun (an,at,aa) f ->
- f.vtype <- at; f.vattr <- aa)
- args f.sformals
-
- | _ -> E.s (E.bug "setFunctionType: not a function type")
-
-
- (* Set the types of arguments and results as given by the function type
- * passed as the second argument *)
-let setFunctionTypeMakeFormals (f: fundec) (t: typ) =
- match unrollType t with
- TFun (rt, Some args, va, a) ->
- if f.sformals <> [] then
- E.s (E.warn "setFunctionTypMakeFormals called on function %s with some formals already"
- f.svar.vname);
- (* Change the function type. *)
- f.svar.vtype <- t;
- f.sformals <- [];
-
- f.sformals <- List.map (fun (n,t,a) -> makeLocal f n t) args;
-
- setFunctionType f t
-
- | _ -> E.s (E.bug "setFunctionTypeMakeFormals: not a function type: %a"
- d_type t)
-
-
-let setMaxId (f: fundec) =
- f.smaxid <- List.length f.sformals + List.length f.slocals
-
-
- (* Make a formal variable for a function. Insert it in both the sformals
- * and the type of the function. You can optionally specify where to insert
- * this one. If where = "^" then it is inserted first. If where = "$" then
- * it is inserted last. Otherwise where must be the name of a formal after
- * which to insert this. By default it is inserted at the end. *)
-let makeFormalVar fdec ?(where = "$") name typ : varinfo =
- (* Search for the insertion place *)
- let thenewone = ref fdec.svar in (* Just a placeholder *)
- let makeit () : varinfo =
- let vi = makeLocal fdec name typ in
- thenewone := vi;
- vi
- in
- let rec loopFormals = function
- [] ->
- if where = "$" then [makeit ()]
- else E.s (E.error "makeFormalVar: cannot find insert-after formal %s"
- where)
- | f :: rest when f.vname = where -> f :: makeit () :: rest
- | f :: rest -> f :: loopFormals rest
- in
- let newformals =
- if where = "^" then makeit () :: fdec.sformals else
- loopFormals fdec.sformals in
- setFormals fdec newformals;
- !thenewone
-
- (* Make a global variable. Your responsibility to make sure that the name
- * is unique *)
-let makeGlobalVar name typ =
- let vi = makeVarinfo true name typ in
- vi
-
-
- (* Make an empty function *)
-let emptyFunction name =
- { svar = makeGlobalVar name (TFun(voidType, Some [], false,[]));
- smaxid = 0;
- slocals = [];
- sformals = [];
- sbody = mkBlock [];
- smaxstmtid = None;
- sallstmts = [];
- }
-
-
-
- (* A dummy function declaration handy for initialization *)
-let dummyFunDec = emptyFunction "@dummy"
-let dummyFile =
- { globals = [];
- fileName = "<dummy>";
- globinit = None;
- globinitcalled = false;}
-
-let saveBinaryFile (cil_file : file) (filename : string) =
- let outchan = open_out_bin filename in
- Marshal.to_channel outchan cil_file [] ;
- close_out outchan
-
-let saveBinaryFileChannel (cil_file : file) (outchan : out_channel) =
- Marshal.to_channel outchan cil_file []
-
-let loadBinaryFile (filename : string) : file =
- let inchan = open_in_bin filename in
- let cil_file = (Marshal.from_channel inchan : file) in
- close_in inchan ;
- cil_file
-
-
-(* Take the name of a file and make a valid symbol name out of it. There are
- * a few chanracters that are not valid in symbols *)
-let makeValidSymbolName (s: string) =
- let s = String.copy s in (* So that we can update in place *)
- let l = String.length s in
- for i = 0 to l - 1 do
- let c = String.get s i in
- let isinvalid =
- match c with
- '-' | '.' -> true
- | _ -> false
- in
- if isinvalid then
- String.set s i '_';
- done;
- s
-
-
-(*** Define the visiting engine ****)
-(* visit all the nodes in a Cil expression *)
-let doVisit (vis: cilVisitor)
- (startvisit: 'a -> 'a visitAction)
- (children: cilVisitor -> 'a -> 'a)
- (node: 'a) : 'a =
- let action = startvisit node in
- match action with
- SkipChildren -> node
- | ChangeTo node' -> node'
- | _ -> (* DoChildren and ChangeDoChildrenPost *)
- let nodepre = match action with
- ChangeDoChildrenPost (node', _) -> node'
- | _ -> node
- in
- let nodepost = children vis nodepre in
- match action with
- ChangeDoChildrenPost (_, f) -> f nodepost
- | _ -> nodepost
-
-(* mapNoCopy is like map but avoid copying the list if the function does not
- * change the elements. *)
-let rec mapNoCopy (f: 'a -> 'a) = function
- [] -> []
- | (i :: resti) as li ->
- let i' = f i in
- let resti' = mapNoCopy f resti in
- if i' != i || resti' != resti then i' :: resti' else li
-
-let rec mapNoCopyList (f: 'a -> 'a list) = function
- [] -> []
- | (i :: resti) as li ->
- let il' = f i in
- let resti' = mapNoCopyList f resti in
- match il' with
- [i'] when i' == i && resti' == resti -> li
- | _ -> il' @ resti'
-
-(* A visitor for lists *)
-let doVisitList (vis: cilVisitor)
- (startvisit: 'a -> 'a list visitAction)
- (children: cilVisitor -> 'a -> 'a)
- (node: 'a) : 'a list =
- let action = startvisit node in
- match action with
- SkipChildren -> [node]
- | ChangeTo nodes' -> nodes'
- | _ ->
- let nodespre = match action with
- ChangeDoChildrenPost (nodespre, _) -> nodespre
- | _ -> [node]
- in
- let nodespost = mapNoCopy (children vis) nodespre in
- match action with
- ChangeDoChildrenPost (_, f) -> f nodespost
- | _ -> nodespost
-
-let debugVisit = false
-
-let rec visitCilExpr (vis: cilVisitor) (e: exp) : exp =
- doVisit vis vis#vexpr childrenExp e
-and childrenExp (vis: cilVisitor) (e: exp) : exp =
- let vExp e = visitCilExpr vis e in
- let vTyp t = visitCilType vis t in
- let vLval lv = visitCilLval vis lv in
- match e with
- | Const (CEnum(v, s, ei)) ->
- let v' = vExp v in
- if v' != v then Const (CEnum(v', s, ei)) else e
-
- | Const _ -> e
- | SizeOf t ->
- let t'= vTyp t in
- if t' != t then SizeOf t' else e
- | SizeOfE e1 ->
- let e1' = vExp e1 in
- if e1' != e1 then SizeOfE e1' else e
- | SizeOfStr s -> e
-
- | AlignOf t ->
- let t' = vTyp t in
- if t' != t then AlignOf t' else e
- | AlignOfE e1 ->
- let e1' = vExp e1 in
- if e1' != e1 then AlignOfE e1' else e
- | Lval lv ->
- let lv' = vLval lv in
- if lv' != lv then Lval lv' else e
- | UnOp (uo, e1, t) ->
- let e1' = vExp e1 in let t' = vTyp t in
- if e1' != e1 || t' != t then UnOp(uo, e1', t') else e
- | BinOp (bo, e1, e2, t) ->
- let e1' = vExp e1 in let e2' = vExp e2 in let t' = vTyp t in
- if e1' != e1 || e2' != e2 || t' != t then BinOp(bo, e1',e2',t') else e
- | CastE (t, e1) ->
- let t' = vTyp t in let e1' = vExp e1 in
- if t' != t || e1' != e1 then CastE(t', e1') else e
- | AddrOf lv ->
- let lv' = vLval lv in
- if lv' != lv then AddrOf lv' else e
- | StartOf lv ->
- let lv' = vLval lv in
- if lv' != lv then StartOf lv' else e
-
-and visitCilInit (vis: cilVisitor) (i: init) : init =
- doVisit vis vis#vinit childrenInit i
-and childrenInit (vis: cilVisitor) (i: init) : init =
- let fExp e = visitCilExpr vis e in
- let fInit i = visitCilInit vis i in
- let fTyp t = visitCilType vis t in
- match i with
- | SingleInit e ->
- let e' = fExp e in
- if e' != e then SingleInit e' else i
- | CompoundInit (t, initl) ->
- let t' = fTyp t in
- (* Collect the new initializer list, in reverse. We prefer two
- * traversals to ensure tail-recursion. *)
- let newinitl : (offset * init) list ref = ref [] in
- (* Keep track whether the list has changed *)
- let hasChanged = ref false in
- let doOneInit ((o, i) as oi) =
- let o' = visitCilInitOffset vis o in (* use initializer version *)
- let i' = fInit i in
- let newio =
- if o' != o || i' != i then
- begin hasChanged := true; (o', i') end else oi
- in
- newinitl := newio :: !newinitl
- in
- List.iter doOneInit initl;
- let initl' = if !hasChanged then List.rev !newinitl else initl in
- if t' != t || initl' != initl then CompoundInit (t', initl') else i
-
-and visitCilLval (vis: cilVisitor) (lv: lval) : lval =
- doVisit vis vis#vlval childrenLval lv
-and childrenLval (vis: cilVisitor) (lv: lval) : lval =
- (* and visit its subexpressions *)
- let vExp e = visitCilExpr vis e in
- let vOff off = visitCilOffset vis off in
- match lv with
- Var v, off ->
- let v' = doVisit vis vis#vvrbl (fun _ x -> x) v in
- let off' = vOff off in
- if v' != v || off' != off then Var v', off' else lv
- | Mem e, off ->
- let e' = vExp e in
- let off' = vOff off in
- if e' != e || off' != off then Mem e', off' else lv
-
-and visitCilOffset (vis: cilVisitor) (off: offset) : offset =
- doVisit vis vis#voffs childrenOffset off
-and childrenOffset (vis: cilVisitor) (off: offset) : offset =
- let vOff off = visitCilOffset vis off in
- match off with
- Field (f, o) ->
- let o' = vOff o in
- if o' != o then Field (f, o') else off
- | Index (e, o) ->
- let e' = visitCilExpr vis e in
- let o' = vOff o in
- if e' != e || o' != o then Index (e', o') else off
- | NoOffset -> off
-
-(* sm: for offsets in initializers, the 'startvisit' will be the
- * vinitoffs method, but we can re-use the childrenOffset from
- * above since recursive offsets are visited by voffs. (this point
- * is moot according to cil.mli which claims the offsets in
- * initializers will never recursively contain offsets)
- *)
-and visitCilInitOffset (vis: cilVisitor) (off: offset) : offset =
- doVisit vis vis#vinitoffs childrenOffset off
-
-and visitCilInstr (vis: cilVisitor) (i: instr) : instr list =
- let oldloc = !currentLoc in
- currentLoc := (get_instrLoc i);
- assertEmptyQueue vis;
- let res = doVisitList vis vis#vinst childrenInstr i in
- currentLoc := oldloc;
- (* See if we have accumulated some instructions *)
- vis#unqueueInstr () @ res
-
-and childrenInstr (vis: cilVisitor) (i: instr) : instr =
- let fExp = visitCilExpr vis in
- let fLval = visitCilLval vis in
- match i with
- | Set(lv,e,l) ->
- let lv' = fLval lv in let e' = fExp e in
- if lv' != lv || e' != e then Set(lv',e',l) else i
- | Call(None,f,args,l) ->
- let f' = fExp f in let args' = mapNoCopy fExp args in
- if f' != f || args' != args then Call(None,f',args',l) else i
- | Call(Some lv,fn,args,l) ->
- let lv' = fLval lv in let fn' = fExp fn in
- let args' = mapNoCopy fExp args in
- if lv' != lv || fn' != fn || args' != args
- then Call(Some lv', fn', args', l) else i
-
- | Asm(sl,isvol,outs,ins,clobs,l) ->
- let outs' = mapNoCopy (fun ((s,lv) as pair) ->
- let lv' = fLval lv in
- if lv' != lv then (s,lv') else pair) outs in
- let ins' = mapNoCopy (fun ((s,e) as pair) ->
- let e' = fExp e in
- if e' != e then (s,e') else pair) ins in
- if outs' != outs || ins' != ins then
- Asm(sl,isvol,outs',ins',clobs,l) else i
-
-
-(* visit all nodes in a Cil statement tree in preorder *)
-and visitCilStmt (vis: cilVisitor) (s: stmt) : stmt =
- let oldloc = !currentLoc in
- currentLoc := (get_stmtLoc s.skind) ;
- assertEmptyQueue vis;
- let toPrepend : instr list ref = ref [] in (* childrenStmt may add to this *)
- let res = doVisit vis vis#vstmt (childrenStmt toPrepend) s in
- (* Now see if we have saved some instructions *)
- toPrepend := !toPrepend @ vis#unqueueInstr ();
- (match !toPrepend with
- [] -> () (* Return the same statement *)
- | _ ->
- (* Make our statement contain the instructions to prepend *)
- res.skind <- Block { battrs = []; bstmts = [ mkStmt (Instr !toPrepend);
- mkStmt res.skind ] });
- currentLoc := oldloc;
- res
-
-and childrenStmt (toPrepend: instr list ref) (vis:cilVisitor) (s:stmt): stmt =
- let fExp e = (visitCilExpr vis e) in
- let fBlock b = visitCilBlock vis b in
- let fInst i = visitCilInstr vis i in
- (* Just change the statement kind *)
- let skind' =
- match s.skind with
- Break _ | Continue _ | Goto _ | Return (None, _) -> s.skind
- | Return (Some e, l) ->
- let e' = fExp e in
- if e' != e then Return (Some e', l) else s.skind
-(*
- | Loop (b, l, s1, s2) ->
- let b' = fBlock b in
- if b' != b then Loop (b', l, s1, s2) else s.skind
-*)
- | While (e, b, l) ->
- let e' = fExp e in
- let b' = fBlock b in
- if e' != e || b' != b then While (e', b', l) else s.skind
- | DoWhile (e, b, l) ->
- let b' = fBlock b in
- let e' = fExp e in
- if e' != e || b' != b then DoWhile (e', b', l) else s.skind
- | For (bInit, e, bIter, b, l) ->
- let bInit' = fBlock bInit in
- let e' = fExp e in
- let bIter' = fBlock bIter in
- let b' = fBlock b in
- if bInit' != bInit || e' != e || bIter' != bIter || b' != b then
- For (bInit', e', bIter', b', l) else s.skind
- | If(e, s1, s2, l) ->
- let e' = fExp e in
- (*if e queued any instructions, pop them here and remember them so that
- they are inserted before the If stmt, not in the then block. *)
- toPrepend := vis#unqueueInstr ();
- let s1'= fBlock s1 in let s2'= fBlock s2 in
- (* the stmts in the blocks should have cleaned up after themselves.*)
- assertEmptyQueue vis;
- if e' != e || s1' != s1 || s2' != s2 then
- If(e', s1', s2', l) else s.skind
- | Switch (e, b, stmts, l) ->
- let e' = fExp e in
- toPrepend := vis#unqueueInstr (); (* insert these before the switch *)
- let b' = fBlock b in
- (* the stmts in b should have cleaned up after themselves.*)
- assertEmptyQueue vis;
- (* Don't do stmts, but we better not change those *)
- if e' != e || b' != b then Switch (e', b', stmts, l) else s.skind
- | Instr il ->
- let il' = mapNoCopyList fInst il in
- if il' != il then Instr il' else s.skind
- | Block b ->
- let b' = fBlock b in
- if b' != b then Block b' else s.skind
- | TryFinally (b, h, l) ->
- let b' = fBlock b in
- let h' = fBlock h in
- if b' != b || h' != h then TryFinally(b', h', l) else s.skind
- | TryExcept (b, (il, e), h, l) ->
- let b' = fBlock b in
- assertEmptyQueue vis;
- (* visit the instructions *)
- let il' = mapNoCopyList fInst il in
- (* Visit the expression *)
- let e' = fExp e in
- let il'' =
- let more = vis#unqueueInstr () in
- if more != [] then
- il' @ more
- else
- il'
- in
- let h' = fBlock h in
- (* Now collect the instructions *)
- if b' != b || il'' != il || e' != e || h' != h then
- TryExcept(b', (il'', e'), h', l)
- else s.skind
- in
- if skind' != s.skind then s.skind <- skind';
- (* Visit the labels *)
- let labels' =
- let fLabel = function
- Case (e, l) as lb ->
- let e' = fExp e in
- if e' != e then Case (e', l) else lb
- | lb -> lb
- in
- mapNoCopy fLabel s.labels
- in
- if labels' != s.labels then s.labels <- labels';
- s
-
-
-
-and visitCilBlock (vis: cilVisitor) (b: block) : block =
- doVisit vis vis#vblock childrenBlock b
-and childrenBlock (vis: cilVisitor) (b: block) : block =
- let fStmt s = visitCilStmt vis s in
- let stmts' = mapNoCopy fStmt b.bstmts in
- if stmts' != b.bstmts then { battrs = b.battrs; bstmts = stmts'} else b
-
-
-and visitCilType (vis : cilVisitor) (t : typ) : typ =
- doVisit vis vis#vtype childrenType t
-and childrenType (vis : cilVisitor) (t : typ) : typ =
- (* look for types referred to inside t's definition *)
- let fTyp t = visitCilType vis t in
- let fAttr a = visitCilAttributes vis a in
- match t with
- TPtr(t1, a) ->
- let t1' = fTyp t1 in
- let a' = fAttr a in
- if t1' != t || a' != a then TPtr(t1', a') else t
- | TArray(t1, None, a) ->
- let t1' = fTyp t1 in
- let a' = fAttr a in
- if t1' != t || a' != a then TArray(t1', None, a') else t
- | TArray(t1, Some e, a) ->
- let t1' = fTyp t1 in
- let e' = visitCilExpr vis e in
- let a' = fAttr a in
- if t1' != t || e' != e || a' != a then TArray(t1', Some e', a') else t
-
- (* DON'T recurse into the compinfo, this is done in visitCilGlobal.
- User can iterate over cinfo.cfields manually, if desired.*)
- | TComp(cinfo, a) ->
- let a' = fAttr a in
- if a != a' then TComp(cinfo, a') else t
-
- | TFun(rettype, args, isva, a) ->
- let rettype' = fTyp rettype in
- (* iterate over formals, as variable declarations *)
- let argslist = argsToList args in
- let visitArg ((an,at,aa) as arg) =
- let at' = fTyp at in
- let aa' = fAttr aa in
- if at' != at || aa' != aa then (an,at',aa') else arg
- in
- let argslist' = mapNoCopy visitArg argslist in
- let a' = fAttr a in
- if rettype' != rettype || argslist' != argslist || a' != a then
- let args' = if argslist' == argslist then args else Some argslist' in
- TFun(rettype', args', isva, a') else t
-
- | TNamed(t1, a) -> (* Do not go into the type. Will do it at the time of
- * GType *)
- let a' = fAttr a in
- if a' != a then TNamed (t1, a') else t
-
- | _ -> (* other types (TVoid, TInt, TFloat, TEnum, and TBuiltin_va_list)
- don't contain nested types, but they do have attributes. *)
- let a = typeAttrs t in
- let a' = fAttr a in
- if a' != a then setTypeAttrs t a' else t
-
-
-(* for declarations, we visit the types inside; but for uses, *)
-(* we just visit the varinfo node *)
-and visitCilVarDecl (vis : cilVisitor) (v : varinfo) : varinfo =
- doVisit vis vis#vvdec childrenVarDecl v
-and childrenVarDecl (vis : cilVisitor) (v : varinfo) : varinfo =
- v.vtype <- visitCilType vis v.vtype;
- v.vattr <- visitCilAttributes vis v.vattr;
- v
-
-and visitCilAttributes (vis: cilVisitor) (al: attribute list) : attribute list=
- let al' =
- mapNoCopyList (doVisitList vis vis#vattr childrenAttribute) al in
- if al' != al then
- (* Must re-sort *)
- addAttributes al' []
- else
- al
-and childrenAttribute (vis: cilVisitor) (a: attribute) : attribute =
- let fAttrP a = visitCilAttrParams vis a in
- match a with
- Attr (n, args) ->
- let args' = mapNoCopy fAttrP args in
- if args' != args then Attr(n, args') else a
-
-
-and visitCilAttrParams (vis: cilVisitor) (a: attrparam) : attrparam =
- doVisit vis vis#vattrparam childrenAttrparam a
-and childrenAttrparam (vis: cilVisitor) (aa: attrparam) : attrparam =
- let fTyp t = visitCilType vis t in
- let fAttrP a = visitCilAttrParams vis a in
- match aa with
- AInt _ | AStr _ -> aa
- | ACons(n, args) ->
- let args' = mapNoCopy fAttrP args in
- if args' != args then ACons(n, args') else aa
- | ASizeOf t ->
- let t' = fTyp t in
- if t' != t then ASizeOf t' else aa
- | ASizeOfE e ->
- let e' = fAttrP e in
- if e' != e then ASizeOfE e' else aa
- | AAlignOf t ->
- let t' = fTyp t in
- if t' != t then AAlignOf t' else aa
- | AAlignOfE e ->
- let e' = fAttrP e in
- if e' != e then AAlignOfE e' else aa
- | ASizeOfS _ | AAlignOfS _ ->
- ignore (warn "Visitor inside of a type signature.");
- aa
- | AUnOp (uo, e1) ->
- let e1' = fAttrP e1 in
- if e1' != e1 then AUnOp (uo, e1') else aa
- | ABinOp (bo, e1, e2) ->
- let e1' = fAttrP e1 in
- let e2' = fAttrP e2 in
- if e1' != e1 || e2' != e2 then ABinOp (bo, e1', e2') else aa
- | ADot (ap, s) ->
- let ap' = fAttrP ap in
- if ap' != ap then ADot (ap', s) else aa
-
-
-let rec visitCilFunction (vis : cilVisitor) (f : fundec) : fundec =
- if debugVisit then ignore (E.log "Visiting function %s\n" f.svar.vname);
- assertEmptyQueue vis;
- let f = doVisit vis vis#vfunc childrenFunction f in
-
- let toPrepend = vis#unqueueInstr () in
- if toPrepend <> [] then
- f.sbody.bstmts <- mkStmt (Instr toPrepend) :: f.sbody.bstmts;
- f
-
-and childrenFunction (vis : cilVisitor) (f : fundec) : fundec =
- f.svar <- visitCilVarDecl vis f.svar; (* hit the function name *)
- (* visit local declarations *)
- f.slocals <- mapNoCopy (visitCilVarDecl vis) f.slocals;
- (* visit the formals *)
- let newformals = mapNoCopy (visitCilVarDecl vis) f.sformals in
- (* Make sure the type reflects the formals *)
- setFormals f newformals;
- (* Remember any new instructions that were generated while visiting
- variable declarations. *)
- let toPrepend = vis#unqueueInstr () in
-
- f.sbody <- visitCilBlock vis f.sbody; (* visit the body *)
- if toPrepend <> [] then
- f.sbody.bstmts <- mkStmt (Instr toPrepend) :: f.sbody.bstmts;
- f
-
-let rec visitCilGlobal (vis: cilVisitor) (g: global) : global list =
- (*(trace "visit" (dprintf "visitCilGlobal\n"));*)
- let oldloc = !currentLoc in
- currentLoc := (get_globalLoc g) ;
- currentGlobal := g;
- let res = doVisitList vis vis#vglob childrenGlobal g in
- currentLoc := oldloc;
- res
-and childrenGlobal (vis: cilVisitor) (g: global) : global =
- match g with
- | GFun (f, l) ->
- let f' = visitCilFunction vis f in
- if f' != f then GFun (f', l) else g
- | GType(t, l) ->
- t.ttype <- visitCilType vis t.ttype;
- g
-
- | GEnumTagDecl _ | GCompTagDecl _ -> g (* Nothing to visit *)
- | GEnumTag (enum, _) ->
- (trace "visit" (dprintf "visiting global enum %s\n" enum.ename));
- (* Do the values and attributes of the enumerated items *)
- let itemVisit (name, exp, loc) = (name, visitCilExpr vis exp, loc) in
- enum.eitems <- mapNoCopy itemVisit enum.eitems;
- enum.eattr <- visitCilAttributes vis enum.eattr;
- g
-
- | GCompTag (comp, _) ->
- (trace "visit" (dprintf "visiting global comp %s\n" comp.cname));
- (* Do the types and attirbutes of the fields *)
- let fieldVisit = fun fi ->
- fi.ftype <- visitCilType vis fi.ftype;
- fi.fattr <- visitCilAttributes vis fi.fattr
- in
- List.iter fieldVisit comp.cfields;
- comp.cattr <- visitCilAttributes vis comp.cattr;
- g
-
- | GVarDecl(v, l) ->
- let v' = visitCilVarDecl vis v in
- if v' != v then GVarDecl (v', l) else g
- | GVar (v, inito, l) ->
- let v' = visitCilVarDecl vis v in
- (match inito.init with
- None -> ()
- | Some i -> let i' = visitCilInit vis i in
- if i' != i then inito.init <- Some i');
-
- if v' != v then GVar (v', inito, l) else g
-
- | GPragma (a, l) -> begin
- match visitCilAttributes vis [a] with
- [a'] -> if a' != a then GPragma (a', l) else g
- | _ -> E.s (E.unimp "visitCilAttributes returns more than one attribute")
- end
- | _ -> g
-
-
-(** A visitor that does constant folding. If "machdep" is true then we do
- * machine dependent simplification (e.g., sizeof) *)
-class constFoldVisitorClass (machdep: bool) : cilVisitor = object
- inherit nopCilVisitor
-
- method vinst i =
- match i with
- (* Skip two functions to which we add Sizeof to the type arguments.
- See the comments for these above. *)
- Call(_,(Lval (Var vi,NoOffset)),_,_)
- when ((vi.vname = "__builtin_va_arg")
- || (vi.vname = "__builtin_types_compatible_p")) ->
- SkipChildren
- | _ -> DoChildren
- method vexpr (e: exp) =
- (* Do it bottom up *)
- ChangeDoChildrenPost (e, constFold machdep)
-
-end
-let constFoldVisitor (machdep: bool) = new constFoldVisitorClass machdep
-
-(* Iterate over all globals, including the global initializer *)
-let iterGlobals (fl: file)
- (doone: global -> unit) : unit =
- let doone' g =
- currentLoc := get_globalLoc g;
- doone g
- in
- List.iter doone' fl.globals;
- (match fl.globinit with
- None -> ()
- | Some g -> doone' (GFun(g, locUnknown)))
-
-(* Fold over all globals, including the global initializer *)
-let foldGlobals (fl: file)
- (doone: 'a -> global -> 'a)
- (acc: 'a) : 'a =
- let doone' acc g =
- currentLoc := get_globalLoc g;
- doone acc g
- in
- let acc' = List.fold_left doone' acc fl.globals in
- (match fl.globinit with
- None -> acc'
- | Some g -> doone' acc' (GFun(g, locUnknown)))
-
-
-(* A visitor for the whole file that does not change the globals *)
-let visitCilFileSameGlobals (vis : cilVisitor) (f : file) : unit =
- let fGlob g = visitCilGlobal vis g in
- iterGlobals f (fun g ->
- match fGlob g with
- [g'] when g' == g || Util.equals g' g -> () (* Try to do the pointer check first *)
- | gl ->
- ignore (E.log "You used visitCilFilSameGlobals but the global got changed:\n %a\nchanged to %a\n" d_global g (docList ~sep:line (d_global ())) gl);
- ())
-
-(* Be careful with visiting the whole file because it might be huge. *)
-let visitCilFile (vis : cilVisitor) (f : file) : unit =
- let fGlob g = visitCilGlobal vis g in
- (* Scan the globals. Make sure this is tail recursive. *)
- let rec loop (acc: global list) = function
- [] -> f.globals <- List.rev acc
- | g :: restg ->
- loop ((List.rev (fGlob g)) @ acc) restg
- in
- loop [] f.globals;
- (* the global initializer *)
- (match f.globinit with
- None -> ()
- | Some g -> f.globinit <- Some (visitCilFunction vis g))
-
-
-
-(** Create or fetch the global initializer. Tries to put a call to in the the
- * function with the main_name *)
-let getGlobInit ?(main_name="main") (fl: file) =
- match fl.globinit with
- Some f -> f
- | None -> begin
- (* Sadly, we cannot use the Filename library because it does not like
- * function names with multiple . in them *)
- let f =
- let len = String.length fl.fileName in
- (* Find the last path separator and record the first . that we see,
- * going backwards *)
- let lastDot = ref len in
- let rec findLastPathSep i =
- if i < 0 then -1 else
- let c = String.get fl.fileName i in
- if c = '/' || c = '\\' then i
- else begin
- if c = '.' && !lastDot = len then
- lastDot := i;
- findLastPathSep (i - 1)
- end
- in
- let lastPathSep = findLastPathSep (len - 1) in
- let basenoext =
- String.sub fl.fileName (lastPathSep + 1) (!lastDot - lastPathSep - 1)
- in
- emptyFunction
- (makeValidSymbolName ("__globinit_" ^ basenoext))
- in
- fl.globinit <- Some f;
- (* Now try to add a call to the global initialized at the beginning of
- * main *)
- let inserted = ref false in
- List.iter
- (fun g ->
- match g with
- GFun(m, lm) when m.svar.vname = main_name ->
- (* Prepend a prototype to the global initializer *)
- fl.globals <- GVarDecl (f.svar, lm) :: fl.globals;
- m.sbody.bstmts <-
- compactStmts (mkStmt (Instr [Call(None,
- Lval(var f.svar),
- [], locUnknown)])
- :: m.sbody.bstmts);
- inserted := true;
- if !E.verboseFlag then
- ignore (E.log "Inserted the globinit\n");
- fl.globinitcalled <- true;
- | _ -> ())
- fl.globals;
-
- if not !inserted then
- ignore (E.warn "Cannot find %s to add global initializer %s"
- main_name f.svar.vname);
-
- f
- end
-
-
-
-(* Fold over all globals, including the global initializer *)
-let mapGlobals (fl: file)
- (doone: global -> global) : unit =
- fl.globals <- List.map doone fl.globals;
- (match fl.globinit with
- None -> ()
- | Some g -> begin
- match doone (GFun(g, locUnknown)) with
- GFun(g', _) -> fl.globinit <- Some g'
- | _ -> E.s (E.bug "mapGlobals: globinit is not a function")
- end)
-
-
-
-let dumpFile (pp: cilPrinter) (out : out_channel) (outfile: string) file =
- printDepth := 99999; (* We don't want ... in the output *)
- (* If we are in RELEASE mode then we do not print indentation *)
-
- Pretty.fastMode := true;
-
- if !E.verboseFlag then
- ignore (E.log "printing file %s\n" outfile);
- let print x = fprint out 78 x in
- print (text ("/* Generated by CIL v. " ^ cilVersion ^ " */\n" ^
- (* sm: I want to easily tell whether the generated output
- * is with print_CIL_Input or not *)
- "/* print_CIL_Input is " ^ (if !print_CIL_Input then "true" else "false") ^ " */\n\n"));
- iterGlobals file (fun g -> dumpGlobal pp out g);
-
- (* sm: we have to flush the output channel; if we don't then under *)
- (* some circumstances (I haven't figure out exactly when, but it happens *)
- (* more often with big inputs), we get a truncated output file *)
- flush out
-
-
-
-(******************
- ******************
- ******************)
-
-
-
-(******************** OPTIMIZATIONS *****)
-let rec peepHole1 (* Process one statement and possibly replace it *)
- (doone: instr -> instr list option)
- (* Scan a block and recurse inside nested blocks *)
- (ss: stmt list) : unit =
- let rec doInstrList (il: instr list) : instr list =
- match il with
- [] -> []
- | i :: rest -> begin
- match doone i with
- None -> i :: doInstrList rest
- | Some sl -> doInstrList (sl @ rest)
- end
- in
-
- List.iter
- (fun s ->
- match s.skind with
- Instr il -> s.skind <- Instr (doInstrList il)
- | If (e, tb, eb, _) ->
- peepHole1 doone tb.bstmts;
- peepHole1 doone eb.bstmts
- | Switch (e, b, _, _) -> peepHole1 doone b.bstmts
-(*
- | Loop (b, l, _, _) -> peepHole1 doone b.bstmts
-*)
- | While (_, b, _) -> peepHole1 doone b.bstmts
- | DoWhile (_, b, _) -> peepHole1 doone b.bstmts
- | For (bInit, _, bIter, b, _) ->
- peepHole1 doone bInit.bstmts;
- peepHole1 doone bIter.bstmts;
- peepHole1 doone b.bstmts
- | Block b -> peepHole1 doone b.bstmts
- | TryFinally (b, h, l) ->
- peepHole1 doone b.bstmts;
- peepHole1 doone h.bstmts
- | TryExcept (b, (il, e), h, l) ->
- peepHole1 doone b.bstmts;
- peepHole1 doone h.bstmts;
- s.skind <- TryExcept(b, (doInstrList il, e), h, l);
- | Return _ | Goto _ | Break _ | Continue _ -> ())
- ss
-
-let rec peepHole2 (* Process two statements and possibly replace them both *)
- (dotwo: instr * instr -> instr list option)
- (ss: stmt list) : unit =
- let rec doInstrList (il: instr list) : instr list =
- match il with
- [] -> []
- | [i] -> [i]
- | (i1 :: ((i2 :: rest) as rest2)) ->
- begin
- match dotwo (i1,i2) with
- None -> i1 :: doInstrList rest2
- | Some sl -> doInstrList (sl @ rest)
- end
- in
- List.iter
- (fun s ->
- match s.skind with
- Instr il -> s.skind <- Instr (doInstrList il)
- | If (e, tb, eb, _) ->
- peepHole2 dotwo tb.bstmts;
- peepHole2 dotwo eb.bstmts
- | Switch (e, b, _, _) -> peepHole2 dotwo b.bstmts
-(*
- | Loop (b, l, _, _) -> peepHole2 dotwo b.bstmts
-*)
- | While (_, b, _) -> peepHole2 dotwo b.bstmts
- | DoWhile (_, b, _) -> peepHole2 dotwo b.bstmts
- | For (bInit, _, bIter, b, _) ->
- peepHole2 dotwo bInit.bstmts;
- peepHole2 dotwo bIter.bstmts;
- peepHole2 dotwo b.bstmts
- | Block b -> peepHole2 dotwo b.bstmts
- | TryFinally (b, h, l) -> peepHole2 dotwo b.bstmts;
- peepHole2 dotwo h.bstmts
- | TryExcept (b, (il, e), h, l) ->
- peepHole2 dotwo b.bstmts;
- peepHole2 dotwo h.bstmts;
- s.skind <- TryExcept (b, (doInstrList il, e), h, l)
-
- | Return _ | Goto _ | Break _ | Continue _ -> ())
- ss
-
-
-
-
-(*** Type signatures ***)
-
-(* Helper class for typeSig: replace any types in attributes with typsigs *)
-class typeSigVisitor(typeSigConverter: typ->typsig) = object
- inherit nopCilVisitor
- method vattrparam ap =
- match ap with
- | ASizeOf t -> ChangeTo (ASizeOfS (typeSigConverter t))
- | AAlignOf t -> ChangeTo (AAlignOfS (typeSigConverter t))
- | _ -> DoChildren
-end
-
-let typeSigAddAttrs a0 t =
- if a0 == [] then t else
- match t with
- TSBase t -> TSBase (typeAddAttributes a0 t)
- | TSPtr (ts, a) -> TSPtr (ts, addAttributes a0 a)
- | TSArray (ts, l, a) -> TSArray(ts, l, addAttributes a0 a)
- | TSComp (iss, n, a) -> TSComp (iss, n, addAttributes a0 a)
- | TSEnum (n, a) -> TSEnum (n, addAttributes a0 a)
- | TSFun(ts, tsargs, isva, a) -> TSFun(ts, tsargs, isva, addAttributes a0 a)
-
-(* Compute a type signature.
- Use ~ignoreSign:true to convert all signed integer types to unsigned,
- so that signed and unsigned will compare the same. *)
-let rec typeSigWithAttrs ?(ignoreSign=false) doattr t =
- let typeSig = typeSigWithAttrs ~ignoreSign doattr in
- let attrVisitor = new typeSigVisitor typeSig in
- let doattr al = visitCilAttributes attrVisitor (doattr al) in
- match t with
- | TInt (ik, al) ->
- let ik' = if ignoreSign then begin
- match ik with
- | ISChar | IChar -> IUChar
- | IShort -> IUShort
- | IInt -> IUInt
- | ILong -> IULong
- | ILongLong -> IULongLong
- | _ -> ik
- end else
- ik
- in
- TSBase (TInt (ik', doattr al))
- | TFloat (fk, al) -> TSBase (TFloat (fk, doattr al))
- | TVoid al -> TSBase (TVoid (doattr al))
- | TEnum (enum, a) -> TSEnum (enum.ename, doattr a)
- | TPtr (t, a) -> TSPtr (typeSig t, doattr a)
- | TArray (t,l,a) -> (* We do not want fancy expressions in array lengths.
- * So constant fold the lengths *)
- let l' =
- match l with
- Some l -> begin
- match constFold true l with
- Const(CInt64(i, _, _)) -> Some i
- | e -> E.s (E.bug "Invalid length in array type: %a\n"
- (!pd_exp) e)
- end
- | None -> None
- in
- TSArray(typeSig t, l', doattr a)
-
- | TComp (comp, a) ->
- TSComp (comp.cstruct, comp.cname, doattr (addAttributes comp.cattr a))
- | TFun(rt,args,isva,a) ->
- TSFun(typeSig rt,
- List.map (fun (_, atype, _) -> (typeSig atype)) (argsToList args),
- isva, doattr a)
- | TNamed(t, a) -> typeSigAddAttrs (doattr a) (typeSig t.ttype)
- | TBuiltin_va_list al -> TSBase (TBuiltin_va_list (doattr al))
-
-let typeSig t =
- typeSigWithAttrs (fun al -> al) t
-
-let _ = pTypeSig := typeSig
-
-(* Remove the attribute from the top-level of the type signature *)
-let setTypeSigAttrs (a: attribute list) = function
- TSBase t -> TSBase (setTypeAttrs t a)
- | TSPtr (ts, _) -> TSPtr (ts, a)
- | TSArray (ts, l, _) -> TSArray(ts, l, a)
- | TSComp (iss, n, _) -> TSComp (iss, n, a)
- | TSEnum (n, _) -> TSEnum (n, a)
- | TSFun (ts, tsargs, isva, _) -> TSFun (ts, tsargs, isva, a)
-
-
-let typeSigAttrs = function
- TSBase t -> typeAttrs t
- | TSPtr (ts, a) -> a
- | TSArray (ts, l, a) -> a
- | TSComp (iss, n, a) -> a
- | TSEnum (n, a) -> a
- | TSFun (ts, tsargs, isva, a) -> a
-
-
-
-let dExp: doc -> exp =
- fun d -> Const(CStr(sprint !lineLength d))
-
-let dInstr: doc -> location -> instr =
- fun d l -> Asm([], [sprint !lineLength d], [], [], [], l)
-
-let dGlobal: doc -> location -> global =
- fun d l -> GAsm(sprint !lineLength d, l)
-
-let rec addOffset (toadd: offset) (off: offset) : offset =
- match off with
- NoOffset -> toadd
- | Field(fid', offset) -> Field(fid', addOffset toadd offset)
- | Index(e, offset) -> Index(e, addOffset toadd offset)
-
- (* Add an offset at the end of an lv *)
-let addOffsetLval toadd (b, off) : lval =
- b, addOffset toadd off
-
-let rec removeOffset (off: offset) : offset * offset =
- match off with
- NoOffset -> NoOffset, NoOffset
- | Field(f, NoOffset) -> NoOffset, off
- | Index(i, NoOffset) -> NoOffset, off
- | Field(f, restoff) ->
- let off', last = removeOffset restoff in
- Field(f, off'), last
- | Index(i, restoff) ->
- let off', last = removeOffset restoff in
- Index(i, off'), last
-
-let removeOffsetLval ((b, off): lval) : lval * offset =
- let off', last = removeOffset off in
- (b, off'), last
-
- (* Make an AddrOf. Given an lval of type T will give back an expression of
- * type ptr(T) *)
-let mkAddrOf ((b, off) as lval) : exp =
- (* Never take the address of a register variable *)
- (match lval with
- Var vi, off when vi.vstorage = Register -> vi.vstorage <- NoStorage
- | _ -> ());
- match lval with
- Mem e, NoOffset -> e
- | b, Index(z, NoOffset) when isZero z -> StartOf (b, NoOffset)(* array *)
- | _ -> AddrOf lval
-
-
-let mkAddrOrStartOf (lv: lval) : exp =
- match unrollType (typeOfLval lv) with
- TArray _ -> StartOf lv
- | _ -> mkAddrOf lv
-
-
- (* Make a Mem, while optimizing AddrOf. The type of the addr must be
- * TPtr(t) and the type of the resulting lval is t. Note that in CIL the
- * implicit conversion between a function and a pointer to a function does
- * not apply. You must do the conversion yourself using AddrOf *)
-let mkMem ~(addr: exp) ~(off: offset) : lval =
- let res =
- match addr, off with
- AddrOf lv, _ -> addOffsetLval off lv
- | StartOf lv, _ -> (* Must be an array *)
- addOffsetLval (Index(zero, off)) lv
- | _, _ -> Mem addr, off
- in
-(* ignore (E.log "memof : %a:%a\nresult = %a\n"
- d_plainexp addr d_plainoffset off d_plainexp res); *)
- res
-
-
-
-let splitFunctionType (ftype: typ)
- : typ * (string * typ * attributes) list option * bool * attributes =
- match unrollType ftype with
- TFun (rt, args, isva, a) -> rt, args, isva, a
- | _ -> E.s (bug "splitFunctionType invoked on a non function type %a"
- d_type ftype)
-
-let splitFunctionTypeVI (fvi: varinfo)
- : typ * (string * typ * attributes) list option * bool * attributes =
- match unrollType fvi.vtype with
- TFun (rt, args, isva, a) -> rt, args, isva, a
- | _ -> E.s (bug "Function %s invoked on a non function type" fvi.vname)
-
-let isArrayType t =
- match unrollType t with
- TArray _ -> true
- | _ -> false
-
-
-let rec isConstant = function
- | Const _ -> true
- | UnOp (_, e, _) -> isConstant e
- | BinOp (_, e1, e2, _) -> isConstant e1 && isConstant e2
- | Lval (Var vi, NoOffset) ->
- (vi.vglob && isArrayType vi.vtype || isFunctionType vi.vtype)
- | Lval _ -> false
- | SizeOf _ | SizeOfE _ | SizeOfStr _ | AlignOf _ | AlignOfE _ -> true
- | CastE (_, e) -> isConstant e
- | AddrOf (Var vi, off) | StartOf (Var vi, off)
- -> vi.vglob && isConstantOff off
- | AddrOf (Mem e, off) | StartOf(Mem e, off)
- -> isConstant e && isConstantOff off
-
-and isConstantOff = function
- NoOffset -> true
- | Field(fi, off) -> isConstantOff off
- | Index(e, off) -> isConstant e && isConstantOff off
-
-
-let getCompField (cinfo:compinfo) (fieldName:string) : fieldinfo =
- (List.find (fun fi -> fi.fname = fieldName) cinfo.cfields)
-
-
-let rec mkCastT ~(e: exp) ~(oldt: typ) ~(newt: typ) =
- (* Do not remove old casts because they are conversions !!! *)
- if Util.equals (typeSig oldt) (typeSig newt) then begin
- e
- end else begin
- (* Watch out for constants *)
- match newt, e with
- TInt(newik, []), Const(CInt64(i, _, _)) -> kinteger64 newik i
- | _ -> CastE(newt,e)
- end
-
-let mkCast ~(e: exp) ~(newt: typ) =
- mkCastT e (typeOf e) newt
-
-type existsAction =
- ExistsTrue (* We have found it *)
- | ExistsFalse (* Stop processing this branch *)
- | ExistsMaybe (* This node is not what we are
- * looking for but maybe its
- * successors are *)
-let existsType (f: typ -> existsAction) (t: typ) : bool =
- let memo : (int, unit) H.t = H.create 17 in (* Memo table *)
- let rec loop t =
- match f t with
- ExistsTrue -> true
- | ExistsFalse -> false
- | ExistsMaybe ->
- (match t with
- TNamed (t', _) -> loop t'.ttype
- | TComp (c, _) -> loopComp c
- | TArray (t', _, _) -> loop t'
- | TPtr (t', _) -> loop t'
- | TFun (rt, args, _, _) ->
- (loop rt || List.exists (fun (_, at, _) -> loop at)
- (argsToList args))
- | _ -> false)
- and loopComp c =
- if H.mem memo c.ckey then
- (* We are looping, the answer must be false *)
- false
- else begin
- H.add memo c.ckey ();
- List.exists (fun f -> loop f.ftype) c.cfields
- end
- in
- loop t
-
-
-(* Try to do an increment, with constant folding *)
-let increm (e: exp) (i: int) =
- let et = typeOf e in
- let bop = if isPointerType et then PlusPI else PlusA in
- constFold false (BinOp(bop, e, integer i, et))
-
-exception LenOfArray
-let lenOfArray (eo: exp option) : int =
- match eo with
- None -> raise LenOfArray
- | Some e -> begin
- match constFold true e with
- | Const(CInt64(ni, _, _)) when ni >= Int64.zero ->
- Int64.to_int ni
- | e -> raise LenOfArray
- end
-
-
-(*** Make a initializer for zeroe-ing a data type ***)
-let rec makeZeroInit (t: typ) : init =
- match unrollType t with
- TInt (ik, _) -> SingleInit (Const(CInt64(Int64.zero, ik, None)))
- | TFloat(fk, _) -> SingleInit(Const(CReal(0.0, fk, None)))
- | TEnum _ -> SingleInit zero
- | TComp (comp, _) as t' when comp.cstruct ->
- let inits =
- List.fold_right
- (fun f acc ->
- if f.fname <> missingFieldName then
- (Field(f, NoOffset), makeZeroInit f.ftype) :: acc
- else
- acc)
- comp.cfields []
- in
- CompoundInit (t', inits)
-
- | TComp (comp, _) when not comp.cstruct ->
- let fstfield, rest =
- match comp.cfields with
- f :: rest -> f, rest
- | [] -> E.s (unimp "Cannot create init for empty union")
- in
- let fieldToInit =
- if !msvcMode then
- (* ISO C99 [6.7.8.10] says that the first field of the union
- is the one we should initialize. *)
- fstfield
- else begin
- (* gcc initializes the whole union to zero. So choose the largest
- field, and set that to zero. Choose the first field if possible.
- MSVC also initializes the whole union, but use the ISO behavior
- for MSVC because it only allows compound initializers to refer
- to the first union field. *)
- let fieldSize f = try bitsSizeOf f.ftype with SizeOfError _ -> 0 in
- let widestField, widestFieldWidth =
- List.fold_left (fun acc thisField ->
- let widestField, widestFieldWidth = acc in
- let thisSize = fieldSize thisField in
- if thisSize > widestFieldWidth then
- thisField, thisSize
- else
- acc)
- (fstfield, fieldSize fstfield)
- rest
- in
- widestField
- end
- in
- CompoundInit(t, [(Field(fieldToInit, NoOffset),
- makeZeroInit fieldToInit.ftype)])
-
- | TArray(bt, Some len, _) as t' ->
- let n =
- match constFold true len with
- Const(CInt64(n, _, _)) -> Int64.to_int n
- | _ -> E.s (E.unimp "Cannot understand length of array")
- in
- let initbt = makeZeroInit bt in
- let rec loopElems acc i =
- if i < 0 then acc
- else loopElems ((Index(integer i, NoOffset), initbt) :: acc) (i - 1)
- in
- CompoundInit(t', loopElems [] (n - 1))
-
- | TArray (bt, None, at) as t' ->
- (* Unsized array, allow it and fill it in later
- * (see cabs2cil.ml, collectInitializer) *)
- CompoundInit (t', [])
-
- | TPtr _ as t -> SingleInit(CastE(t, zero))
- | x -> E.s (unimp "Cannot initialize type: %a" d_type x)
-
-
-(**** Fold over the list of initializers in a Compound. In the case of an
- * array initializer only the initializers present are scanned (a prefix of
- * all initializers) *)
-let foldLeftCompound
- ~(doinit: offset -> init -> typ -> 'a -> 'a)
- ~(ct: typ)
- ~(initl: (offset * init) list)
- ~(acc: 'a) : 'a =
- match unrollType ct with
- TArray(bt, _, _) ->
- List.fold_left (fun acc (o, i) -> doinit o i bt acc) acc initl
-
- | TComp (comp, _) ->
- let getTypeOffset = function
- Field(f, NoOffset) -> f.ftype
- | _ -> E.s (bug "foldLeftCompound: malformed initializer")
- in
- List.fold_left
- (fun acc (o, i) -> doinit o i (getTypeOffset o) acc) acc initl
-
- | _ -> E.s (unimp "Type of Compound is not array or struct or union")
-
-(**** Fold over the list of initializers in a Compound. Like foldLeftCompound
- * but scans even the zero-initializers that are missing at the end of the
- * array *)
-let foldLeftCompoundAll
- ~(doinit: offset -> init -> typ -> 'a -> 'a)
- ~(ct: typ)
- ~(initl: (offset * init) list)
- ~(acc: 'a) : 'a =
- match unrollType ct with
- TArray(bt, leno, _) -> begin
- let part =
- List.fold_left (fun acc (o, i) -> doinit o i bt acc) acc initl in
- (* See how many more we have to do *)
- match leno with
- Some lene -> begin
- match constFold true lene with
- Const(CInt64(i, _, _)) ->
- let len_array = Int64.to_int i in
- let len_init = List.length initl in
- if len_array > len_init then
- let zi = makeZeroInit bt in
- let rec loop acc i =
- if i >= len_array then acc
- else
- loop (doinit (Index(integer i, NoOffset)) zi bt acc)
- (i + 1)
- in
- loop part (len_init + 1)
- else
- part
- | _ -> E.s (unimp "foldLeftCompoundAll: array with initializer and non-constant length\n")
- end
-
- | _ -> E.s (unimp "foldLeftCompoundAll: TArray with initializer and no length")
- end
- | TComp (comp, _) ->
- let getTypeOffset = function
- Field(f, NoOffset) -> f.ftype
- | _ -> E.s (bug "foldLeftCompound: malformed initializer")
- in
- List.fold_left
- (fun acc (o, i) -> doinit o i (getTypeOffset o) acc) acc initl
-
- | _ -> E.s (E.unimp "Type of Compound is not array or struct or union")
-
-
-
-let rec isCompleteType t =
- match unrollType t with
- | TArray(t, None, _) -> false
- | TArray(t, Some z, _) when isZero z -> false
- | TComp (comp, _) -> (* Struct or union *)
- List.for_all (fun fi -> isCompleteType fi.ftype) comp.cfields
- | _ -> true
-
-
-module A = Alpha
-
-
-(** Uniquefy the variable names *)
-let uniqueVarNames (f: file) : unit =
- (* Setup the alpha conversion table for globals *)
- let gAlphaTable: (string,
- location A.alphaTableData ref) H.t = H.create 113 in
- (* Keep also track of the global names that we have used. Map them to the
- * variable ID. We do this only to check that we do not have two globals
- * with the same name. *)
- let globalNames: (string, int) H.t = H.create 113 in
- (* Scan the file and add the global names to the table *)
- iterGlobals f
- (function
- GVarDecl(vi, l)
- | GVar(vi, _, l)
- | GFun({svar = vi}, l) ->
- (* See if we have used this name already for something else *)
- (try
- let oldid = H.find globalNames vi.vname in
- if oldid <> vi.vid then
- ignore (warn "The name %s is used for two distinct globals"
- vi.vname);
- (* Here if we have used this name already. Go ahead *)
- ()
- with Not_found -> begin
- (* Here if this is the first time we define a name *)
- H.add globalNames vi.vname vi.vid;
- (* And register it *)
- A.registerAlphaName gAlphaTable None vi.vname !currentLoc;
- ()
- end)
- | _ -> ());
-
- (* Now we must scan the function bodies and rename the locals *)
- iterGlobals f
- (function
- GFun(fdec, l) -> begin
- currentLoc := l;
- (* Setup an undo list to be able to revert the changes to the
- * global alpha table *)
- let undolist = ref [] in
- (* Process one local variable *)
- let processLocal (v: varinfo) =
- let newname, oldloc =
- A.newAlphaName gAlphaTable (Some undolist) v.vname
- !currentLoc
- in
- if false && newname <> v.vname then (* Disable this warning *)
- ignore (warn "uniqueVarNames: Changing the name of local %s in %s to %s (due to duplicate at %a)\n"
- v.vname fdec.svar.vname newname d_loc oldloc);
- v.vname <- newname
- in
- (* Do the formals first *)
- List.iter processLocal fdec.sformals;
- (* Fix the type again *)
- setFormals fdec fdec.sformals;
- (* And now the locals *)
- List.iter processLocal fdec.slocals;
- (* Undo the changes to the global table *)
- A.undoAlphaChanges gAlphaTable !undolist;
- ()
- end
- | _ -> ());
- ()
-
-
-(* A visitor that makes a deep copy of a function body *)
-class copyFunctionVisitor (newname: string) = object (self)
- inherit nopCilVisitor
-
- (* Keep here a maping from locals to their copies *)
- val map : (string, varinfo) H.t = H.create 113
- (* Keep here a maping from statements to their copies *)
- val stmtmap : (int, stmt) H.t = H.create 113
- val sid = ref 0 (* Will have to assign ids to statements *)
- (* Keep here a list of statements to be patched *)
- val patches : stmt list ref = ref []
-
- val argid = ref 0
-
- (* This is the main function *)
- method vfunc (f: fundec) : fundec visitAction =
- (* We need a map from the old locals/formals to the new ones *)
- H.clear map;
- argid := 0;
- (* Make a copy of the fundec. *)
- let f' = {f with svar = f.svar} in
- let patchfunction (f' : fundec) =
- (* Change the name. Only this late to allow the visitor to copy the
- * svar *)
- f'.svar.vname <- newname;
- let findStmt (i: int) =
- try H.find stmtmap i
- with Not_found -> E.s (bug "Cannot find the copy of stmt#%d" i)
- in
- let patchstmt (s: stmt) =
- match s.skind with
- Goto (sr, l) ->
- (* Make a copy of the reference *)
- let sr' = ref (findStmt !sr.sid) in
- s.skind <- Goto (sr',l)
- | Switch (e, body, cases, l) ->
- s.skind <- Switch (e, body,
- List.map (fun cs -> findStmt cs.sid) cases, l)
- | _ -> ()
- in
- List.iter patchstmt !patches;
- f'
- in
- patches := [];
- sid := 0;
- H.clear stmtmap;
- ChangeDoChildrenPost (f', patchfunction)
-
- (* We must create a new varinfo for each declaration. Memoize to
- * maintain sharing *)
- method vvdec (v: varinfo) =
- (* Some varinfo have empty names. Give them some name *)
- if v.vname = "" then begin
- v.vname <- "arg" ^ string_of_int !argid; incr argid
- end;
- try
- ChangeTo (H.find map v.vname)
- with Not_found -> begin
- let v' = {v with vid = newVID () } in
- H.add map v.vname v';
- ChangeDoChildrenPost (v', fun x -> x)
- end
-
- (* We must replace references to local variables *)
- method vvrbl (v: varinfo) =
- if v.vglob then SkipChildren else
- try
- ChangeTo (H.find map v.vname)
- with Not_found ->
- E.s (bug "Cannot find the new copy of local variable %s" v.vname)
-
-
- (* Replace statements. *)
- method vstmt (s: stmt) : stmt visitAction =
- s.sid <- !sid; incr sid;
- let s' = {s with sid = s.sid} in
- H.add stmtmap s.sid s'; (* Remember where we copied this *)
- (* if we have a Goto or a Switch remember them to fixup at end *)
- (match s'.skind with
- (Goto _ | Switch _) -> patches := s' :: !patches
- | _ -> ());
- (* Do the children *)
- ChangeDoChildrenPost (s', fun x -> x)
-
- (* Copy blocks since they are mutable *)
- method vblock (b: block) =
- ChangeDoChildrenPost ({b with bstmts = b.bstmts}, fun x -> x)
-
-
- method vglob _ = E.s (bug "copyFunction should not be used on globals")
-end
-
-(* We need a function that copies a CIL function. *)
-let copyFunction (f: fundec) (newname: string) : fundec =
- visitCilFunction (new copyFunctionVisitor(newname)) f
-
-(********* Compute the CFG ********)
-let sid_counter = ref 0
-
-let new_sid () =
- let id = !sid_counter in
- incr sid_counter;
- id
-
-let statements : stmt list ref = ref []
-(* Clear all info about the CFG in statements *)
-class clear : cilVisitor = object
- inherit nopCilVisitor
- method vstmt s = begin
- s.sid <- !sid_counter ;
- incr sid_counter ;
- statements := s :: !statements;
- s.succs <- [] ;
- s.preds <- [] ;
- DoChildren
- end
- method vexpr _ = SkipChildren
- method vtype _ = SkipChildren
- method vinst _ = SkipChildren
-end
-
-let link source dest = begin
- if not (List.mem dest source.succs) then
- source.succs <- dest :: source.succs ;
- if not (List.mem source dest.preds) then
- dest.preds <- source :: dest.preds
-end
-let trylink source dest_option = match dest_option with
- None -> ()
-| Some(dest) -> link source dest
-
-
-(** Cmopute the successors and predecessors of a block, given a fallthrough *)
-let rec succpred_block b fallthrough =
- let rec handle sl = match sl with
- [] -> ()
- | [a] -> succpred_stmt a fallthrough
- | hd :: ((next :: _) as tl) ->
- succpred_stmt hd (Some next) ;
- handle tl
- in handle b.bstmts
-
-
-and succpred_stmt s fallthrough =
- match s.skind with
- Instr _ -> trylink s fallthrough
- | Return _ -> ()
- | Goto(dest,l) -> link s !dest
- | Break _
- | Continue _
- | Switch _ ->
- failwith "computeCFGInfo: cannot be called on functions with break, continue or switch statements. Use prepareCFG first to remove them."
-
- | If(e1,b1,b2,l) ->
- (match b1.bstmts with
- [] -> trylink s fallthrough
- | hd :: tl -> (link s hd ; succpred_block b1 fallthrough )) ;
- (match b2.bstmts with
- [] -> trylink s fallthrough
- | hd :: tl -> (link s hd ; succpred_block b2 fallthrough ))
-
-(*
- | Loop(b,l,_,_) ->
- begin match b.bstmts with
- [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl ->
- link s hd ;
- succpred_block b (Some(hd))
- end
-*)
-
- | While (e, b, l) -> begin match b.bstmts with
- | [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl -> link s hd ;
- succpred_block b (Some(hd))
- end
-
- | DoWhile (e, b, l) ->begin match b.bstmts with
- | [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl -> link s hd ;
- succpred_block b (Some(hd))
- end
-
- | For (bInit, e, bIter, b, l) ->
- (match bInit.bstmts with
- | [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl -> link s hd ;
- succpred_block bInit (Some(hd))) ;
- (match bIter.bstmts with
- | [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl -> link s hd ;
- succpred_block bIter (Some(hd))) ;
- (match b.bstmts with
- | [] -> failwith "computeCFGInfo: empty loop"
- | hd :: tl -> link s hd ;
- succpred_block b (Some(hd))) ;
-
- | Block(b) -> begin match b.bstmts with
- [] -> trylink s fallthrough
- | hd :: tl -> link s hd ;
- succpred_block b fallthrough
- end
- | TryExcept _ | TryFinally _ ->
- failwith "computeCFGInfo: structured exception handling not implemented"
-
-(* [weimer] Sun May 5 12:25:24 PDT 2002
- * This code was pulled from ext/switch.ml because it looks like we really
- * want it to be part of CIL.
- *
- * Here is the magic handling to
- * (1) replace switch statements with if/goto
- * (2) remove "break"
- * (3) remove "default"
- * (4) remove "continue"
- *)
-let is_case_label l = match l with
- | Case _ | Default _ -> true
- | _ -> false
-
-let switch_count = ref (-1)
-let get_switch_count () =
- switch_count := 1 + !switch_count ;
- !switch_count
-
-let switch_label = ref (-1)
-
-let rec xform_switch_stmt s break_dest cont_dest label_index = begin
- s.labels <- List.map (fun lab -> match lab with
- Label _ -> lab
- | Case(e,l) ->
- let suffix =
- match isInteger e with
- | Some value ->
- if value < Int64.zero then
- "neg_" ^ Int64.to_string (Int64.neg value)
- else
- Int64.to_string value
- | None ->
- incr switch_label;
- "exp_" ^ string_of_int !switch_label
- in
- let str = Pretty.sprint !lineLength
- (Pretty.dprintf "switch_%d_%s" label_index suffix) in
- (Label(str,l,false))
- | Default(l) -> (Label(Printf.sprintf
- "switch_%d_default" label_index,l,false))
- ) s.labels ;
- match s.skind with
- | Instr _ | Return _ | Goto _ -> ()
- | Break(l) -> begin try
- s.skind <- Goto(break_dest (),l)
- with e ->
- ignore (error "prepareCFG: break: %a@!" d_stmt s) ;
- raise e
- end
- | Continue(l) -> begin try
- s.skind <- Goto(cont_dest (),l)
- with e ->
- ignore (error "prepareCFG: continue: %a@!" d_stmt s) ;
- raise e
- end
- | If(e,b1,b2,l) -> xform_switch_block b1 break_dest cont_dest label_index ;
- xform_switch_block b2 break_dest cont_dest label_index
- | Switch(e,b,sl,l) -> begin
- (* change
- * switch (se) {
- * case 0: s0 ;
- * case 1: s1 ; break;
- * ...
- * }
- *
- * into:
- *
- * if (se == 0) goto label_0;
- * else if (se == 1) goto label_1;
- * ...
- * else if (0) { // body_block
- * label_0: s0;
- * label_1: s1; goto label_break;
- * ...
- * } else if (0) { // break_block
- * label_break: ; // break_stmt
- * }
- *)
- let i = get_switch_count () in
- let break_stmt = mkStmt (Instr []) in
- break_stmt.labels <-
- [Label((Printf.sprintf "switch_%d_break" i),l,false)] ;
- let break_block = mkBlock [ break_stmt ] in
- let body_block = b in
- let body_if_stmtkind = (If(zero,body_block,break_block,l)) in
-
- (* The default case, if present, must be used only if *all*
- non-default cases fail [ISO/IEC 9899:1999, §6.8.4.2, ¶5]. As a
- result, we sort the order in which we handle the labels (but not the
- order in which we print out the statements, so fall-through still
- works as expected). *)
- let compare_choices s1 s2 = match s1.labels, s2.labels with
- | (Default(_) :: _), _ -> 1
- | _, (Default(_) :: _) -> -1
- | _, _ -> 0
- in
-
- let rec handle_choices sl = match sl with
- [] -> body_if_stmtkind
- | stmt_hd :: stmt_tl -> begin
- let rec handle_labels lab_list = begin
- match lab_list with
- [] -> handle_choices stmt_tl
- | Case(ce,cl) :: lab_tl ->
- let pred = BinOp(Eq,e,ce,intType) in
- let then_block = mkBlock [ mkStmt (Goto(ref stmt_hd,cl)) ] in
- let else_block = mkBlock [ mkStmt (handle_labels lab_tl) ] in
- If(pred,then_block,else_block,cl)
- | Default(dl) :: lab_tl ->
- (* ww: before this was 'if (1) goto label', but as Ben points
- out this might confuse someone down the line who doesn't have
- special handling for if(1) into thinking that there are two
- paths here. The simpler 'goto label' is what we want. *)
- Block(mkBlock [ mkStmt (Goto(ref stmt_hd,dl)) ;
- mkStmt (handle_labels lab_tl) ])
- | Label(_,_,_) :: lab_tl -> handle_labels lab_tl
- end in
- handle_labels stmt_hd.labels
- end in
- s.skind <- handle_choices (List.sort compare_choices sl) ;
- xform_switch_block b (fun () -> ref break_stmt) cont_dest i
- end
-(*
- | Loop(b,l,_,_) ->
- let i = get_switch_count () in
- let break_stmt = mkStmt (Instr []) in
- break_stmt.labels <-
- [Label((Printf.sprintf "while_%d_break" i),l,false)] ;
- let cont_stmt = mkStmt (Instr []) in
- cont_stmt.labels <-
- [Label((Printf.sprintf "while_%d_continue" i),l,false)] ;
- b.bstmts <- cont_stmt :: b.bstmts ;
- let this_stmt = mkStmt
- (Loop(b,l,Some(cont_stmt),Some(break_stmt))) in
- let break_dest () = ref break_stmt in
- let cont_dest () = ref cont_stmt in
- xform_switch_block b break_dest cont_dest label_index ;
- break_stmt.succs <- s.succs ;
- let new_block = mkBlock [ this_stmt ; break_stmt ] in
- s.skind <- Block new_block
-*)
- | While (e, b, l) ->
- let i = get_switch_count () in
- let break_stmt = mkStmt (Instr []) in
- break_stmt.labels <-
- [Label((Printf.sprintf "while_%d_break" i),l,false)] ;
- let cont_stmt = mkStmt (Instr []) in
- cont_stmt.labels <-
- [Label((Printf.sprintf "while_%d_continue" i),l,false)] ;
- b.bstmts <- cont_stmt :: b.bstmts ;
- let this_stmt = mkStmt
- (While(e,b,l)) in
- let break_dest () = ref break_stmt in
- let cont_dest () = ref cont_stmt in
- xform_switch_block b break_dest cont_dest label_index ;
- break_stmt.succs <- s.succs ;
- let new_block = mkBlock [ this_stmt ; break_stmt ] in
- s.skind <- Block new_block
-
- | DoWhile (e, b, l) ->
- let i = get_switch_count () in
- let break_stmt = mkStmt (Instr []) in
- break_stmt.labels <-
- [Label((Printf.sprintf "while_%d_break" i),l,false)] ;
- let cont_stmt = mkStmt (Instr []) in
- cont_stmt.labels <-
- [Label((Printf.sprintf "while_%d_continue" i),l,false)] ;
- b.bstmts <- cont_stmt :: b.bstmts ;
- let this_stmt = mkStmt
- (DoWhile(e,b,l)) in
- let break_dest () = ref break_stmt in
- let cont_dest () = ref cont_stmt in
- xform_switch_block b break_dest cont_dest label_index ;
- break_stmt.succs <- s.succs ;
- let new_block = mkBlock [ this_stmt ; break_stmt ] in
- s.skind <- Block new_block
-
- | For (bInit, e, bIter , b, l) ->
- let i = get_switch_count () in
- let break_stmt = mkStmt (Instr []) in
- break_stmt.labels <-
- [Label((Printf.sprintf "while_%d_break" i),l,false)] ;
- let cont_stmt = mkStmt (Instr []) in
- cont_stmt.labels <-
- [Label((Printf.sprintf "while_%d_continue" i),l,false)] ;
- b.bstmts <- cont_stmt :: b.bstmts ;
- let this_stmt = mkStmt
- (For(bInit,e,bIter,b,l)) in
- let break_dest () = ref break_stmt in
- let cont_dest () = ref cont_stmt in
- xform_switch_block b break_dest cont_dest label_index ;
- break_stmt.succs <- s.succs ;
- let new_block = mkBlock [ this_stmt ; break_stmt ] in
- s.skind <- Block new_block
-
-
- | Block(b) -> xform_switch_block b break_dest cont_dest label_index
-
- | TryExcept _ | TryFinally _ ->
- failwith "xform_switch_statement: structured exception handling not implemented"
-
-end and xform_switch_block b break_dest cont_dest label_index =
- try
- let rec link_succs sl = match sl with
- | [] -> ()
- | hd :: tl -> (if hd.succs = [] then hd.succs <- tl) ; link_succs tl
- in
- link_succs b.bstmts ;
- List.iter (fun stmt ->
- xform_switch_stmt stmt break_dest cont_dest label_index) b.bstmts ;
- with e ->
- List.iter (fun stmt -> ignore
- (warn "prepareCFG: %a@!" d_stmt stmt)) b.bstmts ;
- raise e
-
-(* prepare a function for computeCFGInfo by removing break, continue,
- * default and switch statements/labels and replacing them with Ifs and
- * Gotos. *)
-let prepareCFG (fd : fundec) : unit =
- xform_switch_block fd.sbody
- (fun () -> failwith "prepareCFG: break with no enclosing loop")
- (fun () -> failwith "prepareCFG: continue with no enclosing loop") (-1)
-
-(* make the cfg and return a list of statements *)
-let computeCFGInfo (f : fundec) (global_numbering : bool) : unit =
- if not global_numbering then
- sid_counter := 0 ;
- statements := [];
- let clear_it = new clear in
- ignore (visitCilBlock clear_it f.sbody) ;
- f.smaxstmtid <- Some (!sid_counter) ;
- succpred_block f.sbody (None);
- let res = List.rev !statements in
- statements := [];
- f.sallstmts <- res;
- ()
-
-let initCIL () =
- if not !initCIL_called then begin
- (* Set the machine *)
- theMachine := if !msvcMode then M.msvc else M.gcc;
- (* Pick type for string literals *)
- stringLiteralType := if !theMachine.M.const_string_literals then
- charConstPtrType
- else
- charPtrType;
- (* Find the right ikind given the size *)
- let findIkind (unsigned: bool) (sz: int) : ikind =
- (* Test the most common sizes first *)
- if sz = !theMachine.M.sizeof_int then
- if unsigned then IUInt else IInt
- else if sz = !theMachine.M.sizeof_long then
- if unsigned then IULong else ILong
- else if sz = 1 then
- if unsigned then IUChar else IChar
- else if sz = !theMachine.M.sizeof_short then
- if unsigned then IUShort else IShort
- else if sz = !theMachine.M.sizeof_longlong then
- if unsigned then IULongLong else ILongLong
- else
- E.s(E.unimp "initCIL: cannot find the right ikind for size %d\n" sz)
- in
- upointType := TInt(findIkind true !theMachine.M.sizeof_ptr, []);
- kindOfSizeOf := findIkind true !theMachine.M.sizeof_sizeof;
- typeOfSizeOf := TInt(!kindOfSizeOf, []);
- H.add gccBuiltins "__builtin_memset"
- (voidPtrType, [ voidPtrType; intType; intType ], false);
- wcharKind := findIkind false !theMachine.M.sizeof_wchar;
- wcharType := TInt(!wcharKind, []);
- char_is_unsigned := !theMachine.M.char_is_unsigned;
- little_endian := !theMachine.M.little_endian;
- underscore_name := !theMachine.M.underscore_name;
- nextGlobalVID := 1;
- nextCompinfoKey := 1;
- initCIL_called := true
- end
-
-
-(* We want to bring all type declarations before the data declarations. This
- * is needed for code of the following form:
-
- int f(); // Prototype without arguments
- typedef int FOO;
- int f(FOO x) { ... }
-
- In CIL the prototype also lists the type of the argument as being FOO,
- which is undefined.
-
- There is one catch with this scheme. If the type contains an array whose
- length refers to variables then those variables must be declared before
- the type *)
-
-let pullTypesForward = true
-
-
- (* Scan a type and collect the variables that are refered *)
-class getVarsInGlobalClass (pacc: varinfo list ref) = object
- inherit nopCilVisitor
- method vvrbl (vi: varinfo) =
- pacc := vi :: !pacc;
- SkipChildren
-
- method vglob = function
- GType _ | GCompTag _ -> DoChildren
- | _ -> SkipChildren
-
-end
-
-let getVarsInGlobal (g : global) : varinfo list =
- let pacc : varinfo list ref = ref [] in
- let v : cilVisitor = new getVarsInGlobalClass pacc in
- ignore (visitCilGlobal v g);
- !pacc
-
-let hasPrefix p s =
- let pl = String.length p in
- (String.length s >= pl) && String.sub s 0 pl = p
-
-let pushGlobal (g: global)
- ~(types:global list ref)
- ~(variables: global list ref) =
- if not pullTypesForward then
- variables := g :: !variables
- else
- begin
- (* Collect a list of variables that are refered from the type. Return
- * Some if the global should go with the types and None if it should go
- * to the variables. *)
- let varsintype : (varinfo list * location) option =
- match g with
- GType (_, l) | GCompTag (_, l) -> Some (getVarsInGlobal g, l)
- | GEnumTag (_, l) | GPragma (Attr("pack", _), l)
- | GCompTagDecl (_, l) | GEnumTagDecl (_, l) -> Some ([], l)
- (** Move the warning pragmas early
- | GPragma(Attr(s, _), l) when hasPrefix "warning" s -> Some ([], l)
- *)
- | _ -> None (* Does not go with the types *)
- in
- match varsintype with
- None -> variables := g :: !variables
- | Some (vl, loc) ->
- types :=
- (* insert declarations for referred variables ('vl'), before
- * the type definition 'g' itself *)
- g :: (List.fold_left (fun acc v -> GVarDecl(v, loc) :: acc)
- !types vl)
- end
-
-
-type formatArg =
- Fe of exp
- | Feo of exp option (** For array lengths *)
- | Fu of unop
- | Fb of binop
- | Fk of ikind
- | FE of exp list (** For arguments in a function call *)
- | Ff of (string * typ * attributes) (** For a formal argument *)
- | FF of (string * typ * attributes) list (* For formal argument lists *)
- | Fva of bool (** For the ellipsis in a function type *)
- | Fv of varinfo
- | Fl of lval
- | Flo of lval option (** For the result of a function call *)
- | Fo of offset
- | Fc of compinfo
- | Fi of instr
- | FI of instr list
- | Ft of typ
- | Fd of int
- | Fg of string
- | Fs of stmt
- | FS of stmt list
- | FA of attributes
-
- | Fp of attrparam
- | FP of attrparam list
-
- | FX of string
-
-let d_formatarg () = function
- Fe e -> dprintf "Fe(%a)" d_exp e
- | Feo None -> dprintf "Feo(None)"
- | Feo (Some e) -> dprintf "Feo(%a)" d_exp e
- | FE _ -> dprintf "FE()"
- | Fk ik -> dprintf "Fk()"
- | Fva b -> dprintf "Fva(%b)" b
- | Ff (an, _, _) -> dprintf "Ff(%s)" an
- | FF _ -> dprintf "FF(...)"
- | FA _ -> dprintf "FA(...)"
- | Fu uo -> dprintf "Fu()"
- | Fb bo -> dprintf "Fb()"
- | Fv v -> dprintf "Fv(%s)" v.vname
- | Fl l -> dprintf "Fl(%a)" d_lval l
- | Flo None -> dprintf "Flo(None)"
- | Flo (Some l) -> dprintf "Flo(%a)" d_lval l
- | Fo o -> dprintf "Fo"
- | Fc ci -> dprintf "Fc(%s)" ci.cname
- | Fi i -> dprintf "Fi(...)"
- | FI i -> dprintf "FI(...)"
- | Ft t -> dprintf "Ft(%a)" d_type t
- | Fd n -> dprintf "Fd(%d)" n
- | Fg s -> dprintf "Fg(%s)" s
- | Fp _ -> dprintf "Fp(...)"
- | FP n -> dprintf "FP(...)"
- | Fs _ -> dprintf "FS"
- | FS _ -> dprintf "FS"
-
- | FX _ -> dprintf "FX()"
-
-