Caml1999I031a[#Tmc'rewriteY@&Lambda&lambda@@@&lambda@@@@@@.lambda/tmc.mliQ [ [Q [ y@@B@@%#Tmc0:(d)2"Y(Warnings0Ӷ.5S6V%Types0AF3Ai4.Type_immediacy0Xp '%Subst00gDQ,Wp -Stdlib__Uchar0 |K?bޣ ˠ.Stdlib__String0L%BWx:6+Stdlib__Set0PSVl8 ;+Stdlib__Seq0yt\eǟ&Q,}+Stdlib__Map0ҭfȨ؜ׇ0.Stdlib__Lexing0zsc\ZoQ,Stdlib__Lazy0'rruSZY/Stdlib__Hashtbl0!z9ϸ@`VǠ.Stdlib__Format0=z+.m׸.Stdlib__Either0 }rCT0J){9).Stdlib__Digest0@~8x2.Stdlib__Buffer0'ON͋[h#ڗA&Stdlib0>,W:(%Shape0-#\wz5)Primitive0.>}7Fmd*ՠ$Path0"nA_8K 1)Parsetree03p雲Ҳ$+Outcometree0xHU ͧTƠ$Misc0KH(1Xk5o\)Longident0{C 3C(Location0>gc 7پI{YG)Load_path0@d0X&Lambda0A x~72~,Identifiable0g+AbڀO"q,%Ident0T;~-1ѡ#Env0T\$nd-0qbҠ)Debuginfo0[Q;k SWVӠ*Cmi_format0d S[@0CamlinternalLazy0G -Ϥ;I8CamlinternalFormatBasics0cEXy [] | x :: xs -> let y = f x in y :: map f xs |} becomes (expressed in almost-source-form; the translation is in fact at the Lambda-level) {| let rec map f = function | [] -> [] | x :: xs -> let y = f x in let dst = y :: Placeholder in map_dps dst 1 f xs; dst and map_dps dst offset f = function | [] -> dst.offset <- [] | x :: xs -> let y = f x in let dst' = y :: Placeholder in dst.offset <- dst'; map_dps dst 1 f fx |} In this example, the expression (y :: map f xs) had a call in non-tail-position, and it gets rewritten into tail-calls. TMC handles all such cases where the continuation of the call (what needs to be done after the return) is a "construction", the creation of a (possibly nested) data block. The code transformation generates two versions of the input function, the "direct" version with the same type and behavior as the original one (here just [map]), and the "destination-passing-style" version (here [map_dps]). Any call to the original function from outside the let..rec declaration gets transformed into a call into the direct version, which will itself call the destination-passing-style versions on recursive calls that may benefit from it (they are in tail-position modulo constructors). Because of this inherent code duplication, the transformation may not always improve performance. In this implementation, TMC is opt-in, we only transform functions that the user has annotated with an attribute to request the transformation. BXRRCM J L@@@@@@Aࠐ&Lambda&LambdaPO N SQO N Y@@A0ONNOOOOO@N @AUO N N@@S@'rewriteX_Q [ _`Q [ f@б@г&lambdajQ [ ikQ [ o@@ @@@ d@@г*&lambdawQ [ sxQ [ y@@ @@@ e*@@@@@ f-@@@Q [ [ @@B@ @@3@,@@0@6. @A@ H************************************************************************A@@A@L@ H BMMBM@ H OCaml CC@ H DD3@ J Frédéric Bour E44E4@ H Gabriel Scherer, projet Partout, INRIA Saclay FF@ I Basile Clément, projet Cambium, INRIA Paris GG@ H HHj@ H Copyright 2020 Institut National de Recherche en Informatique et IkkIk@ H en Automatique. JJ@ H KKQ@ H All rights reserved. This file is distributed under the terms of LRRLR@ H the GNU Lesser General Public License version 2.1, with the MM@ H special exception on linking described in the file LICENSE. NN8@ H O99O9@ H************************************************************************PP@ x* Tail-modulo-cons optimization. {b Warning:} this module is unstable and part of {{!Compiler_libs}compiler-libs}.  * TMC (Tail Modulo Cons) is a code transformation that rewrites transformed functions in destination-passing-style, in such a way that certain calls that were not in tail position in the original program become tail-calls in the transformed program. As a classic example, the following program {| let[@tail_mod_cons] rec map f = function | [] -> [] | x :: xs -> let y = f x in y :: map f xs |} becomes (expressed in almost-source-form; the translation is in fact at the Lambda-level) {| let rec map f = function | [] -> [] | x :: xs -> let y = f x in let dst = y :: Placeholder in map_dps dst 1 f xs; dst and map_dps dst offset f = function | [] -> dst.offset <- [] | x :: xs -> let y = f x in let dst' = y :: Placeholder in dst.offset <- dst'; map_dps dst 1 f fx |} In this example, the expression (y :: map f xs) had a call in non-tail-position, and it gets rewritten into tail-calls. TMC handles all such cases where the continuation of the call (what needs to be done after the return) is a "construction", the creation of a (possibly nested) data block. The code transformation generates two versions of the input function, the "direct" version with the same type and behavior as the original one (here just [map]), and the "destination-passing-style" version (here [map_dps]). Any call to the original function from outside the let..rec declaration gets transformed into a call into the direct version, which will itself call the destination-passing-style versions on recursive calls that may benefit from it (they are in tail-position modulo constructors). Because of this inherent code duplication, the transformation may not always improve performance. In this implementation, TMC is opt-in, we only transform functions that the user has annotated with an attribute to request the transformation. @-./boot/ocamlc"-g)-nostdlib"-I$boot*-use-prims2runtime/primitives0-strict-sequence*-principal(-absname"-w>+a-4-9-40-41-42-44-45-48-66-70+-warn-error"+a*-bin-annot,-safe-string/-strict-formats"-I%utils"-I'parsing"-I&typing"-I(bytecomp"-I,file_formats"-I&lambda"-I*middle_end"-I2middle_end/closure"-I2middle_end/flambda"-I=middle_end/flambda/base_types"-I'asmcomp"-I&driver"-I(toplevel"-c */home/barsac/ci/builds/workspace/bootstrap - @0ZRgLfC*0-,,-----@+@@(Asttypes0{EX P5Build_path_prefix_map0 5 ttY8CamlinternalFormatBasics0cEXygc 7پI{YG)Longident0{C 3C$Misc0KH(1Xk5o\+Outcometree0xHU ͧTƠ)Parsetree03p雲Ҳ$$Path0"nA_8K 1)Primitive0.>}7Fmd*ՠ%Shape0-#\wz5&Stdlib0>,W:(.Stdlib__Buffer0'ON͋[h#ڗA.Stdlib__Digest0@~8x2.Stdlib__Either0 }rCT0J){9).Stdlib__Format0=z+.m׸/Stdlib__Hashtbl0!z9ϸ@`VǠ,Stdlib__Lazy0'rruSZY.Stdlib__Lexing0zsc\ZoQ+Stdlib__Map0ҭfȨ؜ׇ0+Stdlib__Seq0yt\eǟ&Q,}+Stdlib__Set0PSVl8 ;.Stdlib__String0L%BWx:6-Stdlib__Uchar0 |K?bޣ ˠ%Subst00gDQ,Wp 0:(d)2"Y.Type_immediacy0Xp '%Types0AF3Ai4(Warnings0Ӷ.5S6V@0:(d)2"YAA@ji@@@@@@@@@@@@@@@@@P@