1(**************************************************************************) 2(* *) 3(* OCaml *) 4(* *) 5(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) 6(* *) 7(* Copyright 1996 Institut National de Recherche en Informatique et *) 8(* en Automatique. *) 9(* *) 10(* All rights reserved. This file is distributed under the terms of *) 11(* the GNU Lesser General Public License version 2.1, with the *) 12(* special exception on linking described in the file LICENSE. *) 13(* *) 14(**************************************************************************) 15 16(* Compilation of pattern matching *) 17 18open Misc 19open Asttypes 20open Types 21open Typedtree 22open Lambda 23open Parmatch 24open Printf 25 26 27let dbg = false 28 29(* See Peyton-Jones, ``The Implementation of functional programming 30 languages'', chapter 5. *) 31(* 32 Well, it was true at the beginning of the world. 33 Now, see Lefessant-Maranget ``Optimizing Pattern-Matching'' ICFP'2001 34*) 35 36 37(* 38 Many functions on the various data structures of the algorithm : 39 - Pattern matrices. 40 - Default environments: mapping from matrices to exit numbers. 41 - Contexts: matrices whose column are partitioned into 42 left and right. 43 - Jump summaries: mapping from exit numbers to contexts 44*) 45 46let string_of_lam lam = 47 Printlambda.lambda Format.str_formatter lam ; 48 Format.flush_str_formatter () 49 50type matrix = pattern list list 51 52let add_omega_column pss = List.map (fun ps -> omega::ps) pss 53 54type ctx = {left:pattern list ; right:pattern list} 55 56let pretty_ctx ctx = 57 List.iter 58 (fun {left=left ; right=right} -> 59 prerr_string "LEFT:" ; 60 pretty_line left ; 61 prerr_string " RIGHT:" ; 62 pretty_line right ; 63 prerr_endline "") 64 ctx 65 66let le_ctx c1 c2 = 67 le_pats c1.left c2.left && 68 le_pats c1.right c2.right 69 70let lshift {left=left ; right=right} = match right with 71| x::xs -> {left=x::left ; right=xs} 72| _ -> assert false 73 74let lforget {left=left ; right=right} = match right with 75| _::xs -> {left=omega::left ; right=xs} 76| _ -> assert false 77 78let rec small_enough n = function 79 | [] -> true 80 | _::rem -> 81 if n <= 0 then false 82 else small_enough (n-1) rem 83 84let ctx_lshift ctx = 85 if small_enough 31 ctx then 86 List.map lshift ctx 87 else (* Context pruning *) begin 88 get_mins le_ctx (List.map lforget ctx) 89 end 90 91let rshift {left=left ; right=right} = match left with 92| p::ps -> {left=ps ; right=p::right} 93| _ -> assert false 94 95let ctx_rshift ctx = List.map rshift ctx 96 97let rec nchars n ps = 98 if n <= 0 then [],ps 99 else match ps with 100 | p::rem -> 101 let chars, cdrs = nchars (n-1) rem in 102 p::chars,cdrs 103 | _ -> assert false 104 105let rshift_num n {left=left ; right=right} = 106 let shifted,left = nchars n left in 107 {left=left ; right = shifted@right} 108 109let ctx_rshift_num n ctx = List.map (rshift_num n) ctx 110 111(* Recombination of contexts (eg: (_,_)::p1::p2::rem -> (p1,p2)::rem) 112 All mutable fields are replaced by '_', since side-effects in 113 guards can alter these fields *) 114 115let combine {left=left ; right=right} = match left with 116| p::ps -> {left=ps ; right=set_args_erase_mutable p right} 117| _ -> assert false 118 119let ctx_combine ctx = List.map combine ctx 120 121let ncols = function 122 | [] -> 0 123 | ps::_ -> List.length ps 124 125 126exception NoMatch 127exception OrPat 128 129let filter_matrix matcher pss = 130 131 let rec filter_rec = function 132 | (p::ps)::rem -> 133 begin match p.pat_desc with 134 | Tpat_alias (p,_,_) -> 135 filter_rec ((p::ps)::rem) 136 | Tpat_var _ -> 137 filter_rec ((omega::ps)::rem) 138 | _ -> 139 begin 140 let rem = filter_rec rem in 141 try 142 matcher p ps::rem 143 with 144 | NoMatch -> rem 145 | OrPat -> 146 match p.pat_desc with 147 | Tpat_or (p1,p2,_) -> filter_rec [(p1::ps) ;(p2::ps)]@rem 148 | _ -> assert false 149 end 150 end 151 | [] -> [] 152 | _ -> 153 pretty_matrix pss ; 154 fatal_error "Matching.filter_matrix" in 155 filter_rec pss 156 157let make_default matcher env = 158 let rec make_rec = function 159 | [] -> [] 160 | ([[]],i)::_ -> [[[]],i] 161 | (pss,i)::rem -> 162 let rem = make_rec rem in 163 match filter_matrix matcher pss with 164 | [] -> rem 165 | ([]::_) -> ([[]],i)::rem 166 | pss -> (pss,i)::rem in 167 make_rec env 168 169let ctx_matcher p = 170 let p = normalize_pat p in 171 match p.pat_desc with 172 | Tpat_construct (_, cstr,omegas) -> 173 begin match cstr.cstr_tag with 174 | Cstr_extension _ -> 175 let nargs = List.length omegas in 176 (fun q rem -> match q.pat_desc with 177 | Tpat_construct (_, _cstr',args) 178 when List.length args = nargs -> 179 p,args @ rem 180 | Tpat_any -> p,omegas @ rem 181 | _ -> raise NoMatch) 182 | _ -> 183 (fun q rem -> match q.pat_desc with 184 | Tpat_construct (_, cstr',args) 185 when cstr.cstr_tag=cstr'.cstr_tag -> 186 p,args @ rem 187 | Tpat_any -> p,omegas @ rem 188 | _ -> raise NoMatch) 189 end 190 | Tpat_constant cst -> 191 (fun q rem -> match q.pat_desc with 192 | Tpat_constant cst' when const_compare cst cst' = 0 -> 193 p,rem 194 | Tpat_any -> p,rem 195 | _ -> raise NoMatch) 196 | Tpat_variant (lab,Some omega,_) -> 197 (fun q rem -> match q.pat_desc with 198 | Tpat_variant (lab',Some arg,_) when lab=lab' -> 199 p,arg::rem 200 | Tpat_any -> p,omega::rem 201 | _ -> raise NoMatch) 202 | Tpat_variant (lab,None,_) -> 203 (fun q rem -> match q.pat_desc with 204 | Tpat_variant (lab',None,_) when lab=lab' -> 205 p,rem 206 | Tpat_any -> p,rem 207 | _ -> raise NoMatch) 208 | Tpat_array omegas -> 209 let len = List.length omegas in 210 (fun q rem -> match q.pat_desc with 211 | Tpat_array args when List.length args=len -> 212 p,args @ rem 213 | Tpat_any -> p, omegas @ rem 214 | _ -> raise NoMatch) 215 | Tpat_tuple omegas -> 216 (fun q rem -> match q.pat_desc with 217 | Tpat_tuple args -> p,args @ rem 218 | _ -> p, omegas @ rem) 219 | Tpat_record (l,_) -> (* Records are normalized *) 220 (fun q rem -> match q.pat_desc with 221 | Tpat_record (l',_) -> 222 let l' = all_record_args l' in 223 p, List.fold_right (fun (_, _,p) r -> p::r) l' rem 224 | _ -> p,List.fold_right (fun (_, _,p) r -> p::r) l rem) 225 | Tpat_lazy omega -> 226 (fun q rem -> match q.pat_desc with 227 | Tpat_lazy arg -> p, (arg::rem) 228 | _ -> p, (omega::rem)) 229 | _ -> fatal_error "Matching.ctx_matcher" 230 231 232 233 234let filter_ctx q ctx = 235 236 let matcher = ctx_matcher q in 237 238 let rec filter_rec = function 239 | ({right=p::ps} as l)::rem -> 240 begin match p.pat_desc with 241 | Tpat_or (p1,p2,_) -> 242 filter_rec ({l with right=p1::ps}::{l with right=p2::ps}::rem) 243 | Tpat_alias (p,_,_) -> 244 filter_rec ({l with right=p::ps}::rem) 245 | Tpat_var _ -> 246 filter_rec ({l with right=omega::ps}::rem) 247 | _ -> 248 begin let rem = filter_rec rem in 249 try 250 let to_left, right = matcher p ps in 251 {left=to_left::l.left ; right=right}::rem 252 with 253 | NoMatch -> rem 254 end 255 end 256 | [] -> [] 257 | _ -> fatal_error "Matching.filter_ctx" in 258 259 filter_rec ctx 260 261let select_columns pss ctx = 262 let n = ncols pss in 263 List.fold_right 264 (fun ps r -> 265 List.fold_right 266 (fun {left=left ; right=right} r -> 267 let transfert, right = nchars n right in 268 try 269 {left = lubs transfert ps @ left ; right=right}::r 270 with 271 | Empty -> r) 272 ctx r) 273 pss [] 274 275let ctx_lub p ctx = 276 List.fold_right 277 (fun {left=left ; right=right} r -> 278 match right with 279 | q::rem -> 280 begin try 281 {left=left ; right = lub p q::rem}::r 282 with 283 | Empty -> r 284 end 285 | _ -> fatal_error "Matching.ctx_lub") 286 ctx [] 287 288let ctx_match ctx pss = 289 List.exists 290 (fun {right=qs} -> 291 List.exists 292 (fun ps -> compats qs ps) 293 pss) 294 ctx 295 296type jumps = (int * ctx list) list 297 298let pretty_jumps (env : jumps) = match env with 299| [] -> () 300| _ -> 301 List.iter 302 (fun (i,ctx) -> 303 Printf.fprintf stderr "jump for %d\n" i ; 304 pretty_ctx ctx) 305 env 306 307 308let rec jumps_extract i = function 309 | [] -> [],[] 310 | (j,pss) as x::rem as all -> 311 if i=j then pss,rem 312 else if j < i then [],all 313 else 314 let r,rem = jumps_extract i rem in 315 r,(x::rem) 316 317let rec jumps_remove i = function 318 | [] -> [] 319 | (j,_)::rem when i=j -> rem 320 | x::rem -> x::jumps_remove i rem 321 322let jumps_empty = [] 323and jumps_is_empty = function 324 | [] -> true 325 | _ -> false 326 327let jumps_singleton i = function 328 | [] -> [] 329 | ctx -> [i,ctx] 330 331let jumps_add i pss jumps = match pss with 332| [] -> jumps 333| _ -> 334 let rec add = function 335 | [] -> [i,pss] 336 | (j,qss) as x::rem as all -> 337 if j > i then x::add rem 338 else if j < i then (i,pss)::all 339 else (i,(get_mins le_ctx (pss@qss)))::rem in 340 add jumps 341 342 343let rec jumps_union (env1:(int*ctx list)list) env2 = match env1,env2 with 344| [],_ -> env2 345| _,[] -> env1 346| ((i1,pss1) as x1::rem1), ((i2,pss2) as x2::rem2) -> 347 if i1=i2 then 348 (i1,get_mins le_ctx (pss1@pss2))::jumps_union rem1 rem2 349 else if i1 > i2 then 350 x1::jumps_union rem1 env2 351 else 352 x2::jumps_union env1 rem2 353 354 355let rec merge = function 356 | env1::env2::rem -> jumps_union env1 env2::merge rem 357 | envs -> envs 358 359let rec jumps_unions envs = match envs with 360 | [] -> [] 361 | [env] -> env 362 | _ -> jumps_unions (merge envs) 363 364let jumps_map f env = 365 List.map 366 (fun (i,pss) -> i,f pss) 367 env 368 369(* Pattern matching before any compilation *) 370 371type pattern_matching = 372 { mutable cases : (pattern list * lambda) list; 373 args : (lambda * let_kind) list ; 374 default : (matrix * int) list} 375 376(* Pattern matching after application of both the or-pat rule and the 377 mixture rule *) 378 379type pm_or_compiled = 380 {body : pattern_matching ; 381 handlers : (matrix * int * Ident.t list * pattern_matching) list ; 382 or_matrix : matrix ; } 383 384type pm_half_compiled = 385 | PmOr of pm_or_compiled 386 | PmVar of pm_var_compiled 387 | Pm of pattern_matching 388 389and pm_var_compiled = 390 {inside : pm_half_compiled ; var_arg : lambda ; } 391 392type pm_half_compiled_info = 393 {me : pm_half_compiled ; 394 matrix : matrix ; 395 top_default : (matrix * int) list ; } 396 397let pretty_cases cases = 398 List.iter 399 (fun (ps,_l) -> 400 List.iter 401 (fun p -> 402 Parmatch.top_pretty Format.str_formatter p ; 403 prerr_string " " ; 404 prerr_string (Format.flush_str_formatter ())) 405 ps ; 406(* 407 prerr_string " -> " ; 408 Printlambda.lambda Format.str_formatter l ; 409 prerr_string (Format.flush_str_formatter ()) ; 410*) 411 prerr_endline "") 412 cases 413 414let pretty_def def = 415 prerr_endline "+++++ Defaults +++++" ; 416 List.iter 417 (fun (pss,i) -> 418 Printf.fprintf stderr "Matrix for %d\n" i ; 419 pretty_matrix pss) 420 def ; 421 prerr_endline "+++++++++++++++++++++" 422 423let pretty_pm pm = pretty_cases pm.cases 424 425 426let rec pretty_precompiled = function 427 | Pm pm -> 428 prerr_endline "++++ PM ++++" ; 429 pretty_pm pm 430 | PmVar x -> 431 prerr_endline "++++ VAR ++++" ; 432 pretty_precompiled x.inside 433 | PmOr x -> 434 prerr_endline "++++ OR ++++" ; 435 pretty_pm x.body ; 436 pretty_matrix x.or_matrix ; 437 List.iter 438 (fun (_,i,_,pm) -> 439 eprintf "++ Handler %d ++\n" i ; 440 pretty_pm pm) 441 x.handlers 442 443let pretty_precompiled_res first nexts = 444 pretty_precompiled first ; 445 List.iter 446 (fun (e, pmh) -> 447 eprintf "** DEFAULT %d **\n" e ; 448 pretty_precompiled pmh) 449 nexts 450 451 452 453(* Identifing some semantically equivalent lambda-expressions, 454 Our goal here is also to 455 find alpha-equivalent (simple) terms *) 456 457(* However, as shown by PR#6359 such sharing may hinders the 458 lambda-code invariant that all bound idents are unique, 459 when switches are compiled to test sequences. 460 The definitive fix is the systematic introduction of exit/catch 461 in case action sharing is present. 462*) 463 464 465module StoreExp = 466 Switch.Store 467 (struct 468 type t = lambda 469 type key = lambda 470 let make_key = Lambda.make_key 471 end) 472 473 474let make_exit i = Lstaticraise (i,[]) 475 476(* Introduce a catch, if worth it *) 477let make_catch d k = match d with 478| Lstaticraise (_,[]) -> k d 479| _ -> 480 let e = next_raise_count () in 481 Lstaticcatch (k (make_exit e),(e,[]),d) 482 483(* Introduce a catch, if worth it, delayed version *) 484let rec as_simple_exit = function 485 | Lstaticraise (i,[]) -> Some i 486 | Llet (Alias,_k,_,_,e) -> as_simple_exit e 487 | _ -> None 488 489 490let make_catch_delayed handler = match as_simple_exit handler with 491| Some i -> i,(fun act -> act) 492| None -> 493 let i = next_raise_count () in 494(* 495 Printf.eprintf "SHARE LAMBDA: %i\n%s\n" i (string_of_lam handler); 496*) 497 i, 498 (fun body -> match body with 499 | Lstaticraise (j,_) -> 500 if i=j then handler else body 501 | _ -> Lstaticcatch (body,(i,[]),handler)) 502 503 504let raw_action l = 505 match make_key l with | Some l -> l | None -> l 506 507 508let tr_raw act = match make_key act with 509| Some act -> act 510| None -> raise Exit 511 512let same_actions = function 513 | [] -> None 514 | [_,act] -> Some act 515 | (_,act0) :: rem -> 516 try 517 let raw_act0 = tr_raw act0 in 518 let rec s_rec = function 519 | [] -> Some act0 520 | (_,act)::rem -> 521 if raw_act0 = tr_raw act then 522 s_rec rem 523 else 524 None in 525 s_rec rem 526 with 527 | Exit -> None 528 529 530(* Test for swapping two clauses *) 531 532let up_ok_action act1 act2 = 533 try 534 let raw1 = tr_raw act1 535 and raw2 = tr_raw act2 in 536 raw1 = raw2 537 with 538 | Exit -> false 539 540(* Nothing is known about exception/extension patterns, 541 because of potential rebind *) 542let rec exc_inside p = match p.pat_desc with 543 | Tpat_construct (_,{cstr_tag=Cstr_extension _},_) -> true 544 | Tpat_any|Tpat_constant _|Tpat_var _ 545 | Tpat_construct (_,_,[]) 546 | Tpat_variant (_,None,_) 547 -> false 548 | Tpat_construct (_,_,ps) 549 | Tpat_tuple ps 550 | Tpat_array ps 551 -> exc_insides ps 552 | Tpat_variant (_, Some q,_) 553 | Tpat_alias (q,_,_) 554 | Tpat_lazy q 555 -> exc_inside q 556 | Tpat_record (lps,_) -> 557 List.exists (fun (_,_,p) -> exc_inside p) lps 558 | Tpat_or (p1,p2,_) -> exc_inside p1 || exc_inside p2 559 560and exc_insides ps = List.exists exc_inside ps 561 562let up_ok (ps,act_p) l = 563 if exc_insides ps then match l with [] -> true | _::_ -> false 564 else 565 List.for_all 566 (fun (qs,act_q) -> 567 up_ok_action act_p act_q || 568 not (Parmatch.compats ps qs)) 569 l 570 571 572(* 573 Simplify fonction normalize the first column of the match 574 - records are expanded so that they possess all fields 575 - aliases are removed and replaced by bindings in actions. 576 However or-patterns are simplified differently, 577 - aliases are not removed 578 - or-patterns (_|p) are changed into _ 579*) 580 581exception Var of pattern 582 583let simplify_or p = 584 let rec simpl_rec p = match p with 585 | {pat_desc = Tpat_any|Tpat_var _} -> raise (Var p) 586 | {pat_desc = Tpat_alias (q,id,s)} -> 587 begin try 588 {p with pat_desc = Tpat_alias (simpl_rec q,id,s)} 589 with 590 | Var q -> raise (Var {p with pat_desc = Tpat_alias (q,id,s)}) 591 end 592 | {pat_desc = Tpat_or (p1,p2,o)} -> 593 let q1 = simpl_rec p1 in 594 begin try 595 let q2 = simpl_rec p2 in 596 {p with pat_desc = Tpat_or (q1, q2, o)} 597 with 598 | Var q2 -> raise (Var {p with pat_desc = Tpat_or (q1, q2, o)}) 599 end 600 | {pat_desc = Tpat_record (lbls,closed)} -> 601 let all_lbls = all_record_args lbls in 602 {p with pat_desc=Tpat_record (all_lbls, closed)} 603 | _ -> p in 604 try 605 simpl_rec p 606 with 607 | Var p -> p 608 609let simplify_cases args cls = match args with 610| [] -> assert false 611| (arg,_)::_ -> 612 let rec simplify = function 613 | [] -> [] 614 | ((pat :: patl, action) as cl) :: rem -> 615 begin match pat.pat_desc with 616 | Tpat_var (id, _) -> 617 (omega :: patl, bind Alias id arg action) :: 618 simplify rem 619 | Tpat_any -> 620 cl :: simplify rem 621 | Tpat_alias(p, id,_) -> 622 simplify ((p :: patl, bind Alias id arg action) :: rem) 623 | Tpat_record ([],_) -> 624 (omega :: patl, action):: 625 simplify rem 626 | Tpat_record (lbls, closed) -> 627 let all_lbls = all_record_args lbls in 628 let full_pat = 629 {pat with pat_desc=Tpat_record (all_lbls, closed)} in 630 (full_pat::patl,action):: 631 simplify rem 632 | Tpat_or _ -> 633 let pat_simple = simplify_or pat in 634 begin match pat_simple.pat_desc with 635 | Tpat_or _ -> 636 (pat_simple :: patl, action) :: 637 simplify rem 638 | _ -> 639 simplify ((pat_simple::patl,action) :: rem) 640 end 641 | _ -> cl :: simplify rem 642 end 643 | _ -> assert false in 644 645 simplify cls 646 647 648 649(* Once matchings are simplified one can easily find 650 their nature *) 651 652let rec what_is_cases cases = match cases with 653| ({pat_desc=Tpat_any} :: _, _) :: rem -> what_is_cases rem 654| (({pat_desc=(Tpat_var _|Tpat_or (_,_,_)|Tpat_alias (_,_,_))}::_),_)::_ 655 -> assert false (* applies to simplified matchings only *) 656| (p::_,_)::_ -> p 657| [] -> omega 658| _ -> assert false 659 660 661 662(* A few operations on default environments *) 663let as_matrix cases = get_mins le_pats (List.map (fun (ps,_) -> ps) cases) 664 665(* For extension matching, record no information in matrix *) 666let as_matrix_omega cases = 667 get_mins le_pats 668 (List.map 669 (fun (ps,_) -> 670 match ps with 671 | [] -> assert false 672 | _::ps -> omega::ps) 673 cases) 674 675let cons_default matrix raise_num default = 676 match matrix with 677 | [] -> default 678 | _ -> (matrix,raise_num)::default 679 680let default_compat p def = 681 List.fold_right 682 (fun (pss,i) r -> 683 let qss = 684 List.fold_right 685 (fun qs r -> match qs with 686 | q::rem when Parmatch.compat p q -> rem::r 687 | _ -> r) 688 pss [] in 689 match qss with 690 | [] -> r 691 | _ -> (qss,i)::r) 692 def [] 693 694(* Or-pattern expansion, variables are a complication w.r.t. the article *) 695let rec extract_vars r p = match p.pat_desc with 696| Tpat_var (id, _) -> IdentSet.add id r 697| Tpat_alias (p, id,_ ) -> 698 extract_vars (IdentSet.add id r) p 699| Tpat_tuple pats -> 700 List.fold_left extract_vars r pats 701| Tpat_record (lpats,_) -> 702 List.fold_left 703 (fun r (_, _, p) -> extract_vars r p) 704 r lpats 705| Tpat_construct (_, _, pats) -> 706 List.fold_left extract_vars r pats 707| Tpat_array pats -> 708 List.fold_left extract_vars r pats 709| Tpat_variant (_,Some p, _) -> extract_vars r p 710| Tpat_lazy p -> extract_vars r p 711| Tpat_or (p,_,_) -> extract_vars r p 712| Tpat_constant _|Tpat_any|Tpat_variant (_,None,_) -> r 713 714exception Cannot_flatten 715 716let mk_alpha_env arg aliases ids = 717 List.map 718 (fun id -> id, 719 if List.mem id aliases then 720 match arg with 721 | Some v -> v 722 | _ -> raise Cannot_flatten 723 else 724 Ident.create (Ident.name id)) 725 ids 726 727let rec explode_or_pat arg patl mk_action rem vars aliases = function 728 | {pat_desc = Tpat_or (p1,p2,_)} -> 729 explode_or_pat 730 arg patl mk_action 731 (explode_or_pat arg patl mk_action rem vars aliases p2) 732 vars aliases p1 733 | {pat_desc = Tpat_alias (p,id, _)} -> 734 explode_or_pat arg patl mk_action rem vars (id::aliases) p 735 | {pat_desc = Tpat_var (x, _)} -> 736 let env = mk_alpha_env arg (x::aliases) vars in 737 (omega::patl,mk_action (List.map snd env))::rem 738 | p -> 739 let env = mk_alpha_env arg aliases vars in 740 (alpha_pat env p::patl,mk_action (List.map snd env))::rem 741 742let pm_free_variables {cases=cases} = 743 List.fold_right 744 (fun (_,act) r -> IdentSet.union (free_variables act) r) 745 cases IdentSet.empty 746 747 748(* Basic grouping predicates *) 749let pat_as_constr = function 750 | {pat_desc=Tpat_construct (_, cstr,_)} -> cstr 751 | _ -> fatal_error "Matching.pat_as_constr" 752 753let group_constant = function 754 | {pat_desc= Tpat_constant _} -> true 755 | _ -> false 756 757and group_constructor = function 758 | {pat_desc = Tpat_construct (_,_,_)} -> true 759 | _ -> false 760 761and group_variant = function 762 | {pat_desc = Tpat_variant (_, _, _)} -> true 763 | _ -> false 764 765and group_var = function 766 | {pat_desc=Tpat_any} -> true 767 | _ -> false 768 769and group_tuple = function 770 | {pat_desc = (Tpat_tuple _|Tpat_any)} -> true 771 | _ -> false 772 773and group_record = function 774 | {pat_desc = (Tpat_record _|Tpat_any)} -> true 775 | _ -> false 776 777and group_array = function 778 | {pat_desc=Tpat_array _} -> true 779 | _ -> false 780 781and group_lazy = function 782 | {pat_desc = Tpat_lazy _} -> true 783 | _ -> false 784 785let get_group p = match p.pat_desc with 786| Tpat_any -> group_var 787| Tpat_constant _ -> group_constant 788| Tpat_construct _ -> group_constructor 789| Tpat_tuple _ -> group_tuple 790| Tpat_record _ -> group_record 791| Tpat_array _ -> group_array 792| Tpat_variant (_,_,_) -> group_variant 793| Tpat_lazy _ -> group_lazy 794| _ -> fatal_error "Matching.get_group" 795 796 797 798let is_or p = match p.pat_desc with 799| Tpat_or _ -> true 800| _ -> false 801 802(* Conditions for appending to the Or matrix *) 803let conda p q = not (compat p q) 804and condb act ps qs = not (is_guarded act) && Parmatch.le_pats qs ps 805 806let or_ok p ps l = 807 List.for_all 808 (function 809 | ({pat_desc=Tpat_or _} as q::qs,act) -> 810 conda p q || condb act ps qs 811 | _ -> true) 812 l 813 814(* Insert or append a pattern in the Or matrix *) 815 816let equiv_pat p q = le_pat p q && le_pat q p 817 818let rec get_equiv p l = match l with 819 | (q::_,_) as cl::rem -> 820 if equiv_pat p q then 821 let others,rem = get_equiv p rem in 822 cl::others,rem 823 else 824 [],l 825 | _ -> [],l 826 827 828let insert_or_append p ps act ors no = 829 let rec attempt seen = function 830 | (q::qs,act_q) as cl::rem -> 831 if is_or q then begin 832 if compat p q then 833 if 834 IdentSet.is_empty (extract_vars IdentSet.empty p) && 835 IdentSet.is_empty (extract_vars IdentSet.empty q) && 836 equiv_pat p q 837 then (* attempt insert, for equivalent orpats with no variables *) 838 let _, not_e = get_equiv q rem in 839 if 840 or_ok p ps not_e && (* check append condition for head of O *) 841 List.for_all (* check insert condition for tail of O *) 842 (fun cl -> match cl with 843 | (q::_,_) -> not (compat p q) 844 | _ -> assert false) 845 seen 846 then (* insert *) 847 List.rev_append seen ((p::ps,act)::cl::rem), no 848 else (* fail to insert or append *) 849 ors,(p::ps,act)::no 850 else if condb act_q ps qs then (* check condition (b) for append *) 851 attempt (cl::seen) rem 852 else 853 ors,(p::ps,act)::no 854 else (* p # q, go on with append/insert *) 855 attempt (cl::seen) rem 856 end else (* q is not an or-pat, go on with append/insert *) 857 attempt (cl::seen) rem 858 | _ -> (* [] in fact *) 859 (p::ps,act)::ors,no in (* success in appending *) 860 attempt [] ors 861 862(* Reconstruct default information from half_compiled pm list *) 863 864let rec rebuild_matrix pmh = match pmh with 865 | Pm pm -> as_matrix pm.cases 866 | PmOr {or_matrix=m} -> m 867 | PmVar x -> add_omega_column (rebuild_matrix x.inside) 868 869let rec rebuild_default nexts def = match nexts with 870| [] -> def 871| (e, pmh)::rem -> 872 (add_omega_column (rebuild_matrix pmh), e):: 873 rebuild_default rem def 874 875let rebuild_nexts arg nexts k = 876 List.fold_right 877 (fun (e, pm) k -> (e, PmVar {inside=pm ; var_arg=arg})::k) 878 nexts k 879 880 881(* 882 Split a matching. 883 Splitting is first directed by or-patterns, then by 884 tests (e.g. constructors)/variable transitions. 885 886 The approach is greedy, every split function attempts to 887 raise rows as much as possible in the top matrix, 888 then splitting applies again to the remaining rows. 889 890 Some precompilation of or-patterns and 891 variable pattern occurs. Mostly this means that bindings 892 are performed now, being replaced by let-bindings 893 in actions (cf. simplify_cases). 894 895 Additionally, if the match argument is a variable, matchings whose 896 first column is made of variables only are splitted further 897 (cf. precompile_var). 898 899*) 900 901 902let rec split_or argo cls args def = 903 904 let cls = simplify_cases args cls in 905 906 let rec do_split before ors no = function 907 | [] -> 908 cons_next 909 (List.rev before) (List.rev ors) (List.rev no) 910 | ((p::ps,act) as cl)::rem -> 911 if up_ok cl no then 912 if is_or p then 913 let ors, no = insert_or_append p ps act ors no in 914 do_split before ors no rem 915 else begin 916 if up_ok cl ors then 917 do_split (cl::before) ors no rem 918 else if or_ok p ps ors then 919 do_split before (cl::ors) no rem 920 else 921 do_split before ors (cl::no) rem 922 end 923 else 924 do_split before ors (cl::no) rem 925 | _ -> assert false 926 927 and cons_next yes yesor = function 928 | [] -> 929 precompile_or argo yes yesor args def [] 930 | rem -> 931 let {me=next ; matrix=matrix ; top_default=def},nexts = 932 do_split [] [] [] rem in 933 let idef = next_raise_count () in 934 precompile_or 935 argo yes yesor args 936 (cons_default matrix idef def) 937 ((idef,next)::nexts) in 938 939 do_split [] [] [] cls 940 941(* Ultra-naive splitting, close to semantics, used for extension, 942 as potential rebind prevents any kind of optimisation *) 943 944and split_naive cls args def k = 945 946 let rec split_exc cstr0 yes = function 947 | [] -> 948 let yes = List.rev yes in 949 { me = Pm {cases=yes; args=args; default=def;} ; 950 matrix = as_matrix_omega yes ; 951 top_default=def}, 952 k 953 | (p::_,_ as cl)::rem -> 954 if group_constructor p then 955 let cstr = pat_as_constr p in 956 if cstr = cstr0 then split_exc cstr0 (cl::yes) rem 957 else 958 let yes = List.rev yes in 959 let {me=next ; matrix=matrix ; top_default=def}, nexts = 960 split_exc cstr [cl] rem in 961 let idef = next_raise_count () in 962 let def = cons_default matrix idef def in 963 { me = Pm {cases=yes; args=args; default=def} ; 964 matrix = as_matrix_omega yes ; 965 top_default = def; }, 966 (idef,next)::nexts 967 else 968 let yes = List.rev yes in 969 let {me=next ; matrix=matrix ; top_default=def}, nexts = 970 split_noexc [cl] rem in 971 let idef = next_raise_count () in 972 let def = cons_default matrix idef def in 973 { me = Pm {cases=yes; args=args; default=def} ; 974 matrix = as_matrix_omega yes ; 975 top_default = def; }, 976 (idef,next)::nexts 977 | _ -> assert false 978 979 and split_noexc yes = function 980 | [] -> precompile_var args (List.rev yes) def k 981 | (p::_,_ as cl)::rem -> 982 if group_constructor p then 983 let yes= List.rev yes in 984 let {me=next; matrix=matrix; top_default=def;},nexts = 985 split_exc (pat_as_constr p) [cl] rem in 986 let idef = next_raise_count () in 987 precompile_var 988 args yes 989 (cons_default matrix idef def) 990 ((idef,next)::nexts) 991 else split_noexc (cl::yes) rem 992 | _ -> assert false in 993 994 match cls with 995 | [] -> assert false 996 | (p::_,_ as cl)::rem -> 997 if group_constructor p then 998 split_exc (pat_as_constr p) [cl] rem 999 else 1000 split_noexc [cl] rem 1001 | _ -> assert false 1002 1003and split_constr cls args def k = 1004 let ex_pat = what_is_cases cls in 1005 match ex_pat.pat_desc with 1006 | Tpat_any -> precompile_var args cls def k 1007 | Tpat_construct (_,{cstr_tag=Cstr_extension _},_) -> 1008 split_naive cls args def k 1009 | _ -> 1010 1011 let group = get_group ex_pat in 1012 1013 let rec split_ex yes no = function 1014 | [] -> 1015 let yes = List.rev yes and no = List.rev no in 1016 begin match no with 1017 | [] -> 1018 {me = Pm {cases=yes ; args=args ; default=def} ; 1019 matrix = as_matrix yes ; 1020 top_default = def}, 1021 k 1022 | cl::rem -> 1023 begin match yes with 1024 | [] -> 1025 (* Could not success in raising up a constr matching up *) 1026 split_noex [cl] [] rem 1027 | _ -> 1028 let {me=next ; matrix=matrix ; top_default=def}, nexts = 1029 split_noex [cl] [] rem in 1030 let idef = next_raise_count () in 1031 let def = cons_default matrix idef def in 1032 {me = Pm {cases=yes ; args=args ; default=def} ; 1033 matrix = as_matrix yes ; 1034 top_default = def }, 1035 (idef, next)::nexts 1036 end 1037 end 1038 | (p::_,_) as cl::rem -> 1039 if group p && up_ok cl no then 1040 split_ex (cl::yes) no rem 1041 else 1042 split_ex yes (cl::no) rem 1043 | _ -> assert false 1044 1045 and split_noex yes no = function 1046 | [] -> 1047 let yes = List.rev yes and no = List.rev no in 1048 begin match no with 1049 | [] -> precompile_var args yes def k 1050 | cl::rem -> 1051 let {me=next ; matrix=matrix ; top_default=def}, nexts = 1052 split_ex [cl] [] rem in 1053 let idef = next_raise_count () in 1054 precompile_var 1055 args yes 1056 (cons_default matrix idef def) 1057 ((idef,next)::nexts) 1058 end 1059 | [ps,_ as cl] 1060 when List.for_all group_var ps && yes <> [] -> 1061 (* This enables an extra division in some frequent cases : 1062 last row is made of variables only *) 1063 split_noex yes (cl::no) [] 1064 | (p::_,_) as cl::rem -> 1065 if not (group p) && up_ok cl no then 1066 split_noex (cl::yes) no rem 1067 else 1068 split_noex yes (cl::no) rem 1069 | _ -> assert false in 1070 1071 match cls with 1072 | ((p::_,_) as cl)::rem -> 1073 if group p then split_ex [cl] [] rem 1074 else split_noex [cl] [] rem 1075 | _ -> assert false 1076 1077and precompile_var args cls def k = match args with 1078| [] -> assert false 1079| _::((Lvar v as av,_) as arg)::rargs -> 1080 begin match cls with 1081 | [_] -> (* as splitted as it can *) 1082 dont_precompile_var args cls def k 1083 | _ -> 1084(* Precompile *) 1085 let var_cls = 1086 List.map 1087 (fun (ps,act) -> match ps with 1088 | _::ps -> ps,act | _ -> assert false) 1089 cls 1090 and var_def = make_default (fun _ rem -> rem) def in 1091 let {me=first ; matrix=matrix}, nexts = 1092 split_or (Some v) var_cls (arg::rargs) var_def in 1093 1094(* Compute top information *) 1095 match nexts with 1096 | [] -> (* If you need *) 1097 dont_precompile_var args cls def k 1098 | _ -> 1099 let rfirst = 1100 {me = PmVar {inside=first ; var_arg = av} ; 1101 matrix = add_omega_column matrix ; 1102 top_default = rebuild_default nexts def ; } 1103 and rnexts = rebuild_nexts av nexts k in 1104 rfirst, rnexts 1105 end 1106| _ -> 1107 dont_precompile_var args cls def k 1108 1109and dont_precompile_var args cls def k = 1110 {me = Pm {cases = cls ; args = args ; default = def } ; 1111 matrix=as_matrix cls ; 1112 top_default=def},k 1113 1114and is_exc p = match p.pat_desc with 1115| Tpat_or (p1,p2,_) -> is_exc p1 || is_exc p2 1116| Tpat_alias (p,_,_) -> is_exc p 1117| Tpat_construct (_,{cstr_tag=Cstr_extension _},_) -> true 1118| _ -> false 1119 1120and precompile_or argo cls ors args def k = match ors with 1121| [] -> split_constr cls args def k 1122| _ -> 1123 let rec do_cases = function 1124 | ({pat_desc=Tpat_or _} as orp::patl, action)::rem -> 1125 let do_opt = not (is_exc orp) in 1126 let others,rem = 1127 if do_opt then get_equiv orp rem 1128 else [],rem in 1129 let orpm = 1130 {cases = 1131 (patl, action):: 1132 List.map 1133 (function 1134 | (_::ps,action) -> ps,action 1135 | _ -> assert false) 1136 others ; 1137 args = (match args with _::r -> r | _ -> assert false) ; 1138 default = default_compat (if do_opt then orp else omega) def} in 1139 let vars = 1140 IdentSet.elements 1141 (IdentSet.inter 1142 (extract_vars IdentSet.empty orp) 1143 (pm_free_variables orpm)) in 1144 let or_num = next_raise_count () in 1145 let new_patl = Parmatch.omega_list patl in 1146 1147 let mk_new_action vs = 1148 Lstaticraise 1149 (or_num, List.map (fun v -> Lvar v) vs) in 1150 1151 let do_optrec,body,handlers = do_cases rem in 1152 do_opt && do_optrec, 1153 explode_or_pat 1154 argo new_patl mk_new_action body vars [] orp, 1155 let mat = if do_opt then [[orp]] else [[omega]] in 1156 ((mat, or_num, vars , orpm):: handlers) 1157 | cl::rem -> 1158 let b,new_ord,new_to_catch = do_cases rem in 1159 b,cl::new_ord,new_to_catch 1160 | [] -> true,[],[] in 1161 1162 let do_opt,end_body, handlers = do_cases ors in 1163 let matrix = (if do_opt then as_matrix else as_matrix_omega) (cls@ors) 1164 and body = {cases=cls@end_body ; args=args ; default=def} in 1165 {me = PmOr {body=body ; handlers=handlers ; or_matrix=matrix} ; 1166 matrix=matrix ; 1167 top_default=def}, 1168 k 1169 1170let split_precompile argo pm = 1171 let {me=next}, nexts = split_or argo pm.cases pm.args pm.default in 1172 if dbg && (nexts <> [] || (match next with PmOr _ -> true | _ -> false)) 1173 then begin 1174 prerr_endline "** SPLIT **" ; 1175 pretty_pm pm ; 1176 pretty_precompiled_res next nexts 1177 end ; 1178 next, nexts 1179 1180 1181(* General divide functions *) 1182 1183let add_line patl_action pm = pm.cases <- patl_action :: pm.cases; pm 1184 1185type cell = 1186 {pm : pattern_matching ; 1187 ctx : ctx list ; 1188 pat : pattern} 1189 1190let add make_matching_fun division eq_key key patl_action args = 1191 try 1192 let (_,cell) = List.find (fun (k,_) -> eq_key key k) division in 1193 cell.pm.cases <- patl_action :: cell.pm.cases; 1194 division 1195 with Not_found -> 1196 let cell = make_matching_fun args in 1197 cell.pm.cases <- [patl_action] ; 1198 (key, cell) :: division 1199 1200 1201let divide make eq_key get_key get_args ctx pm = 1202 1203 let rec divide_rec = function 1204 | (p::patl,action) :: rem -> 1205 let this_match = divide_rec rem in 1206 add 1207 (make p pm.default ctx) 1208 this_match eq_key (get_key p) (get_args p patl,action) pm.args 1209 | _ -> [] in 1210 1211 divide_rec pm.cases 1212 1213 1214let divide_line make_ctx make get_args pat ctx pm = 1215 let rec divide_rec = function 1216 | (p::patl,action) :: rem -> 1217 let this_match = divide_rec rem in 1218 add_line (get_args p patl, action) this_match 1219 | _ -> make pm.default pm.args in 1220 1221 {pm = divide_rec pm.cases ; 1222 ctx=make_ctx ctx ; 1223 pat=pat} 1224 1225 1226 1227(* Then come various functions, 1228 There is one set of functions per matching style 1229 (constants, constructors etc.) 1230 1231 - matcher functions are arguments to make_default (for default handlers) 1232 They may raise NoMatch or OrPat and perform the full 1233 matching (selection + arguments). 1234 1235 1236 - get_args and get_key are for the compiled matrices, note that 1237 selection and getting arguments are separated. 1238 1239 - make_ _matching combines the previous functions for producing 1240 new ``pattern_matching'' records. 1241*) 1242 1243 1244 1245let rec matcher_const cst p rem = match p.pat_desc with 1246| Tpat_or (p1,p2,_) -> 1247 begin try 1248 matcher_const cst p1 rem with 1249 | NoMatch -> matcher_const cst p2 rem 1250 end 1251| Tpat_constant c1 when const_compare c1 cst = 0 -> rem 1252| Tpat_any -> rem 1253| _ -> raise NoMatch 1254 1255let get_key_constant caller = function 1256 | {pat_desc= Tpat_constant cst} -> cst 1257 | p -> 1258 prerr_endline ("BAD: "^caller) ; 1259 pretty_pat p ; 1260 assert false 1261 1262let get_args_constant _ rem = rem 1263 1264let make_constant_matching p def ctx = function 1265 [] -> fatal_error "Matching.make_constant_matching" 1266 | (_ :: argl) -> 1267 let def = 1268 make_default 1269 (matcher_const (get_key_constant "make" p)) def 1270 and ctx = 1271 filter_ctx p ctx in 1272 {pm = {cases = []; args = argl ; default = def} ; 1273 ctx = ctx ; 1274 pat = normalize_pat p} 1275 1276 1277 1278 1279let divide_constant ctx m = 1280 divide 1281 make_constant_matching 1282 (fun c d -> const_compare c d = 0) (get_key_constant "divide") 1283 get_args_constant 1284 ctx m 1285 1286(* Matching against a constructor *) 1287 1288 1289let make_field_args loc binding_kind arg first_pos last_pos argl = 1290 let rec make_args pos = 1291 if pos > last_pos 1292 then argl 1293 else (Lprim(Pfield pos, [arg], loc), binding_kind) :: make_args (pos + 1) 1294 in make_args first_pos 1295 1296let get_key_constr = function 1297 | {pat_desc=Tpat_construct (_, cstr,_)} -> cstr.cstr_tag 1298 | _ -> assert false 1299 1300let get_args_constr p rem = match p with 1301| {pat_desc=Tpat_construct (_, _, args)} -> args @ rem 1302| _ -> assert false 1303 1304let matcher_constr cstr = match cstr.cstr_arity with 1305| 0 -> 1306 let rec matcher_rec q rem = match q.pat_desc with 1307 | Tpat_or (p1,p2,_) -> 1308 begin 1309 try 1310 matcher_rec p1 rem 1311 with 1312 | NoMatch -> matcher_rec p2 rem 1313 end 1314 | Tpat_construct (_, cstr1, []) when cstr.cstr_tag = cstr1.cstr_tag -> 1315 rem 1316 | Tpat_any -> rem 1317 | _ -> raise NoMatch in 1318 matcher_rec 1319| 1 -> 1320 let rec matcher_rec q rem = match q.pat_desc with 1321 | Tpat_or (p1,p2,_) -> 1322 let r1 = try Some (matcher_rec p1 rem) with NoMatch -> None 1323 and r2 = try Some (matcher_rec p2 rem) with NoMatch -> None in 1324 begin match r1,r2 with 1325 | None, None -> raise NoMatch 1326 | Some r1, None -> r1 1327 | None, Some r2 -> r2 1328 | Some (a1::_), Some (a2::_) -> 1329 {a1 with 1330 pat_loc = Location.none ; 1331 pat_desc = Tpat_or (a1, a2, None)}:: 1332 rem 1333 | _, _ -> assert false 1334 end 1335 | Tpat_construct (_, cstr1, [arg]) 1336 when cstr.cstr_tag = cstr1.cstr_tag -> arg::rem 1337 | Tpat_any -> omega::rem 1338 | _ -> raise NoMatch in 1339 matcher_rec 1340| _ -> 1341 fun q rem -> match q.pat_desc with 1342 | Tpat_or (_,_,_) -> raise OrPat 1343 | Tpat_construct (_, cstr1, args) 1344 when cstr.cstr_tag = cstr1.cstr_tag -> args @ rem 1345 | Tpat_any -> Parmatch.omegas cstr.cstr_arity @ rem 1346 | _ -> raise NoMatch 1347 1348let make_constr_matching p def ctx = function 1349 [] -> fatal_error "Matching.make_constr_matching" 1350 | ((arg, _mut) :: argl) -> 1351 let cstr = pat_as_constr p in 1352 let newargs = 1353 if cstr.cstr_inlined <> None then 1354 (arg, Alias) :: argl 1355 else match cstr.cstr_tag with 1356 Cstr_constant _ | Cstr_block _ -> 1357 make_field_args p.pat_loc Alias arg 0 (cstr.cstr_arity - 1) argl 1358 | Cstr_unboxed -> (arg, Alias) :: argl 1359 | Cstr_extension _ -> 1360 make_field_args p.pat_loc Alias arg 1 cstr.cstr_arity argl in 1361 {pm= 1362 {cases = []; args = newargs; 1363 default = make_default (matcher_constr cstr) def} ; 1364 ctx = filter_ctx p ctx ; 1365 pat=normalize_pat p} 1366 1367 1368let divide_constructor ctx pm = 1369 divide 1370 make_constr_matching 1371 (=) get_key_constr get_args_constr 1372 ctx pm 1373 1374(* Matching against a variant *) 1375 1376let rec matcher_variant_const lab p rem = match p.pat_desc with 1377| Tpat_or (p1, p2, _) -> 1378 begin 1379 try 1380 matcher_variant_const lab p1 rem 1381 with 1382 | NoMatch -> matcher_variant_const lab p2 rem 1383 end 1384| Tpat_variant (lab1,_,_) when lab1=lab -> rem 1385| Tpat_any -> rem 1386| _ -> raise NoMatch 1387 1388 1389let make_variant_matching_constant p lab def ctx = function 1390 [] -> fatal_error "Matching.make_variant_matching_constant" 1391 | (_ :: argl) -> 1392 let def = make_default (matcher_variant_const lab) def 1393 and ctx = filter_ctx p ctx in 1394 {pm={ cases = []; args = argl ; default=def} ; 1395 ctx=ctx ; 1396 pat = normalize_pat p} 1397 1398let matcher_variant_nonconst lab p rem = match p.pat_desc with 1399| Tpat_or (_,_,_) -> raise OrPat 1400| Tpat_variant (lab1,Some arg,_) when lab1=lab -> arg::rem 1401| Tpat_any -> omega::rem 1402| _ -> raise NoMatch 1403 1404 1405let make_variant_matching_nonconst p lab def ctx = function 1406 [] -> fatal_error "Matching.make_variant_matching_nonconst" 1407 | ((arg, _mut) :: argl) -> 1408 let def = make_default (matcher_variant_nonconst lab) def 1409 and ctx = filter_ctx p ctx in 1410 {pm= 1411 {cases = []; args = (Lprim(Pfield 1, [arg], p.pat_loc), Alias) :: argl; 1412 default=def} ; 1413 ctx=ctx ; 1414 pat = normalize_pat p} 1415 1416let divide_variant row ctx {cases = cl; args = al; default=def} = 1417 let row = Btype.row_repr row in 1418 let rec divide = function 1419 ({pat_desc = Tpat_variant(lab, pato, _)} as p:: patl, action) :: rem -> 1420 let variants = divide rem in 1421 if try Btype.row_field_repr (List.assoc lab row.row_fields) = Rabsent 1422 with Not_found -> true 1423 then 1424 variants 1425 else begin 1426 let tag = Btype.hash_variant lab in 1427 match pato with 1428 None -> 1429 add (make_variant_matching_constant p lab def ctx) variants 1430 (=) (Cstr_constant tag) (patl, action) al 1431 | Some pat -> 1432 add (make_variant_matching_nonconst p lab def ctx) variants 1433 (=) (Cstr_block tag) (pat :: patl, action) al 1434 end 1435 | _ -> [] 1436 in 1437 divide cl 1438 1439(* 1440 Three ``no-test'' cases 1441 *) 1442 1443(* Matching against a variable *) 1444 1445let get_args_var _ rem = rem 1446 1447 1448let make_var_matching def = function 1449 | [] -> fatal_error "Matching.make_var_matching" 1450 | _::argl -> 1451 {cases=[] ; 1452 args = argl ; 1453 default= make_default get_args_var def} 1454 1455let divide_var ctx pm = 1456 divide_line ctx_lshift make_var_matching get_args_var omega ctx pm 1457 1458(* Matching and forcing a lazy value *) 1459 1460let get_arg_lazy p rem = match p with 1461| {pat_desc = Tpat_any} -> omega :: rem 1462| {pat_desc = Tpat_lazy arg} -> arg :: rem 1463| _ -> assert false 1464 1465let matcher_lazy p rem = match p.pat_desc with 1466| Tpat_or (_,_,_) -> raise OrPat 1467| Tpat_var _ -> get_arg_lazy omega rem 1468| _ -> get_arg_lazy p rem 1469 1470(* Inlining the tag tests before calling the primitive that works on 1471 lazy blocks. This is also used in translcore.ml. 1472 No other call than Obj.tag when the value has been forced before. 1473*) 1474 1475let prim_obj_tag = 1476 Primitive.simple ~name:"caml_obj_tag" ~arity:1 ~alloc:false 1477 1478let get_mod_field modname field = 1479 lazy ( 1480 try 1481 let mod_ident = Ident.create_persistent modname in 1482 let env = Env.open_pers_signature modname Env.initial_safe_string in 1483 let p = try 1484 match Env.lookup_value (Longident.Lident field) env with 1485 | (Path.Pdot(_,_,i), _) -> i 1486 | _ -> fatal_error ("Primitive "^modname^"."^field^" not found.") 1487 with Not_found -> 1488 fatal_error ("Primitive "^modname^"."^field^" not found.") 1489 in 1490 Lprim(Pfield p, 1491 [Lprim(Pgetglobal mod_ident, [], Location.none)], 1492 Location.none) 1493 with Not_found -> fatal_error ("Module "^modname^" unavailable.") 1494 ) 1495 1496let code_force_lazy_block = 1497 get_mod_field "CamlinternalLazy" "force_lazy_block" 1498;; 1499 1500(* inline_lazy_force inlines the beginning of the code of Lazy.force. When 1501 the value argument is tagged as: 1502 - forward, take field 0 1503 - lazy, call the primitive that forces (without testing again the tag) 1504 - anything else, return it 1505 1506 Using Lswitch below relies on the fact that the GC does not shortcut 1507 Forward(val_out_of_heap). 1508*) 1509 1510let inline_lazy_force_cond arg loc = 1511 let idarg = Ident.create "lzarg" in 1512 let varg = Lvar idarg in 1513 let tag = Ident.create "tag" in 1514 let force_fun = Lazy.force code_force_lazy_block in 1515 Llet(Strict, Pgenval, idarg, arg, 1516 Llet(Alias, Pgenval, tag, Lprim(Pccall prim_obj_tag, [varg], loc), 1517 Lifthenelse( 1518 (* if (tag == Obj.forward_tag) then varg.(0) else ... *) 1519 Lprim(Pintcomp Ceq, 1520 [Lvar tag; Lconst(Const_base(Const_int Obj.forward_tag))], 1521 loc), 1522 Lprim(Pfield 0, [varg], loc), 1523 Lifthenelse( 1524 (* ... if (tag == Obj.lazy_tag) then Lazy.force varg else ... *) 1525 Lprim(Pintcomp Ceq, 1526 [Lvar tag; Lconst(Const_base(Const_int Obj.lazy_tag))], 1527 loc), 1528 Lapply{ap_should_be_tailcall=false; 1529 ap_loc=loc; 1530 ap_func=force_fun; 1531 ap_args=[varg]; 1532 ap_inlined=Default_inline; 1533 ap_specialised=Default_specialise}, 1534 (* ... arg *) 1535 varg)))) 1536 1537let inline_lazy_force_switch arg loc = 1538 let idarg = Ident.create "lzarg" in 1539 let varg = Lvar idarg in 1540 let force_fun = Lazy.force code_force_lazy_block in 1541 Llet(Strict, Pgenval, idarg, arg, 1542 Lifthenelse( 1543 Lprim(Pisint, [varg], loc), varg, 1544 (Lswitch 1545 (varg, 1546 { sw_numconsts = 0; sw_consts = []; 1547 sw_numblocks = 256; (* PR#6033 - tag ranges from 0 to 255 *) 1548 sw_blocks = 1549 [ (Obj.forward_tag, Lprim(Pfield 0, [varg], loc)); 1550 (Obj.lazy_tag, 1551 Lapply{ap_should_be_tailcall=false; 1552 ap_loc=loc; 1553 ap_func=force_fun; 1554 ap_args=[varg]; 1555 ap_inlined=Default_inline; 1556 ap_specialised=Default_specialise}) ]; 1557 sw_failaction = Some varg } )))) 1558 1559let inline_lazy_force arg loc = 1560 if !Clflags.native_code then 1561 (* Lswitch generates compact and efficient native code *) 1562 inline_lazy_force_switch arg loc 1563 else 1564 (* generating bytecode: Lswitch would generate too many rather big 1565 tables (~ 250 elts); conditionals are better *) 1566 inline_lazy_force_cond arg loc 1567 1568let make_lazy_matching def = function 1569 [] -> fatal_error "Matching.make_lazy_matching" 1570 | (arg,_mut) :: argl -> 1571 { cases = []; 1572 args = 1573 (inline_lazy_force arg Location.none, Strict) :: argl; 1574 default = make_default matcher_lazy def } 1575 1576let divide_lazy p ctx pm = 1577 divide_line 1578 (filter_ctx p) 1579 make_lazy_matching 1580 get_arg_lazy 1581 p ctx pm 1582 1583(* Matching against a tuple pattern *) 1584 1585 1586let get_args_tuple arity p rem = match p with 1587| {pat_desc = Tpat_any} -> omegas arity @ rem 1588| {pat_desc = Tpat_tuple args} -> 1589 args @ rem 1590| _ -> assert false 1591 1592let matcher_tuple arity p rem = match p.pat_desc with 1593| Tpat_or (_,_,_) -> raise OrPat 1594| Tpat_var _ -> get_args_tuple arity omega rem 1595| _ -> get_args_tuple arity p rem 1596 1597let make_tuple_matching loc arity def = function 1598 [] -> fatal_error "Matching.make_tuple_matching" 1599 | (arg, _mut) :: argl -> 1600 let rec make_args pos = 1601 if pos >= arity 1602 then argl 1603 else (Lprim(Pfield pos, [arg], loc), Alias) :: make_args (pos + 1) in 1604 {cases = []; args = make_args 0 ; 1605 default=make_default (matcher_tuple arity) def} 1606 1607 1608let divide_tuple arity p ctx pm = 1609 divide_line 1610 (filter_ctx p) 1611 (make_tuple_matching p.pat_loc arity) 1612 (get_args_tuple arity) p ctx pm 1613 1614(* Matching against a record pattern *) 1615 1616 1617let record_matching_line num_fields lbl_pat_list = 1618 let patv = Array.make num_fields omega in 1619 List.iter (fun (_, lbl, pat) -> patv.(lbl.lbl_pos) <- pat) lbl_pat_list; 1620 Array.to_list patv 1621 1622let get_args_record num_fields p rem = match p with 1623| {pat_desc=Tpat_any} -> 1624 record_matching_line num_fields [] @ rem 1625| {pat_desc=Tpat_record (lbl_pat_list,_)} -> 1626 record_matching_line num_fields lbl_pat_list @ rem 1627| _ -> assert false 1628 1629let matcher_record num_fields p rem = match p.pat_desc with 1630| Tpat_or (_,_,_) -> raise OrPat 1631| Tpat_var _ -> get_args_record num_fields omega rem 1632| _ -> get_args_record num_fields p rem 1633 1634let make_record_matching loc all_labels def = function 1635 [] -> fatal_error "Matching.make_record_matching" 1636 | ((arg, _mut) :: argl) -> 1637 let rec make_args pos = 1638 if pos >= Array.length all_labels then argl else begin 1639 let lbl = all_labels.(pos) in 1640 let access = 1641 match lbl.lbl_repres with 1642 | Record_regular | Record_inlined _ -> 1643 Lprim (Pfield lbl.lbl_pos, [arg], loc) 1644 | Record_unboxed _ -> arg 1645 | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [arg], loc) 1646 | Record_extension -> Lprim (Pfield (lbl.lbl_pos + 1), [arg], loc) 1647 in 1648 let str = 1649 match lbl.lbl_mut with 1650 Immutable -> Alias 1651 | Mutable -> StrictOpt in 1652 (access, str) :: make_args(pos + 1) 1653 end in 1654 let nfields = Array.length all_labels in 1655 let def= make_default (matcher_record nfields) def in 1656 {cases = []; args = make_args 0 ; default = def} 1657 1658 1659let divide_record all_labels p ctx pm = 1660 let get_args = get_args_record (Array.length all_labels) in 1661 divide_line 1662 (filter_ctx p) 1663 (make_record_matching p.pat_loc all_labels) 1664 get_args 1665 p ctx pm 1666 1667(* Matching against an array pattern *) 1668 1669let get_key_array = function 1670 | {pat_desc=Tpat_array patl} -> List.length patl 1671 | _ -> assert false 1672 1673let get_args_array p rem = match p with 1674| {pat_desc=Tpat_array patl} -> patl@rem 1675| _ -> assert false 1676 1677let matcher_array len p rem = match p.pat_desc with 1678| Tpat_or (_,_,_) -> raise OrPat 1679| Tpat_array args when List.length args=len -> args @ rem 1680| Tpat_any -> Parmatch.omegas len @ rem 1681| _ -> raise NoMatch 1682 1683let make_array_matching kind p def ctx = function 1684 | [] -> fatal_error "Matching.make_array_matching" 1685 | ((arg, _mut) :: argl) -> 1686 let len = get_key_array p in 1687 let rec make_args pos = 1688 if pos >= len 1689 then argl 1690 else (Lprim(Parrayrefu kind, 1691 [arg; Lconst(Const_base(Const_int pos))], 1692 p.pat_loc), 1693 StrictOpt) :: make_args (pos + 1) in 1694 let def = make_default (matcher_array len) def 1695 and ctx = filter_ctx p ctx in 1696 {pm={cases = []; args = make_args 0 ; default = def} ; 1697 ctx=ctx ; 1698 pat = normalize_pat p} 1699 1700let divide_array kind ctx pm = 1701 divide 1702 (make_array_matching kind) 1703 (=) get_key_array get_args_array ctx pm 1704 1705 1706(* 1707 Specific string test sequence 1708 Will be called by the bytecode compiler, from bytegen.ml. 1709 The strategy is first dichotomic search (we perform 3-way tests 1710 with compare_string), then sequence of equality tests 1711 when there are less then T=strings_test_threshold static strings to match. 1712 1713 Increasing T entails (slightly) less code, decreasing T 1714 (slightly) favors runtime speed. 1715 T=8 looks a decent tradeoff. 1716*) 1717 1718(* Utilities *) 1719 1720let strings_test_threshold = 8 1721 1722let prim_string_notequal = 1723 Pccall(Primitive.simple 1724 ~name:"caml_string_notequal" 1725 ~arity:2 1726 ~alloc:false) 1727 1728let prim_string_compare = 1729 Pccall(Primitive.simple 1730 ~name:"caml_string_compare" 1731 ~arity:2 1732 ~alloc:false) 1733 1734let bind_sw arg k = match arg with 1735| Lvar _ -> k arg 1736| _ -> 1737 let id = Ident.create "switch" in 1738 Llet (Strict,Pgenval,id,arg,k (Lvar id)) 1739 1740 1741(* Sequential equality tests *) 1742 1743let make_string_test_sequence loc arg sw d = 1744 let d,sw = match d with 1745 | None -> 1746 begin match sw with 1747 | (_,d)::sw -> d,sw 1748 | [] -> assert false 1749 end 1750 | Some d -> d,sw in 1751 bind_sw arg 1752 (fun arg -> 1753 List.fold_right 1754 (fun (s,lam) k -> 1755 Lifthenelse 1756 (Lprim 1757 (prim_string_notequal, 1758 [arg; Lconst (Const_immstring s)], loc), 1759 k,lam)) 1760 sw d) 1761 1762let rec split k xs = match xs with 1763| [] -> assert false 1764| x0::xs -> 1765 if k <= 1 then [],x0,xs 1766 else 1767 let xs,y0,ys = split (k-2) xs in 1768 x0::xs,y0,ys 1769 1770let zero_lam = Lconst (Const_base (Const_int 0)) 1771 1772let tree_way_test loc arg lt eq gt = 1773 Lifthenelse 1774 (Lprim (Pintcomp Clt,[arg;zero_lam], loc),lt, 1775 Lifthenelse(Lprim (Pintcomp Clt,[zero_lam;arg], loc),gt,eq)) 1776 1777(* Dichotomic tree *) 1778 1779 1780let rec do_make_string_test_tree loc arg sw delta d = 1781 let len = List.length sw in 1782 if len <= strings_test_threshold+delta then 1783 make_string_test_sequence loc arg sw d 1784 else 1785 let lt,(s,act),gt = split len sw in 1786 bind_sw 1787 (Lprim 1788 (prim_string_compare, 1789 [arg; Lconst (Const_immstring s)], loc;)) 1790 (fun r -> 1791 tree_way_test loc r 1792 (do_make_string_test_tree loc arg lt delta d) 1793 act 1794 (do_make_string_test_tree loc arg gt delta d)) 1795 1796(* Entry point *) 1797let expand_stringswitch loc arg sw d = match d with 1798| None -> 1799 bind_sw arg 1800 (fun arg -> do_make_string_test_tree loc arg sw 0 None) 1801| Some e -> 1802 bind_sw arg 1803 (fun arg -> 1804 make_catch e 1805 (fun d -> do_make_string_test_tree loc arg sw 1 (Some d))) 1806 1807(**********************) 1808(* Generic test trees *) 1809(**********************) 1810 1811(* Sharing *) 1812 1813(* Add handler, if shared *) 1814let handle_shared () = 1815 let hs = ref (fun x -> x) in 1816 let handle_shared act = match act with 1817 | Switch.Single act -> act 1818 | Switch.Shared act -> 1819 let i,h = make_catch_delayed act in 1820 let ohs = !hs in 1821 hs := (fun act -> h (ohs act)) ; 1822 make_exit i in 1823 hs,handle_shared 1824 1825 1826let share_actions_tree sw d = 1827 let store = StoreExp.mk_store () in 1828(* Default action is always shared *) 1829 let d = 1830 match d with 1831 | None -> None 1832 | Some d -> Some (store.Switch.act_store_shared d) in 1833(* Store all other actions *) 1834 let sw = 1835 List.map (fun (cst,act) -> cst,store.Switch.act_store act) sw in 1836 1837(* Retrieve all actions, including potentiel default *) 1838 let acts = store.Switch.act_get_shared () in 1839 1840(* Array of actual actions *) 1841 let hs,handle_shared = handle_shared () in 1842 let acts = Array.map handle_shared acts in 1843 1844(* Reconstruct default and switch list *) 1845 let d = match d with 1846 | None -> None 1847 | Some d -> Some (acts.(d)) in 1848 let sw = List.map (fun (cst,j) -> cst,acts.(j)) sw in 1849 !hs,sw,d 1850 1851(* Note: dichotomic search requires sorted input with no duplicates *) 1852let rec uniq_lambda_list sw = match sw with 1853 | []|[_] -> sw 1854 | (c1,_ as p1)::((c2,_)::sw2 as sw1) -> 1855 if const_compare c1 c2 = 0 then uniq_lambda_list (p1::sw2) 1856 else p1::uniq_lambda_list sw1 1857 1858let sort_lambda_list l = 1859 let l = 1860 List.stable_sort (fun (x,_) (y,_) -> const_compare x y) l in 1861 uniq_lambda_list l 1862 1863let rec cut n l = 1864 if n = 0 then [],l 1865 else match l with 1866 [] -> raise (Invalid_argument "cut") 1867 | a::l -> let l1,l2 = cut (n-1) l in a::l1, l2 1868 1869let rec do_tests_fail loc fail tst arg = function 1870 | [] -> fail 1871 | (c, act)::rem -> 1872 Lifthenelse 1873 (Lprim (tst, [arg ; Lconst (Const_base c)], loc), 1874 do_tests_fail loc fail tst arg rem, 1875 act) 1876 1877let rec do_tests_nofail loc tst arg = function 1878 | [] -> fatal_error "Matching.do_tests_nofail" 1879 | [_,act] -> act 1880 | (c,act)::rem -> 1881 Lifthenelse 1882 (Lprim (tst, [arg ; Lconst (Const_base c)], loc), 1883 do_tests_nofail loc tst arg rem, 1884 act) 1885 1886let make_test_sequence loc fail tst lt_tst arg const_lambda_list = 1887 let const_lambda_list = sort_lambda_list const_lambda_list in 1888 let hs,const_lambda_list,fail = 1889 share_actions_tree const_lambda_list fail in 1890 1891 let rec make_test_sequence const_lambda_list = 1892 if List.length const_lambda_list >= 4 && lt_tst <> Pignore then 1893 split_sequence const_lambda_list 1894 else match fail with 1895 | None -> do_tests_nofail loc tst arg const_lambda_list 1896 | Some fail -> do_tests_fail loc fail tst arg const_lambda_list 1897 1898 and split_sequence const_lambda_list = 1899 let list1, list2 = 1900 cut (List.length const_lambda_list / 2) const_lambda_list in 1901 Lifthenelse(Lprim(lt_tst, 1902 [arg; Lconst(Const_base (fst(List.hd list2)))], 1903 loc), 1904 make_test_sequence list1, make_test_sequence list2) 1905 in 1906 hs (make_test_sequence const_lambda_list) 1907 1908 1909module SArg = struct 1910 type primitive = Lambda.primitive 1911 1912 let eqint = Pintcomp Ceq 1913 let neint = Pintcomp Cneq 1914 let leint = Pintcomp Cle 1915 let ltint = Pintcomp Clt 1916 let geint = Pintcomp Cge 1917 let gtint = Pintcomp Cgt 1918 1919 type act = Lambda.lambda 1920 1921 let make_prim p args = Lprim (p,args,Location.none) 1922 let make_offset arg n = match n with 1923 | 0 -> arg 1924 | _ -> Lprim (Poffsetint n,[arg],Location.none) 1925 1926 let bind arg body = 1927 let newvar,newarg = match arg with 1928 | Lvar v -> v,arg 1929 | _ -> 1930 let newvar = Ident.create "switcher" in 1931 newvar,Lvar newvar in 1932 bind Alias newvar arg (body newarg) 1933 let make_const i = Lconst (Const_base (Const_int i)) 1934 let make_isout h arg = Lprim (Pisout, [h ; arg],Location.none) 1935 let make_isin h arg = Lprim (Pnot,[make_isout h arg],Location.none) 1936 let make_if cond ifso ifnot = Lifthenelse (cond, ifso, ifnot) 1937 let make_switch arg cases acts = 1938 let l = ref [] in 1939 for i = Array.length cases-1 downto 0 do 1940 l := (i,acts.(cases.(i))) :: !l 1941 done ; 1942 Lswitch(arg, 1943 {sw_numconsts = Array.length cases ; sw_consts = !l ; 1944 sw_numblocks = 0 ; sw_blocks = [] ; 1945 sw_failaction = None}) 1946 let make_catch = make_catch_delayed 1947 let make_exit = make_exit 1948 1949end 1950 1951(* Action sharing for Lswitch argument *) 1952let share_actions_sw sw = 1953(* Attempt sharing on all actions *) 1954 let store = StoreExp.mk_store () in 1955 let fail = match sw.sw_failaction with 1956 | None -> None 1957 | Some fail -> 1958 (* Fail is translated to exit, whatever happens *) 1959 Some (store.Switch.act_store_shared fail) in 1960 let consts = 1961 List.map 1962 (fun (i,e) -> i,store.Switch.act_store e) 1963 sw.sw_consts 1964 and blocks = 1965 List.map 1966 (fun (i,e) -> i,store.Switch.act_store e) 1967 sw.sw_blocks in 1968 let acts = store.Switch.act_get_shared () in 1969 let hs,handle_shared = handle_shared () in 1970 let acts = Array.map handle_shared acts in 1971 let fail = match fail with 1972 | None -> None 1973 | Some fail -> Some (acts.(fail)) in 1974 !hs, 1975 { sw with 1976 sw_consts = List.map (fun (i,j) -> i,acts.(j)) consts ; 1977 sw_blocks = List.map (fun (i,j) -> i,acts.(j)) blocks ; 1978 sw_failaction = fail; } 1979 1980(* Reintroduce fail action in switch argument, 1981 for the sake of avoiding carrying over huge switches *) 1982 1983let reintroduce_fail sw = match sw.sw_failaction with 1984| None -> 1985 let t = Hashtbl.create 17 in 1986 let seen (_,l) = match as_simple_exit l with 1987 | Some i -> 1988 let old = try Hashtbl.find t i with Not_found -> 0 in 1989 Hashtbl.replace t i (old+1) 1990 | None -> () in 1991 List.iter seen sw.sw_consts ; 1992 List.iter seen sw.sw_blocks ; 1993 let i_max = ref (-1) 1994 and max = ref (-1) in 1995 Hashtbl.iter 1996 (fun i c -> 1997 if c > !max then begin 1998 i_max := i ; 1999 max := c 2000 end) t ; 2001 if !max >= 3 then 2002 let default = !i_max in 2003 let remove = 2004 List.filter 2005 (fun (_,lam) -> match as_simple_exit lam with 2006 | Some j -> j <> default 2007 | None -> true) in 2008 {sw with 2009 sw_consts = remove sw.sw_consts ; 2010 sw_blocks = remove sw.sw_blocks ; 2011 sw_failaction = Some (make_exit default)} 2012 else sw 2013| Some _ -> sw 2014 2015 2016module Switcher = Switch.Make(SArg) 2017open Switch 2018 2019let rec last def = function 2020 | [] -> def 2021 | [x,_] -> x 2022 | _::rem -> last def rem 2023 2024let get_edges low high l = match l with 2025| [] -> low, high 2026| (x,_)::_ -> x, last high l 2027 2028 2029let as_interval_canfail fail low high l = 2030 let store = StoreExp.mk_store () in 2031 2032 let do_store _tag act = 2033 2034 let i = store.act_store act in 2035(* 2036 eprintf "STORE [%s] %i %s\n" tag i (string_of_lam act) ; 2037*) 2038 i in 2039 2040 let rec nofail_rec cur_low cur_high cur_act = function 2041 | [] -> 2042 if cur_high = high then 2043 [cur_low,cur_high,cur_act] 2044 else 2045 [(cur_low,cur_high,cur_act) ; (cur_high+1,high, 0)] 2046 | ((i,act_i)::rem) as all -> 2047 let act_index = do_store "NO" act_i in 2048 if cur_high+1= i then 2049 if act_index=cur_act then 2050 nofail_rec cur_low i cur_act rem 2051 else if act_index=0 then 2052 (cur_low,i-1, cur_act)::fail_rec i i rem 2053 else 2054 (cur_low, i-1, cur_act)::nofail_rec i i act_index rem 2055 else if act_index = 0 then 2056 (cur_low, cur_high, cur_act):: 2057 fail_rec (cur_high+1) (cur_high+1) all 2058 else 2059 (cur_low, cur_high, cur_act):: 2060 (cur_high+1,i-1,0):: 2061 nofail_rec i i act_index rem 2062 2063 and fail_rec cur_low cur_high = function 2064 | [] -> [(cur_low, cur_high, 0)] 2065 | (i,act_i)::rem -> 2066 let index = do_store "YES" act_i in 2067 if index=0 then fail_rec cur_low i rem 2068 else 2069 (cur_low,i-1,0):: 2070 nofail_rec i i index rem in 2071 2072 let init_rec = function 2073 | [] -> [low,high,0] 2074 | (i,act_i)::rem -> 2075 let index = do_store "INIT" act_i in 2076 if index=0 then 2077 fail_rec low i rem 2078 else 2079 if low < i then 2080 (low,i-1,0)::nofail_rec i i index rem 2081 else 2082 nofail_rec i i index rem in 2083 2084 assert (do_store "FAIL" fail = 0) ; (* fail has action index 0 *) 2085 let r = init_rec l in 2086 Array.of_list r, store 2087 2088let as_interval_nofail l = 2089 let store = StoreExp.mk_store () in 2090 let rec some_hole = function 2091 | []|[_] -> false 2092 | (i,_)::((j,_)::_ as rem) -> 2093 j > i+1 || some_hole rem in 2094 let rec i_rec cur_low cur_high cur_act = function 2095 | [] -> 2096 [cur_low, cur_high, cur_act] 2097 | (i,act)::rem -> 2098 let act_index = store.act_store act in 2099 if act_index = cur_act then 2100 i_rec cur_low i cur_act rem 2101 else 2102 (cur_low, cur_high, cur_act):: 2103 i_rec i i act_index rem in 2104 let inters = match l with 2105 | (i,act)::rem -> 2106 let act_index = 2107 (* In case there is some hole and that a switch is emitted, 2108 action 0 will be used as the action of unreacheable 2109 cases (cf. switch.ml, make_switch). 2110 Hence, this action will be shared *) 2111 if some_hole rem then 2112 store.act_store_shared act 2113 else 2114 store.act_store act in 2115 assert (act_index = 0) ; 2116 i_rec i i act_index rem 2117 | _ -> assert false in 2118 2119 Array.of_list inters, store 2120 2121 2122let sort_int_lambda_list l = 2123 List.sort 2124 (fun (i1,_) (i2,_) -> 2125 if i1 < i2 then -1 2126 else if i2 < i1 then 1 2127 else 0) 2128 l 2129 2130let as_interval fail low high l = 2131 let l = sort_int_lambda_list l in 2132 get_edges low high l, 2133 (match fail with 2134 | None -> as_interval_nofail l 2135 | Some act -> as_interval_canfail act low high l) 2136 2137let call_switcher fail arg low high int_lambda_list = 2138 let edges, (cases, actions) = 2139 as_interval fail low high int_lambda_list in 2140 Switcher.zyva edges arg cases actions 2141 2142 2143let rec list_as_pat = function 2144 | [] -> fatal_error "Matching.list_as_pat" 2145 | [pat] -> pat 2146 | pat::rem -> 2147 {pat with pat_desc = Tpat_or (pat,list_as_pat rem,None)} 2148 2149 2150let complete_pats_constrs = function 2151 | p::_ as pats -> 2152 List.map 2153 (pat_of_constr p) 2154 (complete_constrs p (List.map get_key_constr pats)) 2155 | _ -> assert false 2156 2157 2158(* 2159 Following two ``failaction'' function compute n, the trap handler 2160 to jump to in case of failure of elementary tests 2161*) 2162 2163let mk_failaction_neg partial ctx def = match partial with 2164| Partial -> 2165 begin match def with 2166 | (_,idef)::_ -> 2167 Some (Lstaticraise (idef,[])),jumps_singleton idef ctx 2168 | [] -> 2169 (* Act as Total, this means 2170 If no appropriate default matrix exists, 2171 then this switch cannot fail *) 2172 None, jumps_empty 2173 end 2174| Total -> 2175 None, jumps_empty 2176 2177 2178 2179(* In line with the article and simpler than before *) 2180let mk_failaction_pos partial seen ctx defs = 2181 if dbg then begin 2182 prerr_endline "**POS**" ; 2183 pretty_def defs ; 2184 () 2185 end ; 2186 let rec scan_def env to_test defs = match to_test,defs with 2187 | ([],_)|(_,[]) -> 2188 List.fold_left 2189 (fun (klist,jumps) (pats,i)-> 2190 let action = Lstaticraise (i,[]) in 2191 let klist = 2192 List.fold_right 2193 (fun pat r -> (get_key_constr pat,action)::r) 2194 pats klist 2195 and jumps = 2196 jumps_add i (ctx_lub (list_as_pat pats) ctx) jumps in 2197 klist,jumps) 2198 ([],jumps_empty) env 2199 | _,(pss,idef)::rem -> 2200 let now, later = 2201 List.partition 2202 (fun (_p,p_ctx) -> ctx_match p_ctx pss) to_test in 2203 match now with 2204 | [] -> scan_def env to_test rem 2205 | _ -> scan_def ((List.map fst now,idef)::env) later rem in 2206 2207 let fail_pats = complete_pats_constrs seen in 2208 if List.length fail_pats < 32 then begin 2209 let fail,jmps = 2210 scan_def 2211 [] 2212 (List.map 2213 (fun pat -> pat, ctx_lub pat ctx) 2214 fail_pats) 2215 defs in 2216 if dbg then begin 2217 eprintf "POSITIVE JUMPS [%i]:\n" (List.length fail_pats); 2218 pretty_jumps jmps 2219 end ; 2220 None,fail,jmps 2221 end else begin (* Too many non-matched constructors -> reduced information *) 2222 if dbg then eprintf "POS->NEG!!!\n%!" ; 2223 let fail,jumps = mk_failaction_neg partial ctx defs in 2224 if dbg then 2225 eprintf "FAIL: %s\n" 2226 (match fail with 2227 | None -> "<none>" 2228 | Some lam -> string_of_lam lam) ; 2229 fail,[],jumps 2230 end 2231 2232let combine_constant loc arg cst partial ctx def 2233 (const_lambda_list, total, _pats) = 2234 let fail, local_jumps = 2235 mk_failaction_neg partial ctx def in 2236 let lambda1 = 2237 match cst with 2238 | Const_int _ -> 2239 let int_lambda_list = 2240 List.map (function Const_int n, l -> n,l | _ -> assert false) 2241 const_lambda_list in 2242 call_switcher fail arg min_int max_int int_lambda_list 2243 | Const_char _ -> 2244 let int_lambda_list = 2245 List.map (function Const_char c, l -> (Char.code c, l) 2246 | _ -> assert false) 2247 const_lambda_list in 2248 call_switcher fail arg 0 255 int_lambda_list 2249 | Const_string _ -> 2250(* Note as the bytecode compiler may resort to dichotomic search, 2251 the clauses of stringswitch are sorted with duplicates removed. 2252 This partly applies to the native code compiler, which requires 2253 no duplicates *) 2254 let const_lambda_list = sort_lambda_list const_lambda_list in 2255 let sw = 2256 List.map 2257 (fun (c,act) -> match c with 2258 | Const_string (s,_) -> s,act 2259 | _ -> assert false) 2260 const_lambda_list in 2261 let hs,sw,fail = share_actions_tree sw fail in 2262 hs (Lstringswitch (arg,sw,fail,loc)) 2263 | Const_float _ -> 2264 make_test_sequence loc 2265 fail 2266 (Pfloatcomp Cneq) (Pfloatcomp Clt) 2267 arg const_lambda_list 2268 | Const_int32 _ -> 2269 make_test_sequence loc 2270 fail 2271 (Pbintcomp(Pint32, Cneq)) (Pbintcomp(Pint32, Clt)) 2272 arg const_lambda_list 2273 | Const_int64 _ -> 2274 make_test_sequence loc 2275 fail 2276 (Pbintcomp(Pint64, Cneq)) (Pbintcomp(Pint64, Clt)) 2277 arg const_lambda_list 2278 | Const_nativeint _ -> 2279 make_test_sequence loc 2280 fail 2281 (Pbintcomp(Pnativeint, Cneq)) (Pbintcomp(Pnativeint, Clt)) 2282 arg const_lambda_list 2283 in lambda1,jumps_union local_jumps total 2284 2285 2286 2287let split_cases tag_lambda_list = 2288 let rec split_rec = function 2289 [] -> ([], []) 2290 | (cstr, act) :: rem -> 2291 let (consts, nonconsts) = split_rec rem in 2292 match cstr with 2293 Cstr_constant n -> ((n, act) :: consts, nonconsts) 2294 | Cstr_block n -> (consts, (n, act) :: nonconsts) 2295 | Cstr_unboxed -> (consts, (0, act) :: nonconsts) 2296 | Cstr_extension _ -> assert false in 2297 let const, nonconst = split_rec tag_lambda_list in 2298 sort_int_lambda_list const, 2299 sort_int_lambda_list nonconst 2300 2301let split_extension_cases tag_lambda_list = 2302 let rec split_rec = function 2303 [] -> ([], []) 2304 | (cstr, act) :: rem -> 2305 let (consts, nonconsts) = split_rec rem in 2306 match cstr with 2307 Cstr_extension(path, true) -> ((path, act) :: consts, nonconsts) 2308 | Cstr_extension(path, false) -> (consts, (path, act) :: nonconsts) 2309 | _ -> assert false in 2310 split_rec tag_lambda_list 2311 2312 2313let combine_constructor loc arg ex_pat cstr partial ctx def 2314 (tag_lambda_list, total1, pats) = 2315 if cstr.cstr_consts < 0 then begin 2316 (* Special cases for extensions *) 2317 let fail, local_jumps = 2318 mk_failaction_neg partial ctx def in 2319 let lambda1 = 2320 let consts, nonconsts = split_extension_cases tag_lambda_list in 2321 let default, consts, nonconsts = 2322 match fail with 2323 | None -> 2324 begin match consts, nonconsts with 2325 | _, (_, act)::rem -> act, consts, rem 2326 | (_, act)::rem, _ -> act, rem, nonconsts 2327 | _ -> assert false 2328 end 2329 | Some fail -> fail, consts, nonconsts in 2330 let nonconst_lambda = 2331 match nonconsts with 2332 [] -> default 2333 | _ -> 2334 let tag = Ident.create "tag" in 2335 let tests = 2336 List.fold_right 2337 (fun (path, act) rem -> 2338 Lifthenelse(Lprim(Pintcomp Ceq, 2339 [Lvar tag; 2340 transl_path ex_pat.pat_env path], loc), 2341 act, rem)) 2342 nonconsts 2343 default 2344 in 2345 Llet(Alias, Pgenval,tag, Lprim(Pfield 0, [arg], loc), tests) 2346 in 2347 List.fold_right 2348 (fun (path, act) rem -> 2349 Lifthenelse(Lprim(Pintcomp Ceq, 2350 [arg; transl_path ex_pat.pat_env path], loc), 2351 act, rem)) 2352 consts 2353 nonconst_lambda 2354 in 2355 lambda1, jumps_union local_jumps total1 2356 end else begin 2357 (* Regular concrete type *) 2358 let ncases = List.length tag_lambda_list 2359 and nconstrs = cstr.cstr_consts + cstr.cstr_nonconsts in 2360 let sig_complete = ncases = nconstrs in 2361 let fail_opt,fails,local_jumps = 2362 if sig_complete then None,[],jumps_empty 2363 else 2364 mk_failaction_pos partial pats ctx def in 2365 2366 let tag_lambda_list = fails @ tag_lambda_list in 2367 let (consts, nonconsts) = split_cases tag_lambda_list in 2368 let lambda1 = 2369 match fail_opt,same_actions tag_lambda_list with 2370 | None,Some act -> act (* Identical actions, no failure *) 2371 | _ -> 2372 match 2373 (cstr.cstr_consts, cstr.cstr_nonconsts, consts, nonconsts) 2374 with 2375 | (1, 1, [0, act1], [0, act2]) -> 2376 (* Typically, match on lists, will avoid isint primitive in that 2377 case *) 2378 Lifthenelse(arg, act2, act1) 2379 | (n,0,_,[]) -> (* The type defines constant constructors only *) 2380 call_switcher fail_opt arg 0 (n-1) consts 2381 | (n, _, _, _) -> 2382 let act0 = 2383 (* = Some act when all non-const constructors match to act *) 2384 match fail_opt,nonconsts with 2385 | Some a,[] -> Some a 2386 | Some _,_ -> 2387 if List.length nonconsts = cstr.cstr_nonconsts then 2388 same_actions nonconsts 2389 else None 2390 | None,_ -> same_actions nonconsts in 2391 match act0 with 2392 | Some act -> 2393 Lifthenelse 2394 (Lprim (Pisint, [arg], loc), 2395 call_switcher 2396 fail_opt arg 2397 0 (n-1) consts, 2398 act) 2399(* Emit a switch, as bytecode implements this sophisticated instruction *) 2400 | None -> 2401 let sw = 2402 {sw_numconsts = cstr.cstr_consts; sw_consts = consts; 2403 sw_numblocks = cstr.cstr_nonconsts; sw_blocks = nonconsts; 2404 sw_failaction = fail_opt} in 2405 let hs,sw = share_actions_sw sw in 2406 let sw = reintroduce_fail sw in 2407 hs (Lswitch (arg,sw)) in 2408 lambda1, jumps_union local_jumps total1 2409 end 2410 2411let make_test_sequence_variant_constant fail arg int_lambda_list = 2412 let _, (cases, actions) = 2413 as_interval fail min_int max_int int_lambda_list in 2414 Switcher.test_sequence arg cases actions 2415 2416let call_switcher_variant_constant fail arg int_lambda_list = 2417 call_switcher fail arg min_int max_int int_lambda_list 2418 2419 2420let call_switcher_variant_constr loc fail arg int_lambda_list = 2421 let v = Ident.create "variant" in 2422 Llet(Alias, Pgenval, v, Lprim(Pfield 0, [arg], loc), 2423 call_switcher 2424 fail (Lvar v) min_int max_int int_lambda_list) 2425 2426let combine_variant loc row arg partial ctx def 2427 (tag_lambda_list, total1, _pats) = 2428 let row = Btype.row_repr row in 2429 let num_constr = ref 0 in 2430 if row.row_closed then 2431 List.iter 2432 (fun (_, f) -> 2433 match Btype.row_field_repr f with 2434 Rabsent | Reither(true, _::_, _, _) -> () 2435 | _ -> incr num_constr) 2436 row.row_fields 2437 else 2438 num_constr := max_int; 2439 let test_int_or_block arg if_int if_block = 2440 Lifthenelse(Lprim (Pisint, [arg], loc), if_int, if_block) in 2441 let sig_complete = List.length tag_lambda_list = !num_constr 2442 and one_action = same_actions tag_lambda_list in 2443 let fail, local_jumps = 2444 if 2445 sig_complete || (match partial with Total -> true | _ -> false) 2446 then 2447 None, jumps_empty 2448 else 2449 mk_failaction_neg partial ctx def in 2450 let (consts, nonconsts) = split_cases tag_lambda_list in 2451 let lambda1 = match fail, one_action with 2452 | None, Some act -> act 2453 | _,_ -> 2454 match (consts, nonconsts) with 2455 | ([_, act1], [_, act2]) when fail=None -> 2456 test_int_or_block arg act1 act2 2457 | (_, []) -> (* One can compare integers and pointers *) 2458 make_test_sequence_variant_constant fail arg consts 2459 | ([], _) -> 2460 let lam = call_switcher_variant_constr loc 2461 fail arg nonconsts in 2462 (* One must not dereference integers *) 2463 begin match fail with 2464 | None -> lam 2465 | Some fail -> test_int_or_block arg fail lam 2466 end 2467 | (_, _) -> 2468 let lam_const = 2469 call_switcher_variant_constant 2470 fail arg consts 2471 and lam_nonconst = 2472 call_switcher_variant_constr loc 2473 fail arg nonconsts in 2474 test_int_or_block arg lam_const lam_nonconst 2475 in 2476 lambda1, jumps_union local_jumps total1 2477 2478 2479let combine_array loc arg kind partial ctx def 2480 (len_lambda_list, total1, _pats) = 2481 let fail, local_jumps = mk_failaction_neg partial ctx def in 2482 let lambda1 = 2483 let newvar = Ident.create "len" in 2484 let switch = 2485 call_switcher 2486 fail (Lvar newvar) 2487 0 max_int len_lambda_list in 2488 bind 2489 Alias newvar (Lprim(Parraylength kind, [arg], loc)) switch in 2490 lambda1, jumps_union local_jumps total1 2491 2492(* Insertion of debugging events *) 2493 2494let rec event_branch repr lam = 2495 begin match lam, repr with 2496 (_, None) -> 2497 lam 2498 | (Levent(lam', ev), Some r) -> 2499 incr r; 2500 Levent(lam', {lev_loc = ev.lev_loc; 2501 lev_kind = ev.lev_kind; 2502 lev_repr = repr; 2503 lev_env = ev.lev_env}) 2504 | (Llet(str, k, id, lam, body), _) -> 2505 Llet(str, k, id, lam, event_branch repr body) 2506 | Lstaticraise _,_ -> lam 2507 | (_, Some _) -> 2508 Printlambda.lambda Format.str_formatter lam ; 2509 fatal_error 2510 ("Matching.event_branch: "^Format.flush_str_formatter ()) 2511 end 2512 2513 2514(* 2515 This exception is raised when the compiler cannot produce code 2516 because control cannot reach the compiled clause, 2517 2518 Unused is raised initially in compile_test. 2519 2520 compile_list (for compiling switch results) catch Unused 2521 2522 comp_match_handlers (for compiling splitted matches) 2523 may reraise Unused 2524 2525 2526*) 2527 2528exception Unused 2529 2530let compile_list compile_fun division = 2531 2532 let rec c_rec totals = function 2533 | [] -> [], jumps_unions totals, [] 2534 | (key, cell) :: rem -> 2535 begin match cell.ctx with 2536 | [] -> c_rec totals rem 2537 | _ -> 2538 try 2539 let (lambda1, total1) = compile_fun cell.ctx cell.pm in 2540 let c_rem, total, new_pats = 2541 c_rec 2542 (jumps_map ctx_combine total1::totals) rem in 2543 ((key,lambda1)::c_rem), total, (cell.pat::new_pats) 2544 with 2545 | Unused -> c_rec totals rem 2546 end in 2547 c_rec [] division 2548 2549 2550let compile_orhandlers compile_fun lambda1 total1 ctx to_catch = 2551 let rec do_rec r total_r = function 2552 | [] -> r,total_r 2553 | (mat,i,vars,pm)::rem -> 2554 begin try 2555 let ctx = select_columns mat ctx in 2556 let handler_i, total_i = compile_fun ctx pm in 2557 match raw_action r with 2558 | Lstaticraise (j,args) -> 2559 if i=j then 2560 List.fold_right2 (bind Alias) vars args handler_i, 2561 jumps_map (ctx_rshift_num (ncols mat)) total_i 2562 else 2563 do_rec r total_r rem 2564 | _ -> 2565 do_rec 2566 (Lstaticcatch (r,(i,vars), handler_i)) 2567 (jumps_union 2568 (jumps_remove i total_r) 2569 (jumps_map (ctx_rshift_num (ncols mat)) total_i)) 2570 rem 2571 with 2572 | Unused -> 2573 do_rec (Lstaticcatch (r, (i,vars), lambda_unit)) total_r rem 2574 end in 2575 do_rec lambda1 total1 to_catch 2576 2577 2578let compile_test compile_fun partial divide combine ctx to_match = 2579 let division = divide ctx to_match in 2580 let c_div = compile_list compile_fun division in 2581 match c_div with 2582 | [],_,_ -> 2583 begin match mk_failaction_neg partial ctx to_match.default with 2584 | None,_ -> raise Unused 2585 | Some l,total -> l,total 2586 end 2587 | _ -> 2588 combine ctx to_match.default c_div 2589 2590(* Attempt to avoid some useless bindings by lowering them *) 2591 2592(* Approximation of v present in lam *) 2593let rec approx_present v = function 2594 | Lconst _ -> false 2595 | Lstaticraise (_,args) -> 2596 List.exists (fun lam -> approx_present v lam) args 2597 | Lprim (_,args,_) -> 2598 List.exists (fun lam -> approx_present v lam) args 2599 | Llet (Alias, _k, _, l1, l2) -> 2600 approx_present v l1 || approx_present v l2 2601 | Lvar vv -> Ident.same v vv 2602 | _ -> true 2603 2604let rec lower_bind v arg lam = match lam with 2605| Lifthenelse (cond, ifso, ifnot) -> 2606 let pcond = approx_present v cond 2607 and pso = approx_present v ifso 2608 and pnot = approx_present v ifnot in 2609 begin match pcond, pso, pnot with 2610 | false, false, false -> lam 2611 | false, true, false -> 2612 Lifthenelse (cond, lower_bind v arg ifso, ifnot) 2613 | false, false, true -> 2614 Lifthenelse (cond, ifso, lower_bind v arg ifnot) 2615 | _,_,_ -> bind Alias v arg lam 2616 end 2617| Lswitch (ls,({sw_consts=[i,act] ; sw_blocks = []} as sw)) 2618 when not (approx_present v ls) -> 2619 Lswitch (ls, {sw with sw_consts = [i,lower_bind v arg act]}) 2620| Lswitch (ls,({sw_consts=[] ; sw_blocks = [i,act]} as sw)) 2621 when not (approx_present v ls) -> 2622 Lswitch (ls, {sw with sw_blocks = [i,lower_bind v arg act]}) 2623| Llet (Alias, k, vv, lv, l) -> 2624 if approx_present v lv then 2625 bind Alias v arg lam 2626 else 2627 Llet (Alias, k, vv, lv, lower_bind v arg l) 2628| _ -> 2629 bind Alias v arg lam 2630 2631let bind_check str v arg lam = match str,arg with 2632| _, Lvar _ ->bind str v arg lam 2633| Alias,_ -> lower_bind v arg lam 2634| _,_ -> bind str v arg lam 2635 2636let comp_exit ctx m = match m.default with 2637| (_,i)::_ -> Lstaticraise (i,[]), jumps_singleton i ctx 2638| _ -> fatal_error "Matching.comp_exit" 2639 2640 2641 2642let rec comp_match_handlers comp_fun partial ctx arg first_match next_matchs = 2643 match next_matchs with 2644 | [] -> comp_fun partial ctx arg first_match 2645 | rem -> 2646 let rec c_rec body total_body = function 2647 | [] -> body, total_body 2648 (* Hum, -1 means never taken 2649 | (-1,pm)::rem -> c_rec body total_body rem *) 2650 | (i,pm)::rem -> 2651 let ctx_i,total_rem = jumps_extract i total_body in 2652 begin match ctx_i with 2653 | [] -> c_rec body total_body rem 2654 | _ -> 2655 try 2656 let li,total_i = 2657 comp_fun 2658 (match rem with [] -> partial | _ -> Partial) 2659 ctx_i arg pm in 2660 c_rec 2661 (Lstaticcatch (body,(i,[]),li)) 2662 (jumps_union total_i total_rem) 2663 rem 2664 with 2665 | Unused -> 2666 c_rec (Lstaticcatch (body,(i,[]),lambda_unit)) 2667 total_rem rem 2668 end in 2669 try 2670 let first_lam,total = comp_fun Partial ctx arg first_match in 2671 c_rec first_lam total rem 2672 with Unused -> match next_matchs with 2673 | [] -> raise Unused 2674 | (_,x)::xs -> comp_match_handlers comp_fun partial ctx arg x xs 2675 2676(* To find reasonable names for variables *) 2677 2678let rec name_pattern default = function 2679 (pat :: _, _) :: rem -> 2680 begin match pat.pat_desc with 2681 Tpat_var (id, _) -> id 2682 | Tpat_alias(_, id, _) -> id 2683 | _ -> name_pattern default rem 2684 end 2685 | _ -> Ident.create default 2686 2687let arg_to_var arg cls = match arg with 2688| Lvar v -> v,arg 2689| _ -> 2690 let v = name_pattern "match" cls in 2691 v,Lvar v 2692 2693 2694(* 2695 The main compilation function. 2696 Input: 2697 repr=used for inserting debug events 2698 partial=exhaustiveness information from Parmatch 2699 ctx=a context 2700 m=a pattern matching 2701 2702 Output: a lambda term, a jump summary {..., exit number -> context, .. } 2703*) 2704 2705let rec compile_match repr partial ctx m = match m with 2706| { cases = []; args = [] } -> comp_exit ctx m 2707| { cases = ([], action) :: rem } -> 2708 if is_guarded action then begin 2709 let (lambda, total) = 2710 compile_match None partial ctx { m with cases = rem } in 2711 event_branch repr (patch_guarded lambda action), total 2712 end else 2713 (event_branch repr action, jumps_empty) 2714| { args = (arg, str)::argl } -> 2715 let v,newarg = arg_to_var arg m.cases in 2716 let first_match,rem = 2717 split_precompile (Some v) 2718 { m with args = (newarg, Alias) :: argl } in 2719 let (lam, total) = 2720 comp_match_handlers 2721 ((if dbg then do_compile_matching_pr else do_compile_matching) repr) 2722 partial ctx newarg first_match rem in 2723 bind_check str v arg lam, total 2724| _ -> assert false 2725 2726 2727(* verbose version of do_compile_matching, for debug *) 2728 2729and do_compile_matching_pr repr partial ctx arg x = 2730 prerr_string "COMPILE: " ; 2731 prerr_endline (match partial with Partial -> "Partial" | Total -> "Total") ; 2732 prerr_endline "MATCH" ; 2733 pretty_precompiled x ; 2734 prerr_endline "CTX" ; 2735 pretty_ctx ctx ; 2736 let (_, jumps) as r = do_compile_matching repr partial ctx arg x in 2737 prerr_endline "JUMPS" ; 2738 pretty_jumps jumps ; 2739 r 2740 2741and do_compile_matching repr partial ctx arg pmh = match pmh with 2742| Pm pm -> 2743 let pat = what_is_cases pm.cases in 2744 begin match pat.pat_desc with 2745 | Tpat_any -> 2746 compile_no_test 2747 divide_var ctx_rshift repr partial ctx pm 2748 | Tpat_tuple patl -> 2749 compile_no_test 2750 (divide_tuple (List.length patl) (normalize_pat pat)) ctx_combine 2751 repr partial ctx pm 2752 | Tpat_record ((_, lbl,_)::_,_) -> 2753 compile_no_test 2754 (divide_record lbl.lbl_all (normalize_pat pat)) 2755 ctx_combine repr partial ctx pm 2756 | Tpat_constant cst -> 2757 compile_test 2758 (compile_match repr partial) partial 2759 divide_constant 2760 (combine_constant pat.pat_loc arg cst partial) 2761 ctx pm 2762 | Tpat_construct (_, cstr, _) -> 2763 compile_test 2764 (compile_match repr partial) partial 2765 divide_constructor 2766 (combine_constructor pat.pat_loc arg pat cstr partial) 2767 ctx pm 2768 | Tpat_array _ -> 2769 let kind = Typeopt.array_pattern_kind pat in 2770 compile_test (compile_match repr partial) partial 2771 (divide_array kind) (combine_array pat.pat_loc arg kind partial) 2772 ctx pm 2773 | Tpat_lazy _ -> 2774 compile_no_test 2775 (divide_lazy (normalize_pat pat)) 2776 ctx_combine repr partial ctx pm 2777 | Tpat_variant(_, _, row) -> 2778 compile_test (compile_match repr partial) partial 2779 (divide_variant !row) 2780 (combine_variant pat.pat_loc !row arg partial) 2781 ctx pm 2782 | _ -> assert false 2783 end 2784| PmVar {inside=pmh ; var_arg=arg} -> 2785 let lam, total = 2786 do_compile_matching repr partial (ctx_lshift ctx) arg pmh in 2787 lam, jumps_map ctx_rshift total 2788| PmOr {body=body ; handlers=handlers} -> 2789 let lam, total = compile_match repr partial ctx body in 2790 compile_orhandlers (compile_match repr partial) lam total ctx handlers 2791 2792and compile_no_test divide up_ctx repr partial ctx to_match = 2793 let {pm=this_match ; ctx=this_ctx } = divide ctx to_match in 2794 let lambda,total = compile_match repr partial this_ctx this_match in 2795 lambda, jumps_map up_ctx total 2796 2797 2798 2799 2800(* The entry points *) 2801 2802(* 2803 If there is a guard in a matching or a lazy pattern, 2804 then set exhaustiveness info to Partial. 2805 (because of side effects, assume the worst). 2806 2807 Notice that exhaustiveness information is trusted by the compiler, 2808 that is, a match flagged as Total should not fail at runtime. 2809 More specifically, for instance if match y with x::_ -> x is flagged 2810 total (as it happens during JoCaml compilation) then y cannot be [] 2811 at runtime. As a consequence, the static Total exhaustiveness information 2812 have to be downgraded to Partial, in the dubious cases where guards 2813 or lazy pattern execute arbitrary code that may perform side effects 2814 and change the subject values. 2815LM: 2816 Lazy pattern was PR #5992, initial patch by lwp25. 2817 I have generalized the patch, so as to also find mutable fields. 2818*) 2819 2820let find_in_pat pred = 2821 let rec find_rec p = 2822 pred p.pat_desc || 2823 begin match p.pat_desc with 2824 | Tpat_alias (p,_,_) | Tpat_variant (_,Some p,_) | Tpat_lazy p -> 2825 find_rec p 2826 | Tpat_tuple ps|Tpat_construct (_,_,ps) | Tpat_array ps -> 2827 List.exists find_rec ps 2828 | Tpat_record (lpats,_) -> 2829 List.exists 2830 (fun (_, _, p) -> find_rec p) 2831 lpats 2832 | Tpat_or (p,q,_) -> 2833 find_rec p || find_rec q 2834 | Tpat_constant _ | Tpat_var _ 2835 | Tpat_any | Tpat_variant (_,None,_) -> false 2836 end in 2837 find_rec 2838 2839let is_lazy_pat = function 2840 | Tpat_lazy _ -> true 2841 | Tpat_alias _ | Tpat_variant _ | Tpat_record _ 2842 | Tpat_tuple _|Tpat_construct _ | Tpat_array _ 2843 | Tpat_or _ | Tpat_constant _ | Tpat_var _ | Tpat_any 2844 -> false 2845 2846let is_lazy p = find_in_pat is_lazy_pat p 2847 2848let have_mutable_field p = match p with 2849| Tpat_record (lps,_) -> 2850 List.exists 2851 (fun (_,lbl,_) -> 2852 match lbl.Types.lbl_mut with 2853 | Mutable -> true 2854 | Immutable -> false) 2855 lps 2856| Tpat_alias _ | Tpat_variant _ | Tpat_lazy _ 2857| Tpat_tuple _|Tpat_construct _ | Tpat_array _ 2858| Tpat_or _ 2859| Tpat_constant _ | Tpat_var _ | Tpat_any 2860 -> false 2861 2862let is_mutable p = find_in_pat have_mutable_field p 2863 2864(* Downgrade Total when 2865 1. Matching accesses some mutable fields; 2866 2. And there are guards or lazy patterns. 2867*) 2868 2869let check_partial is_mutable is_lazy pat_act_list = function 2870 | Partial -> Partial 2871 | Total -> 2872 if 2873 pat_act_list = [] || (* allow empty case list *) 2874 List.exists 2875 (fun (pats, lam) -> 2876 is_mutable pats && (is_guarded lam || is_lazy pats)) 2877 pat_act_list 2878 then Partial 2879 else Total 2880 2881let check_partial_list = 2882 check_partial (List.exists is_mutable) (List.exists is_lazy) 2883let check_partial = check_partial is_mutable is_lazy 2884 2885(* have toplevel handler when appropriate *) 2886 2887let start_ctx n = [{left=[] ; right = omegas n}] 2888 2889let check_total total lambda i handler_fun = 2890 if jumps_is_empty total then 2891 lambda 2892 else begin 2893 Lstaticcatch(lambda, (i,[]), handler_fun()) 2894 end 2895 2896let compile_matching repr handler_fun arg pat_act_list partial = 2897 let partial = check_partial pat_act_list partial in 2898 match partial with 2899 | Partial -> 2900 let raise_num = next_raise_count () in 2901 let pm = 2902 { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list; 2903 args = [arg, Strict] ; 2904 default = [[[omega]],raise_num]} in 2905 begin try 2906 let (lambda, total) = compile_match repr partial (start_ctx 1) pm in 2907 check_total total lambda raise_num handler_fun 2908 with 2909 | Unused -> assert false (* ; handler_fun() *) 2910 end 2911 | Total -> 2912 let pm = 2913 { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list; 2914 args = [arg, Strict] ; 2915 default = []} in 2916 let (lambda, total) = compile_match repr partial (start_ctx 1) pm in 2917 assert (jumps_is_empty total) ; 2918 lambda 2919 2920 2921let partial_function loc () = 2922 (* [Location.get_pos_info] is too expensive *) 2923 let (fname, line, char) = Location.get_pos_info loc.Location.loc_start in 2924 Lprim(Praise Raise_regular, [Lprim(Pmakeblock(0, Immutable, None), 2925 [transl_normal_path Predef.path_match_failure; 2926 Lconst(Const_block(0, 2927 [Const_base(Const_string (fname, None)); 2928 Const_base(Const_int line); 2929 Const_base(Const_int char)]))], loc)], loc) 2930 2931let for_function loc repr param pat_act_list partial = 2932 compile_matching repr (partial_function loc) param pat_act_list partial 2933 2934(* In the following two cases, exhaustiveness info is not available! *) 2935let for_trywith param pat_act_list = 2936 compile_matching None 2937 (fun () -> Lprim(Praise Raise_reraise, [param], Location.none)) 2938 param pat_act_list Partial 2939 2940let simple_for_let loc param pat body = 2941 compile_matching None (partial_function loc) param [pat, body] Partial 2942 2943 2944(* Optimize binding of immediate tuples 2945 2946 The goal of the implementation of 'for_let' below, which replaces 2947 'simple_for_let', is to avoid tuple allocation in cases such as 2948 this one: 2949 2950 let (x,y) = 2951 let foo = ... in 2952 if foo then (1, 2) else (3,4) 2953 in bar 2954 2955 The compiler easily optimizes the simple `let (x,y) = (1,2) in ...` 2956 case (call to Matching.for_multiple_match from Translcore), but 2957 didn't optimize situations where the rhs tuples are hidden under 2958 a more complex context. 2959 2960 The idea comes from Alain Frisch who suggested and implemented 2961 the following compilation method, based on Lassign: 2962 2963 let x = dummy in let y = dummy in 2964 begin 2965 let foo = ... in 2966 if foo then 2967 (let x1 = 1 in let y1 = 2 in x <- x1; y <- y1) 2968 else 2969 (let x2 = 3 in let y2 = 4 in x <- x2; y <- y2) 2970 end; 2971 bar 2972 2973 The current implementation from Gabriel Scherer uses Lstaticcatch / 2974 Lstaticraise instead: 2975 2976 catch 2977 let foo = ... in 2978 if foo then 2979 (let x1 = 1 in let y1 = 2 in exit x1 y1) 2980 else 2981 (let x2 = 3 in let y2 = 4 in exit x2 y2) 2982 with x y -> 2983 bar 2984 2985 The catch/exit is used to avoid duplication of the let body ('bar' 2986 in the example), on 'if' branches for example; it is useless for 2987 linear contexts such as 'let', but we don't need to be careful to 2988 generate nice code because Simplif will remove such useless 2989 catch/exit. 2990*) 2991 2992let rec map_return f = function 2993 | Llet (str, k, id, l1, l2) -> Llet (str, k, id, l1, map_return f l2) 2994 | Lletrec (l1, l2) -> Lletrec (l1, map_return f l2) 2995 | Lifthenelse (lcond, lthen, lelse) -> 2996 Lifthenelse (lcond, map_return f lthen, map_return f lelse) 2997 | Lsequence (l1, l2) -> Lsequence (l1, map_return f l2) 2998 | Levent (l, ev) -> Levent (map_return f l, ev) 2999 | Ltrywith (l1, id, l2) -> Ltrywith (map_return f l1, id, map_return f l2) 3000 | Lstaticcatch (l1, b, l2) -> 3001 Lstaticcatch (map_return f l1, b, map_return f l2) 3002 | Lstaticraise _ | Lprim(Praise _, _, _) as l -> l 3003 | l -> f l 3004 3005(* The 'opt' reference indicates if the optimization is worthy. 3006 3007 It is shared by the different calls to 'assign_pat' performed from 3008 'map_return'. For example with the code 3009 let (x, y) = if foo then z else (1,2) 3010 the else-branch will activate the optimization for both branches. 3011 3012 That means that the optimization is activated if *there exists* an 3013 interesting tuple in one hole of the let-rhs context. We could 3014 choose to activate it only if *all* holes are interesting. We made 3015 that choice because being optimistic is extremely cheap (one static 3016 exit/catch overhead in the "wrong cases"), while being pessimistic 3017 can be costly (one unnecessary tuple allocation). 3018*) 3019 3020let assign_pat opt nraise catch_ids loc pat lam = 3021 let rec collect acc pat lam = match pat.pat_desc, lam with 3022 | Tpat_tuple patl, Lprim(Pmakeblock _, lams, _) -> 3023 opt := true; 3024 List.fold_left2 collect acc patl lams 3025 | Tpat_tuple patl, Lconst(Const_block(_, scl)) -> 3026 opt := true; 3027 let collect_const acc pat sc = collect acc pat (Lconst sc) in 3028 List.fold_left2 collect_const acc patl scl 3029 | _ -> 3030 (* pattern idents will be bound in staticcatch (let body), so we 3031 refresh them here to guarantee binders uniqueness *) 3032 let pat_ids = pat_bound_idents pat in 3033 let fresh_ids = List.map (fun id -> id, Ident.rename id) pat_ids in 3034 (fresh_ids, alpha_pat fresh_ids pat, lam) :: acc 3035 in 3036 3037 (* sublets were accumulated by 'collect' with the leftmost tuple 3038 pattern at the bottom of the list; to respect right-to-left 3039 evaluation order for tuples, we must evaluate sublets 3040 top-to-bottom. To preserve tail-rec, we will fold_left the 3041 reversed list. *) 3042 let rev_sublets = List.rev (collect [] pat lam) in 3043 let exit = 3044 (* build an Ident.tbl to avoid quadratic refreshing costs *) 3045 let add t (id, fresh_id) = Ident.add id fresh_id t in 3046 let add_ids acc (ids, _pat, _lam) = List.fold_left add acc ids in 3047 let tbl = List.fold_left add_ids Ident.empty rev_sublets in 3048 let fresh_var id = Lvar (Ident.find_same id tbl) in 3049 Lstaticraise(nraise, List.map fresh_var catch_ids) 3050 in 3051 let push_sublet code (_ids, pat, lam) = simple_for_let loc lam pat code in 3052 List.fold_left push_sublet exit rev_sublets 3053 3054let for_let loc param pat body = 3055 match pat.pat_desc with 3056 | Tpat_any -> 3057 (* This eliminates a useless variable (and stack slot in bytecode) 3058 for "let _ = ...". See #6865. *) 3059 Lsequence(param, body) 3060 | Tpat_var (id, _) -> 3061 (* fast path, and keep track of simple bindings to unboxable numbers *) 3062 let k = Typeopt.value_kind pat.pat_env pat.pat_type in 3063 Llet(Strict, k, id, param, body) 3064 | _ -> 3065 let opt = ref false in 3066 let nraise = next_raise_count () in 3067 let catch_ids = pat_bound_idents pat in 3068 let bind = map_return (assign_pat opt nraise catch_ids loc pat) param in 3069 if !opt then Lstaticcatch(bind, (nraise, catch_ids), body) 3070 else simple_for_let loc param pat body 3071 3072(* Handling of tupled functions and matchings *) 3073 3074(* Easy case since variables are available *) 3075let for_tupled_function loc paraml pats_act_list partial = 3076 let partial = check_partial_list pats_act_list partial in 3077 let raise_num = next_raise_count () in 3078 let omegas = [List.map (fun _ -> omega) paraml] in 3079 let pm = 3080 { cases = pats_act_list; 3081 args = List.map (fun id -> (Lvar id, Strict)) paraml ; 3082 default = [omegas,raise_num] 3083 } in 3084 try 3085 let (lambda, total) = compile_match None partial 3086 (start_ctx (List.length paraml)) pm in 3087 check_total total lambda raise_num (partial_function loc) 3088 with 3089 | Unused -> partial_function loc () 3090 3091 3092 3093let flatten_pattern size p = match p.pat_desc with 3094| Tpat_tuple args -> args 3095| Tpat_any -> omegas size 3096| _ -> raise Cannot_flatten 3097 3098let rec flatten_pat_line size p k = match p.pat_desc with 3099| Tpat_any -> omegas size::k 3100| Tpat_tuple args -> args::k 3101| Tpat_or (p1,p2,_) -> flatten_pat_line size p1 (flatten_pat_line size p2 k) 3102| Tpat_alias (p,_,_) -> (* Note: if this 'as' pat is here, then this is a 3103 useless binding, solves PR #3780 *) 3104 flatten_pat_line size p k 3105| _ -> fatal_error "Matching.flatten_pat_line" 3106 3107let flatten_cases size cases = 3108 List.map 3109 (fun (ps,action) -> match ps with 3110 | [p] -> flatten_pattern size p,action 3111 | _ -> fatal_error "Matching.flatten_case") 3112 cases 3113 3114let flatten_matrix size pss = 3115 List.fold_right 3116 (fun ps r -> match ps with 3117 | [p] -> flatten_pat_line size p r 3118 | _ -> fatal_error "Matching.flatten_matrix") 3119 pss [] 3120 3121let flatten_def size def = 3122 List.map 3123 (fun (pss,i) -> flatten_matrix size pss,i) 3124 def 3125 3126let flatten_pm size args pm = 3127 {args = args ; cases = flatten_cases size pm.cases ; 3128 default = flatten_def size pm.default} 3129 3130 3131let flatten_precompiled size args pmh = match pmh with 3132| Pm pm -> Pm (flatten_pm size args pm) 3133| PmOr {body=b ; handlers=hs ; or_matrix=m} -> 3134 PmOr 3135 {body=flatten_pm size args b ; 3136 handlers= 3137 List.map 3138 (fun (mat,i,vars,pm) -> flatten_matrix size mat,i,vars,pm) 3139 hs ; 3140 or_matrix=flatten_matrix size m ;} 3141| PmVar _ -> assert false 3142 3143(* 3144 compiled_flattened is a ``comp_fun'' argument to comp_match_handlers. 3145 Hence it needs a fourth argument, which it ignores 3146*) 3147 3148let compile_flattened repr partial ctx _ pmh = match pmh with 3149| Pm pm -> compile_match repr partial ctx pm 3150| PmOr {body=b ; handlers=hs} -> 3151 let lam, total = compile_match repr partial ctx b in 3152 compile_orhandlers (compile_match repr partial) lam total ctx hs 3153| PmVar _ -> assert false 3154 3155let do_for_multiple_match loc paraml pat_act_list partial = 3156 let repr = None in 3157 let partial = check_partial pat_act_list partial in 3158 let raise_num,pm1 = 3159 match partial with 3160 | Partial -> 3161 let raise_num = next_raise_count () in 3162 raise_num, 3163 { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list; 3164 args = [Lprim(Pmakeblock(0, Immutable, None), paraml, loc), Strict]; 3165 default = [[[omega]],raise_num] } 3166 | _ -> 3167 -1, 3168 { cases = List.map (fun (pat, act) -> ([pat], act)) pat_act_list; 3169 args = [Lprim(Pmakeblock(0, Immutable, None), paraml, loc), Strict]; 3170 default = [] } in 3171 3172 try 3173 try 3174(* Once for checking that compilation is possible *) 3175 let next, nexts = split_precompile None pm1 in 3176 3177 let size = List.length paraml 3178 and idl = List.map (fun _ -> Ident.create "match") paraml in 3179 let args = List.map (fun id -> Lvar id, Alias) idl in 3180 3181 let flat_next = flatten_precompiled size args next 3182 and flat_nexts = 3183 List.map 3184 (fun (e,pm) -> e,flatten_precompiled size args pm) 3185 nexts in 3186 3187 let lam, total = 3188 comp_match_handlers 3189 (compile_flattened repr) 3190 partial (start_ctx size) () flat_next flat_nexts in 3191 List.fold_right2 (bind Strict) idl paraml 3192 (match partial with 3193 | Partial -> 3194 check_total total lam raise_num (partial_function loc) 3195 | Total -> 3196 assert (jumps_is_empty total) ; 3197 lam) 3198 with Cannot_flatten -> 3199 let (lambda, total) = compile_match None partial (start_ctx 1) pm1 in 3200 begin match partial with 3201 | Partial -> 3202 check_total total lambda raise_num (partial_function loc) 3203 | Total -> 3204 assert (jumps_is_empty total) ; 3205 lambda 3206 end 3207 with Unused -> 3208 assert false (* ; partial_function loc () *) 3209 3210(* #PR4828: Believe it or not, the 'paraml' argument below 3211 may not be side effect free. *) 3212 3213let param_to_var param = match param with 3214| Lvar v -> v,None 3215| _ -> Ident.create "match",Some param 3216 3217let bind_opt (v,eo) k = match eo with 3218| None -> k 3219| Some e -> Lambda.bind Strict v e k 3220 3221let for_multiple_match loc paraml pat_act_list partial = 3222 let v_paraml = List.map param_to_var paraml in 3223 let paraml = List.map (fun (v,_) -> Lvar v) v_paraml in 3224 List.fold_right bind_opt v_paraml 3225 (do_for_multiple_match loc paraml pat_act_list partial) 3226