From 17f519651feb4a09aa90c89c949469e8a5ab0e88 Mon Sep 17 00:00:00 2001 From: xleroy Date: Sun, 17 Aug 2014 07:52:12 +0000 Subject: - Support "switch" statements over 64-bit integers (in CompCert C to Cminor, included) - Translation of "switch" to decision trees or jumptables made generic over the sizes of integers and moved to the Cminor->CminorSel pass instead of CminorSel->RTL as before. - CminorSel: add "exitexpr" to support the above. - ValueDomain: more precise analysis of comparisons against an integer literal. E.g. "x >=u 0" is always true. git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@2565 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e --- common/Switchaux.ml | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 common/Switchaux.ml (limited to 'common/Switchaux.ml') diff --git a/common/Switchaux.ml b/common/Switchaux.ml new file mode 100644 index 00000000..15480aeb --- /dev/null +++ b/common/Switchaux.ml @@ -0,0 +1,99 @@ +(* *********************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Xavier Leroy, INRIA Paris-Rocquencourt *) +(* *) +(* Copyright Institut National de Recherche en Informatique et en *) +(* Automatique. All rights reserved. This file is distributed *) +(* under the terms of the INRIA Non-Commercial License Agreement. *) +(* *) +(* *********************************************************************) + +open Datatypes +open Camlcoq +open Switch + +(* Compiling a switch table into a decision tree *) + +module ZSet = Set.Make(Z) + +let normalize_table tbl = + let rec norm keys accu = function + | [] -> (accu, keys) + | (key, act) :: rem -> + if ZSet.mem key keys + then norm keys accu rem + else norm (ZSet.add key keys) ((key, act) :: accu) rem + in norm ZSet.empty [] tbl + +let compile_switch_as_tree modulus default tbl = + let sw = Array.of_list tbl in + Array.stable_sort (fun (n1, _) (n2, _) -> Z.compare n1 n2) sw; + let rec build lo hi minval maxval = + match hi - lo with + | 0 -> + CTaction default + | 1 -> + let (key, act) = sw.(lo) in + if Z.sub maxval minval = Z.zero + then CTaction act + else CTifeq(key, act, CTaction default) + | 2 -> + let (key1, act1) = sw.(lo) + and (key2, act2) = sw.(lo+1) in + CTifeq(key1, act1, + if Z.sub maxval minval = Z.one + then CTaction act2 + else CTifeq(key2, act2, CTaction default)) + | 3 -> + let (key1, act1) = sw.(lo) + and (key2, act2) = sw.(lo+1) + and (key3, act3) = sw.(lo+2) in + CTifeq(key1, act1, + CTifeq(key2, act2, + if Z.sub maxval minval = Z.of_uint 2 + then CTaction act3 + else CTifeq(key3, act3, CTaction default))) + | _ -> + let mid = (lo + hi) / 2 in + let (pivot, _) = sw.(mid) in + CTiflt(pivot, + build lo mid minval (Z.sub pivot Z.one), + build mid hi pivot maxval) + in build 0 (Array.length sw) Z.zero modulus + +let compile_switch_as_jumptable default cases minkey maxkey = + let tblsize = 1 + Z.to_int (Z.sub maxkey minkey) in + assert (tblsize >= 0 && tblsize <= Sys.max_array_length); + let tbl = Array.make tblsize default in + List.iter + (fun (key, act) -> + let pos = Z.to_int (Z.sub key minkey) in + tbl.(pos) <- act) + cases; + CTjumptable(minkey, + Z.of_uint tblsize, + Array.to_list tbl, + CTaction default) + +let dense_enough (numcases: int) (minkey: Z.t) (maxkey: Z.t) = + let span = Z.sub maxkey minkey in + assert (Z.ge span Z.zero); + let tree_size = Z.mul (Z.of_uint 4) (Z.of_uint numcases) + and table_size = Z.add (Z.of_uint 8) span in + numcases >= 7 (* small jump tables are always less efficient *) + && Z.le table_size tree_size + && Z.lt span (Z.of_uint Sys.max_array_length) + +let compile_switch modulus default table = + let (tbl, keys) = normalize_table table in + if ZSet.is_empty keys then CTaction default else begin + let minkey = ZSet.min_elt keys + and maxkey = ZSet.max_elt keys in + if dense_enough (List.length tbl) minkey maxkey + then compile_switch_as_jumptable default tbl minkey maxkey + else compile_switch_as_tree modulus default tbl + end + + -- cgit