pub const RECO_RULES: &'static str =
"--\n-- Default optimisation rules for production code.\n-- Only \'known good\' rules should be include here.\n--\n\nlet\n\n min a b = if a < b then a else b\n max a b = if a > b then a else b\n\n all f ls = and (map f ls)\n any f ls = or (map f ls)\n\n rSlice l = sliceFromOW l.rOffset l.width\n wSlice l = sliceFromOW l.wOffset l.width\n\n -- Specifies the link type.\n isTokenLink l = l.width == 0\n isDataLink l = l.width /= 0\n\n -- Specifies that slice B is a narrowing subset of slice A.\n isSubSlice sliceA sliceB =\n (sliceA.offset <= sliceB.offset) &&\n ((sliceA.offset + sliceA.width) >= (sliceB.offset + sliceB.width))\n\n -- Specifies that slice B is the same as slice A.\n isSameSlice sliceA sliceB =\n (sliceA.offset == sliceB.offset) &&\n (sliceA.width == sliceB.width)\n\n -- Specifies that slice B and slice A are adjacent or overlapping.\n isContiguousSlice sliceA sliceB =\n ((sliceA.offset + sliceA.width) >= sliceB.offset) ||\n ((sliceB.offset + sliceB.width) >= sliceA.offset)\n\n -- Determines the offset of a contiguous combined slice.\n contiguousOffset sliceA sliceB =\n min sliceA.offset sliceB.offset\n\n -- Determines the width of a contiguous combined slice.\n contiguousWidth sliceA sliceB =\n (max (sliceA.offset + sliceA.width) (sliceB.offset + sliceB.width)) -\n (min sliceA.offset sliceB.offset)\n\n--\n-- This rule set strips out redundant single input to single output flow\n-- control components.\n--\nrule fal \"remove F aliases\"\n from\n f1: F (i, [o])\n when\n o.fOffset == 0 && i.width == o.width\n alias i => o\n\nrule sal \"remove S aliases\"\n from\n s1: S (i, [o])\n when\n i.width == o.width\n alias i => o\n\nrule jal \"remove J aliases\"\n from\n j1: J ([i], o)\n alias i => o\n\nrule mal \"remove M aliases\"\n from\n m1: M ([i], o)\n alias i => o\n\n--\n-- This rule set performs merging of multiple adjacent \'narrow\' flow control\n-- components into a single \'wide\' flow control component.\n--\nrule ff \"collapse connected Fs\"\n from\n f1: F (_, [...,i,...])\n f2: F (i, f2o)\n to\n f1: F (_, [...,f2o\',...])\n where\n f2o\' = f2o { fOffset = if width == 0 then 0 else fOffset + i.fOffset }\n\nrule mm \"collapse connected Ms\"\n from\n m1: M ([...,i,...], _)\n m2: M (mi, i)\n to\n m1: M ([...,mi,...], _)\n\nrule jj \"collapse connected Js\"\n from\n j1: J ([...,i,...], _)\n j2: J (ji, i)\n to\n j1: J ([...,ji,...], _)\n\n--\n-- This rule set trims the output widths of various components when followed\n-- by a narrowing single output fork.\n--\nrule nsf \"narrow S outputs\"\n from\n s1: S (_, [...,i,...])\n f1: F (i, [j])\n to\n s1: S (_, [...,j\',...])\n where\n j\' = j { sImps = i.sImps, sOffset = i.sOffset + j.fOffset }\n\n--\n-- This rule merges identical directly connected steer/merge links.\n--\nrule sm \"merge shared S-M links\"\n from\n s1: S (_, [...,i,...,j,...])\n m1: M ([...,i,...,j,...], _) permute (i, j)\n when\n i.width == j.width &&\n i.sOffset == j.sOffset\n to\n s1: S (_, [k,...,...,...])\n m1: M ([k,...,...,...], _)\n where\n k = newlink { width = i.width, sImps = i.sImps ++ j.sImps, sOffset = i.sOffset }\n\n--\n-- Remove redundant indirect F-J token links (token link first).\n--\nrule fji1 \"remove redundant F-J token links\"\n from\n f1: F (_, [...,i,...,j,...]) permute (i, j)\n j1: J ([...,i,...,jd,...], _)\n j -|-> jd\n when\n isTokenLink i\n to\n f1: F (_, [...,...,j,...])\n j1: J ([...,...,jd,...], _)\n\n--\n-- Remove redundant indirect F-J token links (token link second).\n--\nrule fji2 \"remove redundant F-J token links\"\n from\n f1: F (_, [...,j,...,i,...]) permute (i, j)\n j1: J ([...,jd,...,i,...], _)\n j -|-> jd\n when\n isTokenLink i\n to\n f1: F (_, [...,j,...,...])\n j1: J ([...,jd,...,...], _)\n\n--\n-- Push control line forks back to operator inputs.\n--\nrule fo \"move Fs through Os\"\n from\n o1: O (oi, oo)\n f1: F (oo, [fol:...,fo,for:...])\n when\n isTokenLink fo &&\n fol ++ for /= []\n to\n o1: O (oi\', oo)\n f1: F (oo, [fol,for])\n f2: F (oi, [oi\',fo])\n where\n oi\' = newlink { width = oi.width, fOffset = 0 }\n\n--\n-- These rules convert cascaded variable reads into parallel accesses on the\n-- same variable.\n--\nrule vrrc1 \"parallelise reads on same V\"\n from\n v1: V ([wgs:...], _, [rgl:...,rg1,rgm:...,rg2,...], [rdl:...,rd1,rdm:...,rd2,...])\n f1: F (rd1, [fol:...,fo,for:...])\n fo -|-> rg2 excluding (wgs)\n when\n length rgl == length rdl &&\n length rgm == length rdm &&\n isTokenLink fo &&\n fol ++ for /= []\n to\n v1: V ([wgs], _, [rgl,rg1\',rgm,rg2,...], [rdl,rd1,rdm,rd2,...])\n f1: F (rd1, [fol,for])\n f2: F (rg1, [rg1\',fo])\n where\n rg1\' = newlink { width = 0, fOffset = 0 }\n\nrule vrrc2 \"parallelise reads on same V\"\n from\n v1: V ([wgs:...], _, [rgl:...,rg2,rgm:...,rg1,...], [rdl:...,rd2,rdm:...,rd1,...])\n f1: F (rd1, [fol:...,fo,for:...])\n fo -|-> rg2 excluding (wgs)\n when\n length rgl == length rdl &&\n length rgm == length rdm &&\n isTokenLink fo &&\n fol ++ for /= []\n to\n v1: V ([wgs], _, [rgl,rg2,rgm,rg1\',...], [rdl,rd2,rdm,rd1,...])\n f1: F (rd1, [fol,for])\n f2: F (rg1, [rg1\',fo])\n where\n rg1\' = newlink { width = 0, fOffset = 0 }\n\n--\n-- This rule converts cascaded variable reads into parallel accesses on\n-- independent variables.\n--\nrule vrrc3 \"parallelise reads on different Vs\"\n from\n v1: V ([wgs1:...], _, [rg1l:...,rg1,...], [rd1l:...,rd1,...])\n f1: F (rd1, [fol:...,rg2,for:...])\n v2: V ([wgs2:...], _, [rg2l:...,rg2,...], [rd2l:...,rd2,...])\n when\n length rg1l == length rd1l &&\n length rg2l == length rd2l &&\n fol ++ for /= []\n to\n v1: V ([wgs1], _, [rg1l,rg1\',...], [rd1l,rd1,...])\n v2: V ([wgs2], _, [rg2l,rg2,...], [rd2l,rd2,...])\n f1: F (rd1, [fol,for])\n f2: F (rg1, [rg1\',rg2])\n where\n rg1\' = newlink { width = 0, fOffset = 0 }\n\n--\n-- Push control line forks back to join inputs (2 input version).\n--\nrule fcj \"move control F\'s through J\'s\"\n from\n j1: J ([ji1,ji2], jo)\n f1: F (jo, [fol:...,fo,for:...])\n when\n isTokenLink fo &&\n fol ++ for /= []\n to\n f2: F (ji1, [fo1,ji1f])\n f3: F (ji2, [fo2,ji2f])\n j1: J ([ji1f,ji2f], jo)\n f1: F (jo, [fol,for])\n j2: J ([fo1,fo2], fo)\n where\n fo1 = newlink { width = 0, fOffset = 0 }\n fo2 = newlink { width = 0, fOffset = 0 }\n ji1f = newlink { width = ji1.width, fOffset = 0 }\n ji2f = newlink { width = ji2.width, fOffset = 0 }\n\n--\n-- Push control line joins forward to operator outputs.\n--\nrule jo \"move Js through Os\"\n from\n j1: J ([jil:...,ji,jir:...], oi)\n o1: O (oi, oo)\n when\n isTokenLink ji &&\n jil ++ jir /= []\n to\n j1: J ([jil,jir], oi)\n o1: O (oi, oo\')\n j2: J ([oo\',ji], oo)\n where\n oo\' = newlink { width = oo.width }\n\n--\n-- This rule removes variable read ports where the \'read go\' is indirectly\n-- connected to the \'write done\'.\n--\nrule tvn \"trim V read ports\"\n from\n v1: V ([wgl:...,wg,wgr:...], [wdl:...,wd,...], [rgl:...,rg,rgr:...], [rdl:...,rd,...])\n wd -|-> rg excluding (wgl,wg,wgr)\n when\n length wgl == length wdl &&\n length rgl == length rdl &&\n isSubSlice (wSlice wg) (rSlice rd) &&\n rgl ++ rgr /= []\n to\n f1: F (wg, [wgf,rdf])\n v1: V ([wgl,wgf,wgr], [wdl,wdv,...], [rgl,rgr], [rdl,...])\n j1: J ([rdf,rg,wdf], rd)\n f2: F (wdv, [wd\',wdf])\n where\n wdv = newlink { width = 0 }\n wdf = newlink { width = 0, fOffset = 0 }\n wd\' = wd { fOffset = 0 }\n wgf = newlink { width = wg.width, fOffset = 0, wOffset = wg.wOffset }\n rdf = newlink { width = rd.width, fOffset = (rd.rOffset - wg.wOffset) }\n\n--\n-- This rule removes variables with a single write port and single read port\n-- where the \'read go\' is indirectly connected to the \'write done\'. Such a\n-- situation arises when intermediate variables are used in a calculation.\n-- Leaves a parallel fork/join control path in the dataflow graph which may\n-- then be optimised out.\n--\nrule svi \"remove indirect `buffer\' Vs\"\n from\n v: V ([wg], [wd], [rg], [rd])\n wd -|-> rg excluding (wg)\n when\n isSubSlice (wSlice wg) (rSlice rd)\n to\n f1: F (wg, [wd\', rd\'])\n j1: J ([rd\', rg], rd)\n where\n wd\' = wd { fOffset = 0 }\n rd\' = newlink { width = rd.width, fOffset = (rd.rOffset - wg.wOffset) }\n\n--\n-- This rule combines variable write ports which are immediately followed by\n-- a write done merge. This configuration is generated when a variable is\n-- assigned different values under different conditional branches.\n--\nrule vmw \"combine merged V write ports\"\n from\n v1: V ([wgl:...,wg1,wgm:...,wg2,...], [wdl:...,wd1,wdm:...,wd2,...], _, _)\n m1: M ([...,wd1,...,wd2,...], _) permute (wd1, wd2)\n when\n length wgl == length wdl &&\n length wgm == length wdm &&\n isSameSlice (wSlice wg1) (wSlice wg2)\n to\n v1: V ([wgl,wg\',wgm,...], [wdl,wd1,wdm,...], _, _)\n m1: M ([...,wd1,...,...], _)\n m2: M ([wg1,wg2], wg\')\n where\n wg\' = newlink { width = wg1.width, wOffset = wg1.wOffset }\n\n--\n-- This rule pushes select operations through variable read ports, which will\n-- allow common reads on different conditional branches to be merged.\n--\nrule vsr \"move Ss through V reads\"\n from\n s1: S (si, [sol:...,rg,sor:...])\n v1: V (_, _, [rgl:...,rg,rgr:...], [rdl:...,rd,rdr:...])\n when\n length rgl == length rdl &&\n length rgl + length rgr < 7\n to\n f1: F (si, [sij,rg\'])\n v1: V (_, _, [rgl,rg\',rgr], [rdl,rdj,rdr])\n j1: J ([sij,rdj], si\')\n s1: S (si\', [sol,sor,rd\'])\n where\n rg\' = rg { fOffset = 0 }\n sij = newlink { width = si.width, fOffset = 0 }\n rdj = newlink { width = rd.width, rOffset = rd.rOffset }\n si\' = newlink { width = si.width + rd.width }\n rd\' = rd { sOffset = si.width, sImps = rg.sImps }\n\n--\n-- This rule pushes select operations through variable read ports, where the\n-- variable read operation is triggered by a data fork, which will allow loop\n-- termination tests to be optimised. This works by appending the read data\n-- to the select input, so can only be applied to the select output slice\n-- which occupies the upper bit positions of the select input.\n--\nrule vsrf1 \"move Ss through forked V reads\"\n from\n s1: S (si, [sol:...,so,sor:...])\n f1: F (so, [fol:...,rg,for:...])\n v1: V (_, _, [rgl:...,rg,...], [rdl:...,rd,...])\n when\n isDataLink so &&\n so.sOffset + so.width == si.width &&\n length rgl == length rdl\n to\n f2: F (si, [sij,rg\'])\n v1: V (_, _, [rgl,rg\',...], [rdl,rdj,...])\n j1: J ([sij,rdj], si\')\n s1: S (si\', [sol,sor,so\'])\n f1: F (so\', [fol,for,rd\'])\n where\n rg\' = rg { fOffset = 0 }\n sij = newlink { width = si.width, fOffset = 0 }\n rdj = newlink { width = rd.width, rOffset = rd.rOffset }\n si\' = newlink { width = si.width + rd.width }\n so\' = newlink { width = so.width + rd.width, sOffset = so.sOffset, sImps = so.sImps }\n rd\' = rd { fOffset = so.width }\n\n--\n-- This rule pushes select operations through variable read ports, where the\n-- variable read operation is triggered by a control fork, which will allow\n-- common reads on different conditional branches to be merged.\n--\nrule vsrf2 \"move Ss through forked V reads\"\n from\n s1: S (si, [sol:...,so,sor:...])\n f1: F (so, [fol:...,rg,for:...])\n v1: V (_, _, [rgl:...,rg,...], [rdl:...,rd,...])\n when\n isTokenLink so &&\n length rgl == length rdl\n to\n f2: F (si, [sij,rg\'])\n v1: V (_, _, [rgl,rg\',...], [rdl,rdj,...])\n j1: J ([sij,rdj], si\')\n s1: S (si\', [sol,sor,so\'])\n f1: F (so\', [fol,for,rd\'])\n where\n rg\' = rg { fOffset = 0 }\n sij = newlink { width = si.width, fOffset = 0 }\n rdj = newlink { width = rd.width, rOffset = rd.rOffset }\n si\' = newlink { width = si.width + rd.width }\n so\' = newlink { width = rd.width, sOffset = si.width, sImps = so.sImps }\n rd\' = rd { fOffset = 0 }\n\n--\n-- This rule combines variable read ports which form a contiguous slice and\n-- which are accessed in parallel.\n--\nrule vcr \"combine parallel V read ports\"\n from\n f1: F (_, [fol:...,rg1,fom:...,rg2,...]) permute (rg1, rg2)\n v1: V (_, _, [rgl:...,rg1,rgm:...,rg2,...], [rdl:...,rd1,rdm:...,rd2,...])\n when\n length rgl == length rdl &&\n length rgm == length rdm &&\n isContiguousSlice (rSlice rd1) (rSlice rd2)\n to\n f1: F (_, [fol,rg1,fom,...])\n v1: V (_, _, [rgl,rg1,rgm,...], [rdl,rd\',rdm,...])\n f2: F (rd\', [rd1\',rd2\'])\n where\n rdWidth = contiguousWidth (rSlice rd1) (rSlice rd2)\n rdOffset = contiguousOffset (rSlice rd1) (rSlice rd2)\n rd\' = newlink { width = rdWidth, rOffset = rdOffset }\n rd1\' = rd1 { fOffset = rd1.rOffset - rdOffset }\n rd2\' = rd2 { fOffset = rd2.rOffset - rdOffset }\n\n--\n-- This rule splits out joined token and data signals into independent merge\n-- components, pushing the token and data join components to their output.\n--\nrule jms \"split token and data Ms\"\n from\n m1: M ([...,mi1,...,mi2,...], mo)\n j1: J ([jl1:...,i,jr1:...], mi1)\n j2: J ([jl2:...,j,jr2:...], mi2)\n when\n isTokenLink i &&\n isTokenLink j &&\n jl1 ++ jr1 /= [] &&\n jl2 ++ jr2 /= []\n to\n m1: M ([...,jo,...,...], mo)\n j1: J ([jl1,jr1], mi1)\n j2: J ([jl2,jr2], mi2)\n m2: M ([i,j], mo1)\n m3: M ([mi1,mi2], mo2)\n j3: J ([mo1,mo2], jo)\n where\n mo1 = newlink { width = 0 }\n mo2 = newlink { width = mo.width }\n jo = newlink { width = mo.width }\n\n--\n-- These rules move variable reads that are triggered by a write on another\n-- variable so that they occur in parallel with the variable write operation.\n--\nrule vwrp \"parallelise V writes and V reads\"\n from\n v1: V ([wgl:...,wg,...], [wdl:...,wd,...], _, _)\n v2: V (_, _, [rgl:...,wd,...], [rdl:...,rd,...])\n when\n length wgl == length wdl &&\n length rgl == length rdl\n to\n f1: F (wg, [rg, wg\'])\n v1: V ([wgl,wg\',...], [wdl,wd,...], _, _)\n v2: V (_, _, [rgl,rg,...], [rdl,rd\',...])\n j1: J ([wd,rd\'], rd)\n where\n rg = newlink { width = 0, fOffset = 0 }\n wg\' = newlink { width = wg.width, wOffset = wg.wOffset, fOffset = 0 }\n rd\' = newlink { width = rd.width, rOffset = rd.rOffset }\n\nrule vwrp \"parallelise V writes and forked V reads\"\n from\n v1: V ([wgl:...,wg,...], [wdl:...,wd,...], _, _)\n f1: F (wd, [...,fo,...])\n v2: V (_, _, [rgl:...,fo,...], [rdl:...,rd,...])\n when\n length wgl == length wdl &&\n length rgl == length rdl &&\n isTokenLink fo\n to\n f2: F (wg, [rg, wg\'])\n v1: V ([wgl,wg\',...], [wdl,wd,...], _, _)\n f1: F (wd, [...,fo,...])\n v2: V (_, _, [rgl,rg,...], [rdl,rd\',...])\n j1: J ([fo,rd\'], rd)\n where\n rg = newlink { width = 0, fOffset = 0 }\n wg\' = newlink { width = wg.width, wOffset = wg.wOffset, fOffset = 0 }\n rd\' = newlink { width = rd.width, rOffset = rd.rOffset }\n\n--\n-- These rules move constant generation that is triggered by a variable write\n-- completion so that it occurs in parallel with the variable write operation.\n-- Works for any operators which convert a control path input into a data path\n-- output.\n--\nrule vwcp \"parallelise V writes and O constant generation\"\n from\n v1: V ([wgl:...,wg,...], [wdl:...,wd,...], _, _)\n o1: O (wd, oo)\n when\n length wgl == length wdl\n to\n f1: F (wg, [oi, wg\'])\n v1: V ([wgl,wg\',...], [wdl,wd,...], _, _)\n o1: O (oi, oo\')\n j1: J ([wd,oo\'], oo)\n where\n oi = newlink { width = 0, fOffset = 0 }\n wg\' = newlink { width = wg.width, wOffset = wg.wOffset, fOffset = 0 }\n oo\' = newlink { width = oo.width }\n\nrule vwcpf \"parallelise V writes and forked O constant generation\"\n from\n v1: V ([wgl:...,wg,...], [wdl:...,wd,...], _, _)\n f1: F (wd, [...,fo,...])\n o1: O (fo, oo)\n when\n length wgl == length wdl &&\n isTokenLink fo\n to\n f2: F (wg, [oi, wg\'])\n v1: V ([wgl,wg\',...], [wdl,wd,...], _, _)\n f1: F (wd, [...,fo,...])\n o1: O (oi, oo\')\n j1: J ([fo,oo\'], oo)\n where\n oi = newlink { width = 0, fOffset = 0 }\n wg\' = newlink { width = wg.width, wOffset = wg.wOffset, fOffset = 0 }\n oo\' = newlink { width = oo.width }\n\n--\n-- This rule moves constant generation that is triggered by a variable read\n-- completion so that it occurs in parallel with the variable read operation.\n--\nrule vrcp \"parallelise V reads and O constant generation\"\n from\n v1: V (_, _, [rgl:...,rg,...], [rdl:...,rd,...])\n f1: F (rd, [...,fo,...])\n o1: O (fo, oo)\n when\n length rgl == length rdl &&\n isTokenLink fo\n to\n f2: F (rg, [oi, rg\'])\n v1: V (_, _, [rgl,rg\',...], [rdl,rd,...])\n f1: F (rd, [...,fo,...])\n o1: O (oi, oo\')\n j1: J ([fo,oo\'], oo)\n where\n oi = newlink { width = 0, fOffset = 0 }\n rg\' = newlink { width = 0, fOffset = 0 }\n oo\' = newlink { width = oo.width }\n\n--\n-- This rule discards any non-sideffecting operator where its result\n-- is discarded\n--\nrule of \"remove o -> control f\"\n from\n o1: O (oi, oo)\n f1: F (oo, [fo:...])\n when\n all isTokenLink fo &&\n not (any isBuiltinCall o1.terms)\n to\n f2: F (oi, [fo])\n"