diff --git a/common.typ b/common.typ index 50ea9ce..3cf96d1 100644 --- a/common.typ +++ b/common.typ @@ -212,6 +212,22 @@ ] } +#let spoiler(content) = { + [#context if is-html() { + html-style(class:"hide", "", content) + } else { + content + }] +} + +#let inline-block(content) = { + [#context if is-html() { + html-style("white-space:nowrap;", content) + } else { + block(breakable:false, content) + }] +} + #let table-of-contents() = { html-style(class:"table-of-contents", "", box( stroke: black, @@ -235,14 +251,18 @@ ] }) ])) + html-style(class:"table-of-contents", "", html-script-dom-onload(" - let tags = ['h2','h3','h4'].flatMap(x => Array.from(document.getElementsByTagName(x))); - document.getElementById('headingr-0').classList.add('current') - document.addEventListener('scroll', (event) => { - let curr = tags.map(x => [x, (x.getBoundingClientRect().top + x.getBoundingClientRect().bottom) / 2]).filter(x => x[1] >= 0).sort((a,b) => a[1] > b[1])[0][0]; - let idx = tags.sort((a,b) => a.getBoundingClientRect().top > b.getBoundingClientRect().top).map((x, idx) => [idx, x]).filter(x => x[1] == curr)[0][0]; - Array.from(document.getElementsByClassName('headingr')).map(x => x.classList.remove('current')) - document.getElementById('headingr-'+idx).classList.add('current') - }); +let tags = ['h2', 'h3', 'h4'].flatMap(x => Array.from(document.getElementsByTagName(x))).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top); +let pageHeight = document.documentElement.scrollHeight-window.innerHeight; +document.addEventListener('scroll', (event) => { + let progress = -(document.documentElement.getBoundingClientRect().y / pageHeight); + let delta = progress * window.innerHeight; + let idx = tags.map(x => 0 > x.getBoundingClientRect().top - delta).lastIndexOf(true); + Array.from(document.getElementsByClassName('headingr')).map(x => x.classList.remove('current')); + if (idx != -1) { + document.getElementById('headingr-' + idx).classList.add('current'); + } +} +); ") + [ #context if is-html() { html.elem("style", " diff --git a/pages/compiler-pattern-matching.typ b/pages/compiler-pattern-matching.typ index b879846..a1cf7c0 100644 --- a/pages/compiler-pattern-matching.typ +++ b/pages/compiler-pattern-matching.typ @@ -59,7 +59,7 @@ Doing pattern matching this way has many disadvantages. \ - Some (but not all) disadvantages: + Some (but not all): - debugging pattern match rules can be hard - IR rewrites need to be tracked manually (for debugging) - source locations and debug information also need to be tracked manually, which often isn't implemented very well. @@ -166,7 +166,7 @@ - the compiler could AOT compile patterns - the compiler could optimize, analyze, and combine patterns to reduce compile time. - IR (de-)serialization infrastructure in the compiler can also be used to exchange peephole optimizations. - - bragging rights: your compiler represents it's own patterns in it's own IR + - bragging rights: your compiler represents its patterns in it's own IR ] #section[ @@ -177,6 +177,29 @@ The advantage of this over just having a rewrite dialect is that it makes patterns even more readable (and maintainable!) ] +#section[ + == egg + Some people might say: "bUt Im JuSt GoInG tO uSe EgG, i DoNt NeEd A pAtTeRn MaTcHiNg DiAlEcT" + (specifically #spoiler[otesunki] said something like that) + + #flink("https://egraphs-good.github.io/")[egg] is a IR pattern matching and transformation library + that uses #inline-block(flink("https://en.wikipedia.org/wiki/E-graph")[E-Graphs]) to + magically solves (almost) all problems regarding IR pattern matching. + + Even though egg solves most problems, I still recommend using a pattern matching dialect, especially in multi-level compilers, + to be more flexible, and have more future-proof pattern matching, if for example there suddenly is a better alternative to egg, + or you decide that you want to match some complex patterns manually. +] + +#section[ + A problem with using egg in combination with pattern matching dialects is that it might be harder + to write the code to convert the pattern matching dialect to egg patterns. + + Additionally, some more complex transformations (not the matches) can't always be directly converted to egg transformations + (depending on the feature set provided by the transformation dialect), + but that can be solved by using a custom ```rust egg::Applier``` +] + #section[ = More Advantages of Structured Pattern Matching @@ -192,7 +215,7 @@ #section[ == Reversible Transformations I don't think that there currently is any compiler that does this. - If you do know one, again, please #flink(alex_contact_url)[contact me.] + If you do know one, again, please contact me. ] #section[ @@ -207,7 +230,7 @@ #section[ This is not just the case for "low-level" things like bit tests, but also high level concepts, like a reduction over an array, or even the implementation of a whole algorithm. - For example LLVM, since recently, can detect implementations of #flink("https://en.wikipedia.org/wiki/Cyclic_redundancy_check")[CRC]. + For example LLVM, since recently, can detect implementations of #flink("https://en.wikipedia.org/wiki/Cyclic_redundancy_check")[CRC.] ] #section[ @@ -244,6 +267,54 @@ I don't think any compiler currently does this either. ] +#section[ + = Problems with Pattern Matching + The main problem is ordering the patterns. + + As an example, consider these three patterns: + #context html-frame[```lisp + ;; A + (add x:Const y) => (add y x) + + ;; B + (sub (add x y:Const) z:Const) => (lea x y (const_neg z)) + + ;; C + (add x 1) => (inc x) + ```] +] + +#section[ + Now what should the compiler do when it sees this? + #context html-frame[```lisp (sub (add 5 1) 2)```] +] + +#section[ + All three patterns would match: + #context html-frame[```lisp + ;; apply A + (sub (add 5 1) 2) => (sub (add 1 5) 2) + ;; only B applies now + (sub (add 1 5) 2) => (lea 1 5 (const_neg 2)) + ;; nothing applies anymore + + ;; alternatively apply B + (sub (add 5 1) 2) => (lea 5 1 (const_neg 2)) + ;; nothing applies anymore + + ;; atlernatively apply C + (sub (add 5 1) 2) => (sub (inc 5) 2) + ;; nothing applies anymore + ```] +] + +#section[ + Now which of those transformations should be performed? + + This is not as easy to solve as it seems, especially in the context of instruction selection (specifically scheduling), + where the performance on processors depends on a sequence of instructions, instead of just a single instruction. +] + #section[ = Conclusion One can see how pattern matching dialects are the best option by far. diff --git a/simple-page-layout.typ b/simple-page-layout.typ index 19c40be..eabaf1c 100644 --- a/simple-page-layout.typ +++ b/simple-page-layout.typ @@ -60,6 +60,9 @@ width: 100% !important; } } + + .hide { display: inline; background: black; transition: background 0.3s linear; } + .hide:hover, .hide:focus { background: transparent; } ") }], )),