diff --git a/src/lib/backend/c/checks/CCoreTyper.ml b/src/lib/backend/c/checks/CCoreTyper.ml index 8427045b..5dac5d31 100644 --- a/src/lib/backend/c/checks/CCoreTyper.ml +++ b/src/lib/backend/c/checks/CCoreTyper.ml @@ -94,6 +94,9 @@ let rec unify_lists env f_unify xs ys = List.fold_left2 f_unify env xs ys ;; +let list_equal f xs ys = + List.length xs = List.length ys && List.for_all2 f xs ys + let rec unify_raw_ty env rawty1 rawty2 : env = match rawty1, rawty2 with (* abstract types unify with their inner types *) @@ -123,7 +126,7 @@ let rec unify_raw_ty env rawty1 rawty2 : env = | TEnum(variants1), TEnum(variants2) -> let ids1, _ = List.split variants1 in let ids2, _ = List.split variants2 in - if not (List.equal (Cid.equal) ids1 ids2) then + if not (list_equal (Cid.equal) ids1 ids2) then (raise (TypeError("enum types have different variants"))); env | TBuiltin(cid1, tys1), TBuiltin(cid2, tys2) -> diff --git a/src/lib/backend/tofino/RegularizeArrayOpAddrs.ml b/src/lib/backend/tofino/RegularizeArrayOpAddrs.ml new file mode 100644 index 00000000..96944a74 --- /dev/null +++ b/src/lib/backend/tofino/RegularizeArrayOpAddrs.ml @@ -0,0 +1,370 @@ +(* This is a tofino-specific normalization pass that ensures all array operations + use addresses in a tofino-compatible way. The requirements are: + 1. array operations placed in the same table must all access the array with the same address + 2. for array operations placed in different tables, the match condition of each table + must be exact (no wildcards). + + This module contains 2 passes that ensure these requirements are met: + Pass 1 (in TofinoCore IR, before layout or conversion to graph form): + if any path constraint is not exact-match compatible, + add address variable and transform into single-access address form + Pass 2 (in graph form, right before layout): + 1. make sure all statements that touch an array that is accessed by statements with multiple addresses are exact + 2. (after graph form) remove all negation rules -- since they're exact, it doesn't matter + 3. (after graph form) make nodes solitary + + Then, in the layout algorithm, the following should happen without any modifications: + - for each statement group that accesses an array: + - if they have multiple addresses, each statement will be + 1. exact + 2. solitary + So each statement will be exact, meaning it can be implemented by an exact table. + And also, since each statment is solitary, we know that there will be no cross-product + effect that creates a need for a wildcard rule. + - if they don't have multiple addresses, then it doesn't matter as they can be placed wherever +*) + +open InterpHelpers +open CoreSyntax +open TofinoCore +open TofinoResources + +let array_fun_cids = + List.map + (fun (fundef : InterpState.State.global_fun) -> fundef.cid) + (Arrays.defs@PairArrays.defs) +;; + +(**** helpers ****) +let list_contains lst target = + List.exists (fun x -> x = target) lst +;; +let rec recursive_exp_filter exp f = + if f exp then true + else match exp.e with + | EVal _ | EVar _ -> false + | EOp (_, exp_list) | ECall (_, exp_list, _) | EHash (_, exp_list) -> + List.exists (fun e -> recursive_exp_filter e f) exp_list + | EFlood e | EProj (e, _) -> + recursive_exp_filter e f + | ETuple exp_list -> + List.exists (fun e -> recursive_exp_filter e f) exp_list + | ERecord exp_list -> + List.exists (fun (_, e) -> recursive_exp_filter e f) exp_list +;; + +let has_inequality_exp exp = + (* does an expression contain an inequality? *) + let is_inequality_op op = + match op with + | Neq | Less | More | Leq | Geq -> true + | _ -> false + in + recursive_exp_filter exp (fun e -> + match e.e with + | EOp (op, _) -> is_inequality_op op + | _ -> false + ) +;; +let unique_ct xs f_equiv = + let rec aux acc xs = + match xs with + | [] -> acc + | x::xs' -> + if List.exists (f_equiv x) acc then + aux acc xs' + else + aux (x::acc) xs' + in + List.length (aux [] xs) +;; + +(* get array and index from args to Array method *) +let args_to_arr_addr args = match args with + | arr_exp::addr_exp::_ -> InterpHelpers.name_from_exp arr_exp, addr_exp + | _ -> raise (Failure "Array function call with less than 2 arguments") +;; + + +(* get the list of arrays that need to have + their address argument pre-computed, + and the type of each array's address variables *) +let find_arrays_to_transform component = + let array_addrs = Hashtbl.create 10 in + let array_has_wildcard_branch = Hashtbl.create 10 in + let v = + object (self) + inherit [_] s_iter as super + method! visit_TDGlobal _ id ty _ = + match ty.raw_ty with + | TName(cid, _) when + ((Cid.equal cid Arrays.t_id) || + (Cid.equal cid PairArrays.t_id)) -> + (* this is an array, add an entry to the hash tables *) + Hashtbl.add array_addrs (Cid.id id) []; + Hashtbl.add array_has_wildcard_branch (Cid.id id) false + | _ -> () + + method! visit_SMatch in_wc_branch _ branches = + let rec process_branches in_wc_branch branches = + match branches with + | [] -> () + | (pats, stmt)::rest -> + (* check if this branch is guarded by a wildcard *) + let in_wc_branch = in_wc_branch || has_wildcard_pat pats in + (* recurse on it *) + self#visit_statement in_wc_branch stmt; + (* process the rest of the branches *) + process_branches in_wc_branch rest + in + process_branches in_wc_branch branches + method! visit_SIf in_wc_branch econd stmt1 stmt2 = + self#visit_statement (in_wc_branch || has_inequality_exp econd) stmt1; + self#visit_statement true stmt2 + + method! visit_ECall in_wc_branch cid args _ = + (* if this is an array call *) + if list_contains array_fun_cids cid then ( + (* add the addr exp to the list *) + let arr_cid, addr_exp = args_to_arr_addr args in + let arr_addrs = Hashtbl.find array_addrs arr_cid in + Hashtbl.replace array_addrs arr_cid (arr_addrs@[addr_exp]); + (* if this is in a branch with a wildcard, mark it *) + if in_wc_branch then ( + Hashtbl.replace array_has_wildcard_branch arr_cid true + ) + ) + end + in + (* get the array address expressions and the path condition complexity flag *) + v#visit_component false component; + + let array_addrvar_tys = Hashtbl.fold (fun k v acc -> + acc@[k, (List.hd v).ety]) + array_addrs [] + in + + (* go through all array address expression lists, count unique using CoreSyntax.equiv_exp *) + let array_addr_cts = Hashtbl.fold (fun k v acc -> + acc@[k, (unique_ct v CoreSyntax.equiv_exp)]) + array_addrs [] + in + let array_wildcards = Hashtbl.to_seq array_has_wildcard_branch |> List.of_seq in + let arrays_to_transform = List.filter + (fun (cid, ct) -> + let has_wildcard = match List.assoc_opt cid array_wildcards with + | Some b -> b + | None -> false + in + ct > 1 && has_wildcard + ) + array_addr_cts + in + let arrays_to_transform = List.map fst arrays_to_transform in + arrays_to_transform, array_addrvar_tys +;; + +(* Walk the AST a second time. + 1. For each array that needs to be transformed, add + a new intermediate variable for the address argument. + 2. For each Array method call that takes + an array that needs to be transformed: + - transform each array call of the form + ECall(arr_fcn_cid, [arr_exp; addr_exp; ...], ..) -> + ECall(arr_fcn_cid, [arr_exp; addr_cid_exp; ...], ..) + - add a new assignment to the addr_cid var in the + statement right before the ECall. + Statement (... ECall ...) -> + SSeq( + Statement(... addr_cid_exp = addr_exp ...), + Statement(... ECall ...) + ) + *) +let arrayid_to_addrid arr_cid = + Cid.to_id arr_cid |> Id.prepend_string "addr" |> Cid.id +;; + +let transform_array_calls component + (arrays_to_transform : Cid.t list) + (array_addrvar_tys : (Cid.t * ty) list) = + (* the statement that initializes an address var before + an array method call that uses it as an argument. + This should always be empty at the start end end of + processing each statement. + Before returning from a statement visitor, the + visitor should check to see if this is empty. If it is not, + the visitor should return the sequence of the init statement + and the processed statement. *) + let init_stmts = ref [] in + let v = + + object (_) + inherit [_] s_map as super + + method! visit_exp () exp = + let exp = super#visit_exp () exp in + match exp.e with + (* call to an array function *) + | ECall (cid, args, u) when list_contains array_fun_cids cid -> ( + let arr_cid, addr_exp = args_to_arr_addr args in + if list_contains arrays_to_transform arr_cid then ( + (* update the address argument expression *) + let new_args = match args with + | arr_exp::addr_exp::rest -> + let new_addr_exp = evar_cid (arrayid_to_addrid arr_cid) addr_exp.ety in + arr_exp::new_addr_exp::rest + | _ -> raise (Failure "Array function call with less than 2 arguments") + in + (* create the assignment expression *) + let init_stmt = sassign (arrayid_to_addrid arr_cid) addr_exp in + (* update the call expression *) + let new_exp = { exp with e = ECall (cid, new_args, u) } in + init_stmts := init_stmt::(!init_stmts); + new_exp + ) (* a call to something, but not an array function *) + else exp + ) + (* not a call *) + | _ -> super#visit_exp () exp + + method! visit_statement () stmt = + (* make sure that init_stmts is empty, else throw an errpr *) + if List.length !init_stmts > 0 then + raise (Failure "init_stmts not empty at start of statement processing"); + (* process the statement *) + let stmt = super#visit_statement () stmt in + (* prepend init stmts if necessary *) + if List.length !init_stmts > 0 then ( + let rv = sequence_stmts ((List.rev !init_stmts)@[stmt]) in + init_stmts := []; + rv) + else stmt + end + in + (* update all the array calls *) + let component = v#visit_component () component in + (* now, add a shared local for each array *) + let tds = List.fold_left + (fun tds arr_cid -> + let addr_ty = List.assoc arr_cid array_addrvar_tys in + let addrcid = arrayid_to_addrid arr_cid in + add_shared_local tds (addrcid |> Cid.to_id) addr_ty |> snd + ) + component.comp_decls + arrays_to_transform + in + { component with comp_decls = tds } +;; + +let process_component component = + (* first, find the arrays to transform and the array idx var tys *) + let arrays_to_transform, array_addrvar_tys = find_arrays_to_transform component in + (* second, transform the array calls *) + transform_array_calls component arrays_to_transform array_addrvar_tys +;; + +let process_core core_prog = + (* process the components individually *) + List.map process_component core_prog +;; + + +(*** dependency graph node passes ***) +open TofinoCfg + + +let hashtbl_entry_append h k v = + match (Hashtbl.find_opt h k) with + | Some lst -> Hashtbl.replace h k (v::lst) + | None -> Hashtbl.add h k [v] +;; +let string_of_fcncid cid = + Caml.String.concat "." @@ Cid.names cid +;; + +(* traverse the graph, find all the (array, addr) pairs *) +(* let get_array_addrs stmt = *) +let acc_array_addrs = + object (_) + inherit [_] s_iter as super + method! visit_exp result exp = + super#visit_exp result exp; + match exp.e with + | ECall(fid, args, _) -> ( + match (string_of_fcncid fid) with + | "Array.get"| "Array.getm" | "Array.set" + | "Array.setm" | "Array.update" + | "Array.update_complex" | "PairArray.update" -> + let arr_cid = List.hd args |> InterpHelpers.name_from_exp in + let addr_exp = List.hd (List.tl args) in + hashtbl_entry_append result arr_cid addr_exp; + | _ -> () + ) + | _ -> () + end +;; + + +let acc_arrays_addrs_over_vertex v arr_addrs = + acc_array_addrs#visit_statement arr_addrs v.stmt; arr_addrs +;; + +(* get the unique (array * address arg list) list from the dfg *) +let array_addrs_of_dfg dfg = + let arr_addrs = + TofinoDfg.Dfg.fold_vertex + acc_arrays_addrs_over_vertex + dfg + (Hashtbl.create 10) + in + let arr_addrs = Hashtbl.to_seq arr_addrs |> List.of_seq in + let unique_arr_addrs = List.map (fun (cid, addrs) -> + cid, MiscUtils.unique_list_of_eq equiv_exp addrs) + arr_addrs + in + unique_arr_addrs +;; + +let remove_exact_noop_branches statement = + match statement.s with + | SMatch(exps, branches) -> + let branches = List.filter (fun branch -> not + (is_exact_branch branch && is_noop (snd branch)) + ) branches + in + {statement with s = SMatch(exps, branches)} + | _ -> statement +;; + +(* for each vertex statement that accesses an array who has multiple addresses: + 1. check that all the calls are in exact match vertex statements + 2. mark the vertex statement as solitary + 3. remove all negative branches from the vertex statement *) +let normalize_vertex_statement arr_addrs vs = + let arrs = TofinoResources.arrays_of_stmt vs.stmt in + match arrs with + | [arr] -> ( + match List.assoc_opt arr arr_addrs with + | Some addrs -> + if (List.length addrs) > 1 then ( + if (is_exact_match vs.stmt) then ( + {vs with stmt = remove_exact_noop_branches vs.stmt; solitary = true} + ) + else ( + let err_str = "Array with multiple addresses in non-exact match statement: "^(CorePrinting.stmt_to_string vs.stmt) in + error err_str; + ) + ) + else vs + | None -> vs + ) + | _ -> vs +;; + + +let process_dfg dfg = + let arr_addrs = array_addrs_of_dfg dfg in + TofinoDfg.Dfg.map_vertex (normalize_vertex_statement arr_addrs) dfg +;; + + diff --git a/src/lib/backend/tofino/core/AddIngressParser.ml b/src/lib/backend/tofino/core/AddIngressParser.ml index 868e6194..012a8bb0 100644 --- a/src/lib/backend/tofino/core/AddIngressParser.ml +++ b/src/lib/backend/tofino/core/AddIngressParser.ml @@ -181,8 +181,6 @@ let inline_parsers ?(with_payloads=true) parser_entry_ty pkt_var bg_events decls | CallInvalid -> error "[inline_parsers] invalid parser entry type -- this should have been caught earlier" in let ctx = CidMap.add (Cid.id Builtins.lucid_parse_id) ([Id.create "pkt", pkt_arg_ty], lucid_bg_event_block) CidMap.empty in - print_endline ("decls: "); - CorePrinting.decls_to_string decls |> print_endline; inline_parsers_rec ctx decls ;; @@ -376,7 +374,7 @@ let check_valid_entry_parse_block parse_block : lucid_entry_block_ty = let acns, _ = List.split acns_spans in match acns, step with (* parser main() { do_lucid_parsing(); } *) - | [], PCall({e=ECall(cid, _, _); _}) when cid_is_ingress_port cid -> + | [], PCall({e=ECall(cid, _, _); _}) when ((Cid.names cid |> List.hd) = (Builtins.lucid_parse_id |> fst)) -> CallAlways (* parser main() { match ingress_port with , where branches either directly call the lucid parser or never call the lucid parser } *) diff --git a/src/lib/backend/tofino/layout/TofinoLayout.ml b/src/lib/backend/tofino/layout/TofinoLayout.ml index 325e5205..60b8adfd 100644 --- a/src/lib/backend/tofino/layout/TofinoLayout.ml +++ b/src/lib/backend/tofino/layout/TofinoLayout.ml @@ -754,8 +754,8 @@ let try_place_in_stage prog_info (prior_stages, stmt_group_opt) stage = (match stmt_group.arr with | Some(arr) -> ( let stage_num = List.length prior_stages in - print_endline - ("[try_place_in_stage] failed to place array " + print_string + ("\n[try_place_in_stage] failed to place array " ^(CorePrinting.cid_to_string arr) ^" in stage "^string_of_int stage_num^"." ^" Reason: "^reason^"."); @@ -779,8 +779,8 @@ let try_place_in_stage prog_info (prior_stages, stmt_group_opt) stage = (match stmt_group.arr with | Some(arr) -> ( let stage_num = List.length prior_stages in - print_endline - ("[try_place_in_stage] SUCCESS. placed array " + print_string + ("\n[try_place_in_stage] SUCCESS. placed array " ^(CorePrinting.cid_to_string arr) ^" in stage "^string_of_int stage_num^"."); ) diff --git a/src/lib/backend/tofino/layout/TofinoResources.ml b/src/lib/backend/tofino/layout/TofinoResources.ml index 8b506682..f8fab944 100644 --- a/src/lib/backend/tofino/layout/TofinoResources.ml +++ b/src/lib/backend/tofino/layout/TofinoResources.ml @@ -358,8 +358,6 @@ let rec array_stmts_of_stmt stmt : statement list = res ;; -(* this isn't right. pick up tomorrow. *) - let hash_bits_of_stmt dbg stmt = let _, hash_ops = hash_ops_of_stmt [] stmt in (* let hash_stmts = hashers_of_stmt stmt |> (MatchAlgebra.unique_stmt_list) in @@ -372,3 +370,23 @@ let hash_bits_of_stmt dbg stmt = exit 1; ); hbits ;; + + +let has_wildcard_pat pats = + (* does a branch pattern have a wildcard? *) + List.exists (fun pat -> match pat with + | PWild -> true + | PBit xs -> List.exists (fun x -> x = -1) xs + | _ -> false + ) pats +;; +let is_exact_branch branch = not (has_wildcard_pat (fst branch)) ;; +let is_exact_match (stmt : statement) = + match stmt.s with + | SMatch(_, branches) -> + (* last branch is default, expected to be wildcard even in exact match *) + let non_default_branches = List.rev branches |> List.tl |> List.rev in + List.for_all is_exact_branch non_default_branches + | _ -> false +;; + diff --git a/src/lib/backend/tofino/p4/TofinoCoreToP4.ml b/src/lib/backend/tofino/p4/TofinoCoreToP4.ml index 0bcc60a1..ee98b31f 100644 --- a/src/lib/backend/tofino/p4/TofinoCoreToP4.ml +++ b/src/lib/backend/tofino/p4/TofinoCoreToP4.ml @@ -778,74 +778,85 @@ let stmt_to_table env (_:pragma) (ignore_pragmas: (id * pragma) list) (tid, stmt tbl_decl, tbl_call | SMatch(exps, branches) -> ( let (_, keys), _ = translate_exps env exps in - (* small optimization: if there's only 1 key and all the patterns matching that key are exact (except for a final default case) emit an exact table. Otherwise, a ternary table. *) - let patses = List.map fst branches in - let last_pats = List.rev patses |> List.hd in - let fst_patses = List.rev patses |> List.tl in - let is_exact = - (List.for_all - (fun pats -> - match pats with - | [TofinoCore.PNum _] -> true - | _ -> false) - fst_patses) - && - (match last_pats with - | [TofinoCore.PWild] -> true | _ -> false) + + (* Types of tables: + 1. one rule with no match fields, just an action + 2. exact match table + 3. ternary match table *) + + let is_direct_call = match branches with + | [([], _)] -> true + | _ -> false in - match is_exact with - | true -> ( - let keys = List.map exp_to_exact_key keys in - let actions = List.map action_cid_of_branch branches - |> MiscUtils.unique_list_of - |> List.map evar_noretmethod - in - let rec branches_to_rules branches = - match branches with - | [] -> [], None - (* expect the last branch to be a wildcard *) - | [([TofinoCore.PWild], call_stmt)] -> ( - [], Some(translate_sunit_ecall call_stmt) - ) - | _::[] -> (error "[stmt_to_table] invalid final branch in table") - | (pats, call_stmt)::branches -> ( - let pats' = List.map translate_pat pats in - let call_stmt' = translate_sunit_ecall call_stmt in - let rules, default = branches_to_rules branches in - (pats', call_stmt')::rules, default - ) - in - let rules, default_opt = branches_to_rules branches in - let tbl_dec = - dtable tid keys actions rules default_opt None ignore_parallel_tbls_pragmas - in - let tbl_call = sunit (ecall_table tid) in - (tbl_dec, tbl_call) - ) - | false -> + (* emit an exact table if possible *) + let is_exact = TofinoResources.is_exact_match stmt in + + if (is_direct_call) then ( let keys = List.map exp_to_ternary_key keys in - let actions = List.map action_cid_of_branch branches - |> MiscUtils.unique_list_of - |> List.map evar_noretmethod - in - let rules, default_opt = match branches with - (* a single empty branch means there are no const rules, just a default action *) - | [([], call_stmt)] -> ([], Some(translate_sunit_ecall call_stmt)) - (* anything else means there are const rules and no default *) - | branches -> ( - (List.fold_left - (fun branches' (pats, stmt) -> - branches' - @[(List.map translate_pat pats, translate_sunit_ecall stmt)]) - [] - branches) - , None) - in - let tbl_dec = - dtable tid keys actions rules default_opt None ignore_parallel_tbls_pragmas + let default_action = match branches with + | [([], call_stmt)] -> translate_sunit_ecall call_stmt + | _ -> error "[stmt_to_table] invalid direct call" in - let tbl_call = sunit (ecall_table tid) in + let tbl_dec = dtable tid keys [] [] (Some default_action) None ignore_parallel_tbls_pragmas in + let tbl_call = sunit (ecall_table tid) in (tbl_dec, tbl_call) + ) + else ( + if is_exact then ( + let keys = List.map exp_to_exact_key keys in + let actions = List.map action_cid_of_branch branches + |> MiscUtils.unique_list_of + |> List.map evar_noretmethod + in + let rec branches_to_rules (branches : CoreSyntax.branch list) = + match branches with + | [] -> [], None + (* expect the last branch to be a wildcard *) + | [(pats, call_stmt)] when (TofinoResources.has_wildcard_pat pats) -> ( + [], Some(translate_sunit_ecall call_stmt) + ) + | _::[] -> (error "[stmt_to_table] invalid final branch in table") + (* the other branches get translated normally, the same as in a ternary table *) + | (pats, call_stmt)::branches -> ( + let pats' = List.map translate_pat pats in + let call_stmt' = translate_sunit_ecall call_stmt in + let rules, default = branches_to_rules branches in + (pats', call_stmt')::rules, default + ) + in + let rules, default_opt = branches_to_rules branches in + let tbl_dec = + dtable tid keys actions rules default_opt None ignore_parallel_tbls_pragmas + in + let tbl_call = sunit (ecall_table tid) in + (tbl_dec, tbl_call) + ) + else ( (* case: not exact *) + let keys = List.map exp_to_ternary_key keys in + let actions = List.map action_cid_of_branch branches + |> MiscUtils.unique_list_of + |> List.map evar_noretmethod + in + let rules, default_opt = match branches with + (* a single empty branch means there are no const rules, just a default action *) + | [([], _)] -> error "[stmt_to_table] should have been recognized as direct call" + (* anything else means there are const rules and no default *) + | branches -> ( + (List.fold_left + (fun branches' (pats, stmt) -> + branches' + @[(List.map translate_pat pats, translate_sunit_ecall stmt)]) + [] + branches) + , None) + in + let tbl_dec = + dtable tid keys actions rules default_opt None ignore_parallel_tbls_pragmas + in + let tbl_call = sunit (ecall_table tid) in + (tbl_dec, tbl_call) + ) + ) ) | _ -> error "[generate_table] not a match statement!" ;; diff --git a/src/lib/backend/tofino/tofinoPipeline.ml b/src/lib/backend/tofino/tofinoPipeline.ml index 7d481270..cb0d4dd6 100644 --- a/src/lib/backend/tofino/tofinoPipeline.ml +++ b/src/lib/backend/tofino/tofinoPipeline.ml @@ -188,6 +188,8 @@ let tofinocore_passes core_prog portspec = let core_prog = IfToMatch.process_core core_prog in report_if_verbose "-------Converting all memops to complex form-------"; let core_prog = RegularizeMemops.process_core core_prog in + report_if_verbose "-------Allocating array address variables-------"; + let core_prog = RegularizeArrayOpAddrs.process_core core_prog in report_if_verbose "-------Allocating memop input variables-------"; dump_prog "before ShareMemopInputsSat" "tofinocore_pre_memop_overlay" core_prog; let core_prog = ShareMemopInputsSat.process_core core_prog in @@ -231,8 +233,12 @@ let layout (prog : TofinoCore.prog) = let dfg = TofinoDfg.process cdg in TofinoDfg.print_dfg (logging_prefix ^ "_dfg.dot") dfg; report_if_verbose (Printf.sprintf "-------Layout for %s: scheduling data dependency graph to pipeline-------" cn); + let dfg = RegularizeArrayOpAddrs.process_dfg dfg in + report_if_verbose (Printf.sprintf "-------------------- LAYOUT FOR %s --------------------" (String.uppercase_ascii cn)); let pipeline_stmts = TofinoLayout.process_new comp.comp_decls dfg in let num_stages = List.length(pipeline_stmts) in + report_if_verbose (Printf.sprintf "--------- LAYOUT FOR %s SUCCEEDED IN %i STAGES --------" (String.uppercase_ascii cn) num_stages); + layout_info := (!layout_info)@[(cn, (string_of_int num_stages))]; let main_handler = TofinoCore.main_handler_of_decls comp.comp_decls in let main_handler' = {main_handler with hdl_body = TofinoCore.SPipeline(pipeline_stmts);} in diff --git a/src/lib/backend/tofino/tofinocore/TofinoCore.ml b/src/lib/backend/tofino/tofinocore/TofinoCore.ml index 419c12d0..12e47f8c 100644 --- a/src/lib/backend/tofino/tofinocore/TofinoCore.ml +++ b/src/lib/backend/tofino/tofinocore/TofinoCore.ml @@ -559,6 +559,8 @@ let add_preallocated_locals pvars params = pvars@params ;; +(* add a shared local variable to the main handler + of the program. *) let add_shared_local tds tmp_id tmp_ty = let tmp_e = var_sp (Cid.id tmp_id) tmp_ty Span.default in let main_handler = main_handler_of_decls tds in diff --git a/src/lib/dune b/src/lib/dune index 97f9ab47..a798ae54 100644 --- a/src/lib/dune +++ b/src/lib/dune @@ -143,6 +143,7 @@ PropagateEvars IfToMatch RegularizeMemops + RegularizeArrayOpAddrs ShareMemopInputsSat SingleTableMatch ActionsToFunctions