Constant project_init::includes::RECO_RULES [] [src]

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"