A CIL Tutorial - Department of Computer Science - ETH Zürich

A CIL Tutorial - Department of Computer Science - ETH Zürich A CIL Tutorial - Department of Computer Science - ETH Zürich

29.01.2014 Views

CHAPTER 3. DATAFLOW ANALYSIS 28 let varmap list handle inst (i : instr) (vml : varmap list) : varmap list = match i with | Set((Var vi, NoOffset), e, loc) when ¬(vi.vglob) ∧ (isIntegralType vi.vtype) → let k = oekind of exp vml e in varmap list replace vml (vi.vid, (vi, k)) | Set((Mem , ), , ) | Call → varmap list kill vml (∗ Kill vars with vaddrof set ∗) | → vml (∗ Not handling inline assembly. Ignoring writes to struct elds ∗) The module OddEvenDF implements the ForwardsTransfer signature, and is the input module to the DF.ForwardsDataFlow functor. The meanings of its members are documented in detail in dataflow.mli. We include here only the interesting members. The function combinePredecessors is used to determine when the analysis should terminate. If newly calculated incoming state fails to change the old value, then it returns None, otherwise it calculates the join of the states and returns the result. The function doInstr calls our transfer function varmap list handle inst to obtain the state after an instruction given the incoming state ll. module OddEvenDF = struct (∗...∗) let combinePredecessors (s : stmt) £(old : t) (ll : t) = if varmap list equal old ll then None else Some(varmap list combine old ll) let doInstr (i : instr) (ll : t) = let action = varmap list handle inst i in DF.Post action (∗...∗) end Other members of the ForwardsTransfer signature may also be implemented to implement a more sophisticated analysis. We nally invoke the functor to obtain the module OddEven, which contains the function compute, which performs the dataow analysis. module OddEven = DF.ForwardsDataFlow(OddEvenDF) 3.1.5 Running the analysis The collectVars function determines the initial abstract state (Bottom) on entry to the rst statement of a function.

CHAPTER 3. DATAFLOW ANALYSIS 29 let collectVars (fd : fundec) : varmap list = (fd.sformals @ fd.slocals) |> L.filter (fun vi → isIntegralType vi.vtype) |> L.map (fun vi → (vi.vid, (vi, Bottom))) Here, the function computeOddEven calls the compute function of the OddEven module. First though, use CIL's Cfg module to compute the control-ow graph for the function. Then, we grab the rst statement of the function and add it to the stmtStartData hash with a state indicating that on entry to the function the state for every variable is Bottom, which we get from the collectVars function. In practice, this code should be placed in a try...with block, to handle cases where, e.g. the function is empty. let computeOddEven (fd : fundec) : unit = Cfg.clearCFGinfo fd; ignore(Cfg.cfgFun fd); let first stmt = L.hd fd.sbody.bstmts in let vml = collectVars fd in IH.clear OddEvenDF.stmtStartData; IH.add OddEvenDF.stmtStartData first stmt.sid vml; OddEven.compute [first stmt] 3.1.6 Using the results The function getOddEvens returns the state on entry to a statement by looking it up in the hash table OddEvenDF.stmtStartData, which is lled in by OddEven.compute. let getOddEvens (sid : int) : varmap list option = try Some(IH.find OddEvenDF.stmtStartData sid) with Not found → None The function instrOddEvens calculates the states that exist on entry to each of a list of instructions. In addition to the list of instructions, it takes as input the state on entry to the rst instruction in the list.

CHAPTER 3. DATAFLOW ANALYSIS 28<br />

let varmap list handle inst (i : instr) (vml : varmap list) : varmap list =<br />

match i with<br />

| Set((Var vi, NoOffset), e, loc) when ¬(vi.vglob) ∧ (isIntegralType vi.vtype) →<br />

let k = oekind <strong>of</strong> exp vml e in<br />

varmap list replace vml (vi.vid, (vi, k))<br />

| Set((Mem , ), , )<br />

| Call → varmap list kill vml (∗ Kill vars with vaddr<strong>of</strong> set ∗)<br />

| → vml (∗ Not handling inline assembly. Ignoring writes to struct elds ∗)<br />

The module OddEvenDF implements the ForwardsTransfer signature, and is the input module<br />

to the DF.ForwardsDataFlow functor. The meanings <strong>of</strong> its members are documented in detail in<br />

dataflow.mli. We include here only the interesting members. The function combinePredecessors<br />

is used to determine when the analysis should terminate. If newly calculated incoming state fails to<br />

change the old value, then it returns None, otherwise it calculates the join <strong>of</strong> the states and returns<br />

the result. The function doInstr calls our transfer function varmap list handle inst to obtain<br />

the state after an instruction given the incoming state ll.<br />

module OddEvenDF = struct<br />

(∗...∗)<br />

let combinePredecessors (s : stmt) £(old : t) (ll : t) =<br />

if varmap list equal old ll then None else<br />

Some(varmap list combine old ll)<br />

let doInstr (i : instr) (ll : t) =<br />

let action = varmap list handle inst i in<br />

DF.Post action<br />

(∗...∗)<br />

end<br />

Other members <strong>of</strong> the ForwardsTransfer signature may also be implemented to implement a more<br />

sophisticated analysis.<br />

We nally invoke the functor to obtain the module OddEven, which contains the function<br />

compute, which performs the dataow analysis.<br />

module OddEven = DF.ForwardsDataFlow(OddEvenDF)<br />

3.1.5 Running the analysis<br />

The collectVars function determines the initial abstract state (Bottom) on entry to the rst statement<br />

<strong>of</strong> a function.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!