From 05e73f1329b2d8088ce56b58f3b8685967577fce Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 12 Mar 2025 09:55:59 -0700 Subject: Bring back `make view` --- chapter20/Makefile | 2 +- chapter20/src/main/java/com/seaofnodes/simple/print/JSViewer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chapter20/Makefile b/chapter20/Makefile index f96cfea3..c5d8fa71 100644 --- a/chapter20/Makefile +++ b/chapter20/Makefile @@ -87,7 +87,7 @@ build/release/simple.jar: $(main_classes) $(test_classes) # Launch viewer view: $(main_classes) @echo "viewing " - @$(JVM) com.seaofnodes.simple.JSViewer + @$(JVM) com.seaofnodes.simple.print.JSViewer .PHONY: clean clean: diff --git a/chapter20/src/main/java/com/seaofnodes/simple/print/JSViewer.java b/chapter20/src/main/java/com/seaofnodes/simple/print/JSViewer.java index 76c64c71..a2b674c9 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/print/JSViewer.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/print/JSViewer.java @@ -72,7 +72,7 @@ public class JSViewer implements AutoCloseable { public static void show() { if( SERVER!=null && SHOW ) _show(); } private static void _show() { // Skip util we at least get the Parse object made - if( CODE._phase==null || CODE._phase.ordinal() < CodeGen.Phase.Parse.ordinal() ) + if( CODE._phase == null ) return; boolean midParse = CODE._phase == CodeGen.Phase.Parse; Stack xScopes = midParse ? CODE.P._xScopes : null; -- cgit v1.2.3 From dfc82c5023a0b5595b6ed198d2111bf889f5bce6 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 10:19:59 -0700 Subject: Create ASimpleReply.md --- ASimpleReply.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 ASimpleReply.md diff --git a/ASimpleReply.md b/ASimpleReply.md new file mode 100644 index 00000000..0a87acf3 --- /dev/null +++ b/ASimpleReply.md @@ -0,0 +1,52 @@ + +A Simple Reply to https://www.reddit.com/r/Compilers/comments/1jjldhu/land_ahoy_leaving_the_sea_of_nodes/ +Because reddit crashes when I try to post this. + +## prolog +I kept quiet for awhile on this one, as any response I make is going to sound either defensive or mis-aligned, and in some sense that's right. Also chat/email/IRC are terrible places to hold in-depth tech discussions. But I've had quite a number of people rise up to the defense of SoN both here and in other forums, so I finally decided to join the fray. :-P +Looking at the design choices, it seems clear to me that V8 hobbled itself from the start. V8 made a number of choices leading to a number of problems which in my mind have obvious fixes. + +## Effects +*Equivalence class aliasing* is a powerful tool, and a key part of SoN. It appears to me that V8 threw this away from the start, and then spent the next several years dealing with its lack. +#### "Too many nodes on the effects chain" +Equivalence class aliasing comes for free, literally free, in any strongly typed language. It comes directly out of the parser (be it JVM bytecodes, Simple, C), and need not be ever touched again. With it, Java/Simple/C have very sparse and clean effects chains. Definitely not "too many". +JS is *not* strongly typed, so there's an engineering tradeoff being made. I was under the believe that V8 (and other JS engines) used *specialization* aggressively to bring back strong typing in code regions; in those areas again ECA should just work directly. +#### "Managing the effect and control chains manually is hard" +Equivalence class aliasing is *directly* represented in SoN, as just normal nodes and edges. There's no special handling for it anywhere, the normal graph maintenance functions manipulate those nodes and edges just the same as they do anything else. Two nodes that might alias directly have connecting edges, nodes that do not - do not, and hence *cannot* be influenced about what happens in other alias classes. +As result of those two observations (free to obtain from strong typing, normal node/edge maintenance) this form of effect handling is been vastly simpler to build and maintain, and vastly faster to use than any other compiled I've ever worked on - and that's quite a few. 25yrs of C2 on Java shows that it can be very effective for performance and plenty fast in a JIT. + +Me thinks V8 did itself no favors here. + +## Control on Effect nodes +Guard tests for correctness: either null checks on fields or range checks on arrays. Perhaps for JS (and certainly C2/Java) also some type/specialization checks. C2 also adds a control edge to guard effect nodes. These then get optimized away (controlling edge removed) in one of two generic ways: +*Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and meet is commutative and associative.) +After a guarding test we can lift the type - using a Cast tied to the guard test, where the Cast does a lattice *join* (not *meet*). Effect nodes that need that guard pick up the Cast on the base pointer - not the control edge. If, later, we prove the Cast's *join* is useless e.g. `_t.join(in(1)._type)==_t`, the Cast constant folds away, and the effect Node can now float more freely. This analysis (comes as part of the normal c-prop) removes > 90% of Java's casting needs. +The other generic test is range-checks, which start life as a direct control edge dependency. These generally do not trivially fold away - something with all constant sizes and array indices might, but mostly no. Then C2 runs *Range Check Elimination*, a special pass just for Java safe arrays, and removes dynamically nearly all of them. I would expect to see the same come from any serious safe-language optimization. + +## Debugging +Yeah, don't use graphs to debug. Use normal ASCII dumps like the ones being shown in this article. That's what *I* do anyways. Certainly I didn't have access to fast easy graph layouts back when C2 started, I just debugged it "the normal way". +Graphs are nice for intuition but they don't scale well. That being said I've seen more recent successes in getting better graphs-for-debug scenarios (don't use D3, sucks on cycles, dump to a file; file watcher picks up and refreshes window, keep graph window visible aside of editor, etc). Maybe I'll revisit this, but for now, for me, ASCII dumps rule. + +## Complex schedule +The Click thesis scheduler missed out on anti-dependencies. C2 - and then the easier to read Simple Chapter 10 corrected this. The algorithm is fast and simple enough, no more complex than e.g. the natural loop finding version of SCC. Source code is available from Simple. + +### Late arriving control flow from expanding small "diamonds" +Yup, same solution for C2; I kept things like `min` or `max` as single pure nodes. At some late point in the game they expanded. For things as trivial as `min` which does NOT need any internal registers - I expanded them in the encoding phase post RA. For more complex things, I expanded them just after Global Code Motion brought me back to an official CFG. +In any case, this problem (and its solution) seem... trivial to me. Doesn't carry much weight on the IR choice argument; each IR has its issues all will need dozens of such "fixes". + +## Visitation order. + +#### Finding a good visitation order is hard" +Yes, so don't bother. Use a worklist! Hard guaranteed linear time to completion, fast and simple. Back-edges are needed and they are well worth the cost. I start C2 without them, couldn't get closure with a few passes, added backedges and everything got lots *faster*. Edge maintenance code deals with the work, so I don't have to think about it, its all cache-resident L1 hits. Fast, fast, fast. + +## Other things? +Dead code elimination: free with backedges; basically when the backedge/ref-count drops to zero, recursively delete nodes. There's maybe 10 lines dedicated to this in Simple. +"Hard to introduce new control flow": Hello compiler writers? Sorry, can't hardly believe this one; editing a CFG is morally the same as editing the SoN, what's the issue? In the specific `min` case, the goal is to pick a place in the CFG to expand... which means a place needs to be picked, which for SoN usually means after Global Code Motion when "places" (e.g. classic CFG) is available again. +"Hard to figure out what's inside a loop": Again, Hello compiler writers? C2 certainly does lots of aggressive loop optimizations - which start by running a standard SCC, finding loop headers, walking the graph area constrained by the loop, producing a loop body for further manipulations... yada yada. Basically, I build loops and a loop tree via the Olde Fashioned method of running SCC. +"Compiling is slow" - Compiling is fast. He-said-She-said. Neen-neener. Data? Perf discussions with facts? Apples to apples comparisons? No? So how about the "compilation speed vs code quality" didn't meet our goals? +"Cache-unfriendly" - Same (lack of) argument. Certainly when I did C2 I was highly focused on cache-friendly and based on the vast compile speedup I obtained over all competitions (at that time every AOT compiler, GCC, LLVM) I was larger successful. C2 compiles take far less footprint (both cache and memory) that my "competitors". Mostly C2 compiles, despite aggressive inlining, fit easily in L2, nearly always in L1. Getting this right is important, so I suspect other things happened to make it miss for you. But also... no numbers from me either, so neen-neener again. + +## postlog +Although I'll point out most of the above discussion is things that surely made V8's life harder - and slower - and are things I never would have done. OTOH I've not done a JS compiler, so I have no facts here also. + +Cliff -- cgit v1.2.3 From 358496a9b250a42035575af1cf9ecf33e3013f03 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 10:30:41 -0700 Subject: Update ASimpleReply.md --- ASimpleReply.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ASimpleReply.md b/ASimpleReply.md index 0a87acf3..20a377f2 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -41,9 +41,13 @@ Yes, so don't bother. Use a worklist! Hard guaranteed linear time to completio ## Other things? Dead code elimination: free with backedges; basically when the backedge/ref-count drops to zero, recursively delete nodes. There's maybe 10 lines dedicated to this in Simple. + "Hard to introduce new control flow": Hello compiler writers? Sorry, can't hardly believe this one; editing a CFG is morally the same as editing the SoN, what's the issue? In the specific `min` case, the goal is to pick a place in the CFG to expand... which means a place needs to be picked, which for SoN usually means after Global Code Motion when "places" (e.g. classic CFG) is available again. + "Hard to figure out what's inside a loop": Again, Hello compiler writers? C2 certainly does lots of aggressive loop optimizations - which start by running a standard SCC, finding loop headers, walking the graph area constrained by the loop, producing a loop body for further manipulations... yada yada. Basically, I build loops and a loop tree via the Olde Fashioned method of running SCC. + "Compiling is slow" - Compiling is fast. He-said-She-said. Neen-neener. Data? Perf discussions with facts? Apples to apples comparisons? No? So how about the "compilation speed vs code quality" didn't meet our goals? + "Cache-unfriendly" - Same (lack of) argument. Certainly when I did C2 I was highly focused on cache-friendly and based on the vast compile speedup I obtained over all competitions (at that time every AOT compiler, GCC, LLVM) I was larger successful. C2 compiles take far less footprint (both cache and memory) that my "competitors". Mostly C2 compiles, despite aggressive inlining, fit easily in L2, nearly always in L1. Getting this right is important, so I suspect other things happened to make it miss for you. But also... no numbers from me either, so neen-neener again. ## postlog -- cgit v1.2.3 From 3b26e3acdd25e3dbdb75cec49faacca62c0b15c2 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 10:36:08 -0700 Subject: Update ASimpleReply.md --- ASimpleReply.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ASimpleReply.md b/ASimpleReply.md index 20a377f2..e72e586f 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -8,9 +8,11 @@ Looking at the design choices, it seems clear to me that V8 hobbled itself from ## Effects *Equivalence class aliasing* is a powerful tool, and a key part of SoN. It appears to me that V8 threw this away from the start, and then spent the next several years dealing with its lack. + #### "Too many nodes on the effects chain" Equivalence class aliasing comes for free, literally free, in any strongly typed language. It comes directly out of the parser (be it JVM bytecodes, Simple, C), and need not be ever touched again. With it, Java/Simple/C have very sparse and clean effects chains. Definitely not "too many". JS is *not* strongly typed, so there's an engineering tradeoff being made. I was under the believe that V8 (and other JS engines) used *specialization* aggressively to bring back strong typing in code regions; in those areas again ECA should just work directly. + #### "Managing the effect and control chains manually is hard" Equivalence class aliasing is *directly* represented in SoN, as just normal nodes and edges. There's no special handling for it anywhere, the normal graph maintenance functions manipulate those nodes and edges just the same as they do anything else. Two nodes that might alias directly have connecting edges, nodes that do not - do not, and hence *cannot* be influenced about what happens in other alias classes. As result of those two observations (free to obtain from strong typing, normal node/edge maintenance) this form of effect handling is been vastly simpler to build and maintain, and vastly faster to use than any other compiled I've ever worked on - and that's quite a few. 25yrs of C2 on Java shows that it can be very effective for performance and plenty fast in a JIT. @@ -19,9 +21,9 @@ Me thinks V8 did itself no favors here. ## Control on Effect nodes Guard tests for correctness: either null checks on fields or range checks on arrays. Perhaps for JS (and certainly C2/Java) also some type/specialization checks. C2 also adds a control edge to guard effect nodes. These then get optimized away (controlling edge removed) in one of two generic ways: -*Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and meet is commutative and associative.) +(1) *Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and meet is commutative and associative.) After a guarding test we can lift the type - using a Cast tied to the guard test, where the Cast does a lattice *join* (not *meet*). Effect nodes that need that guard pick up the Cast on the base pointer - not the control edge. If, later, we prove the Cast's *join* is useless e.g. `_t.join(in(1)._type)==_t`, the Cast constant folds away, and the effect Node can now float more freely. This analysis (comes as part of the normal c-prop) removes > 90% of Java's casting needs. -The other generic test is range-checks, which start life as a direct control edge dependency. These generally do not trivially fold away - something with all constant sizes and array indices might, but mostly no. Then C2 runs *Range Check Elimination*, a special pass just for Java safe arrays, and removes dynamically nearly all of them. I would expect to see the same come from any serious safe-language optimization. +(2) The other generic test is range-checks, which start life as a direct control edge dependency. These generally do not trivially fold away - something with all constant sizes and array indices might, but mostly no. Then C2 runs *Range Check Elimination*, a special pass just for Java safe arrays, and removes dynamically nearly all of them. I would expect to see the same come from any serious safe-language optimization. ## Debugging Yeah, don't use graphs to debug. Use normal ASCII dumps like the ones being shown in this article. That's what *I* do anyways. Certainly I didn't have access to fast easy graph layouts back when C2 started, I just debugged it "the normal way". -- cgit v1.2.3 From 202a8f8ac528d304dfb67f8b0bcb8f07a4b6e20d Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 10:37:23 -0700 Subject: Update ASimpleReply.md --- ASimpleReply.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ASimpleReply.md b/ASimpleReply.md index e72e586f..4699d86a 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -21,8 +21,11 @@ Me thinks V8 did itself no favors here. ## Control on Effect nodes Guard tests for correctness: either null checks on fields or range checks on arrays. Perhaps for JS (and certainly C2/Java) also some type/specialization checks. C2 also adds a control edge to guard effect nodes. These then get optimized away (controlling edge removed) in one of two generic ways: + (1) *Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and meet is commutative and associative.) + After a guarding test we can lift the type - using a Cast tied to the guard test, where the Cast does a lattice *join* (not *meet*). Effect nodes that need that guard pick up the Cast on the base pointer - not the control edge. If, later, we prove the Cast's *join* is useless e.g. `_t.join(in(1)._type)==_t`, the Cast constant folds away, and the effect Node can now float more freely. This analysis (comes as part of the normal c-prop) removes > 90% of Java's casting needs. + (2) The other generic test is range-checks, which start life as a direct control edge dependency. These generally do not trivially fold away - something with all constant sizes and array indices might, but mostly no. Then C2 runs *Range Check Elimination*, a special pass just for Java safe arrays, and removes dynamically nearly all of them. I would expect to see the same come from any serious safe-language optimization. ## Debugging -- cgit v1.2.3 From ff88b7fc00808b91892577b1b1541908928fe3f7 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 10:50:16 -0700 Subject: Update ASimpleReply.md --- ASimpleReply.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/ASimpleReply.md b/ASimpleReply.md index 4699d86a..378c26a3 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -11,6 +11,7 @@ Looking at the design choices, it seems clear to me that V8 hobbled itself from #### "Too many nodes on the effects chain" Equivalence class aliasing comes for free, literally free, in any strongly typed language. It comes directly out of the parser (be it JVM bytecodes, Simple, C), and need not be ever touched again. With it, Java/Simple/C have very sparse and clean effects chains. Definitely not "too many". + JS is *not* strongly typed, so there's an engineering tradeoff being made. I was under the believe that V8 (and other JS engines) used *specialization* aggressively to bring back strong typing in code regions; in those areas again ECA should just work directly. #### "Managing the effect and control chains manually is hard" @@ -22,7 +23,7 @@ Me thinks V8 did itself no favors here. ## Control on Effect nodes Guard tests for correctness: either null checks on fields or range checks on arrays. Perhaps for JS (and certainly C2/Java) also some type/specialization checks. C2 also adds a control edge to guard effect nodes. These then get optimized away (controlling edge removed) in one of two generic ways: -(1) *Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and meet is commutative and associative.) +(1) *Lattice*: For null and type checks there is a Node `Type` which includes things like null-ness or sub-classing. Not-null pointers are known not-null based on the type; null checks against them constant-fold, etc. (The `Types` form a *lattice* with strong properties like symmetric, complete, bounded (ranked), and *meet* is commutative and associative.) After a guarding test we can lift the type - using a Cast tied to the guard test, where the Cast does a lattice *join* (not *meet*). Effect nodes that need that guard pick up the Cast on the base pointer - not the control edge. If, later, we prove the Cast's *join* is useless e.g. `_t.join(in(1)._type)==_t`, the Cast constant folds away, and the effect Node can now float more freely. This analysis (comes as part of the normal c-prop) removes > 90% of Java's casting needs. @@ -30,32 +31,39 @@ After a guarding test we can lift the type - using a Cast tied to the guard test ## Debugging Yeah, don't use graphs to debug. Use normal ASCII dumps like the ones being shown in this article. That's what *I* do anyways. Certainly I didn't have access to fast easy graph layouts back when C2 started, I just debugged it "the normal way". -Graphs are nice for intuition but they don't scale well. That being said I've seen more recent successes in getting better graphs-for-debug scenarios (don't use D3, sucks on cycles, dump to a file; file watcher picks up and refreshes window, keep graph window visible aside of editor, etc). Maybe I'll revisit this, but for now, for me, ASCII dumps rule. +Graphs are nice for intuition but they don't scale well. That being said I've seen more recent successes in getting better graphs-for-debug scenarios (don't use D3, sucks on cycles, dump to a file; file watcher picks up and refreshes window, keep graph window visible aside of editor, etc). Maybe I'll revisit this, but for now, for me, ASCII dumps rule. ## Complex schedule The Click thesis scheduler missed out on anti-dependencies. C2 - and then the easier to read Simple Chapter 10 corrected this. The algorithm is fast and simple enough, no more complex than e.g. the natural loop finding version of SCC. Source code is available from Simple. ### Late arriving control flow from expanding small "diamonds" Yup, same solution for C2; I kept things like `min` or `max` as single pure nodes. At some late point in the game they expanded. For things as trivial as `min` which does NOT need any internal registers - I expanded them in the encoding phase post RA. For more complex things, I expanded them just after Global Code Motion brought me back to an official CFG. + In any case, this problem (and its solution) seem... trivial to me. Doesn't carry much weight on the IR choice argument; each IR has its issues all will need dozens of such "fixes". -## Visitation order. +## Visitation order -#### Finding a good visitation order is hard" +#### "Finding a good visitation order is hard" Yes, so don't bother. Use a worklist! Hard guaranteed linear time to completion, fast and simple. Back-edges are needed and they are well worth the cost. I start C2 without them, couldn't get closure with a few passes, added backedges and everything got lots *faster*. Edge maintenance code deals with the work, so I don't have to think about it, its all cache-resident L1 hits. Fast, fast, fast. ## Other things? -Dead code elimination: free with backedges; basically when the backedge/ref-count drops to zero, recursively delete nodes. There's maybe 10 lines dedicated to this in Simple. -"Hard to introduce new control flow": Hello compiler writers? Sorry, can't hardly believe this one; editing a CFG is morally the same as editing the SoN, what's the issue? In the specific `min` case, the goal is to pick a place in the CFG to expand... which means a place needs to be picked, which for SoN usually means after Global Code Motion when "places" (e.g. classic CFG) is available again. +#### "Dead code elimination" +free with backedges; basically when the backedge/ref-count drops to zero, recursively delete nodes. There's maybe 10 lines dedicated to this in Simple. + +#### "Hard to introduce new control flow" +Hello compiler writers? Sorry, can't hardly believe this one; editing a CFG is morally the same as editing the SoN, what's the issue? In the specific `min` case, the goal is to pick a place in the CFG to expand... which means a place needs to be picked, which for SoN usually means after Global Code Motion when "places" (e.g. classic CFG) is available again. -"Hard to figure out what's inside a loop": Again, Hello compiler writers? C2 certainly does lots of aggressive loop optimizations - which start by running a standard SCC, finding loop headers, walking the graph area constrained by the loop, producing a loop body for further manipulations... yada yada. Basically, I build loops and a loop tree via the Olde Fashioned method of running SCC. +#### "Hard to figure out what's inside a loop" +Again, Hello compiler writers? C2 certainly does lots of aggressive loop optimizations - which start by running a standard SCC, finding loop headers, walking the graph area constrained by the loop, producing a loop body for further manipulations... yada yada. Basically, I build loops and a loop tree via the Olde Fashioned method of running SCC. -"Compiling is slow" - Compiling is fast. He-said-She-said. Neen-neener. Data? Perf discussions with facts? Apples to apples comparisons? No? So how about the "compilation speed vs code quality" didn't meet our goals? +#### "Compiling is slow" +Compiling is fast. He-said-She-said. Neen-neener. Data? Perf discussions with facts? Apples to apples comparisons? No? So how about "compilation speed vs code quality didn't meet our goals"? -"Cache-unfriendly" - Same (lack of) argument. Certainly when I did C2 I was highly focused on cache-friendly and based on the vast compile speedup I obtained over all competitions (at that time every AOT compiler, GCC, LLVM) I was larger successful. C2 compiles take far less footprint (both cache and memory) that my "competitors". Mostly C2 compiles, despite aggressive inlining, fit easily in L2, nearly always in L1. Getting this right is important, so I suspect other things happened to make it miss for you. But also... no numbers from me either, so neen-neener again. +#### "Cache-unfriendly" +Same (lack of) argument. Certainly when I did C2 I was highly focused on cache-friendly and based on the vast compile speedup I obtained over all competitions (at that time every AOT compiler, GCC, LLVM) I was largely successful. C2 compiles take far less footprint (both cache and memory) that my "competitors". Mostly C2 compiles, despite aggressive inlining, fit easily in L2, nearly always in L1. Getting this right is important, so I suspect other things happened to make it miss for V8. But also... no numbers from me either, so neen-neener again. ## postlog -Although I'll point out most of the above discussion is things that surely made V8's life harder - and slower - and are things I never would have done. OTOH I've not done a JS compiler, so I have no facts here also. +I'll point out most of the above discussion is things that surely made V8's life harder - and slower - and are things I never would have done. OTOH I've not done a JS compiler, so I have no facts here also. Cliff -- cgit v1.2.3 From 0d136066278e4aa80328c40036723b69c5110afd Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 26 Mar 2025 12:03:09 -0700 Subject: Update ASimpleReply.md --- ASimpleReply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ASimpleReply.md b/ASimpleReply.md index 378c26a3..ddd5fdfa 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -12,7 +12,7 @@ Looking at the design choices, it seems clear to me that V8 hobbled itself from #### "Too many nodes on the effects chain" Equivalence class aliasing comes for free, literally free, in any strongly typed language. It comes directly out of the parser (be it JVM bytecodes, Simple, C), and need not be ever touched again. With it, Java/Simple/C have very sparse and clean effects chains. Definitely not "too many". -JS is *not* strongly typed, so there's an engineering tradeoff being made. I was under the believe that V8 (and other JS engines) used *specialization* aggressively to bring back strong typing in code regions; in those areas again ECA should just work directly. +JS is *not* strongly typed, so there's an engineering tradeoff being made. I was under the belief that V8 (and other JS engines) used *specialization* aggressively to bring back strong typing in code regions; in those areas again ECA should just work directly. #### "Managing the effect and control chains manually is hard" Equivalence class aliasing is *directly* represented in SoN, as just normal nodes and edges. There's no special handling for it anywhere, the normal graph maintenance functions manipulate those nodes and edges just the same as they do anything else. Two nodes that might alias directly have connecting edges, nodes that do not - do not, and hence *cannot* be influenced about what happens in other alias classes. -- cgit v1.2.3 From 7360b8455d095811fbe481f3ab3095c212e57687 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Fri, 28 Mar 2025 09:54:34 -0700 Subject: ASimpleReply setup --- ASimpleReply.md | 1 + ASimpleReply/ASimpleReply2.md | 29 +++++++++++++++++++++++++++++ ASimpleReply/ASimpleReplyChain.md | 31 +++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 ASimpleReply/ASimpleReply2.md create mode 100644 ASimpleReply/ASimpleReplyChain.md diff --git a/ASimpleReply.md b/ASimpleReply.md index ddd5fdfa..b208658f 100644 --- a/ASimpleReply.md +++ b/ASimpleReply.md @@ -1,5 +1,6 @@ A Simple Reply to https://www.reddit.com/r/Compilers/comments/1jjldhu/land_ahoy_leaving_the_sea_of_nodes/ + Because reddit crashes when I try to post this. ## prolog diff --git a/ASimpleReply/ASimpleReply2.md b/ASimpleReply/ASimpleReply2.md new file mode 100644 index 00000000..62f1a5ba --- /dev/null +++ b/ASimpleReply/ASimpleReply2.md @@ -0,0 +1,29 @@ +# A Simple Reply (2) + +Hi Dadals, we got to stop meeting like this. + +The whole reply chain: + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md + +I find long, involved, multi-part discussions difficult to follow because +basically we're really having 8 unrelated technical discussions. I broke up my +replies so each part is easier to consider on its own. + + +# Reply - Using t effect chains based on equivalence classes + +# Reply - "Guard tests for correctness" + +# Reply - "Graphs are nice for intuition but they don't scale well." + +# Reply - "Use a worklist!" +I think we agree, at least in theory, here. + +# Reply - Late arriving control flow from expanding small "diamonds" + +# Reply - "Data? Perf discussions with facts? Apples to apples comparisons? No?" + +# Reply - Hard to introduce new control flow + +# Reply - It's easy in Simple diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md new file mode 100644 index 00000000..2d53a8ee --- /dev/null +++ b/ASimpleReply/ASimpleReplyChain.md @@ -0,0 +1,31 @@ +# A Simple Reply ... Chain + +Hi Dadals, we got to stop meeting like this. + +### Original message: + +https://v8.dev/blog/leaving-the-sea-of-nodes +https://www.reddit.com/r/Compilers/comments/1jjldhu/land_ahoy_leaving_the_sea_of_nodes/ + +### Cliff's Reply: + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply.md + +### Dadal's Reply: + +https://gist.github.com/DadaIsCrazy/8ce07d409f8f74bad7b36e74b77a3129 + +### Cliff's Reply(2): + +(first, this reply-chain to gather all the parts) + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply2.md + + + +[room for more conversations] + +No conversations here, its just the chain. + +Cliff + -- cgit v1.2.3 From 6265a241492b611a14675e8b5610764094bffcbe Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sat, 29 Mar 2025 09:15:02 -0700 Subject: Update README.md --- chapter19/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter19/README.md b/chapter19/README.md index 87a4c3a6..a866876d 100644 --- a/chapter19/README.md +++ b/chapter19/README.md @@ -1,4 +1,4 @@ -Ch# Chapter 19: Instruction Selection and Portable Compilation +# Chapter 19: Instruction Selection and Portable Compilation You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter19) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter18...linear-chapter19) it to the previous chapter. -- cgit v1.2.3 From 6636079699775b56a2fd9913f340a9d6d4878638 Mon Sep 17 00:00:00 2001 From: godalming123 <68993177+godalming123@users.noreply.github.com> Date: Sat, 29 Mar 2025 16:41:06 +0000 Subject: Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 --- chapter03/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chapter03/README.md b/chapter03/README.md index 35075e7e..ddb9fafa 100644 --- a/chapter03/README.md +++ b/chapter03/README.md @@ -167,10 +167,12 @@ scope and deeper indices representing more nested scopes. Popping returns the current scope and moves to the outer one. There is a direct one-to-one mapping between each index and its corresponding scope. -The first nested scope(04-08) +The first nested scope(04-08): + ![Graph4](./docs/03-graph4.svg) -The second nested scope(09-13) +The second nested scope(09-13): + ![Graph5](./docs/03-graph5.svg) - In both cases the index which represents the deepness of the scope is 1. @@ -192,4 +194,4 @@ The graph for above, is displayed below. ![Graph2](./docs/03-graph3.svg) The return node has the constant `8` as its data value! When the parsing ends -and the scope at level 0 is removed, only the `return 8` remains. \ No newline at end of file +and the scope at level 0 is removed, only the `return 8` remains. -- cgit v1.2.3 From 1189d2ae57938fa593fdc9f1a74303b0c9ccb923 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 3 Apr 2025 21:28:44 -0700 Subject: Update ASimpleReply2.md --- ASimpleReply/ASimpleReply2.md | 123 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/ASimpleReply/ASimpleReply2.md b/ASimpleReply/ASimpleReply2.md index 62f1a5ba..45017b61 100644 --- a/ASimpleReply/ASimpleReply2.md +++ b/ASimpleReply/ASimpleReply2.md @@ -7,23 +7,128 @@ The whole reply chain: https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md I find long, involved, multi-part discussions difficult to follow because -basically we're really having 8 unrelated technical discussions. I broke up my +basically we're really having 6 unrelated technical discussions. I broke up my replies so each part is easier to consider on its own. -# Reply - Using t effect chains based on equivalence classes +## Reply - "Guard tests for correctness" -# Reply - "Guard tests for correctness" +Score one for static typing! -# Reply - "Graphs are nice for intuition but they don't scale well." +Here perhaps there is another win, but not really SoN related as least not +directly. Every "guardable" aspect in Java - except range checks - falls +neatly into a type *lattice*. This includes all kinds of subtype checks +(including instanceof, checkcast, user-written, arraystore, etc), null checks, +and constant bounds. A type *lattice* allows Sparse Conditional Constant +Propagation on all these types, which makes for a linear time, super cheap +analysis which wipes out that 90% of checks. -# Reply - "Use a worklist!" + +## Reply - "Graphs are nice for intuition but they don't scale well." + +Could be that graph viz tech has improved enough - although I tried hard with +GraphViz on Simple, and other than some pretty demos its not cut out for +serious debugging work. Meanwhile, ASCII dumps in C2 run into the 100 +thousands of lines, are instantly quick, land in my editor buffer where they +are ready to be searched, grep'ed, folded, stapled and mutalilated. Of course +they appear as a full CFG, with loop structure, typed, backlinks to source code, +etc. So maybe the answer is: "if you work on your debugging tools long enough, +they work for you". + + +## Reply - "Use a worklist!" I think we agree, at least in theory, here. -# Reply - Late arriving control flow from expanding small "diamonds" -# Reply - "Data? Perf discussions with facts? Apples to apples comparisons? No?" +## Reply - "Data? Perf discussions with facts? Apples to apples comparisons? No?" + +Yeah, apples & oranges. The obvious observation to make about any comparison +is that many benchmarkers have a desired outcome in mind... and will pick their +comparison according. Turboshaft was compared with the V8 variant SoN. +I'll betcha when doing comparable work C2 is *very* competitive with +Turboshaft, *especially* on a cache miss basis. This was *the number one +timing thing* I tracked in during C2's development. "Back in the day" nearly +all small to medium methods (plus inlines) fit in those processors *L1* cache. + + +## Reply - Late arriving control flow from expanding small "diamonds" +## Reply - Hard to introduce new control flow + +Full optimization of "diamond like things", without being a diamond and +remaining "pure" (no CFG at least), is done generally via the type lattice on +higher level common ops. They get lowered after there's no hope of other +optimization (provable no-progress by the lattice) - which is generally during +instruction scheduling for C2. + +If that's not enough and if you want to introduce control flow - its the same +problem in a CFG as in SoN (which *has* a CFG embedded). So whatever solution +you have for your CFG approach... SoN can use directly. + + +## Reply - It's easy in Simple + +Yeah, yeah, more opcodes and complexier semantics. C2 also has a zillion +opcodes, and deopts and re-opts, handles large graphs, multi IR levels, and +sings and dances.... and Simple has all the right compiler pieces to slot into +a runtime as complex as a JVM. I don't buy the "its easy because its Simple", +its easy because... its *simple*. Simplicity is a virtue in its own right, and +many hard looking things become, well, *simple* when you start from the right +base. + + +## Reply - Using multiple effect chains based on equivalence classes + +Well, this is the biggest failure I see in the V8 SoN effort and deserves the +most inspection... and has the most room for valid design tradeoffs. So I'm +saying a little more here, to match your larger writings, but also because +there's just more stuff to chew on. + + +"It requires typing the whole graph throughout the whole pipeline" - yes. This +is basically free in Simple/SoN, or at least costs some modest count of cpu +cycles (and generally no cache misses). Then it sits as a pointer in an IR +node. There's no bulk copy/bulk read going on, so... it costs nothing to sit +there. But then, when you need some type info - lo! There it is! C2 +maintains type info end-to-end, because its free to do so and because its +useful. + +"Equivalence classes are much weaker for arrays" - sure. And basically make no +differece to 99% of all Java programs. 1-d arrays vectorize just fine; stencil +calculations also fine. Register blocking and tiling? First Java needs to +change how multi-D arrays are laid out then we can worry about loop carried +aliasing. Basically, Java was never intended to replace Fortran, although in +the 1-D space it can hold its own. + +"Every call to user-defined functions, as well as most builtin calls have +arbitrary side effects" - sure same as Java. Doesn't really matter in the +grand scheme of things. If you can inline, the problem goes away. If not, +well *There's Yer Problem*. The lack of call aliasing info means you didn't +optimize some things around the call - all dwarfed by the call overhead itself. + +"Memory optimizations also cannot typically float past deoptimization state" - +plenty of those in Java too. C2 also does not sink stores *below* a deopt +state. At least for Java, we can float loads *up* past a deopt state (and do +so plenty). + +Also, call inline points *completely* disappear in C2. There is no +optimization barrier after inlining, even for memory effects. This is +different from *deoptimization* in this regard. + +# "Because of polymorphism.... but rather union types". + +Here I honestly don't know. I can fit some kinds of union types in a type +*lattice*, and then we're back to "basically free types". On the other hand, +the usefulness of the equivalence class model is based on "since you *cannot* +alias, the other aliases are not even representable". + +This gets into a weak argument from me about how after specialization guards, +we're back to equivalence classes... but I honestly dunno. Not tried it in JS +at least (C2 certainly does this, but its not so common as JS). +Very curious though... + +Curious enough for Google to fund a reprise with me lending a hand? + +:-) -# Reply - Hard to introduce new control flow +Cliff -# Reply - It's easy in Simple -- cgit v1.2.3 From e6f75306bc1da2d7fce47cba7256a6f478a8d7d1 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 3 Apr 2025 21:30:00 -0700 Subject: Update ASimpleReplyChain.md --- ASimpleReply/ASimpleReplyChain.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md index 2d53a8ee..2d2a31ca 100644 --- a/ASimpleReply/ASimpleReplyChain.md +++ b/ASimpleReply/ASimpleReplyChain.md @@ -17,8 +17,6 @@ https://gist.github.com/DadaIsCrazy/8ce07d409f8f74bad7b36e74b77a3129 ### Cliff's Reply(2): -(first, this reply-chain to gather all the parts) - https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply2.md -- cgit v1.2.3 From 05504d2911016529500da4b7931a914330862102 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 7 Apr 2025 10:04:42 -0700 Subject: Ignore unicorn --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 45ae6585..0ccb7896 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ TAGS # Libs */lib/*jar +Unicorn/ -- cgit v1.2.3 From a7f717078397da1d709df9deb1241970400038a5 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 7 Apr 2025 10:06:08 -0700 Subject: More simple replies --- ASimpleReply/ASimpleReplyChain.md | 11 ++++++++ ASimpleReply/DadalReply2.md | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 ASimpleReply/DadalReply2.md diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md index 2d2a31ca..6d62afb1 100644 --- a/ASimpleReply/ASimpleReplyChain.md +++ b/ASimpleReply/ASimpleReplyChain.md @@ -19,6 +19,17 @@ https://gist.github.com/DadaIsCrazy/8ce07d409f8f74bad7b36e74b77a3129 https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply2.md +### Dadal's Reply(2): + +https://studio.youtube.com/channel/UCbutMk6cKrH8q4sJyQHGPVQ/comments/inbox?filter=%5B%5D +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/DadalReply2.md + + +### Cliff's Reply(3) + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply2.md + + [room for more conversations] diff --git a/ASimpleReply/DadalReply2.md b/ASimpleReply/DadalReply2.md new file mode 100644 index 00000000..99d8e84b --- /dev/null +++ b/ASimpleReply/DadalReply2.md @@ -0,0 +1,53 @@ + +This is Dadal's reply from U-tube, recreated here (permission pending) so its +both easier to find and not lost if U-tube changes their mind. + +The original link I copied from: + +https://studio.youtube.com/channel/UCbutMk6cKrH8q4sJyQHGPVQ/comments/inbox?filter=%5B%5D + + +Type checks: to give an example: + +``` +foo(o) { + let x = o.x; + .... + let y = o.y; +} +``` + +Assuming polymorphic feedback (which is very frequent in JS), this will become something like (using JS-like syntax, but this happening inside the compiler of course) +``` +foo (o) { + let x; + if (o.map == Map1) { + x = RawLoad(o, offset=8); + } else if (o.map == Map2) { + x = RawLoad(o, offset=16); + } else if (o.map == Map3) { + x = RawLoad(o, offset=12); + } + .... + let y; + if (o.map == Map1) { + y = RawLoad(o, offset=0); + } else if (o.map == Map2) { + y = RawLoad(o, offset=20); + } else if (o.map == Map3) { + y = RawLoad(o, offset=4); + } +} +``` + +Here, it's not like any of the type-checks when loading `y` could be removed. Well, in some cases, we do things like double-diamond elimination to remove some checks, but often it's not possible. + +For monomorphic cases, subsequent checks will be removed when possible, but objects can change shapes in JavaScript. This means that if you have something like +``` +foo (o) { + let x = o.x; + bar(); + let y = o.y; +} +``` +If `bar` isn't inlined, then we have to assume that `bar` could change the shape of `o`, and thus a type-check is needed before loading `y`. Oh, and `bar` could be changing the shape of `o` only some times, so `o.x` could have monomorphic feedback while `o.y` could have polymorphic feedback. Or the other way around :) -- cgit v1.2.3 From 5a415cb394835cb9f4af7cc76dcbe7629135fd93 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 7 Apr 2025 10:37:26 -0700 Subject: ASimpleReply3 --- ASimpleReply/ASimpleReply3.md | 122 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 ASimpleReply/ASimpleReply3.md diff --git a/ASimpleReply/ASimpleReply3.md b/ASimpleReply/ASimpleReply3.md new file mode 100644 index 00000000..0d77ca87 --- /dev/null +++ b/ASimpleReply/ASimpleReply3.md @@ -0,0 +1,122 @@ +# A Simple Reply (3) + +The whole reply chain: + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md + + +## Unzipping + +Starting from Dadal's code, which has inlined some specialization checks: + +``` +foo (o) { + let x; + if (o.map == Map1) { + x = RawLoad(o, offset=8); + } else if (o.map == Map2) { + x = RawLoad(o, offset=16); + } else if (o.map == Map3) { + x = RawLoad(o, offset=12); + } else throw deopt; // Cliff added + .... // Cliff adds: call this code "S1" + let y; + if (o.map == Map1) { + y = RawLoad(o, offset=0); + } else if (o.map == Map2) { + y = RawLoad(o, offset=20); + } else if (o.map == Map3) { + y = RawLoad(o, offset=4); + } else throw depopt; // Cliff added +} +``` + +I added the "throw deopt", which I assume Dadal implies when `x` and `y` are +none of `Map1, Map2, Map3`. + +Dadal then adds: "Here, it's not like any of the type-checks when loading `y` +could be removed. Well, in some cases, we do things like double-diamond +elimination to remove some checks, but often it's not possible." + +C2 sees this kind of pattern fairly often as well; generally replacing `o.map +== Map1` with `o instanceof Map1`; not that it matters. C2 uses a "unzipping" +xform for repeated checks; I've talked about it publically numerous times. +Here C2 will look at the `S1` code above, and based on a heuristic (mostly +size) it will clone `S1` to remove the excess checks: + +``` +foo (o) { + let x,y; + if (o.map == Map1) { + x = RawLoad(o, offset=8); + S1; + y = RawLoad(o, offset=0); + + } else if (o.map == Map2) { + x = RawLoad(o, offset=16); + S1; + y = RawLoad(o, offset=20); + + } else if (o.map == Map3) { + x = RawLoad(o, offset=12); + S1; + y = RawLoad(o, offset=4); + + } else throw deopt; // Cliff added +} +``` + +Now you get 3 chunks of specialized code where in each case you know the type +of `o.map` throughout. This process can be repeated at all kinds of levels, +and assuming the strong knowledge of `o.map` allows more optimizations, can pay +for itself despite cloning some amount of `S1`. Its certainly common for C2 to +clone long runs of repeated checks such that in the end there's a fast-path +where all checks pass "the good way", and bail-out points all long that go to a +correct but slow path. + + +## Common Case vs Deopt + +``` +foo (o) { + let x = o.x; + bar(); // Might change the "shape" of `o` + let y = o.y; +} +``` + +Dadal: "If `bar` isn't inlined, then we have to assume that `bar` could change +the shape of `o`, and thus a type-check is needed before loading `y`." + +In a similar situation C2 will do the same. Of course, for sufficiently hot +`foo` and modest `bar`, inlining is the answer. This makes me wonder if C2's +inlininhg budget is substantially higher than V8's. + +Dadal: "Oh, and `bar` could be changing the shape of `o` only some times" + +In any of these "sometimes Bad Things Happens" situations, C2's go-to answer is +to register a dependency and deopt if the Bad Thing happens. The set of Bad +Things that happen between JS and the JVM are different, but it seems to me the +general theory still holds. Similar (not exact) situation: + +```java +foo( Object o ) { + var x = ((Cat)o).x; // Dependency that Cat has no subclasses + x.bar(); // Always a `Cat` so call Cat.bar +} +``` + +If later `Cat` is extended with `Siamese` which implements an alternative +`bar`, this code is deopt'd. The existing calls to `foo` can finish - they are +correct because they got called with a `Cat` and cannot change that - but no +new calls are allowed; they will use an alternative more conservative execution +until a fresh JITd code for `foo` can be made. + + +## Summary + +Yeah, the problems between JS and the JVM are different... but not hugely so. +And the problems shown here are *utterly* unrelated to the Sea-of-Nodes. +I'd do this stuff in a normal CFG framework just the same. + +Cliff -- cgit v1.2.3 From 723216153e152b84a55b57cfc198aaf828ec8819 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 7 Apr 2025 13:49:39 -0700 Subject: Update DadalReply2.md --- ASimpleReply/DadalReply2.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ASimpleReply/DadalReply2.md b/ASimpleReply/DadalReply2.md index 99d8e84b..bb30e155 100644 --- a/ASimpleReply/DadalReply2.md +++ b/ASimpleReply/DadalReply2.md @@ -6,6 +6,11 @@ The original link I copied from: https://studio.youtube.com/channel/UCbutMk6cKrH8q4sJyQHGPVQ/comments/inbox?filter=%5B%5D +The whole replace chain: + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md + + Type checks: to give an example: -- cgit v1.2.3 From 23ef82af763e597029a603c4a403c0f838b5a558 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 7 Apr 2025 13:50:02 -0700 Subject: Update ASimpleReplyChain.md --- ASimpleReply/ASimpleReplyChain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md index 6d62afb1..f8c9eb7d 100644 --- a/ASimpleReply/ASimpleReplyChain.md +++ b/ASimpleReply/ASimpleReplyChain.md @@ -27,7 +27,7 @@ https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/DadalReply2.md ### Cliff's Reply(3) -https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply2.md +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply3.md -- cgit v1.2.3 From fbbf5e3c095ba27cf0b504151ccda57cc4520e6e Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 9 Apr 2025 09:38:58 -0700 Subject: More Simply Reply --- ASimpleReply/ASimpleReplyChain.md | 3 +++ ASimpleReply/DadalReply3.md | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 ASimpleReply/DadalReply3.md diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md index f8c9eb7d..eb0bc80e 100644 --- a/ASimpleReply/ASimpleReplyChain.md +++ b/ASimpleReply/ASimpleReplyChain.md @@ -29,6 +29,9 @@ https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/DadalReply2.md https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReply3.md +### Dadal's Reply(3) + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/DadalReply3.md diff --git a/ASimpleReply/DadalReply3.md b/ASimpleReply/DadalReply3.md new file mode 100644 index 00000000..e5e89aa4 --- /dev/null +++ b/ASimpleReply/DadalReply3.md @@ -0,0 +1,25 @@ + +This is Dadal's reply from U-tube, recreated here (permission pending) so its +both easier to find and not lost if U-tube changes their mind. + +The original link I copied from: + +https://www.youtube.com/watch?v=iNWAgSAEPAg&lc=Ugwn_YpruALAauwRLqt4AaABAg.AGbLSQ5tlmFAGcQm0uZyZO + +The whole replace chain: + +https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md + + + +On medium sized functions, everything tends to be inlined in V8, but on larger +functions it tends to be more complicated. We've tried before to increase the +inclining budget, but this means reducing compile time, which means delaying +the time until the optimized code starts being executed, which in turns +regresses whatever benchmarks we're using to measure how fast V8 is. One +difference with Java here might be 1- how slow unoptimized JS code is (after +all, V8 bytecodes are ultra-generic, assuming any types for inputs, and having +to check a ton of various cases) and 2- how fast-running JS applications are +compared to Java (not in the sense that "JS is faster" but in the sense that +"JS applications probably stop running at least one order of magnitude earlier +than Java ones") -- cgit v1.2.3 From 94f43b86a3240c0af1db2b0fd0429e6ef98d04b7 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Fri, 11 Apr 2025 09:06:29 -0700 Subject: Update ASimpleReply3.md --- ASimpleReply/ASimpleReply3.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ASimpleReply/ASimpleReply3.md b/ASimpleReply/ASimpleReply3.md index 0d77ca87..395f4b77 100644 --- a/ASimpleReply/ASimpleReply3.md +++ b/ASimpleReply/ASimpleReply3.md @@ -34,9 +34,11 @@ foo (o) { I added the "throw deopt", which I assume Dadal implies when `x` and `y` are none of `Map1, Map2, Map3`. -Dadal then adds: "Here, it's not like any of the type-checks when loading `y` -could be removed. Well, in some cases, we do things like double-diamond -elimination to remove some checks, but often it's not possible." +Dadal then adds: + +> "Here, it's not like any of the type-checks when loading `y` could be +> removed. Well, in some cases, we do things like double-diamond elimination to +> remove some checks, but often it's not possible." C2 sees this kind of pattern fairly often as well; generally replacing `o.map == Map1` with `o instanceof Map1`; not that it matters. C2 uses a "unzipping" @@ -85,14 +87,17 @@ foo (o) { } ``` -Dadal: "If `bar` isn't inlined, then we have to assume that `bar` could change -the shape of `o`, and thus a type-check is needed before loading `y`." +Dadal: + +> "If `bar` isn't inlined, then we have to assume that `bar` could change +> the shape of `o`, and thus a type-check is needed before loading `y`." In a similar situation C2 will do the same. Of course, for sufficiently hot `foo` and modest `bar`, inlining is the answer. This makes me wonder if C2's inlininhg budget is substantially higher than V8's. -Dadal: "Oh, and `bar` could be changing the shape of `o` only some times" +Dadal: +> "Oh, and `bar` could be changing the shape of `o` only some times" In any of these "sometimes Bad Things Happens" situations, C2's go-to answer is to register a dependency and deopt if the Bad Thing happens. The set of Bad -- cgit v1.2.3 From 5d026780154ddd9ca111303df4dce9eac1c2d1c2 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 24 Apr 2025 14:38:36 -0700 Subject: Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 37da12391989265ae9560e6b08d1d309ac961db5 Merge: 7357dd1a 94f43b86 Author: Cliff Click Date: Thu Apr 24 14:37:32 2025 -0700 Merge branch 'main' into ch21 commit 7357dd1af9e7d4a2355d82a3e42a0123f465bd28 Author: Cliff Click Date: Thu Apr 24 12:14:00 2025 -0700 minor deps elide commit 811f17eb70afa23ed58595518e1c9fb8d93a6d76 Author: Cliff Click Date: Thu Apr 24 11:25:03 2025 -0700 inf loop tree fixes double-ended infinite loops slightly wrong loop tree commit 282d976283fc75f001b8446302f75d349c2a53d5 Author: Cliff Click Date: Thu Apr 24 10:21:03 2025 -0700 Minor formatting. Replace if-trees with array lookups or expression switch. Same CALLOC sentinel for all commit a6b76731cd72fb1edef02b6b449ba7f10bb73167 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Thu Apr 24 17:36:30 2025 +0100 arm eval calloc sentinel (#210) * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * Update ASimpleReply2.md * Update ASimpleReplyChain.md * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * Ignore unicorn * More simple replies * ASimpleReply3 * brainfuck and fib * brain fuck * Update DadalReply2.md * Update ASimpleReplyChain.md * arg_count, person * add ignore * More Simply Reply * Update ASimpleReply3.md * typo * riscv test sieve attempt * minor changes * riscv5 emulator additions * arm eval setup * Update riscv.java * arm eval basics * delta fixes * arm fixes * testfib arm * arg_count * small update for test newton * small update for test newton * testNewton runs on x64, riscv and arm * arm additions * arm pc eval fix * arm workings * debugging * arm sieve test * test person push * brainFuck arm --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit d80cf39073ce13c3ad6a707cff719852cbcdfab2 Author: Cliff Click Date: Wed Apr 23 20:29:34 2025 -0700 Fix some arm encoding Fix some OBOB in R5 calloc encoding. Sort EvalArm by major opcodes. Add ASL. Remove leading switch. Fix OBOB in calloc. Fix shift in ld/st with reg+offset commit eb346519783e29a849bdd85e1d7622e33e0d8eaa Author: Cliff Click Date: Wed Apr 23 16:57:51 2025 -0700 Progress sieve on ARM Most ops need WMASK as the output, to exclude RSP. calloc sentinal changes to multiple of 4 NewArm needs to set arg X0 to #1; arg X1 is length. Fix EvalARM calling calloc & not advancing PC. Fix EvalARM using ints vs longs. Fix EvalARM missing AndI encoding. commit 955e7816da5bcb39843230438a4a0e1e4dd7f9f8 Author: Cliff Click Date: Tue Apr 22 09:59:23 2025 -0700 bring back more loop help from ch22 commit 6d80212003d2b03c2df06683efe696238f391cf7 Author: Cliff Click Date: Mon Apr 21 14:11:27 2025 -0700 Update README.md commit 5fb03752b195e99dd251c9d497cccc93335bffe2 Author: Cliff Click Date: Mon Apr 21 11:57:04 2025 -0700 Code quality on loop with many continues commit 79d6d7b2a882046da6be199da0a0651c6c13bb2b Author: Cliff Click Date: Sun Apr 20 12:17:41 2025 -0700 Turn back on newton on ARM commit c0b6e387d7c40aec9e8d626976f4cfac27c54f90 Author: Cliff Click Date: Sun Apr 20 12:14:22 2025 -0700 Fix bugs One more encoding invert-branch test version, with extensive comments and symmetry pointed out. Fixes missing back branch at loop end. Switch the arguments to `dep.addDep(this)` to become `this.addDep(dep)` shortened to `addDep(dep)`. One more missing dep in Region fusing. commit 0f3ece57429baf2014fd08a4fd167c6ad7b1315b Author: Cliff Click Date: Sun Apr 20 10:46:50 2025 -0700 Correct test case ULP commit d761c267362e618e9e01de5b1fc0a405f5b466dc Author: Cliff Click Date: Sun Apr 20 09:46:32 2025 -0700 C program silently fails on CI? `sqrt(2)` is returning a `2.0` not e.g. `1.715...` commit 6abe323a0cb8a3a6a52ab13ea7217a28654f55ca Author: Cliff Click Date: Sun Apr 20 09:40:19 2025 -0700 Update newtonFloat.c commit 0cb35914c6a92be41108a7e3f16801b955967432 Author: Cliff Click Date: Sat Apr 19 16:43:25 2025 -0700 Better block layout Keeps loops self-contained, handles more variants of infinite loops. Fold region-to-regions together, in an effort to have fewer junk jumps commit 4402980faff51393a4a8d35557f1ed8c06596f23 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sat Apr 19 22:01:05 2025 +0100 TestNewton arm (#209) * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * Update ASimpleReply2.md * Update ASimpleReplyChain.md * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * Ignore unicorn * More simple replies * ASimpleReply3 * brainfuck and fib * brain fuck * Update DadalReply2.md * Update ASimpleReplyChain.md * arg_count, person * add ignore * More Simply Reply * Update ASimpleReply3.md * typo * riscv test sieve attempt * minor changes * riscv5 emulator additions * arm eval setup * Update riscv.java * arm eval basics * delta fixes * arm fixes * testfib arm * arg_count * small update for test newton * small update for test newton * testNewton runs on x64, riscv and arm --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit 2c8f9a01f5ccdac7e145f171fa95330923521f41 Author: Cliff Click Date: Thu Apr 17 10:17:32 2025 -0700 Fix arm D_OFFSET commit e8e8335258b85f95f24ac506f770fbdd08f4a083 Author: Cliff Click Date: Thu Apr 17 10:00:59 2025 -0700 win64 spills more than sys5 commit 71835b1cc3d597234e7fb50e7ddddf2b20cf10e2 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Thu Apr 17 17:54:03 2025 +0100 Arm eval (#208) * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * Update ASimpleReply2.md * Update ASimpleReplyChain.md * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * Ignore unicorn * More simple replies * ASimpleReply3 * brainfuck and fib * brain fuck * Update DadalReply2.md * Update ASimpleReplyChain.md * arg_count, person * add ignore * More Simply Reply * Update ASimpleReply3.md * typo * riscv test sieve attempt * minor changes * riscv5 emulator additions * arm eval setup * Update riscv.java * arm eval basics * delta fixes * arm fixes * testfib arm * arg_count * small update for test newton * small update for test newton --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit 38fd3c17c672c42fc768b0f31680b5d9679cac6d Author: Cliff Click Date: Thu Apr 17 09:42:52 2025 -0700 Fix CmpIX86/Jmp swap args bug Some x86 cmp need to swap args, then Set/Jmp both need to swap `bop`. Fix missing padding in ASM printer. MergeSort test like brainfuck - runs on arm. commit bd0f7963b117d3760cd0206ddfa54573c3e9b149 Author: Cliff Click Date: Wed Apr 16 14:17:17 2025 -0700 Remove redundant BrainFuck test Move all flavors into BrainFuck,java. Check x86 by linking with C & running. Check risc5 by running in EvalRisc5. Check arm by encoding, but no sim (yet). commit d3bc904d9d44bd9ad1e1b6e72c5f9c1a8c428f0b Author: Cliff Click Date: Wed Apr 16 13:56:16 2025 -0700 Fix risc5 branch invert Had conditions on forced invert mixed up. Sometimes need both a negate and a swap. rename invert as negate. commit 3ee7184fb99f8f389e1ff7178ae58e3e90571b07 Author: Cliff Click Date: Wed Apr 16 09:18:34 2025 -0700 Missed cutout test commit 2a3b2d4d4bc6099ab9fead00cfaa3f0a8e6aeb9f Author: Cliff Click Date: Tue Apr 15 19:41:55 2025 -0700 R5 fcmp, flt load from pool exportELF(null) now patches the cpool entries as well as globals. Repeated cpool entries folded. Fixed FltRISC, FCMP encoding. commit 2fb0ec312d76f22534331023c86e68b7a62b98e6 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Tue Apr 15 22:46:50 2025 +0100 riscv emulator (#206) * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * Update ASimpleReply2.md * Update ASimpleReplyChain.md * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * Ignore unicorn * More simple replies * ASimpleReply3 * brainfuck and fib * brain fuck * Update DadalReply2.md * Update ASimpleReplyChain.md * arg_count, person * add ignore * More Simply Reply * Update ASimpleReply3.md * typo * riscv test sieve attempt * minor changes * riscv5 emulator additions * arm eval setup * Update riscv.java --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit b74f35618c087e4e6634707c6e03ca669315bcc9 Author: Darrick Wiebe Date: Tue Apr 15 17:39:27 2025 -0400 Remove incorrect assert (#205) commit d4d894407b9cbf83217da3bde1ecbd6d783297e4 Author: Cliff Click Date: Tue Apr 15 12:58:13 2025 -0700 Revamp calling convention math Handles win64 shadow stack space correctly. Unifies most of the caller-save mask, return mask, arg mask computations. Unifies most of the frame-size math across all chips. Large documentation comment in Machine about how stack math is computed. commit 5e7223504d356cbb48c397bed0cd0012eb075935 Author: Cliff Click Date: Mon Apr 14 10:42:50 2025 -0700 win64 shadow stack killed by calls commit e1351e0f4788779e9f37a77f0abb936f2869cbfc Author: Cliff Click Date: Mon Apr 14 10:37:53 2025 -0700 NewXXX honors declared CC commit faf6bae55523f12c32b0e21b3c39445459c50f71 Author: Cliff Click Date: Mon Apr 14 10:08:33 2025 -0700 Missing hasCalls for Newxxx commit 40a6f7b90e9e5d42bdacabb1c9e93fab5d27f63d Author: Cliff Click Date: Sun Apr 13 19:51:04 2025 -0700 EvalRISC5 handles calloc Patch calls to calloc with a sentinel; emulator spots call to sentinel and mimics calloc on the internal heap. commit 450dd5169ebbfd8664d073b0d8baea201dae0ed2 Author: Cliff Click Date: Sun Apr 13 19:49:31 2025 -0700 Cleanup recent phi xform Missing deps commit 2308671cd2a95aec8ab42b4eec5cb6f5cba5302c Author: Cliff Click Date: Sun Apr 13 11:30:47 2025 -0700 negate on x86,risc,arm commit 1e28b27ec2d1129d4a219a57ec0c661c74720493 Author: Cliff Click Date: Sun Apr 13 10:23:18 2025 -0700 Handle infinite loops Loop tree building (and breaking infinite loops) needs to happen *before* instruction selection, which is optional. Best done as a new compiler phase... which now wants a driver. Add a compiler driver; adjust tests to use. Add "never-branch" handling to the 3 CPU port main branch ops. commit 0ac2721f28c729c06c28fce14f8f863f8c57e41b Merge: a42aa8e3 53bb3207 Author: Cliff Click Date: Sat Apr 12 14:08:59 2025 -0700 Merge branch 'ch21' of https://github.com/SeaOfNodes/Simple into ch21 commit a42aa8e31488f34315717743cf075e4d7b6e3677 Author: Cliff Click Date: Sat Apr 12 14:08:57 2025 -0700 Phi generic pull down is stronger commit 53bb3207c85bc438b9cc28f84bce458e5068ee45 Author: Darrick Wiebe Date: Sat Apr 12 16:33:57 2025 -0400 Add a constructor to MemOpNode for M2 (#203) commit d08925c1ff212e2157356eacbd748e679b80954d Author: Cliff Click Date: Sat Apr 12 11:41:58 2025 -0700 2 more encoding bugs Missing constant NIL, arm CAST commit 798bd959410eb6c2e0b9f7ae1222181ac2b295d4 Author: Darrick Wiebe Date: Sat Apr 12 13:40:20 2025 -0400 MemStore interface (#201) * Hook for pre-encoding work needed by M2 * Add MemStore interface * Add both MemLoad and MemStore interfaces * Fix NPE printing StopNode * Attach merged mem to return when forcing a loop exit * Made requested changes. This breaks a few tests, possibly because... ...I am not sure whether some X86 ops are loads or stores. * Mach ops need anti-deps too MemOp subclasses are either "Load-like" or "Store-like" based on a flag, and not on subclassing LoadNode nor StoreNode. Mach ops pick up anti-deps, no reg mask for those. x86 bug: do not allow "dst = [mem] + #imm", no such instruction Empty merge-mem folds away. x86 add-to-mem works both ways --------- Co-authored-by: Cliff Click commit 47711b81ea915eeeb46b2ad8ebb291fb21cbaf6e Author: Darrick Wiebe Date: Sat Apr 12 11:46:53 2025 -0400 Don't print ante-deps on multinodes when generating asm dumps (#202) commit 08421921cbb885fdfb785b896f21b59937b99f39 Author: Darrick Wiebe Date: Sat Apr 12 00:25:08 2025 -0400 Hook for pre-encoding work needed by M2 (#200) commit 6ab61f8c6ae0fb26802cfff0f4d007e8a55e817e Author: Cliff Click Date: Fri Apr 11 21:08:03 2025 -0700 Update Chapter20Test.java commit 404fb8dadfef10d0954abf6e84901b7d6a469f14 Author: Cliff Click Date: Fri Apr 11 21:05:51 2025 -0700 Remove debug prints commit a2614064a6d86d146af07d0db50c2e76a2c37274 Author: Cliff Click Date: Fri Apr 11 21:01:53 2025 -0700 Larger frame encodings commit 4e467263058c015ec0838487d1523b51fb42fcfd Author: Cliff Click Date: Fri Apr 11 20:52:50 2025 -0700 Encoding bugs NewX86 using wrong killmap. Split: moving from xmm to gpr inverted REX bits commit 3f97f091c40ab92b8ea0def108e1db870b5a6f09 Author: Cliff Click Date: Fri Apr 11 19:54:36 2025 -0700 Update TestC.java commit 81985bd73393c95b34334b5b57613873ffad95ae Author: Cliff Click Date: Fri Apr 11 19:35:53 2025 -0700 One more try for CI commit 62f94ffd6020a6cb45ea7ee0bdf1f5295977f1b1 Author: Cliff Click Date: Fri Apr 11 19:23:22 2025 -0700 Update README.md commit 752bc3e5df6e72e8b639e01a860f80c9d9b5db80 Author: Cliff Click Date: Thu Apr 10 17:34:15 2025 -0700 Update NewX86.java commit d89e11f08591f5ff05395b5dc552b630aee5d5b8 Author: Cliff Click Date: Thu Apr 10 17:26:55 2025 -0700 Update NewX86.java commit 58141543b8365fe5246fec107a9a68f26c5a7edf Author: Cliff Click Date: Thu Apr 10 17:25:38 2025 -0700 Update NewX86.java commit 006c2351ce7eed1209296b8811f64f3f72f64045 Author: Cliff Click Date: Thu Apr 10 17:23:04 2025 -0700 better ci error commit b6765473a3ce3db943355abba8e8ff765a3f8a3b Author: Cliff Click Date: Thu Apr 10 17:18:53 2025 -0700 C tests check both Win64 qnd Sys5 NewX86 links against OS-specific `calloc`, uses OS-specific calling convention, and not the declared convention. Encoding bug, byte-store of SIL, DIL, BPL needs a blank REX. OBOB errors in Sys5 large-arg-count calling. commit b68dafa3e6e231bd0d0b0e613986c7e3181349b9 Author: Cliff Click Date: Thu Apr 10 13:47:06 2025 -0700 More README updates commit 0b8c694910ccf5e615b8fb68049cffd47be2c3b9 Author: Cliff Click Date: Thu Apr 10 13:33:08 2025 -0700 Update Makefile commit f13661bd35bedb211075b8d1ac48bbbbf394001e Author: Cliff Click Date: Thu Apr 10 10:16:32 2025 -0700 Update README.md commit 7d22a8e805befd5d733d079cbbbce634bb6ae623 Author: Cliff Click Date: Thu Apr 10 09:38:18 2025 -0700 README commit 074f718a104dbbb8b1b0a2205c176659a27dfd9f Author: Cliff Click Date: Wed Apr 9 17:12:56 2025 -0700 Handle large arg count function 2 print modes for stack slots - slot# or stack offset, only available after encoding. Compute maxArgSlot in one place on all archs. X86 yank flags from Splits - lest we split a XMM into the flags??? commit b32c6a879c0be7aebad25fabae6f0a24d5670366 Author: Darrick Wiebe Date: Tue Apr 8 21:52:12 2025 -0400 Make eq() public (#199) commit 938c09baca29b0647dcd56e9581540d7a8142fb4 Author: Cliff Click Date: Tue Apr 8 14:28:51 2025 -0700 Fix risc5 bugs from emulator commit 06872d180720c376d3fdcc0bd0a2a973bf9341c4 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Tue Apr 8 21:40:41 2025 +0100 arg_count, person (#198) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * brainfuck and fib * brain fuck * arg_count, person * add ignore --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit 22cb2b4555b6b539a5204c2e2b60748c8138d8dc Author: Cliff Click Date: Tue Apr 8 11:55:35 2025 -0700 Add 32b risc5 emulator commit a0f70ef9b432fdad06879c333c59e3f3a4dbfe54 Author: Cliff Click Date: Mon Apr 7 14:55:19 2025 -0700 Clean tests commit b7603e71510b4d0e82681b9639a56cc77bab40d6 Author: Cliff Click Date: Mon Apr 7 14:50:30 2025 -0700 Update Encoding.java commit 840bfd14b3658f49429cbf84fbc39980477d5f6e Author: Cliff Click Date: Mon Apr 7 14:50:24 2025 -0700 x86 shift imm are 2-addr commit 635ef128b8e3c5a993e8551454f986098dd5092e Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Mon Apr 7 22:00:29 2025 +0100 Minor arm fixes (#197) * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write * brainfuck minor fixes * minor arm fixes * split fix * brainfuck and fib * brain fuck --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit cac92d551e16e13530f0254548476ab122d30b8b Author: Cliff Click Date: Sun Apr 6 19:23:47 2025 -0700 Math lib by default for CI commit 07530e8c5ec3e2ab98be92769d6abcb9024cfbea Author: Cliff Click Date: Sun Apr 6 19:19:49 2025 -0700 ignore gcc warning during CI commit 7030243523999bd647938cd39013f47d9dfc6e88 Author: Cliff Click Date: Sun Apr 6 19:09:10 2025 -0700 Debug printing for CI commit a81794df00369f6adf4a06e2f0247d309a196e27 Author: Cliff Click Date: Sun Apr 6 16:22:38 2025 -0700 Fix sieve RA returns maxSlot+1 FunX86 prints as `subi`, uses Sub; Ret uses Add X86 knows that always RPC is passed on stack "as if" a stack arg. sieve uses unsigned ints. Driver expects an array pointer commit 4c4778f8cc3dd4fd354832bfb0ba1a8c03ee744d Author: Cliff Click Date: Sun Apr 6 14:43:39 2025 -0700 Fix store ref/0x66 prefix commit 819963deb617ea622a27918101867aab3c522c3c Author: Cliff Click Date: Sun Apr 6 11:42:55 2025 -0700 More encoding bugs Stack adjust needs REX. Boolean load/store same as U8 Calling calloc needs size of 1 in RCX, bytes in RDX commit abd2fc675d0fc29d5b525cdbe5b949e1c85b1e7e Merge: e30990ad 8db8f750 Author: Cliff Click Date: Sun Apr 6 10:37:17 2025 -0700 Merge branch 'ch21' of https://github.com/SeaOfNodes/Simple into ch21 commit e30990ad8929084cf433894843adc04b577d6e9f Author: Cliff Click Date: Sun Apr 6 10:37:16 2025 -0700 End-to-end testing of x86 encoding commit 8db8f75006a1daf522976ee97048aa4f06780c8e Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sun Apr 6 17:11:18 2025 +0100 StringHash x64 fixed (#195) * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * minor fixes * minor fixes * update float test case * stringHash fix on x64 * remove conditional ConstantPool write --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit bb97129daa1504d67a8e3a76f16d6db15f7e5e7b Author: Cliff Click Date: Sat Apr 5 15:55:48 2025 -0700 Float uses unsigned compare commit 532b34d34fde93b2841f4c9544c673a0d89434ea Author: Cliff Click Date: Sat Apr 5 15:53:10 2025 -0700 Fix vs0 bugs Use a BoolNode.NE instead of inverting outputs; the outputs are already matched and cannot be inverted. Use a `swap` not an `invert` when switching sides in a compare. commit 7277ab049ab9cae5fa64cd5ea958f69278f773a4 Author: Cliff Click Date: Sat Apr 5 13:58:07 2025 -0700 Fix elf constants Record more relocation info in the machine-specific encodings. Use it when building ELF. Switch to simpler Newtons; some encoding bug in the complex one. commit fc7d2bce649854982a3c16de164bbaafec11bc27 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sat Apr 5 19:38:40 2025 +0100 Ch20 encoding (#194) * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * Bring back `make view` * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * Create ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * Update ASimpleReply.md * fix global symbol numbering for constants * ASimpleReply setup * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * Update README.md * replace hard coded opcodes with major opcodes * Fix some formatting (#184) * Fix title in chapter 19 * Wrap nseted scope images onto newlines in chapter 3 * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes * remove constant pool from encoder TODO: add flag for JIT * extend test cases * minor fixes * minor fixes * update float test case --------- Co-authored-by: Cliff Click Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> commit 1741cb3039555b1446a1b0c1c3768f3763a0d9e6 Author: Cliff Click Date: Sat Apr 5 11:30:35 2025 -0700 Add in-memory linker Encoding supports writing cpool to either Elf or in memory ElfFile writes constant pool commit 631b699a4cf65f6c91a24df49329bb285aec09fc Author: Cliff Click Date: Sat Apr 5 10:04:42 2025 -0700 Move PORTS into CodeGen commit 3016c9fcf8361cb1a0c494dbb7b997df33df5728 Author: Cliff Click Date: Fri Apr 4 16:32:25 2025 -0700 Support constant tuples commit 887f3d9caf68b051c630bab6c8895778be8f044f Author: Cliff Click Date: Fri Apr 4 12:29:46 2025 -0700 Partial progress cpool in ELF Align functions to 16b commit cc32b0cf801620f1d289cb6ae183e079111540fc Author: Cliff Click Date: Thu Apr 3 11:31:06 2025 -0700 Fix RA parallel phi assign Force spills when phi uses phi same loop header. This is effectively a parallel assignment, generally shifting values from one iteration to the next. commit 37b46799c03244241d589085e24582bef8a59efb Author: Cliff Click Date: Thu Apr 3 09:32:33 2025 -0700 Allow stacked cloneables For RISC 2-part immediates, both parts can be treated as constants and moved/cloned commit 35057d50ae21e143bf89158a65e2db139fcb76fa Author: Cliff Click Date: Wed Apr 2 16:39:17 2025 -0700 Bug Fix RegAlloc RA, self-conflict around backedge of loop predates loop, must still split. Eager splitting here leads to bad allocations, but never splitting is broken. Move building adj lists into IFG from Coalesce. testNewtonFloat not so fragile. Hack around bug SetArm commit fa846b232a9eca4a7691ab59b3ea92e53c6b85a6 Merge: b73a1146 abdb59f9 Author: Cliff Click Date: Wed Apr 2 14:55:51 2025 -0700 Merge branch 'ch21' of https://github.com/SeaOfNodes/Simple into ch21 commit b73a1146a1af2eabe6af1ba043fc6ff5ef8731ab Author: Cliff Click Date: Wed Apr 2 14:55:48 2025 -0700 parse negative floats commit abdb59f94008f8620d8c654980c8850ce94a15ad Author: Darrick Wiebe Date: Wed Apr 2 14:45:45 2025 -0400 Make eq public on ConstantNode (#193) commit 9452d347d07ff38f6897be0ff8e9a50b7b43ddc3 Author: Cliff Click Date: Wed Apr 2 11:32:42 2025 -0700 Stronger inf loop assert Handle returning value after inf loop. Loop nesting check does not use depth until after loop tree is built. ASMPrint can be called no machine. commit 4cd6517df6f9fbf77215525cf0b736ab4f90b143 Author: Cliff Click Date: Tue Apr 1 19:59:02 2025 -0700 Fix bug encoded inf loops Assert functions laid out end to end. Fix bug with layout on inf loops. Swap default Never jump order. commit f4542326141578053122f8e3c11fd3a1932c6866 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Wed Apr 2 03:37:23 2025 +0100 Minor bug fixes (#190) * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * fix global symbol numbering for constants * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * replace hard coded opcodes with major opcodes * add asserts and fix reg numbering * add asserts and fix reg numbering * minor updates * revert changes --------- Co-authored-by: Cliff Click commit fc783af92ecab0288b94c7b1d6ce1b1e2cab5d42 Author: Cliff Click Date: Tue Apr 1 15:42:52 2025 -0700 bugfix commit f6a047a93971574f64a779cf59dc41ff52cdfe27 Author: Cliff Click Date: Tue Apr 1 15:05:31 2025 -0700 More infinite loop encodings commit f691d2de7217b04844da51c2c6ecc0fd9137c7d6 Author: Cliff Click Date: Tue Apr 1 14:26:46 2025 -0700 RA tighter def of being "in" or "out" of loop commit d8a39c7063ecaa26a3bb962b730837a678ed4d93 Author: Cliff Click Date: Tue Apr 1 12:07:36 2025 -0700 Encode infinite loops for RISC commit 40e0111061e174810eb75c898034fc5255b025d8 Author: Cliff Click Date: Tue Apr 1 09:23:31 2025 -0700 remove debug print commit ea737ed0a49b091478e954e125a58a1842a89e5f Author: Darrick Wiebe Date: Tue Apr 1 01:53:31 2025 -0400 Get SLT[IU]* working (#192) commit 28a873ea522190733e89602b1d50f042c41d20bc Author: Cliff Click Date: Mon Mar 31 16:57:26 2025 -0700 RA uses killOrdered commit 950d57cc74a36655a770daea7c28cee03b60e707 Author: Cliff Click Date: Mon Mar 31 15:40:03 2025 -0700 Create intermediate dirs commit 6d50b541a7a5c6757ee507da24a995bc02354270 Author: Darrick Wiebe Date: Mon Mar 31 18:30:45 2025 -0400 Make risc op constructors public so that I can subclass them. (#191) commit 22318a9654f4a6c3f26e6ad6800a875c16f472a2 Author: Cliff Click Date: Mon Mar 31 15:24:16 2025 -0700 Fix encoding FIB Use common utility for walking CFG chains of empty blocks commit 760e2b4f57ceac91017ad018f2e9234af351bf5b Author: Cliff Click Date: Mon Mar 31 11:41:51 2025 -0700 X86 float splits commit d98a5c8cdf7a249f3c227fc00f014d53452af858 Author: Cliff Click Date: Mon Mar 31 10:15:36 2025 -0700 Move insertAfterAndReplace to RA Fix Split printing commit 3a7a9bde8ee95b4e2f4c08588428c59125d727e4 Author: Darrick Wiebe Date: Mon Mar 31 12:38:12 2025 -0400 Fix sameBlockNoClobber and refine insertAfterAndReplace (#189) Also fix firstReg when empty commit ec9a8a7f49f7a8b22897ca96cf2aff8c47e475f8 Author: Cliff Click Date: Sun Mar 30 16:46:18 2025 -0700 Fix bug j_type encoding Switch I_TYPE to OP_IMM to match the other major opcodes commit a7a9069f29b112a355596756bc53cff73e597a3f Author: Cliff Click Date: Sun Mar 30 16:12:49 2025 -0700 Pass new reg asserts Handle -1 reg in X86 in several places. SplitARM Float spills still wrong, but less wrong. Cleanup RISC load/store handling. commit aea468c0b09891f89a8346de7bb37982f7767c2b Author: Cliff Click Date: Sun Mar 30 14:54:16 2025 -0700 Update x86_64_v2.java commit 150bbf6d1f71411c9cdffdc0081013a5dd0f4f4e Author: Cliff Click Date: Sun Mar 30 14:54:08 2025 -0700 Remove leftover prints commit 2ce631b2086f2491e34728fae3ff397b3a35ee73 Author: Cliff Click Date: Sun Mar 30 14:53:50 2025 -0700 Fix some RISC encodings around FP spills commit f9710b82df0eb51090514c56e64e743d32d06b12 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sun Mar 30 21:33:48 2025 +0100 Extra assert for reg numbering (#188) * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * fix global symbol numbering for constants * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * replace hard coded opcodes with major opcodes * add asserts and fix reg numbering * add asserts and fix reg numbering --------- Co-authored-by: Cliff Click commit fe08995cca0196850855c0f81619d264cf66b716 Author: Darrick Wiebe Date: Sun Mar 30 15:33:43 2025 -0400 Make RegMaskRW public and add mutating or; Fix coelesce bug (#186) * Make RegMaskRW public and add union to it. * Rename union to or * Split popular non-constant * Fix coelesce bug --------- Co-authored-by: Cliff Click commit 2fd3cd57934ef168b090e3b0ec7da7b41fa595b3 Author: Cliff Click Date: Sun Mar 30 11:22:27 2025 -0700 fix indent commit 79263e424709885da08a0cada2ace6cd744158d7 Author: Cliff Click Date: Sun Mar 30 11:19:14 2025 -0700 Encode ptr loads ptrs become 64b Fix Cmp encoding commit 8701c671c8e6d6eedc01436ea38bde01fba634f0 Author: Cliff Click Date: Sun Mar 30 10:54:39 2025 -0700 Fix BB layout bug Fix split of popular value bug. commit 7d60f55d2c97677e03a6b01869b4832111a12267 Author: Cliff Click Date: Sat Mar 29 16:48:49 2025 -0700 Force split during a parallel assignment Was not inserting same-block split, but actually required if doing parallel assignment from fixed regs to fixed regs commit 8ea9c74afef87cb562604bf94f803853babe2d33 Author: Darrick Wiebe Date: Sat Mar 29 18:22:54 2025 -0400 Enable asm printing to be flipped to big-endian (#185) * Suppress unchecked operation warnings * Selectable asm dump endianness * Fix a crash in coalesce when v2._adj is null, so has no adjacent nodes anyway. commit 99d3fe964eb556370d0f23327b29c26cee9b3edb Author: Cliff Click Date: Sat Mar 29 14:47:33 2025 -0700 Fix non-deterministic bug commit b09370af9db2be3b763eb72a61a34aecb743dcd9 Author: Cliff Click Date: Sat Mar 29 10:48:05 2025 -0700 Split popular constants commit 7c0a57d1693b2d714f5871f4615b17c29d15ad46 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sat Mar 29 16:39:00 2025 +0000 Arm major opcodes, riscv load-store fixes (#183) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * fix global symbol numbering for constants * fix TFP pathc on arm and riscv, keep symbols in good order. * fix opcode for store and loads, memOpRisc for Store and splitting * replace hard coded opcodes with major opcodes * replace hard coded opcodes with major opcodes --------- Co-authored-by: Cliff Click commit 7a22f7be12dadf9936a5102757b048a354a40bf5 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sat Mar 29 02:45:44 2025 +0000 Ch20 encoding (#181) * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm * readme fixups * fix global symbol numbering for constants * fix TFP pathc on arm and riscv, keep symbols in good order. --------- Co-authored-by: Cliff Click commit 82b4b2187d51f96f3217b10febfbf18071ec61fc Author: Cliff Click Date: Fri Mar 28 15:58:58 2025 -0700 risc5 encoding bug commit b3c108731794fed83015ba92a651af13a3a1477d Author: Cliff Click Date: Fri Mar 28 14:05:49 2025 -0700 More custom op names commit e5f156803488ade996c04b5135ac87942c354245 Author: Cliff Click Date: Fri Mar 28 09:29:39 2025 -0700 Update LoadRISC.java commit d18505d598fd7c96d152d57f6f5d1f34124defc3 Author: Cliff Click Date: Thu Mar 27 11:55:31 2025 -0700 R5 encoding bug fixes Remove extra branch-to-next commit e16cf5d94bce81a27f5080be6f90da448544ee2a Author: Cliff Click Date: Wed Mar 26 16:53:49 2025 -0700 Update LUI.java commit c2dbd396024d4ecf21747c16f410fa31a1dfdf91 Author: Cliff Click Date: Wed Mar 26 14:42:40 2025 -0700 more portable commit d90baa2a8c0a8ce9a84befec756b39ec49360b8e Author: Cliff Click Date: Wed Mar 26 12:16:15 2025 -0700 Minor improves to portability commit 37150e852041029792176f9d559eb714a2a6726b Author: Cliff Click Date: Tue Mar 25 19:56:36 2025 -0700 few more publics commit 7225eb931c2cefa105b17f393fe242c00b02a185 Author: Cliff Click Date: Tue Mar 25 12:11:42 2025 -0700 RISC5 branch encoding bug commit 4bbfd2f561f4a28fc749dd36bbb417ce03de5f78 Author: Cliff Click Date: Tue Mar 25 11:21:35 2025 -0700 Minor cleanups Custom op for risc5, a few more things public for external port commit 5fd3508bd3c45ed83757b47caa7a24361bec71cb Author: XmiliaH <45106915+XmiliaH@users.noreply.github.com> Date: Tue Mar 25 18:44:41 2025 +0100 Call Simple function from C (#179) * Call simple function from c * Small fix * Use different test values commit 1f87fba4ee6b874eed6c3652e3e8a25b5b0726aa Author: Cliff Click Date: Tue Mar 25 08:53:55 2025 -0700 Update UJmpRISC.java commit 321193056bf13d525399885afed16ffece3c2e5a Author: Cliff Click Date: Mon Mar 24 16:35:48 2025 -0700 Make more public Allows custom risc5 to override commit ac3855c4313d6cab8e2bb778b5bfa679415cb519 Author: Dmitry Stogov Date: Mon Mar 24 18:56:05 2025 +0300 Driver related fixes and improvements (#175) * Fix simple.sh (pass arguments) * Consistently replace "_" with "-" in command-line options * Add "--dump-time" option to print compilation statistics * Add "--dump-size" option to print generated code size commit 3db126e018388facfab368ecb2c8f8bc566afe1a Author: XmiliaH <45106915+XmiliaH@users.noreply.github.com> Date: Mon Mar 24 00:09:33 2025 +0100 First run as elf binary (#178) commit 8d6de0e10358fc197490cdacb10cbcedc18bb4f6 Author: Cliff Click Date: Sun Mar 23 15:59:23 2025 -0700 Coalesacing Fix bug IFG adding interference to from 1 reg live range, even if success in clearing reg Fix bug LRG merging when both masks have already been trimmed. Missing ARM stack adjust commit 0afb4876e602faa75319bb1faf9adc7f6f7476c2 Author: Cliff Click Date: Sun Mar 23 11:26:16 2025 -0700 Correct golden spill counts Encoding: bad test cutout required JMP AddIRISC bad edges during spill. commit 3e17e811c4429cda194ccdb892ddb2bd10fa71ea Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sun Mar 23 17:10:41 2025 +0000 Ch20 encoding (#177) * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch * Store/load float arm/riscv/x64 * got rid of debug print * splits for x86, riscv and arm --------- Co-authored-by: Cliff Click commit 880329e6b4ba209ea35ca647bb14157c1b4234fb Author: Cliff Click Date: Sun Mar 23 10:06:43 2025 -0700 More RegAlloc Forcing kills on allocations broke a bunch of things. Color: pickRisky single-Def cloneables that are not next to their uses. I.e., a X86 flags-producer far away from a required jump: Pick as Risky, fail to color, and spill (clone) next to jump. Remove a bunch of premature split fold-thrus commit 05925aa5a73c48f4c380ec919583cb56057383ea Author: Cliff Click Date: Sun Mar 23 10:02:41 2025 -0700 x86 test op Invert "Bool(#0,x); If " to "CmpI(x,#0); Jmp!XX" commit e1b6befcfb865e0a8e34d895a0ddc82bf31d6d4b Author: Cliff Click Date: Sun Mar 23 10:01:32 2025 -0700 Robust pre-encoding commit d333a9001c4f1db159dca8395b5e59c2d2aa92d7 Author: Cliff Click Date: Sun Mar 23 10:01:20 2025 -0700 Share a bunch of larger common tests Move them to `*.smp` files commit 71d882bae6c88ce20353b787cb3699860d52b3d5 Author: Cliff Click Date: Sun Mar 23 10:00:33 2025 -0700 riscv load/store does not do [reg+reg] riscv load/store does not do [reg+reg], so the base might not be object base. commit 94ea5ac5871b74273537d6124a1aeb64bba495d9 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Fri Mar 21 22:49:50 2025 +0000 Ch20 encoding (#176) * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name * add test export * merged * store opt * store and load optimised forms handled * tfp patch --------- Co-authored-by: Cliff Click commit de2d08cfaa659d1c22f2cbbfa84748bd5c307ac4 Author: Cliff Click Date: Fri Mar 21 15:12:05 2025 -0700 Stack slot updates Spill code work commit 442b5060a7f5857cfdedcc69384d90fd5fed9036 Author: Cliff Click Date: Wed Mar 19 09:54:45 2025 -0700 constant pool commit 352c6927252137a252ab942c83695890fb332004 Author: Cliff Click Date: Wed Mar 19 09:54:38 2025 -0700 ELF exporting takes a target file commit 0328057dc9e5a7b4bcee4b9fe9260c91a59d5b5e Author: Cliff Click Date: Tue Mar 18 15:13:43 2025 -0700 Update Chapter21Test.java commit fbe1e0a84e154b17e09055b184f33cdb08a0138c Author: Cliff Click Date: Tue Mar 18 15:13:30 2025 -0700 bugz Fix RA bug using Win64 and not full spilling in a single block. riscv/arm demand SystemV calling convention Cleanup ch21 tests; add 1 export test commit 0b107134d7c4081a4529d9cbb15897bfcdc83910 Author: Cliff Click Date: Tue Mar 18 14:28:19 2025 -0700 Missing address size on risc commit 59173187cc8c01506d1bc25447bd7a7f5fee8604 Author: Cliff Click Date: Tue Mar 18 14:25:49 2025 -0700 Fix missed peep only missing when running without asserts. commit 3bf52024aee9021521bfb85f7e894a3b343e6c85 Author: Cliff Click Date: Tue Mar 18 13:57:02 2025 -0700 better printing commit 129f7a9ce2b9b170f35b07367d80179744776732 Author: Cliff Click Date: Tue Mar 18 13:56:54 2025 -0700 add sh and bat drivers commit 3848ef1cab34690dea7c9fba0ff08fe14b7a13e5 Author: Cliff Click Date: Tue Mar 18 13:50:39 2025 -0700 Missed merge piece commit 0f5ebdf4563f4d71d349a32f511137cfad37d828 Author: Dmitry Stogov Date: Tue Mar 18 22:00:24 2025 +0300 Create a better driver programn (#168) This allows: - read "Simple" programs from files or stdin - selectivley dump sea-of-nodes after earch optimization pass - save *.dot files - print generated assembler - evaluate progrmas with given arguments (Eval2::eval() needs improvement) - select CPU and ABI for code-generation commit 5cab242acdb68045e5993b75fc67b54901002072 Author: Cliff Click Date: Tue Mar 18 11:37:26 2025 -0700 Fix comment printing Minor encoding bugs for large- x86 jumps and arm external call commit e625a921d8fc9540a277e5becc8fe49b557c49fc Author: Cliff Click Date: Tue Mar 18 11:22:07 2025 -0700 changed relo ABI Missing patch/merge from ARM ldst-encoding Explicit external calls. Better printing for multi-op template encodings commit efc53c6d4b8d11cb08ba84800d85bc725b2f2d5b Author: Cliff Click Date: Tue Mar 18 09:02:20 2025 -0700 Update CallRISC.java commit 5faaadb794ad864ce3e26ed6a5fc4457a8aa2f15 Author: Cliff Click Date: Tue Mar 18 00:34:34 2025 -0700 progress on patching calls commit 9929bca5617c2b0134ae16fb174df8d247443af8 Author: Yasser Arguelles Snape Date: Mon Mar 17 14:59:33 2025 -0700 ELF exporting (but in Chapter 21) (#173) * Updated ELF exporting code, added function relocations * added big constants (only floats currently) commit 65ff94cc06005208d454b6759503b8604135e607 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Mon Mar 17 21:40:44 2025 +0000 Ch20 encoding (#174) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. * REX after PREFIX * fixup load and store indirect * updated rex prefix, if its 0x40 then its not needed * Rex fix for floats, got rid of unnecessary stuff. * rename to camel case, better param name --------- Co-authored-by: Cliff Click commit d5b91a513b53c0e69a82f66f350b4e91a86f615d Author: Cliff Click Date: Mon Mar 17 12:22:33 2025 -0700 patch branch offsets commit 1a60b525475c3ad6e548af2e9417e4639aee210c Author: Cliff Click Date: Sun Mar 16 22:25:45 2025 -0700 Update LeaX86.java commit f727c10fe7ec84de7e8fefe16e9774bdae8eee6b Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Mon Mar 17 05:07:11 2025 +0000 Ch20 encoding (#172) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding * tfparm and intarm * uncontional jump encoding for arm and riscv * smarter IntARM, Intx86 does not always include rex. --------- Co-authored-by: Cliff Click commit 309da044c29f7f5e92f00aca911e69c8bfad7caf Author: Cliff Click Date: Sun Mar 16 22:03:51 2025 -0700 short-form x86 encodings commit 248ac2317de092ea5f302266962fdbec17045d42 Author: Cliff Click Date: Sun Mar 16 10:50:13 2025 -0700 Add unconditional arm,risc commit d15e43400bb7c7d0d27257d4c907206257c912b3 Author: Cliff Click Date: Sun Mar 16 10:41:20 2025 -0700 Unconditional jumps commit 30cea7d810dd9460fa7bd40d1dfb1393c71a0ee9 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sun Mar 16 00:03:20 2025 +0000 floatarm (#170) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv * readme init * Merged pr/169 * Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= * floatarm encoding --------- Co-authored-by: Cliff Click commit 251622b0111f9f49e04528a11e4ea4f19376b3ef Author: Cliff Click Date: Sat Mar 15 16:42:13 2025 -0700 Fixed the array1 test encodings Clean up branch invert logic during BB layout Cleanup branch target printing for RISC,ARM ImmRISC ops mask imm12 to 12 bits Fix NewRISC; hardcode RPC as part of call Fix RISC inverting branchs >,>= commit d4c1895977755a94602d9cbbe8ee743e6bdeb894 Author: Cliff Click Date: Sat Mar 15 16:11:27 2025 -0700 Merged pr/169 commit dc3a84cea6ad0b99c05ff7f6ab98edb905af0c4f Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Sat Mar 15 23:09:53 2025 +0000 Ch21 fixups (#169) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings * switch to binary literals over decimals for opcodes * logical immediates fixed, bitwise ops imm forms * tfp and setArm fixed * PC relative float for riscv --------- Co-authored-by: Cliff Click commit 5097e9f08dacb25e4c4aca20b48aa7d523067628 Author: Cliff Click Date: Sat Mar 15 16:05:04 2025 -0700 Encoding fixes commit fe27a3326becaf1a59286fa03d9aaa22504ec4ee Author: Cliff Click Date: Sat Mar 15 12:55:57 2025 -0700 Tests all pass commit b6cbd3d7b7698922e60e2c3eadadab51a430efe1 Author: Cliff Click Date: Sat Mar 15 12:06:11 2025 -0700 Progress towards no crashes Multi-part constant expansion was buggy when splitting down into functions. Improved printing for RISC multi-part constants. commit a36369843133a170718006600890d12ceb66a553 Author: Cliff Click Date: Fri Mar 14 16:48:07 2025 -0700 Buncha encoding related fixes. RA cloning `CmpIxxx` stretches the input live range, new for cloning... and was making broken graph. Several cloning related bugs in RISC & ARM. Invariant around RA cloning vs InstSelect is too complex commit 3fa376db5d05d738b6e1b6d01680ca5bfd79962d Author: Cliff Click Date: Fri Mar 14 15:17:49 2025 -0700 Progress on not-encoding tests commit 49a9c088087918f2018a2a6173805f044fd6a70c Author: Cliff Click Date: Fri Mar 14 14:33:03 2025 -0700 Push a driver for ARM logical 12-bit immediates commit 8784736848d846f40c90c41edeb9162c00d0bdbd Author: Cliff Click Date: Fri Mar 14 13:38:11 2025 -0700 ASM printer includes encodings commit de7fbdcf3f2002903d03c7737f573fa1e84cb306 Author: Cliff Click Date: Fri Mar 14 12:27:21 2025 -0700 Call encode commit f3ca559f9fe58d221e2d465845932f92278a7928 Author: Cliff Click Date: Fri Mar 14 12:24:17 2025 -0700 Encoding driver ch21 commit fd0123589d21c5055e4314b8bdf7e883f3d6d956 Author: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Date: Fri Mar 14 16:56:58 2025 +0000 Ch20 encoding (#167) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * First cut BuildLRG RegMask.EMPTY -> null * fix minor bug * Setup for first simple split * First cut split code for mismatch regs * delete non existing matches * replace RegMask.Empty with null * Live Ranges U-F BuildLRG for Phi Add CmpFX86 * FPR return CallEndX86 needed to tell fp return from gpr ret Call has no output regs. * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * turn off ch20 tests * Update Chapter20Test.java * RISC-V basic isel (#156) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java --------- Co-authored-by: Cliff Click * Bring pr/154 to ch 20 RISC5 changes. Some missing x86 ops. Still needs some calling convention love. * First cut regalloc working Biased coloring; tracking splits around a LRG. Separate split for self-conflicts. postColor to remove junk splits. Some minor riscv fixes. * Compile some riscv codes If SplitEmptyMask does not apply, fall back to normal split. Missing CmpFRISC. Renamed riscv flags. RetRISC handls FPR remove extra RegMask constructurs * add riscv port to readme * arm init * Progress reg alloc Handle multi-node projections. A little smarter about 2-addr scheduling RegAlloc must-have single registers removes from other masks instead of interfering; had the mask removal backwards in a few cases. LRG/RegMask COW expand masks before mutating. Clone small constants instead of spilling. Alloc & ProjX86 get output reg masks. Full print large reg masks with sp+offset * UF LRGs can be null during coloring * Finish UF find * work in progress * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * arm2 bs * Push RISC WMASK avoid writing to RSP * work in progress * clearnup arm * Progress calling convention allocations Call unlinks before reg alloc. CallEnd tracks RPC CallX86 requires TFP for correct ABI Bias Color tracks 2-addr. RPC gets a mask/stack-slot Clean up call/fun ABI Fix mask RET, RET_F Fix print stack slot Remove isMultiHead, isMultiTail Better all-asm print * Beef up Newton test * fixed main pr problems * regmask extra comments * Clean pass normal tests New fcn print upgrades several golden rule tests. Move the unlink-all from the walk::err call (which IS used during IterPeeps) to GCM. CallEnd upgrades return type based on constant call. Fix unlink to also unlink CallEnd Constant TFP print checks constant Tested an untested Load * Arm basics, minor changes in riscv (#160) * Initial push Major CodeGen cleanup; most static globals move into the CodeGen object. * Minor progress bug with mutual recursion * Add test from pr#148 * First cut x86 "port" Only "return 0;", no registers, no encoding, but yah gotta start somewhere * Update README.md * Update README.md * Update ListScheduler.java * command line launcher for simple Parser bug fref in args Some new test cases. * Add basic RegMask for more than 64 bits of register mask. Add calling convention basics to X86; con+ret RegMasks. GCM computes CFG for all users. Drop unused MultiUse. Pick up reg-pressure aware ListScheduler. Re-layout CodeGen file to get code & data chunks nearer each other. minor Ary extension * ASM Printer InstSel handles folding 2+ ideal ops into 1 machine op * handle instSel for some control flow Bool,If,CProj,Region,Phi Handle 2-op expansions Shuffle instSel graph walk back again. * Basic if-block inst selects and asm prints * Add mul-by-coinstant to shift * left shift codegen basic * exclude RSP from *write* mask * 2-arg add (not immediate) mul-by-small constant opt. Some utilities. * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * inst select for new struct allocation * Float, bitwise and arithmetic operands codegen x86-64 (#150) * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * Handle first loop Change inst sel walk again to pre-order, to set an early visit bit to stop cycles. CFGNode copies dom/loop info. Cmp not-immediate form. Ret/Fun lazy updates * float ops without imm values * merge * merge * inst select for new struct allocation * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * Remove non-exsting FP+imm ops * left shift codegen basic * sar codegen basic * merge * some basic ops * addf * divf, subf, mulf * rsp allowed in bitwise input, not output * formatting * float ops without imm values * merge * merge * Rebased on ch 19 * Update tests --------- Co-authored-by: Cliff Click * cleanup after merge alpha-sort helper fcns implicit test vs zero/null * Add LEA op asm print works on ideal nodes for all tests * Minor cleanup lea * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * x86 addressing modes during inst select Drop New taking inits; just follow with initializing stores. Simplifies inst selelection which otherwise needs to undo this optimization and emit following init stores. Basic load/store for now, op-to-mem comes later add same becomes Shl by 1. Drop DivF-immiedate * call setup * extended ch13, 14,15,16 (#153) * merge2 * merge3 * Fix a few minor fuzzer bugs * Force array layout ld/st get size (but not signed/unsigned) Add unsigned LT for later range checks. * Fix a bunch of float issues was deleting required inputs * simpler invariant defensive copy inputs for simpler invariant in complex sharing patterns inc/dec form (just the opcode now). * Call & CallR X86 instructions * merge2 * Add-from-memory op Remove FP immediate forms. * Remove name from TFP Never shoulda been there (but was convenient for awhile). Moved into FunNode, found by checking the linker table with a TFP. * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI * New (#154) * merge2 * merge3 * GCM for float ops fixed, other cleanup - small extensions * call setup * merge2 * remove debug prints add check for bad call convention fix 3 tests (bad merge?) * cleanup call convention abi Needs more love at some point... * one more cleanup ABI --------- Co-authored-by: Cliff Click * Add CmpMem form Common addressing mode print LEA can skip a base * Add a AddFMemX86 A bunch of mem op patterns are missing, hopefully they are just cut-n-paste from the existing patterns. * Docs * XMM reg mask fix Minor README updates * Allow inverted cmp/mem narrowing stores can bypass an AndMask Array length loads do not need control Some missing print info * Support "*ptr op= val" at least for MemAdd * missed golden rule update * Array len is u32 load-after-store zero/sign-extends if the store is truncating * One more missed case * riscv init * added not imm form bitwise shifts and ops plus test cases * addressing modes(high chance it'll get deleted) * fix minor bug * delete non existing matches * replace RegMask.Empty with null * riscv handle store and load, fltRisch uses risc reg now * load float into GPR and then later in RA do hard split. * minor changes * turn off ch20 tests * Update Chapter20Test.java * add riscv port to readme * arm init * work in progress * arm2 bs * work in progress * clearnup arm * fixed main pr problems * regmask extra comments --------- Co-authored-by: Cliff Click * Update Chapter20Test.java * Weaken range-check test since no range checks... test cannot fail (pass) * Fix issue #161 Error adding 'null' and '5' * bug fixs, cloning constants Fix bug missing Find. Fix bug setDef does unordered removal from basic blocks. Use cloned constants for spilling. * RA fixes SplitSelfConflict MUST split before uses and after defs. Split global constants across functions Missing find in union; Inserting split after new inserted wrong place Pre-remove null LRGs before color. Bias color hunts through Phis Shorten InstructionSelection. Rename !unified() to leader() AddMemX86 is 2-addr Add CastXXX to preserve register across cast. * encoding init * encoding init 2 * rex fix * indirect addressing modes * setop change opcode, rename FLOAT_OFFSET * mask sib and modrm with 3 bits, 4th bit goes into rex. * sign extend div with cqo * idiv input is fixed to rax and RMASK, grab input from second slot when encoding * encoding of newx86 * tfp and CallEndNode encoding * sib improvement * more cleanups * more cleanups * Allow a killMap to kill regs. Bugfix scheduler. Bugfix spiller - self-conflict order depended on hashtable iteration order, which depended on System.hashCode which would vary run to run. Improvements to coloring Improvements to spill quality testing * Added flags-kill for XOR * Missing add-deps from fuzzer * Update Chapter14Test.java * fixed order of operands * base rex fixup * more bug fix * remove jukn files * minimal "make release" * further fixes * minor fixes * minor fixes * minor fixes * base != -1 check, precedence fix * Add regkills in IFG building Fix bug LRG union stats Adjust self-conflict splits to be slightly less aggressive In every use-side split, dont split-after-split same block. NewNode is a multi, does not define a register * 64 bit encoding for gpr(s) load * RA improvements Attempt to commute to keep reg-masks compatible. Clones with kills (x86 XOR killing flags to zero) fail before the flag-def. Bugfix failed to color last lrg. More smarts on picking trivial LRGs during coloring Drop isSplit, add SplitNode Pass regalloc round to all splits for debugging Self-conflict no split on loop backedge. Handle split that gets made goes dead No-reg-mask spilling handles case with many def/uses. Add DivIX86 BrainFuck, MergeSort now allocate as testing * 8 bit imm support * conditional jump fix * Push l,ast change, unbreak branch * XOR remove extra opcode, imm size supports 8 bit. * Finally pass the `new [u8]` double-copy test * Fix several ARM reg setup problems Finish Split bypass check ARM: rsp is also a fixed zero, in R31. R0 is a valid register. CallArm prints args, passes TFP for arg selection. Does not return a register. All CallEndARM which DOES return a register. Parms missing tfp for float args. ProjARM after a New missing regs. RetARM missing RPC. Remove hopeful DivIX86 * 64 bit imm for alu ops encoded in extra reg then use it in Op as an operand * Bunch of minor arm, risc fixes small constants not cloning * jump invert encoding * warning comment * Much ARM fixage One More Go-Round with Better Biased Colors Fix bug picking deepest spills to bias. ARM: remove default 2-address. Fix regmask overflow. Rename some ops to be canonical. * Fixes to release Port does not have to be in a Simple named directory. Call convention is just a string, no enum Missed some tests running RISC, ARM. * Minor release change to allow another foreign port * better split encoding and fix CallInMask * notNode * fix callInMask * riscv init * riscv basic ALU ops and types of instructions * Allowing non-Simple repo ports Expanding public API slightly so alternative (non-Simple repo) ports can happen. RegMask supports single-bit-set and a long bitmask. Bugfix GCM splitting multiple global constants. Bugfix LCM grabbing a projection vs multi Bugfix RegAlloc when avoiding splitting a clonable Source code in release More timing in CodeGen * riscv indirect addressing and function calls * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * Store Risc adjustments, no imm in MemOpRISC * specific print encoding for cpus * merge fixup * More x86,risc,arm call convention fixes Collect callee and caller save masks (inverts of each other, except for spills). Reorg layout to be closer to each other; remove dead mask definitions; add final keyword * lui fix up with 32 bit immediates * Callee-save registers Callee-save registers and masks and inserting LRGs for same and spilling and picking good spills. Insert CalleeSaveNodes and edges to RetXXXs and RegMasks for those edges. Iterators for regmask. Better printing post-allocation * RegMask supports 128 bits All regs available arm, risc. MergeSort compiles & runs * added flags splitting * Fix risc5 compares No flags on risc5. Branch takes 2 inputs (one can be imm12). Float compare only sets a GPR to 0/1. Bool has a isFloat Common risc5 imm-form handling * extend test cases * imm encoding, flags fixed * grep for Todo: relocs * float riscv fixed * flags for set * lui fix for small bits [0, 12] * arm init * arm last touches * fmov still needs fix * minor fixes * minor fixes(2) * got rid of unnecessary stuff * create ch21 * remove encodings from chapter20 dir * 1/2 pass cleaning up ARM encoding API * ARM encoding compiles * Risc R_TYPE and I_TYPE * Progress RISC encodings Missing lots of stuff still * progress risc encoding * risc encodings compile * Update README.md * Fold up redundant OP/OP-FP risc5 encoding * x86 mem opcodes first cut break out MemOp encodings into parts; change x86 indirectAdr to use Encoding class, remove redundant asserts & code * x86 mem op encodings * x86 reg+imm forms * most reg-reg forms * More x86 encodings * Last few encodings --------- Co-authored-by: Cliff Click commit d8e9a8152d1d3122b5d0da6d1c7a12203011a0f7 Author: Cliff Click Date: Mon Mar 10 12:55:06 2025 -0700 First cut BB layout commit 10013969971a6c2f3a8b0966323ae35e9a3fb1d8 Author: Cliff Click Date: Mon Mar 10 12:54:46 2025 -0700 Update README.md commit 4d5538c4b9df61d6c2524868bd005030123b3189 Author: Cliff Click Date: Sat Mar 8 15:17:22 2025 -0800 first cut encoding driver ASM printer skips jmps to next-blocks commit 1fd6f46cca3541861d56f3710728d34791beedf8 Author: Cliff Click Date: Sat Mar 8 11:01:01 2025 -0800 chapter 21 encodings first push --- README.md | 1 + chapter19/README.md | 36 +- chapter20/README.md | 66 +- .../com/seaofnodes/simple/codegen/RegAlloc.java | 2 +- .../java/com/seaofnodes/simple/node/CFGNode.java | 3 +- .../seaofnodes/simple/node/cpus/arm/NotARM.java | 26 + .../seaofnodes/simple/node/cpus/arm/SubIARM.java | 42 + .../seaofnodes/simple/node/cpus/riscv/NotRISC.java | 25 + .../simple/node/cpus/x86_64_v2/CallRX86.java | 7 +- .../simple/node/cpus/x86_64_v2/CallX86.java | 8 +- .../simple/node/cpus/x86_64_v2/FunX86.java | 2 +- .../simple/node/cpus/x86_64_v2/NotX86.java | 26 + .../simple/node/cpus/x86_64_v2/ParmX86.java | 4 +- .../simple/node/cpus/x86_64_v2/ProjX86.java | 2 +- .../simple/node/cpus/x86_64_v2/RetX86.java | 7 +- .../simple/node/cpus/x86_64_v2/XorX86.java | 36 + chapter21/Makefile | 114 ++ chapter21/README.md | 800 ++++++++ chapter21/docs/18-grammar.md | 132 ++ chapter21/docs/Makefile | 12 + chapter21/docs/d3-graphviz.js | 2014 ++++++++++++++++++++ chapter21/docs/d3.v7.min.js | 2 + chapter21/docs/font-awesome-4.7.0.zip | Bin 0 -> 669808 bytes chapter21/docs/graphviz.umd.js | 7 + chapter21/docs/ifg_trim.pdf | Bin 0 -> 155190 bytes chapter21/docs/index.html | 218 +++ chapter21/docs/lattice.gv | 203 ++ chapter21/docs/lattice.svg | 691 +++++++ chapter21/docs/lattice2.gv | 85 + chapter21/docs/lattice2.svg | 260 +++ chapter21/docs/pardoe.docx | Bin 0 -> 22583 bytes chapter21/docs/webtcp.min.js | 65 + chapter21/pom.xml | 14 + chapter21/simple | 0 chapter21/simple.bat | 1 + chapter21/simple.sh | 2 + .../src/main/java/com/seaofnodes/simple/Ary.java | 228 +++ .../main/java/com/seaofnodes/simple/IterPeeps.java | 199 ++ .../main/java/com/seaofnodes/simple/Parser.java | 1751 +++++++++++++++++ .../src/main/java/com/seaofnodes/simple/SB.java | 99 + .../src/main/java/com/seaofnodes/simple/Utils.java | 53 + .../src/main/java/com/seaofnodes/simple/Var.java | 55 + .../com/seaofnodes/simple/codegen/BuildLRG.java | 90 + .../com/seaofnodes/simple/codegen/Coalesce.java | 105 + .../com/seaofnodes/simple/codegen/CodeGen.java | 463 +++++ .../com/seaofnodes/simple/codegen/ElfExpr.java | 87 + .../com/seaofnodes/simple/codegen/ElfFile.java | 381 ++++ .../com/seaofnodes/simple/codegen/Encoding.java | 475 +++++ .../simple/codegen/GlobalCodeMotion.java | 285 +++ .../java/com/seaofnodes/simple/codegen/IFG.java | 551 ++++++ .../java/com/seaofnodes/simple/codegen/LRG.java | 234 +++ .../com/seaofnodes/simple/codegen/LinkMem.java | 23 + .../seaofnodes/simple/codegen/ListScheduler.java | 261 +++ .../com/seaofnodes/simple/codegen/Machine.java | 93 + .../com/seaofnodes/simple/codegen/RIPRelSize.java | 14 + .../com/seaofnodes/simple/codegen/RegAlloc.java | 625 ++++++ .../com/seaofnodes/simple/codegen/RegMask.java | 126 ++ .../com/seaofnodes/simple/codegen/RegMaskRW.java | 36 + .../java/com/seaofnodes/simple/node/AddFNode.java | 44 + .../java/com/seaofnodes/simple/node/AddNode.java | 199 ++ .../java/com/seaofnodes/simple/node/AndNode.java | 61 + .../java/com/seaofnodes/simple/node/BoolNode.java | 149 ++ .../java/com/seaofnodes/simple/node/CFGNode.java | 192 ++ .../java/com/seaofnodes/simple/node/CProjNode.java | 68 + .../com/seaofnodes/simple/node/CallEndNode.java | 130 ++ .../java/com/seaofnodes/simple/node/CallNode.java | 168 ++ .../com/seaofnodes/simple/node/CalleeSaveNode.java | 23 + .../java/com/seaofnodes/simple/node/CastNode.java | 64 + .../com/seaofnodes/simple/node/ConstantNode.java | 70 + .../java/com/seaofnodes/simple/node/CtrlNode.java | 15 + .../java/com/seaofnodes/simple/node/DivFNode.java | 41 + .../java/com/seaofnodes/simple/node/DivNode.java | 46 + .../java/com/seaofnodes/simple/node/FRefNode.java | 35 + .../java/com/seaofnodes/simple/node/FunNode.java | 216 +++ .../java/com/seaofnodes/simple/node/IfNode.java | 97 + .../java/com/seaofnodes/simple/node/LoadNode.java | 210 ++ .../com/seaofnodes/simple/node/LogicalNode.java | 29 + .../java/com/seaofnodes/simple/node/LoopNode.java | 101 + .../seaofnodes/simple/node/MachConcreteNode.java | 27 + .../java/com/seaofnodes/simple/node/MachNode.java | 58 + .../com/seaofnodes/simple/node/MemMergeNode.java | 162 ++ .../java/com/seaofnodes/simple/node/MemOpNode.java | 110 ++ .../com/seaofnodes/simple/node/MinusFNode.java | 36 + .../java/com/seaofnodes/simple/node/MinusNode.java | 40 + .../java/com/seaofnodes/simple/node/MulFNode.java | 51 + .../java/com/seaofnodes/simple/node/MulNode.java | 87 + .../java/com/seaofnodes/simple/node/MultiNode.java | 29 + .../java/com/seaofnodes/simple/node/NeverNode.java | 22 + .../java/com/seaofnodes/simple/node/NewNode.java | 119 ++ .../main/java/com/seaofnodes/simple/node/Node.java | 731 +++++++ .../java/com/seaofnodes/simple/node/NotNode.java | 32 + .../java/com/seaofnodes/simple/node/OrNode.java | 55 + .../java/com/seaofnodes/simple/node/ParmNode.java | 48 + .../java/com/seaofnodes/simple/node/PhiNode.java | 221 +++ .../java/com/seaofnodes/simple/node/ProjNode.java | 54 + .../com/seaofnodes/simple/node/ReadOnlyNode.java | 30 + .../com/seaofnodes/simple/node/RegionNode.java | 167 ++ .../com/seaofnodes/simple/node/ReturnNode.java | 168 ++ .../com/seaofnodes/simple/node/RoundF32Node.java | 38 + .../java/com/seaofnodes/simple/node/SarNode.java | 50 + .../java/com/seaofnodes/simple/node/ScopeNode.java | 429 +++++ .../java/com/seaofnodes/simple/node/ShlNode.java | 53 + .../java/com/seaofnodes/simple/node/ShrNode.java | 46 + .../java/com/seaofnodes/simple/node/SplitNode.java | 25 + .../java/com/seaofnodes/simple/node/StartNode.java | 57 + .../java/com/seaofnodes/simple/node/StopNode.java | 65 + .../java/com/seaofnodes/simple/node/StoreNode.java | 112 ++ .../com/seaofnodes/simple/node/StructNode.java | 46 + .../java/com/seaofnodes/simple/node/SubFNode.java | 44 + .../java/com/seaofnodes/simple/node/SubNode.java | 59 + .../com/seaofnodes/simple/node/ToFloatNode.java | 34 + .../java/com/seaofnodes/simple/node/XCtrlNode.java | 15 + .../java/com/seaofnodes/simple/node/XorNode.java | 54 + .../seaofnodes/simple/node/cpus/arm/AddARM.java | 20 + .../seaofnodes/simple/node/cpus/arm/AddFARM.java | 22 + .../seaofnodes/simple/node/cpus/arm/AddIARM.java | 27 + .../seaofnodes/simple/node/cpus/arm/AndARM.java | 21 + .../seaofnodes/simple/node/cpus/arm/AndIARM.java | 24 + .../seaofnodes/simple/node/cpus/arm/AsrARM.java | 18 + .../seaofnodes/simple/node/cpus/arm/AsrIARM.java | 31 + .../seaofnodes/simple/node/cpus/arm/BranchARM.java | 76 + .../seaofnodes/simple/node/cpus/arm/CallARM.java | 47 + .../simple/node/cpus/arm/CallEndARM.java | 8 + .../seaofnodes/simple/node/cpus/arm/CallRRARM.java | 32 + .../seaofnodes/simple/node/cpus/arm/CastARM.java | 18 + .../seaofnodes/simple/node/cpus/arm/CmpARM.java | 22 + .../seaofnodes/simple/node/cpus/arm/CmpFARM.java | 22 + .../seaofnodes/simple/node/cpus/arm/CmpIARM.java | 40 + .../seaofnodes/simple/node/cpus/arm/DivARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/DivFARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/FloatARM.java | 45 + .../seaofnodes/simple/node/cpus/arm/FunARM.java | 22 + .../seaofnodes/simple/node/cpus/arm/I2F8ARM.java | 25 + .../seaofnodes/simple/node/cpus/arm/IntARM.java | 67 + .../seaofnodes/simple/node/cpus/arm/LoadARM.java | 39 + .../seaofnodes/simple/node/cpus/arm/LslARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/LslIARM.java | 33 + .../seaofnodes/simple/node/cpus/arm/LsrARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/LsrIARM.java | 29 + .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 69 + .../seaofnodes/simple/node/cpus/arm/MulARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/MulFARM.java | 18 + .../seaofnodes/simple/node/cpus/arm/NegARM.java | 25 + .../seaofnodes/simple/node/cpus/arm/NewARM.java | 36 + .../seaofnodes/simple/node/cpus/arm/NotARM.java | 28 + .../com/seaofnodes/simple/node/cpus/arm/OrARM.java | 20 + .../seaofnodes/simple/node/cpus/arm/OrIARM.java | 24 + .../seaofnodes/simple/node/cpus/arm/ParmARM.java | 17 + .../seaofnodes/simple/node/cpus/arm/ProjARM.java | 15 + .../seaofnodes/simple/node/cpus/arm/RetARM.java | 15 + .../seaofnodes/simple/node/cpus/arm/SetARM.java | 32 + .../seaofnodes/simple/node/cpus/arm/SplitARM.java | 66 + .../seaofnodes/simple/node/cpus/arm/StoreARM.java | 43 + .../seaofnodes/simple/node/cpus/arm/SubARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/SubFARM.java | 18 + .../seaofnodes/simple/node/cpus/arm/SubIARM.java | 29 + .../seaofnodes/simple/node/cpus/arm/TFPARM.java | 53 + .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 48 + .../seaofnodes/simple/node/cpus/arm/XorARM.java | 19 + .../seaofnodes/simple/node/cpus/arm/XorIARM.java | 27 + .../com/seaofnodes/simple/node/cpus/arm/arm.java | 815 ++++++++ .../seaofnodes/simple/node/cpus/riscv/AUIPC.java | 41 + .../simple/node/cpus/riscv/AddFRISC.java | 17 + .../simple/node/cpus/riscv/AddIRISC.java | 21 + .../seaofnodes/simple/node/cpus/riscv/AddRISC.java | 21 + .../simple/node/cpus/riscv/AndIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/AndRISC.java | 16 + .../simple/node/cpus/riscv/BranchRISC.java | 92 + .../simple/node/cpus/riscv/CallEndRISC.java | 8 + .../simple/node/cpus/riscv/CallRISC.java | 60 + .../simple/node/cpus/riscv/CallRRISC.java | 31 + .../simple/node/cpus/riscv/CastRISC.java | 18 + .../simple/node/cpus/riscv/DivFRISC.java | 19 + .../seaofnodes/simple/node/cpus/riscv/DivRISC.java | 17 + .../seaofnodes/simple/node/cpus/riscv/FltRISC.java | 47 + .../seaofnodes/simple/node/cpus/riscv/FunRISC.java | 22 + .../simple/node/cpus/riscv/I2F8RISC.java | 23 + .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 54 + .../seaofnodes/simple/node/cpus/riscv/IntRISC.java | 30 + .../com/seaofnodes/simple/node/cpus/riscv/LUI.java | 32 + .../simple/node/cpus/riscv/LoadRISC.java | 29 + .../simple/node/cpus/riscv/MemOpRISC.java | 74 + .../simple/node/cpus/riscv/MulFRISC.java | 17 + .../seaofnodes/simple/node/cpus/riscv/MulRISC.java | 17 + .../seaofnodes/simple/node/cpus/riscv/NegRISC.java | 20 + .../seaofnodes/simple/node/cpus/riscv/NewRISC.java | 46 + .../seaofnodes/simple/node/cpus/riscv/NotRISC.java | 20 + .../seaofnodes/simple/node/cpus/riscv/OrIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/OrRISC.java | 16 + .../simple/node/cpus/riscv/ParmRISC.java | 17 + .../simple/node/cpus/riscv/ProjRISC.java | 15 + .../seaofnodes/simple/node/cpus/riscv/RetRISC.java | 21 + .../simple/node/cpus/riscv/SetFRISC.java | 33 + .../simple/node/cpus/riscv/SetIRISC.java | 17 + .../seaofnodes/simple/node/cpus/riscv/SetRISC.java | 20 + .../simple/node/cpus/riscv/SllIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/SllRISC.java | 17 + .../simple/node/cpus/riscv/SplitRISC.java | 66 + .../simple/node/cpus/riscv/SraIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/SraRISC.java | 17 + .../simple/node/cpus/riscv/SrlIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/SrlRISC.java | 17 + .../simple/node/cpus/riscv/StoreRISC.java | 47 + .../simple/node/cpus/riscv/SubFRISC.java | 17 + .../seaofnodes/simple/node/cpus/riscv/SubRISC.java | 16 + .../seaofnodes/simple/node/cpus/riscv/TFPRISC.java | 55 + .../simple/node/cpus/riscv/UJmpRISC.java | 46 + .../simple/node/cpus/riscv/XorIRISC.java | 12 + .../seaofnodes/simple/node/cpus/riscv/XorRISC.java | 16 + .../seaofnodes/simple/node/cpus/riscv/riscv.java | 542 ++++++ .../simple/node/cpus/x86_64_v2/AddFMemX86.java | 44 + .../simple/node/cpus/x86_64_v2/AddFX86.java | 33 + .../simple/node/cpus/x86_64_v2/AddIX86.java | 13 + .../simple/node/cpus/x86_64_v2/AddMemX86.java | 34 + .../simple/node/cpus/x86_64_v2/AddX86.java | 11 + .../simple/node/cpus/x86_64_v2/AndIX86.java | 11 + .../simple/node/cpus/x86_64_v2/AndX86.java | 11 + .../simple/node/cpus/x86_64_v2/CallEndX86.java | 8 + .../simple/node/cpus/x86_64_v2/CallRX86.java | 33 + .../simple/node/cpus/x86_64_v2/CallX86.java | 45 + .../simple/node/cpus/x86_64_v2/CastX86.java | 16 + .../simple/node/cpus/x86_64_v2/CmpFX86.java | 32 + .../simple/node/cpus/x86_64_v2/CmpIX86.java | 44 + .../simple/node/cpus/x86_64_v2/CmpMemX86.java | 78 + .../simple/node/cpus/x86_64_v2/CmpX86.java | 26 + .../simple/node/cpus/x86_64_v2/DivFX86.java | 34 + .../simple/node/cpus/x86_64_v2/DivX86.java | 33 + .../simple/node/cpus/x86_64_v2/FltX86.java | 47 + .../simple/node/cpus/x86_64_v2/FunX86.java | 34 + .../simple/node/cpus/x86_64_v2/I2f8X86.java | 31 + .../simple/node/cpus/x86_64_v2/ImmX86.java | 37 + .../simple/node/cpus/x86_64_v2/IntX86.java | 76 + .../simple/node/cpus/x86_64_v2/JmpX86.java | 80 + .../simple/node/cpus/x86_64_v2/LeaX86.java | 55 + .../simple/node/cpus/x86_64_v2/LoadX86.java | 60 + .../simple/node/cpus/x86_64_v2/MemAddX86.java | 39 + .../simple/node/cpus/x86_64_v2/MemOpX86.java | 88 + .../simple/node/cpus/x86_64_v2/MulFX86.java | 32 + .../simple/node/cpus/x86_64_v2/MulIX86.java | 11 + .../simple/node/cpus/x86_64_v2/MulX86.java | 29 + .../simple/node/cpus/x86_64_v2/NegX86.java | 21 + .../simple/node/cpus/x86_64_v2/NewX86.java | 25 + .../simple/node/cpus/x86_64_v2/NotX86.java | 39 + .../simple/node/cpus/x86_64_v2/OrIX86.java | 11 + .../simple/node/cpus/x86_64_v2/OrX86.java | 11 + .../simple/node/cpus/x86_64_v2/ParmX86.java | 17 + .../simple/node/cpus/x86_64_v2/ProjX86.java | 15 + .../simple/node/cpus/x86_64_v2/RegX86.java | 26 + .../simple/node/cpus/x86_64_v2/RetX86.java | 19 + .../simple/node/cpus/x86_64_v2/SarIX86.java | 40 + .../simple/node/cpus/x86_64_v2/SarX86.java | 24 + .../simple/node/cpus/x86_64_v2/SetX86.java | 53 + .../simple/node/cpus/x86_64_v2/ShlIX86.java | 40 + .../simple/node/cpus/x86_64_v2/ShlX86.java | 24 + .../simple/node/cpus/x86_64_v2/ShrIX86.java | 35 + .../simple/node/cpus/x86_64_v2/ShrX86.java | 24 + .../simple/node/cpus/x86_64_v2/SplitX86.java | 100 + .../simple/node/cpus/x86_64_v2/StoreX86.java | 85 + .../simple/node/cpus/x86_64_v2/SubFX86.java | 31 + .../simple/node/cpus/x86_64_v2/SubX86.java | 10 + .../simple/node/cpus/x86_64_v2/TFPX86.java | 66 + .../simple/node/cpus/x86_64_v2/UJmpX86.java | 53 + .../simple/node/cpus/x86_64_v2/XorIX86.java | 11 + .../simple/node/cpus/x86_64_v2/XorX86.java | 11 + .../simple/node/cpus/x86_64_v2/x86_64_v2.java | 644 +++++++ .../com/seaofnodes/simple/print/ASMPrinter.java | 286 +++ .../seaofnodes/simple/print/GraphVisualizer.java | 287 +++ .../com/seaofnodes/simple/print/IRPrinter.java | 331 ++++ .../java/com/seaofnodes/simple/print/JSViewer.java | 405 ++++ .../seaofnodes/simple/print/SimpleWebSocket.java | 149 ++ .../java/com/seaofnodes/simple/type/Field.java | 74 + .../main/java/com/seaofnodes/simple/type/Type.java | 236 +++ .../java/com/seaofnodes/simple/type/TypeFloat.java | 95 + .../com/seaofnodes/simple/type/TypeFunPtr.java | 107 ++ .../com/seaofnodes/simple/type/TypeInteger.java | 128 ++ .../java/com/seaofnodes/simple/type/TypeMem.java | 74 + .../com/seaofnodes/simple/type/TypeMemPtr.java | 105 + .../java/com/seaofnodes/simple/type/TypeNil.java | 62 + .../java/com/seaofnodes/simple/type/TypePtr.java | 53 + .../java/com/seaofnodes/simple/type/TypeRPC.java | 100 + .../com/seaofnodes/simple/type/TypeStruct.java | 249 +++ .../java/com/seaofnodes/simple/type/TypeTuple.java | 115 ++ .../java/com/seaofnodes/simple/BrainFuckTest.java | 38 + .../java/com/seaofnodes/simple/Chapter01Test.java | 95 + .../java/com/seaofnodes/simple/Chapter02Test.java | 61 + .../java/com/seaofnodes/simple/Chapter03Test.java | 73 + .../java/com/seaofnodes/simple/Chapter04Test.java | 131 ++ .../java/com/seaofnodes/simple/Chapter05Test.java | 186 ++ .../java/com/seaofnodes/simple/Chapter06Test.java | 305 +++ .../java/com/seaofnodes/simple/Chapter07Test.java | 222 +++ .../java/com/seaofnodes/simple/Chapter08Test.java | 208 ++ .../java/com/seaofnodes/simple/Chapter09Test.java | 296 +++ .../java/com/seaofnodes/simple/Chapter10Test.java | 397 ++++ .../java/com/seaofnodes/simple/Chapter11Test.java | 551 ++++++ .../java/com/seaofnodes/simple/Chapter12Test.java | 61 + .../java/com/seaofnodes/simple/Chapter13Test.java | 261 +++ .../java/com/seaofnodes/simple/Chapter14Test.java | 226 +++ .../java/com/seaofnodes/simple/Chapter15Test.java | 354 ++++ .../java/com/seaofnodes/simple/Chapter16Test.java | 261 +++ .../java/com/seaofnodes/simple/Chapter17Test.java | 555 ++++++ .../java/com/seaofnodes/simple/Chapter18Test.java | 370 ++++ .../java/com/seaofnodes/simple/Chapter19Test.java | 331 ++++ .../java/com/seaofnodes/simple/Chapter20Test.java | 151 ++ .../java/com/seaofnodes/simple/Chapter21Test.java | 276 +++ .../test/java/com/seaofnodes/simple/Compile.java | 65 + .../src/test/java/com/seaofnodes/simple/Eval2.java | 450 +++++ .../test/java/com/seaofnodes/simple/EvalArm64.java | 751 ++++++++ .../test/java/com/seaofnodes/simple/EvalRisc5.java | 353 ++++ .../java/com/seaofnodes/simple/FuzzerWrap.java | 43 + .../src/test/java/com/seaofnodes/simple/Main.java | 18 + .../java/com/seaofnodes/simple/MergeSortTest.java | 44 + .../java/com/seaofnodes/simple/SchedulerTest.java | 74 + .../test/java/com/seaofnodes/simple/Simple.java | 313 +++ .../test/java/com/seaofnodes/simple/TestArm64.java | 42 + .../src/test/java/com/seaofnodes/simple/TestC.java | 89 + .../test/java/com/seaofnodes/simple/TestRisc5.java | 50 + .../test/java/com/seaofnodes/simple/TypeTest.java | 158 ++ .../com/seaofnodes/simple/evaluator/Evaluator.java | 383 ++++ .../com/seaofnodes/simple/evaluator/Scheduler.java | 606 ++++++ .../java/com/seaofnodes/simple/fuzzer/Fuzzer.java | 174 ++ .../com/seaofnodes/simple/fuzzer/FuzzerUtils.java | 111 ++ .../java/com/seaofnodes/simple/fuzzer/Reducer.java | 176 ++ .../seaofnodes/simple/fuzzer/ScriptGenerator.java | 869 +++++++++ .../java/com/seaofnodes/simple/progs/antiDep1.smp | 11 + .../java/com/seaofnodes/simple/progs/arg_count.c | 10 + .../java/com/seaofnodes/simple/progs/arg_count.smp | 6 + .../java/com/seaofnodes/simple/progs/array1.smp | 9 + .../java/com/seaofnodes/simple/progs/brain_fuck.c | 18 + .../com/seaofnodes/simple/progs/brain_fuck.smp | 46 + .../test/java/com/seaofnodes/simple/progs/fib.c | 16 + .../test/java/com/seaofnodes/simple/progs/fib.smp | 11 + .../test/java/com/seaofnodes/simple/progs/jig.smp | 9 + .../test/java/com/seaofnodes/simple/progs/loop2.c | 7 + .../java/com/seaofnodes/simple/progs/loop2.smp | 10 + .../java/com/seaofnodes/simple/progs/newtonFloat.c | 16 + .../com/seaofnodes/simple/progs/newtonFloat.smp | 12 + .../seaofnodes/simple/progs/no_stack_arg_count.smp | 6 + .../test/java/com/seaofnodes/simple/progs/person.c | 34 + .../java/com/seaofnodes/simple/progs/person.smp | 9 + .../test/java/com/seaofnodes/simple/progs/sieve.c | 19 + .../java/com/seaofnodes/simple/progs/sieve.smp | 31 + .../test/java/com/seaofnodes/simple/progs/sort.c | 28 + .../test/java/com/seaofnodes/simple/progs/sort.smp | 38 + .../java/com/seaofnodes/simple/progs/stringHash.c | 30 + .../com/seaofnodes/simple/progs/stringHash.smp | 31 + pom.xml | 1 + 346 files changed, 36526 insertions(+), 33 deletions(-) create mode 100644 chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java create mode 100644 chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java create mode 100644 chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java create mode 100644 chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java create mode 100644 chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java create mode 100644 chapter21/Makefile create mode 100644 chapter21/README.md create mode 100644 chapter21/docs/18-grammar.md create mode 100644 chapter21/docs/Makefile create mode 100644 chapter21/docs/d3-graphviz.js create mode 100644 chapter21/docs/d3.v7.min.js create mode 100644 chapter21/docs/font-awesome-4.7.0.zip create mode 100644 chapter21/docs/graphviz.umd.js create mode 100644 chapter21/docs/ifg_trim.pdf create mode 100644 chapter21/docs/index.html create mode 100644 chapter21/docs/lattice.gv create mode 100644 chapter21/docs/lattice.svg create mode 100644 chapter21/docs/lattice2.gv create mode 100644 chapter21/docs/lattice2.svg create mode 100644 chapter21/docs/pardoe.docx create mode 100644 chapter21/docs/webtcp.min.js create mode 100644 chapter21/pom.xml create mode 100644 chapter21/simple create mode 100644 chapter21/simple.bat create mode 100755 chapter21/simple.sh create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/Ary.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/IterPeeps.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/Parser.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/SB.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/Utils.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/Var.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/LRG.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/Machine.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/RIPRelSize.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/RegMask.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/codegen/RegMaskRW.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/AndNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CFGNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/FunNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/MultiNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/Node.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/OrNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/SarNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ShlNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ShrNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/XorNode.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CastARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/print/JSViewer.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/Field.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/Type.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeFloat.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeInteger.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeMem.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeNil.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypePtr.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeRPC.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeStruct.java create mode 100644 chapter21/src/main/java/com/seaofnodes/simple/type/TypeTuple.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter01Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter02Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter03Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter05Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter06Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter07Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter08Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter09Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter10Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter13Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter14Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter16Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter17Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Compile.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Eval2.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/FuzzerWrap.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Main.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/MergeSortTest.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/SchedulerTest.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/Simple.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/TestC.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/TypeTest.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/fuzzer/Reducer.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/antiDep1.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/arg_count.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/arg_count.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/array1.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/brain_fuck.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/fib.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/fib.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/loop2.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/loop2.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/newtonFloat.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/newtonFloat.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/no_stack_arg_count.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/person.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/person.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/sort.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/sort.smp create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/stringHash.c create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/stringHash.smp diff --git a/README.md b/README.md index 5eeccb1e..e2923fb5 100644 --- a/README.md +++ b/README.md @@ -64,3 +64,4 @@ The Simple language is styled after a subset of C or Java. * [Chapter 18](chapter18/README.md): Functions and calls. * [Chapter 19](chapter19/README.md): Instruction selection and portable compilation * [Chapter 20](chapter20/README.md): Graph Coloring Register Allocation +* [Chapter 21](chapter21/README.md): Instruction Encodings & ELF diff --git a/chapter19/README.md b/chapter19/README.md index a866876d..0d8e481f 100644 --- a/chapter19/README.md +++ b/chapter19/README.md @@ -3,6 +3,20 @@ You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter19) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter18...linear-chapter19) it to the previous chapter. +## Meta-Issues / Code-Dev Issues of Instruction Selection, Register Allocation and Encodings + +The output of Instruction Selection - the mapping from idealized Simple Nodes +to machine-specific ones - is difficult to test in bulk without an execution +strategy. We won't have an execution stratgy until all three of Instruction +Selection, Register Allocation and Encodings are done. Hence in and around the +completion of Encoding we expect to find lots of bugs in Instruction Selection +and Register Allocation. We certainly hand-inspect the output and fix obvious +problems, but still lots bugs linger until we can actually run the code. + +This means that other chapters have updates and bug-fixes to the work being +described here. + + ## Portable Compilation A new abstract `Machine` class is added, one per unique CPU port. `Machine` @@ -24,8 +38,8 @@ implementation at least the ability to add CPU ports lazily. ## Machine Specific Nodes -We add a notion of "machine specific" Nodes, which implement the `Mach` -interface. `Mach` nodes define incoming and outgoing registers for every +We add a notion of "machine specific" Nodes, which implement the `MachNode` +interface. `MachNode` nodes define incoming and outgoing registers for every instruction, their bit encodings and user representations. Later we'll add function unit information for a better local schedule. @@ -110,11 +124,11 @@ E.g `lea` is not present. ### Branching -In `x86_64_v2`, branching requires a comparison instruction to set flags, -followed by a jump instruction that uses those flags. -In contrast, RISC-V includes all necessary operands within the -branch instruction itself, eliminating the need for a separate -comparison step. + +In `x86_64_v2`, branching requires a comparison instruction to set flags, +followed by a jump instruction that uses those flags. In contrast, RISC-V +includes all necessary operands within the branch instruction itself, +eliminating the need for a separate comparison step. E.g ``` @@ -122,9 +136,10 @@ beq x10, x11, some_label ``` `CBranchRISC` implements this behavior. + ### No R-Flags -No R-flags exist in RiSC-V. To obtain similar functionality: +No R-flags exist in RiSC-V. To obtain similar functionality: We can set the value of registers based on the result of the comparison this way explicitly. ``` xor a0, a0, a1 @@ -135,8 +150,9 @@ The `seqz` instruction will set `a0` to 1 if `a0` is zero from the previous oper This matches `SetRISC` in the `nodes/cpus/riscv` port. ### Fixed instruction length -RISC-V instructions have fixed length of 32 bits(in most cases) which means that we can benefit -from displacements in the encoding side. + +RISC-V instructions have fixed length of 32 bits(in most cases) which means +that we can benefit from displacements in the encoding side. E.g ``` diff --git a/chapter20/README.md b/chapter20/README.md index ae2b9df0..ab1d9ca4 100644 --- a/chapter20/README.md +++ b/chapter20/README.md @@ -11,7 +11,9 @@ Chaitin's original: https://en.wikipedia.org/wiki/Register_allocation#CITEREFCha Briggs additions: https://dl.acm.org/doi/10.1145/177492.177575 -There are several other useful link that can be found by searching for Briggs +Nice lecture slides pdf of Briggs/Chaitin: https://aktemur.github.io/cs544/lectures/chapter%2013%20registerAllocation.pdf + +There are several other useful links that can be found by searching for Briggs or Chaitin in combination. Basically there was a spate of register allocation improvements in this era that made it into many high-end mainstream compilers. @@ -19,6 +21,20 @@ I've included a very old unpublished paper on speeding up graph coloring allocators: [Interference Graph Triming](docs/ifg_trim.pdf). +## Meta-Issues / Code-Dev Issues of Instruction Selection, Register Allocation and Encodings + +The output of Register Allocation - an allocation of registers to ops - is +difficult to test in bulk without an execution strategy. We won't have an +execution stratgy until all three of Instruction Selection, Register Allocation +and Encodings are done. Hence in and around the completion of Encoding we +expect to find lots of bugs in Instruction Selection and Register Allocation. +We certainly hand-inspect the output and fix obvious problems, but still lots +bugs linger until we can actually run the code. + +This means that other chapters have updates and bug-fixes to the work being +described here. + + You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter20) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter19...linear-chapter20) it to the previous chapter. @@ -48,7 +64,7 @@ allocation quality becomes heavily dependent on splitting and coloring heuristics. Hence, much of the "high theory" will be used to drive the core coloring -algorithm, but much of the "actual success" will depend on a large collection +algorithm, but much of the actual success will depend on a large collection of heuristics. ### Coloring Rounds @@ -72,8 +88,8 @@ Coloring proceeds in rounds until we get a coloring: also have a set of reaching defs per-block. - Color the interference graph. Nodes (live ranges) in the graph which are - strictly low degree (more available registers than neighbors) will guaranteed - get a color. These can be removed from the graph - since they will + strictly low degree (more available registers than neighbors) are guaranteed + to get a color. These can be removed from the graph - since they will guaranteed get a register (color) because they have so few conflicting neighbors. Removing these trivial nodes makes more nodes go trivial, and this process repeats until either we run out (and are guaranteed a coloring) @@ -214,8 +230,8 @@ If the live range `_mask` field goes empty, you might have a *hard conflict* or have gotten *killed*. Live ranges can self-interfere, making a *self-conflict*. During coloring you might discover an uncolorable clique of interfering live ranges, leading to a *capacity spill*. This leads to a set of -levels of conflicts within a live range (and thus a different heuristics for -handling them). +levels of conflicts within a live range (and different heuristics for handling +them). ### Hard-Conflicts @@ -247,7 +263,7 @@ collection - and hence speedup allocation by a large constant factor. ### Self-Conflicts -A live-range can *self-conflict* be alive twice with 2 different values but +A live-range can *self-conflict*: be alive twice with 2 different values but require the same register. This live range *must* split and thus picks up a copy from the split. This happens with loop-carried dependencies as seen in e.g. a simple `fib` program: @@ -357,12 +373,13 @@ risky live range to color after all. Here we failed to get a coloring - and need to split. Some specific live ranges did not color and we will need to decide how to split. Again there are -tensions here: too much splitting leads to a bad allocation, to little leads to +tensions here: too much splitting leads to a bad allocation, too little leads to no-progress bugs (manifested as too many rounds of splitting past some arbitrary cutoff). -We start by looking at each spilling live range in turn, and deciding -on a splitting strategy. +We start by sorting the spills to be deterministic (else they are sorted by +HashMap visitation order), then looking at each spilling live range in turn +and deciding on a splitting strategy. ### Split Self Conflict @@ -383,7 +400,7 @@ This set of splits is fairly aggressive... but test cases requiring a split in each of the listed locations are including in Chapter 20's test cases. We cannot even attempt a color while we have self conflicts, so its important to break up these live ranges quickly. This tends to over-split and the allocator -leans on Biased Coloring to remove some of the extras. +leans on Biased Coloring and Coalescing to remove some of the extras. ### Split Hard Conflict @@ -393,9 +410,14 @@ direct def/use conflicts (e.g. defined in `rdi` and used in `rax`). They also can be discovered during the "Build the Interference Graph" pass (e.g. incoming argument in `rdi` used later in the program and killed by a `Call`). -For simple hard-conflicts, we have the exact def and use kept in the Live Range -itself. We split once after the def and once before the use (and only on sides -with restricted registers). +For simple hard-conflicts (a single def and single use), we have the exact def +and use kept in the Live Range itself. We split once after the def and once +before the use (and only on sides with restricted registers). + +Another common case is popular constants (e.g. 0): a single def with many uses, +and some of the uses require certain registers. Instead of splitting the +popular constant everywhere, we first split it into "register classes" and see +if we can remove the hard conflict with fewer spills. For more complex cases we use the capacity spilling/loop-nest technique. @@ -422,6 +444,22 @@ splitting around the next inner loop nest. This process repeats until we end up splitting in the inner-most loops. +### Helpers + +RA uses a series of helper functions, each is fairly self-contained. + +- **findAllLRG** - find all the defs and uses of a live range in time O(|LRG|) + instead of time O(N). +- **insertBefore** and **insertAfter** - insert a split either before a use or + after a def. Includes the work to put the split in its proper ordering in + a Basic Block and do all edge maintenance. +- **makeSplit** - Make a split (either clone a clonable constant, or ask the + `Machine` for a port-specific `SplitNode`. +- **ldepth** - Given a min&max loop depth (compacted in a `long`), expand the + loop depth range for a given node `n`. Used to decide when a def or use is + "inside" a loop, which in turn is used to split around loops. + + ## Post Allocation After a successful coloring, we want to pull out any same-same register splits. diff --git a/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java index 9e607349..badec740 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java @@ -123,7 +123,7 @@ public class RegAlloc { } - public int regnum( Node n ) { + public short regnum( Node n ) { LRG lrg = lrg(n); return lrg==null ? -1 : lrg._reg; } diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CFGNode.java index c5cd95f0..37d08fb0 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/CFGNode.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CFGNode.java @@ -170,12 +170,11 @@ public abstract class CFGNode extends Node { return pre; } - boolean skip(CFGNode usecfg) { + private boolean skip(CFGNode usecfg) { // Only walk control users that are alive. // Do not walk from a Call to linked Fun's. return usecfg instanceof XCtrlNode || (this instanceof CallNode && usecfg instanceof FunNode) || (this instanceof ReturnNode && usecfg instanceof CallEndNode); } - } diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java new file mode 100644 index 00000000..28ebd60d --- /dev/null +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java @@ -0,0 +1,26 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.LRG; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.ByteArrayOutputStream; + +import com.seaofnodes.simple.node.MachConcreteNode; + +public class NotARM extends MachConcreteNode implements MachNode{ + NotARM(NotNode not) {super(not);} + @Override public RegMask regmap(int i) { return arm.RMASK; } + @Override public RegMask outregmap() { return arm.RMASK; } + + @Override public int twoAddress( ) { return 0; } + + @Override public int encoding(ByteArrayOutputStream bytes) { + throw Utils.TODO(); + } + + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } + @Override public String op() { return "not"; } +} diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java new file mode 100644 index 00000000..d19210cb --- /dev/null +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java @@ -0,0 +1,42 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.node.MachConcreteNode; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.LRG; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.ByteArrayOutputStream; + +public class SubIARM extends MachConcreteNode implements MachNode { + final TypeInteger _ti; + SubIARM(Node sub, TypeInteger ti) { + super(sub); + _inputs.pop(); + _ti = ti; + } + + // Register mask allowed on input i. + @Override public RegMask regmap(int i) { return arm.RMASK; } + + // Register mask allowed as a result. 0 for no register. + @Override public RegMask outregmap() { return arm.RMASK; } + + // Encoding is appended into the byte array; size is returned + @Override public int encoding(ByteArrayOutputStream bytes) { + throw Utils.TODO(); + } + + // General form: "subi rd = rs1 - imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - #"); + _ti.print(sb); + } + + @Override public String op() { + return (_ti.value() == -1 ? "dec" : "subi"); + } + +} diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java new file mode 100644 index 00000000..6d30cd1c --- /dev/null +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java @@ -0,0 +1,25 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.LRG; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.ByteArrayOutputStream; + +public class NotRISC extends MachConcreteNode implements MachNode { + NotRISC(NotNode not) {super(not);} + @Override public RegMask regmap(int i) { return riscv.RMASK; } + @Override public RegMask outregmap() { return riscv.RMASK; } + + @Override public int twoAddress( ) { return 0; } + + @Override public int encoding(ByteArrayOutputStream bytes) { + throw Utils.TODO(); + } + + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } + @Override public String op() { return "not"; } +} diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java index ec6f9993..ac35d17b 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java @@ -21,7 +21,12 @@ public class CallRX86 extends CallNode implements MachNode { // Encoding is appended into the byte array; size is returned @Override public int encoding(ByteArrayOutputStream bytes) { - throw Utils.TODO(); + bytes.write(0xe8); + int beforeSize = bytes.size(); + // address + //TODO: relocs + bytes.write(0x00); + return bytes.size() - beforeSize; } @Override public void asm(CodeGen code, SB sb) { diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java index 959ec81e..e2f68c1f 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java @@ -32,7 +32,13 @@ public class CallX86 extends CallNode implements MachNode { // Encoding is appended into the byte array; size is returned @Override public int encoding(ByteArrayOutputStream bytes) { - throw Utils.TODO(); + // linker will fix this up + bytes.write(0xe8); + int beforeSize = bytes.size(); + // TODO: relocs + // address + bytes.write(0x00); + return bytes.size() - beforeSize; } @Override public void asm(CodeGen code, SB sb) { diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java index 5239670b..7346ae05 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java @@ -17,6 +17,6 @@ public class FunX86 extends FunNode implements MachNode { // Encoding is appended into the byte array; size is returned @Override public int encoding(ByteArrayOutputStream bytes) { - throw Utils.TODO(); + return 0; } } diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java new file mode 100644 index 00000000..a4b82de8 --- /dev/null +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java @@ -0,0 +1,26 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.LRG; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; +import java.io.ByteArrayOutputStream; + +public class NotX86 extends MachConcreteNode implements MachNode { + NotX86(NotNode not) {super(not);} + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.RMASK; } + + @Override public int twoAddress( ) { return 0; } + + // NotNode(BoolNode) = Inverted BoolNode(1) + // NotNode(NotNode(BoolNode)) = BoolNode(2) + // anything else to test & setz(3) + @Override public int encoding(ByteArrayOutputStream bytes) { + throw Utils.TODO(); + } + @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); } + @Override public String op() { return "not"; } +} diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java index 4d47f76d..69ebb74e 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java @@ -21,5 +21,7 @@ public class ParmX86 extends ParmNode implements MachNode { @Override public RegMask outregmap() { return _rmask; } // Encoding is appended into the byte array. Returns size - @Override public int encoding(ByteArrayOutputStream bytes) { return 0; } + @Override public int encoding(ByteArrayOutputStream bytes) { + return 0; + } } diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java index 40d8b6c2..7ac014e6 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java @@ -18,6 +18,6 @@ public class ProjX86 extends ProjNode implements MachNode { // Encoding is appended into the byte array; size is returned @Override public int encoding(ByteArrayOutputStream bytes) { - throw Utils.TODO(); + return 0; } } diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java index cdb20fd4..433f64cc 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java @@ -28,7 +28,12 @@ public class RetX86 extends ReturnNode implements MachNode { // Encoding is appended into the byte array; size is returned @Override public int encoding(ByteArrayOutputStream bytes) { - throw Utils.TODO(); + // Without imm form + // Near return + int beforeSize = bytes.size(); + bytes.write(0xC3); // opcode + + return bytes.size() - beforeSize; } @Override public void asm(CodeGen code, SB sb) { diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java new file mode 100644 index 00000000..3322d951 --- /dev/null +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java @@ -0,0 +1,36 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.LRG; +import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeInteger; +import java.io.ByteArrayOutputStream; + +public class XorX86 extends MachConcreteNode implements MachNode{ + XorX86(Node xor) {super(xor);} + + @Override public RegMask regmap(int i) { return x86_64_v2.WMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + + // Output is same register as input#1 + @Override public int twoAddress() { return 1; } + + // Encoding is appended into the byte array; size is returned + @Override public int encoding(ByteArrayOutputStream bytes) { + throw Utils.TODO(); + } + + // General form + // General form: "xor ^ reg + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2))); + } + + @Override public String op() { return "xor"; } + +} diff --git a/chapter21/Makefile b/chapter21/Makefile new file mode 100644 index 00000000..0d187b7c --- /dev/null +++ b/chapter21/Makefile @@ -0,0 +1,114 @@ +SHELL := /bin/bash +.DELETE_ON_ERROR: + + +# for printing variable values +# usage: make print-VARIABLE +# > VARIABLE = value_of_variable +print-% : ; @echo $* = $($*) + +# literal space +space := $() $() + +# Decide OS-specific questions +# jar-file seperator +ifeq ($(OS),Windows_NT) + SEP = ; +else + SEP = : +endif +# Find a reasonable ctags. +CTAGS = $(shell which ctags) +# Hack for MacOS: /usr/bin/ctags is unfriendly, so look for ctags from brew +ifeq ($(UNAME),Darwin) + CTAGS = $(shell brew list ctags 2> /dev/null | grep bin/ctags) +endif + +# Fun Args to javac. Mostly limit to java8 source definitions, and fairly +# aggressive lint warnings. +JAVAC_ARGS = -g + +# Source code +SIMPLE := com/seaofnodes/simple +SRC := src/main/java +TST := src/test/java +CLZDIR:= build/classes +main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC)/$(SIMPLE)/node/cpus/*/*java) +test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java) +main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas)) +test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas)) +test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) +classes = $(main_classes) $(test_classes) +# All the libraries +libs = $(wildcard lib/*jar) +jars = $(subst $(space),$(SEP),$(libs)) + + +default_targets := $(main_classes) $(test_classes) +# Optionally add ctags to the default target if a reasonable one was found. +ifneq ($(CTAGS),) +default_targets += tags +endif + +default: $(default_targets) + +# Compile just the out-of-date files +$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java + @echo "compiling " $@ " because " $? + @[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main + @javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas) + +$(test_classes): $(CLZDIR)/test/%class: $(TST)/%java $(main_classes) + @echo "compiling " $@ " because " $? + @[ -d $(CLZDIR)/test ] || mkdir -p $(CLZDIR)/test + @javac $(JAVAC_ARGS) -cp "$(CLZDIR)/test$(SEP)$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(TST) -d $(CLZDIR)/test $(test_javas) + +# Base launch line for JVM tests +JVM=nice java -ea -cp "$(CLZDIR)/main${SEP}${jars}${SEP}$(CLZDIR)/test" + +tests: $(default_targets) + @echo "testing " $(test_cp) + @[ -d build/objs ] || mkdir -p build/objs + @$(JVM) org.junit.runner.JUnitCore $(test_cp) + @$(JVM) org.junit.runner.JUnitCore com.seaofnodes.simple.FuzzerWrap + +fuzzer: $(default_targets) + @echo "fuzzing " $(test_cp) + @$(JVM) org.junit.runner.JUnitCore com.seaofnodes.simple.FuzzerWrap + +# Build a Simple jar +release: build/release/simple.jar + +# Build a Simple jar +build/release/simple.jar: $(main_classes) $(test_classes) + @echo "jarring " $@ " because " $? + @[ -d $(dir $@) ] || mkdir -p $(dir $@) + @jar cf build/release/simple.jar -C $(CLZDIR)/main . -C $(CLZDIR)/test . -C $(SRC)/$(SIMPLE) . -C $(TST)/$(SIMPLE) . + +# Launch viewer +view: $(main_classes) + @echo "viewing " + @$(JVM) com.seaofnodes.simple.JSViewer + +.PHONY: clean +clean: + rm -rf build + rm -f TAGS + (find . -name "*~" -exec rm {} \; 2>/dev/null; exit 0) + +# Download libs from maven +lib: lib/junit-4.12.jar lib/hamcrest-core-1.3.jar + +# Jars +lib/junit-4.12.jar: + @[ -d lib ] || mkdir -p lib + @(cd lib; wget https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar) + +lib/hamcrest-core-1.3.jar: + @[ -d lib ] || mkdir -p lib + @(cd lib; wget https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) + +# Build emacs tags (part of a tasty emacs ide experience) +tags: $(main_javas) $(test_javas) + @rm -f TAGS + @$(CTAGS) -e --recurse=yes --extras=+q --fields=+fksaiS $(SRC) $(TST) diff --git a/chapter21/README.md b/chapter21/README.md new file mode 100644 index 00000000..ec47ac3b --- /dev/null +++ b/chapter21/README.md @@ -0,0 +1,800 @@ +# Chapter 21: Instruction Encoding and ELF + +## Meta-Issues / Code-Dev Issues of Instruction Selection, Register Allocation and Encodings + +The output of Encodings - conversion of machine Nodes to instruction bits - is +difficult to test in bulk without an execution strategy. We won't have an +execution strategy until all three of Instruction Selection, Register Allocation +and Encodings are done. Hence in and around the completion of Encoding we +expect to find lots of bugs in Instruction Selection and Register Allocation. +We certainly hand-inspect the output and fix obvious problems, but still lots +bugs linger until we can actually run the code. + +This means that other chapters have updates and bug-fixes to the work being +described here. + +Encodings are an entirely bit-picky nit-picky affair. There's no real rocket +science here, but instead there's an boundless opportunity for off-by-1 errors. +If you find a bug here, do not be surprised! Its almost surely a "shallow" +bug... and there's bound to be a few until Simple gets more programmer hours +under its belt. + + + +You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter21) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter20...linear-chapter21) it to the previous chapter. + +# Table of Contents + +1. [Instruction Encodings](#instruction-encodings) +2. [Infrastructure](#infrastructure) +3. [AMD64](#amd64) + - [REX PREFIX](#rex-prefix) + - [Large constants](#large-constants) + - [MODR/M](#modrm) + - [SIB](#sib) + - [Displacement](#displacement) + - [Immediate](#immediate) + - [Float](#float) + - [Indirect](#indirectmemop) + - [Conditional flags](#conditional-flags) +4. [ARM](#arm) + - [Reg-form](#reg-form) + - [Shift immediates](#shift-immediates) + - [asri](#asrimmediate) + - [LSL(immediate)](#lslimmediate) + - [LSR(immediate)](#lsrimmediate) + + - [Logical Immediates](#logical-immediates) + - [Float](#float) + - [Function constant](#function-constant) + - [Immediate](#immediate) + - [Conditional flags](#conditional-flags) + - [Indirect](#indirectmemop-1) + - [Branching](#branching-) + - [Rip relative](#rip-relative) + - [Compare](#compare) + +5. [RISCV](#riscv) + - [Instruction formats](#instruction-formats) + - [Float](#float) + - [Indirect](#indirectmemop-2) + - [Branch](#branch) + - [Function Constant](#function-constant) + - [LUI](#lui) + - [Large constants](#large-constants) + +This chapter will add instruction encodings. Instruction encoding refers to +the representation of machine instructions in a specific binary format defined +by the processor's instruction set architecture (ISA). + + +After completing instruction selection, the next step is to encode the +instructions before writing them into an ELF object file. + +To avoid ambiguity, we define the sources of the information we use to encode the instructions: + +Currently, we support these architectures: + +### AMD64: +For *x86-64(amd64):*, we use the latest Intel manual for the [encoding rules](https://www.felixcloutier.com/x86/). + +### RISC-V: + +For *riscv* we currently target [RVA23U64](https://msyksphinz-self.github.io/riscv-isadoc/html/). + +### ARMV8/AArch64 : +For *arm*(aarch64) we use this collection for the [encoding rules](https://docsmirror.github.io/A64/20a23-06/index.html). +*Note*: We only support 64 bits ARM encodings. + +--- + +## Instruction Encodings + + +## Infrastructure + +The instruction selection phase creates the machine friendly nodes from ideal +nodes. These machine friendly nodes define an *encoding* function that is +called from the Encoding driver found in CodeGen. + +```java +for( CFGNode bb : _code._cfg ) + for( Node n : bb._outputs ) + if( n instanceof MachNode mach ) { + int off = _bits.size(); + mach.encoding(this); + _opLen[n._nid] = (byte)(_bits.size()-off); + } +``` + +Based on the selected target, we either need to look out for little endian or +big endian encodings. These are being handled by `add4` which adds to the bit +stream in the correct order. As of now the bitstream is a simple +ByteArrayOutputStream structure. + +```java +@Override public void encoding( Encoding enc ) { + enc.add4(0); // adds 4 bytes to the bitstream +} +``` + +On *RISC-V*, where the documentation provides big-endian encodings, this +function also converts them to little-endian. For other architectures, no +conversion is necessary. + +## Endianness + +ARM, RISC-V, and x86 are all little-endian architectures in practice, meaning +the least significant byte is stored first. We ensure that instruction +encodings are generated in little-endian format accordingly. + +```java +// Little endian write of a 32b opcode +public void add4( int op ) { + _bits.write(op ); + _bits.write(op>> 8); + _bits.write(op>>16); + _bits.write(op>>24); +} +``` +For example, consider a 32-bit encoding for fixed-width instructions: +*10110101100111101011001001101101*. + +We append the least significant byte first, then the next byte, and so on. +``` +_bits.write(op ); +``` + +`_bits.write()` only appends the least significant byte. By shifting the value +to the right, we can bring the next byte into the least significant position, +allowing us to write each byte in sequence. + + +## AMD64 X86-64 + +As opposed to riscv arhitectures, where the instruction width is fixed, +*x86-64* has variable width instructions. This is common with *CISC (Complex +Instruction Set Computer)* architectures, where the instruction width can vary +from 1 to 15 bytes. Since AMD64 supports many indirect addressing modes, the +goal with *CISC* in general is to complete a task in as few lines of assembly +as possible. + +### REX PREFIX + +Since we are targeting the 64-bit version of x86, we need to handle this +prefix. In 32-bit mode, however, it is typically unnecessary. + +Generally speaking the *REX* prefix must be encoded when: + - using one of the extended registers (R8 to R15, XMM8 to XMM15, YMM8 to YMM15, CR8 to CR15 and DR8 to DR15); + - using 64-bit operand size and the instruction does not default to 64-bit operand size(most ALU ops) + - using a 8-bit operand with RSI, RDI, RBP + +A *REX* prefix must not be encoded when: + - using one of the high byte registers AH, CH, BH or DH (not done currently in Simple) + +*Note:* When encoding SSE instruction, the *REX* prefix (0x40) must come after +the `SSE` prefix. In all other cases, it is ignored. + +In Simple, the REX prefix is just appended to the beginning of the bit stream +(except SEE float instructions). The layout is the following: + +| **Field** | **Length** | **Description** | +|:---------:|:----------:|---------------------------------------------------------------------------------| +| `0100` | 4 bits | Fixed bit pattern | +| `W` | 1 bit | When 1, a 64-bit operand size is used. Otherwise, 32-bit operand size is used. | +| `R` | 1 bit | Extension to the **MODRM.reg** field. | +| `X` | 1 bit | Extension to the **SIB.index** field. | +| `B` | 1 bit | Extension to the **MODRM.rm** or **SIB.base** field. | + + +```java + public static int REX_W = 0x48; +``` + +```java +public static int rex(int reg, int ptr, int idx, boolean wide) { + // assuming 64 bit by default so: 0100 1000 + int rex = wide ? REX_W : REX; + if( 8 <= reg && reg <= 15 ) rex |= 0b00000100; // REX.R + if( 8 <= ptr && ptr <= 15 ) rex |= 0b00000001; // REX.B + if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X + return rex; +} + + ... + enc.add1(x86_64_v2.rex(dst, src, 0)); +``` + +Setting THE `W` bit gives us: +`0b01001000 = 0x48;` + +#### Opcode +In our case, the opcode is a 1 byte field that specifies the operation to be performed. +``` +enc.add1(opcode()); // opcode +``` + +#### MODR/M + +| **Field** | **Length** | **Description** | +|:-------------:|:----------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **MODRM.mod** | 2 bits | In general, when this field is `b11`, then register-direct addressing mode is used; otherwise register-indirect addressing mode is used. +| **MODRM.reg** | 3 bits | This field can have one of two values:

• A 3-bit opcode extension, which is used by some instructions but has no further meaning other than distinguishing the instruction from other instructions.

• A 3-bit register reference, which can be used as the source or the destination of an instruction (depending on the instruction). The referenced register depends on the operand-size of the instruction and the instruction itself. The `REX.R`, `VEX.~R` or `XOP.~R` field can extend this field with 1 most-significant bit to 4 bits total. | +| **MODRM.rm** | 3 bits | Specifies a direct or indirect register operand, optionally with a displacement. The `REX.B`, `VEX.~B` or `XOP.~B` field can extend this field with 1 most-significant bit to 4 bits total. | + + +We deal with the MODR/M byte in a similar way: + +The first thing we need for the modrm byte is the 2 bits mod. + +##### mod + +The layout for mod is the following: +``` +public enum MOD { + INDIRECT, // [mem] + INDIRECT_disp8, // [mem + 0x12] + INDIRECT_disp32,// [mem + 0x12345678] + DIRECT, // mem +}; +``` + +##### reg +The reg field is a 3 bit field capable of encoding 15 different registers. + +##### r/m + +The rm field specifies a direct or indirect register operand and is capable of encoding 15 different registers. + + +```java +public static int modrm(MOD mod, int reg, int m_r) { + // combine all the bits + return (mod.ordinal() << 6) | ((reg & 0x07) << 3) | m_r & 0x07; +} +``` + +The `modrm` function is then used to build up the `ModR/M` byte. +Usually this follows after the opcode. + +``` +enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); +``` + +Encoding a reg form might look like this: +``` +short dst = enc.reg(this ); // src1 +short src = enc.reg(in(2)); // src2 +enc.add1(x86_64_v2.rex(dst, src, 0)); +enc.add1(opcode()); // opcode +enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src)); +``` + +#### SIB +The SIB byte has the following fields: + +| **Field** | **Length** | **Description** | +|:-------------:|:----------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **SIB.scale** | 2 bits | This field indicates the scaling factor of `SIB.index`, where **s** (as used in the tables) equals 2^SIB.scale^. | +| **SIB.index** | 3 bits | The index register to use. See Registers for the values to use for each of the registers. The `REX.X`, `VEX.~X` or `XOP.~X` field can extend this field with 1 most-significant bit to 4 bits total. | +| **SIB.base** | 3 bits | The base register to use. See Registers for the values to use for each of the registers. The `REX.B`, `VEX.~B` or `XOP.~B` field can extend this field with 1 most-significant bit to 4 bits total. | + +It has the same layout as the MODR/M byte. +```java +public static int sib(int scale, int index, int base) { + return (scale << 6) | ((index & 0x07) << 3) | base & 0x07; +} +``` + +```java +enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP)); +``` + +#### Displacement +Displacement can happen in 2 forms: +```java +public enum MOD { +INDIRECT, // [mem] +INDIRECT_disp8, // [mem + 0x12] +INDIRECT_disp32,// [mem + 0x12345678] +DIRECT, // mem +}; +``` + +```java +if( mod == MOD.INDIRECT_disp8 ) { + enc.add1(offset); +} else if( mod == MOD.INDIRECT_disp32 ) { + enc.add4(offset); +} +``` +The displacement goes before the immediate, so for example: +``` +sub [eax + 2], 4 +``` +``` +bytes.write(0x83); +bytes.write(modrm(INDIRECT8, 5, 0 /* eax */)); +bytes.write(2); // displcement goes first +bytes.write(4); +``` + +#### Immediate +The immediate byte/bytes go after the `ModR/M` byte, we are capable of encoding 4 bytes of immediates depending on the need. +```java +// immediate(4 bytes) 32 bits or (1 byte)8 bits +if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); +else enc.add4(_imm); +``` + +#### INDIRECT(MemOp) +X86-64 support multiple indirect addressing modes: + + +#### Float +For float operations we use `SEE SIMD` instructions that operate on scalar single precision floating0-point values located in the +XMM registers or memory. +*Note*: When using XMM registers for ALU operations, the encoding is really similar with the exception that we need +to subtract the `XMM_OFFSET` from the register number. +We count the registers continuously, so we need to subtract the offset to get the GPR register pair that corresponds to the XMM register. + +```java +short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET); +``` + +```java +public static int XMM_OFFSET = 16; +``` + +| **X.Reg** | **8-bit GP** | **16-bit GP** | **32-bit GP** | **64-bit GP** | **80-bit x87** | **64-bit MMX** | **128-bit XMM** | **256-bit YMM** | **16-bit Segment** | **32-bit Control** | **32-bit Debug** | +|:--------:|:------------:|:-------------:|:-------------:|:-------------:|:-------------:|:-------------:|:--------------:|:--------------:|:-----------------:|:-----------------:|:---------------:| +| `0.000 (0)` | AL | AX | EAX | RAX | ST0 | MMX0 | XMM0 | YMM0 | ES | CR0 | DR0 | + +We see that `XMM0` corresponds to `RAX` and so on. + +#### Large constants + +##### INT: We just use `MOV r64, imm64` instruction form. + +##### FLOAT: We use relocation and use constant from memory. + +#### Function constant +To load a function constant we use lea which will load the address into the specified reg +relative to the instruction pointer. +`lea rax, [rip+disp32]` + +#### Conditional flags: +The FLAGS register is the status register that contains the current state of an x86 CPU. + +Let's consider a simple example that presents all the instructions that we need to encode for +conditional code. + +``` +int square(int a) { + // cmp DWORD PTR [rbp-0x8],0x1 + // `sete al` + bool da = a == 1; + + // cmp eax,0x1 + if(da == 1) { + return 1; + } + return 2; +} +``` + +First we need a compare instruction comparing `a` with 1. +``` +cmp DWORD PTR [rbp-0x8],0x1 +``` + +This compare instruction then sets the conditional flags: +> The CF, OF, SF, ZF, AF, and PF flags are set according to the result. + +We then use the `sete` instruction to save out the result of the comparison to a register: + +`sete al` + +For the if condition we do an extra comparison based on the result of the first bool. +``` + cmp eax,0x1 +``` + +And then a conditional branch that is relying on the flags set by the comparison(`a == 1`). +``` +jne 1159 +``` + + +We'll see how this differs in ARM and RISCV. + +--- + + +## ARM +Arm instructions are all 32 bits wide, and are always little-endian. +Arm is a RISC architecture, it prioritizes "register-to-register" forms. + +#### Reg-form +We encode the regs forms as [shifted registers](https://docsmirror.github.io/A64/2023-06/orr_log_shift.html). +``` +orr reg1, reg2 +``` +``` +x0 = x0 | (x1 << 0) +``` +The same thing applies for all the other reg forms. +Because of this similarity, we can lift the encoding of the reg form to a common function. + +```java +short self = enc.reg(n); +short reg1 = enc.reg(n.in(1)); +short reg2 = enc.reg(n.in(2)); +int body = r_reg(opcode, 0, reg2, 0, reg1, self); +enc.add4(body); +``` +*imm6* and +*shift* +are irelevant for the reg form, so we just set them to 0. + +### Shift immediates +This refers to: *asri, lsli, lsri* +Encode to shift immediates if the shift amount is between [0, 63] inclusive. + +#### ASR(immediate) +For arithmetic Shift Right immediates, we set *immr* to the immediate we wish to encode, and imms to `63` = `111111`. +This is following the rules of [asri encoding](https://docsmirror.github.io/A64/2023-06/asr_sbfm.html). + +The `sf` bit is included in the opcode, `N` is implicitly added to the bitstream after the execution of the +`imm_shift` function. +```java +enc.add4(arm.imm_shift(0b100100110,_imm, 0b111111, rn, rd)); +``` + +#### LSL(immediate) + +```java +// UBFM , , #(- MOD 64), #(63-) +// immr must be (- MOD 64) = 64 - shift +enc.add4(arm.imm_shift(0b110100110, 64 - _imm, (64 - _imm) - 1, rn, rd)); +``` + +We know that `_imm` is never a negative number and is between 0 and 63, so we can safely use `64 - _imm` as the `immr` value. +We take away this form of the immediate from 64 to invert the bits. + +For *imms* - the following condition must hold *imms + 1 = immr*; +After subbing in the values we get: + +> imms + 1 = 64 - _imm; + +> imms = (64 - _imm) - 1; + +Hence, the `imms` value is `(64 - _imm) - 1`. + +#### LSR(immediate) +Same as *ASR*. + + +#### Logical Immediates +Logical immediates refer to *andi, xori, orri*. + +```java +// Can we encode this in ARM's 12-bit LOGICAL immediate form? +// Some combination of shifted bit-masks. +private static int imm12Logical(TypeInteger ti) { + if( !ti.isConstant() ) return -1; + if( !ti.isConstant() ) return -1; + long val = ti.value(); + if (val == 0 || val == -1) return -1; // Special cases are not allowed + int immr = 0; + // Rotate until we have 0[...]1 + while (val < 0 || (val & 1)==0) { + val = (val >>> 63) | (val << 1); + immr++; + } + int size = 32; + long pattern = val; + // Is upper half of pattern the same as the lower? + while ((pattern & ((1L<> size)) { + // Then only take one half + pattern >>= size; + size >>= 1; + } + size <<= 1; + int imms = Long.bitCount(pattern); + // Pattern should now be zeros followed by ones 0000011111 + if (pattern != (1L< cond = is one of the standard conditions. + +--- + +## RISCV +RISCV instructions are all 32 bits wide, and are always little-endian. +RISCV is a RISC architecture, it prioritizes "register-to-register" forms. + +#### Instruction formats + +##### R-TYPE +This encoding format is used for reg-to-reg operations. +Such as `AddRISC`, `MulRISC` etc. +```java +public static int r_type(int opcode, int rd, int func3, int rs1, int rs2, int func7) { + return (func7 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; +} +``` + +##### I-TYPE +This layout is used for immediate formats. Such as `AddIRISC` + +```java + public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) { + assert opcode >= 0 && rd >=0 && func3 >=0 && rs1 >=0 && imm12 >= 0; // Zero-extend by caller + return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; + } +``` + +##### S-TYPE + +This encoding format is used for `StoreRISC`. + +```java +public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { + assert imm12 >= 0; // Masked to high zero bits by caller + int imm_lo = imm12 & 0x1F; + int imm_hi = imm12 >> 5; + return (imm_hi << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (imm_lo << 7) | opcode; +} +``` + +##### B-TYPE + +This encoding layout is used by `BranchRISC`. +```java + // immf = first imm + // immd = second imm + // BRANCH +public static int b_type(int opcode, int immf, int func3, int rs1, int rs2, int immd) { + return (immd << 25 ) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (immf << 7) | opcode; + } +``` + +##### U-TYPE +This layout is used for `AUIPC` and `LUI`(upper immediate is 20-bits). + +```java + public static int u_type(int opcode, int rd, int imm20) { + return (imm20 << 12) | (rd << 7) | opcode; + } +``` + +##### J-TYPE +Used for unconditional jumps. (`UJmpRISC`) +```java + public static int j_type(int opcode, int rd, int imm20) { + return imm20 << 12 | rd << 7 | opcode; + } +``` + +#### FLOAT +For loading float constants, we use indirect memory load(PC-relative). +``` +AUIPC dst,#hi20_constant_pool +Load dst,[dst+#low12_constant_pool] +``` + +#### INDIRECT(MemOp) + +[Load](https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html#lw): `lw rd,offset(rs1)` + +[Store](https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html#sw): `sw rs2,offset(rs1)` + +#### BRANCH +RISC-V is unusual because branch instructions include the comparison and branch target in one instruction. + +#### Immediates +We only encode the imm form for the *ALU* operations if they fit into 12 bits (signed). +Otherwise we do a Load Upper Immediate (high 20 bits) or both. + +``` +addiw a5,a5,123 +``` +vs +(do it with extra load): +``` +addw a5,a5,a4 +``` + +### FLOAT Constants +- Stored in the **constant pool**. +- Accessed via **PC-relative loads**. + +### INT Constants +- **12-bit constants** + - Use `ADDI` +- **20-bit constants** + - Use `LUI` +- **32-bit constants** + - Use `LUI` + `ADDI` combo + - + +#### Function Constant +In our RISC-V code, when we need to load a function-local constant, +we store the current PC into a register and use that as a base to access the constant. However, we usually try to avoid loads, since simple arithmetic like addition is faster and more efficient than accessing memory. + +```java +// auipc t0,0 +// addi t1,t0 + #0 +``` + + + +## Relocation + +Relocation allows code to be *relocated* to a new code offset. Code often +refers to other code and data; `call` instructions target subroutines, +`branches` target other instructions, large constants are often loaded from a +*constant pool*. + +### Local Relocation + +Local relocation patches up local, or self-referential, code; the most common +form is branch targets. When writing instructions into the `BAOS` (bit stream) +forwards branches towards future instructions have an unknown offset - the +offset depends on the size of the encodings in between the branch and target. +For `riscv` and `arm` targets this sounds easy (and instructions are 4 bytes, +so just count instructions)... except that some encodings use multiple +instructions so are not actually 4 bytes long. For X86's wild psuedo-random +instruction lengths the act of figuring out the opcode length is just as hard +as writing the opcode in the first place. + +Alson X86 adds another wrinkle: short and long form branches. If a branch +target lies within a signed byte range (+/-127) X86 will use a 2 byte branch +encoding, otherwise a 6 byte encoding. Simple includes a pass to compact these +branches and use 2 bytes wherever possible - but this pass has to slide code +around to make space for the extra 4 bytes as needed, which changes all the +other branch offsets. + +Once the code is finally settled into "shape", a local relocation pass is made +to update all the self-references. Basically, the branch offsets in the byte +array get overwritten with the actual values. + +At the end of this pass, the code is locally correct at some offset (generally +0), but this is not the end - code is often *linked* against other code +generated in other compilations, and again various offsets will need to be +adjusted. + +### Global Relocation + +Code in one compilation unit wants to call code in another... this requires a +*global relocation*. A common example is a *loader* loading an *ELF* file, +which mostly happens every time a new program is run, and requires the +relocation information to be stored to disk (in e.g. the ELF file). JIT +systems will neeed to do this as well across different compilations, although +the relocation information can stay in memory. + +#### Getting Relocations to All Agree + +Since the relocations can be written to disk, the disk format, loader and "code +shape" all have to agree. Suppose we want to call from one compilation unit to +another - e.g. the program is calling `malloc` from `libc`. The caller is a +Simple using a machine-specific version of generic `CallNode` with the target +being C-compiled code. During loading, the placement of the `call` and `libc` +is determined by the loader; the two different blocks of code are written into +memory in some order (generally with lots of other blocks of code). Now we +need to patch the `call`'s target to be `malloc` in the `libc` block of code. + +For an X86 external call, the encoding is a 5-byte instruction, one byte of +opcode and 4 bytes of PC-relative target address. The needed patch is the +delta between the X86-specific `call` instruction *end* and the start of +`malloc`, and is written directly on the last 4 bytes of the `call`. The +encoding type in the ELF file has to describe this. + +For a RISCV external call, the encoding is 2 4-byte instructions each carrying +some of the bits. The `LUI` loads the target upper 20 bits, and then the +`JALR` adds in the lower 12 bits (32-bit absolute target range). The `LUI` +might be replaced with a `AUIPC` to get a 32-bit pc-relative range. Patching +here updates 20bits in one instruction and 12bits in another. Again the ELF +file encoding type has to describe this; using a X86-style patch here will just +crush the wrong bits and make a broken program. + +#### Large Constants + +Large constants are those which cannot be easily directly loaded into a +register, and instead are loaded from memory. For security reasons they are +often kept in a seperate address space with e.g. *read-only* permissions instead +of *execute* permissions. This means their final address, relative to the code, +varies according to placement - same as for calls crossing compilation units. + +Also large constants can be shared across compilation units (one can imagine +repeated uses of `pi` in HPC codes); sharing reduces cache footprint. In any +case, one the locations of the code and constants are known, the code needs to +be patched to load at the correct offset. Like the `call` example above, the +load instruction variant and patch variant all need to agree. An X86 might use +either a 4-byte address or an 8-byte address depending on X86 variant; the +RISCV probably uses some variant of an `LUI` and a `Load`, with the immediate +split into 20/12 bits. Also the RISCV probably wants to "share" the constant +pool 20 bits in the same `LUI`, but have different loads for different +constants coming out of the same pool. ARM will have yet another variant. + diff --git a/chapter21/docs/18-grammar.md b/chapter21/docs/18-grammar.md new file mode 100644 index 00000000..7b611fbf --- /dev/null +++ b/chapter21/docs/18-grammar.md @@ -0,0 +1,132 @@ +# Grammar for Chapter 16 + +```antlrv4 +grammar SimpleLanguage; + +program : block EOF ; + +block : statement+ ; + + +statement + : '{' block '}' + | returnStatement + | ifStatement + | whileStatement + | breakStatement + | continueStatement + | metaStatement + | structDeclaration + | expressionStatement + ; + + +returnStatement : 'return' expression ';' ; + +ifStatement : 'if' '(' expression ')' statement ('else' statement)? ; + +whileStatement : 'while' '(' expression ')' statement ; + +breakStatement : 'break' ';' ; + +continueStatement : 'continue' ';' ; + +metaStatement : '#showGraph' ';' ; + +structDeclaration : 'struct' IDENTIFIER '{' block '}' ; + +expressionStatement + : type IDENTIFIER ';' + | type IDENTIFIER '=' expression ';' + | IDENTIFIER '=' expression ';' + | expression + ; + +PRIMTYPE + : 'int' + | 'i8' + | 'i16' + | 'i32' + | 'i64' + | 'u8' + | 'u16' + | 'u32' + | 'flt' + | 'f32' + | 'f64' + | 'bool' + ; + +type + : PRIMTYPE + | typeName '?'? + | typeName nestedArray+ + ; + +nestedArray : '?'? '[]'* ; + +typeName : IDENTIFIER ; + + +expression : bitWiseExpression ; + +bitWiseExpression + : comparisonExpression ( '&' | '|' | '^' ) comparisonExpression)* + ; + +comparisonExpression + : shiftExpression (('==' | '!='| '>'| '<'| '>='| '<=') shiftExpression)* + ; + +shiftExpression + : additiveExpression ( '<<' | '>>>' | '>>' ) additiveExpression)* + ; + +additiveExpression + : multiplicativeExpression (('+' | '-') multiplicativeExpression)* + ; + +multiplicativeExpression + : unaryExpression (('*' | '/') unaryExpression)* + ; + +unaryExpression + : ('-') unaryExpression + | '!' unaryExpression + | primaryExpression postAssign + ; + +primaryExpression + : INTEGER_LITERAL + | FLOAT_LITERAL + | '(' expression ')' + | 'true' + | 'false' + | 'null' + | newExpression + | IDENTIFIER + ; + +newExpression + : 'new' IDENTIFIER [ '{' block '}' ] + | 'new' IDENTIFIER '[' expression ']' + ; + +postAssign : postFix [ '=' expression ] | [ '#' ]; + +postFix + : '.' IDENTIFIER postFix + | '[' expression ']' postFix + ; + + +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; + +INTEGER_LITERAL + : [1-9]DIGIT* + | [0] + ; + +NON_DIGIT: [a-zA-Z_]; +DIGIT: [0-9]; +``` diff --git a/chapter21/docs/Makefile b/chapter21/docs/Makefile new file mode 100644 index 00000000..12659b8f --- /dev/null +++ b/chapter21/docs/Makefile @@ -0,0 +1,12 @@ +GV := $(wildcard *.gv) +SVG := $(patsubst %.gv,%.svg,$(GV)) + +.PHONY: all +all: $(SVG) + +%.svg: %.gv + dot -Tsvg $< > $@ + +.PHONY: clean +clean: + @rm -f $(SVG) diff --git a/chapter21/docs/d3-graphviz.js b/chapter21/docs/d3-graphviz.js new file mode 100644 index 00000000..7439ba65 --- /dev/null +++ b/chapter21/docs/d3-graphviz.js @@ -0,0 +1,2014 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-dispatch'), require('d3-transition'), require('d3-timer'), require('d3-interpolate'), require('d3-zoom'), require('d3-format'), require('d3-path')) : + typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-dispatch', 'd3-transition', 'd3-timer', 'd3-interpolate', 'd3-zoom', 'd3-format', 'd3-path'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["d3-graphviz"] = {}, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3, global.d3)); +})(this, (function (exports, d3, d3Dispatch, d3Transition, d3Timer, d3Interpolate, d3Zoom, d3Format, d3Path) { 'use strict'; + + function _interopNamespaceDefault(e) { + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n.default = e; + return Object.freeze(n); + } + + var d3__namespace = /*#__PURE__*/_interopNamespaceDefault(d3); + + function _arrayLikeToArray(r, a) { + (null == a || a > r.length) && (a = r.length); + for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; + return n; + } + function _arrayWithoutHoles(r) { + if (Array.isArray(r)) return _arrayLikeToArray(r); + } + function _defineProperty(e, r, t) { + return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { + value: t, + enumerable: !0, + configurable: !0, + writable: !0 + }) : e[r] = t, e; + } + function _iterableToArray(r) { + if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toConsumableArray(r) { + return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); + } + function _toPrimitive(t, r) { + if ("object" != typeof t || !t) return t; + var e = t[Symbol.toPrimitive]; + if (void 0 !== e) { + var i = e.call(t, r || "default"); + if ("object" != typeof i) return i; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return ("string" === r ? String : Number)(t); + } + function _toPropertyKey(t) { + var i = _toPrimitive(t, "string"); + return "symbol" == typeof i ? i : i + ""; + } + function _unsupportedIterableToArray(r, a) { + if (r) { + if ("string" == typeof r) return _arrayLikeToArray(r, a); + var t = {}.toString.call(r).slice(8, -1); + return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; + } + } + + function extractElementData(element) { + var datum = {}; + var tag = element.node().nodeName; + datum.tag = tag; + if (tag == '#text') { + datum.text = element.text(); + } else if (tag == '#comment') { + datum.comment = element.text(); + } + datum.attributes = {}; + var attributes = element.node().attributes; + if (attributes) { + for (var i = 0; i < attributes.length; i++) { + var attribute = attributes[i]; + var name = attribute.name; + var value = attribute.value; + datum.attributes[name] = value; + } + } + var transform = element.node().transform; + if (transform && transform.baseVal.numberOfItems != 0) { + var matrix = transform.baseVal.consolidate().matrix; + datum.translation = { + x: matrix.e, + y: matrix.f + }; + datum.scale = matrix.a; + } + if (tag == 'ellipse') { + datum.center = { + x: datum.attributes.cx, + y: datum.attributes.cy + }; + } + if (tag == 'polygon') { + var points = element.attr('points').split(' '); + var x = points.map(function (p) { + return p.split(',')[0]; + }); + var y = points.map(function (p) { + return p.split(',')[1]; + }); + var xmin = Math.min.apply(null, x); + var xmax = Math.max.apply(null, x); + var ymin = Math.min.apply(null, y); + var ymax = Math.max.apply(null, y); + var bbox = { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + datum.bbox = bbox; + datum.center = { + x: (xmin + xmax) / 2, + y: (ymin + ymax) / 2 + }; + } + if (tag == 'path') { + var d = element.attr('d'); + var points = d.split(/[A-Z ]/); + points.shift(); + var x = points.map(function (p) { + return +p.split(',')[0]; + }); + var y = points.map(function (p) { + return +p.split(',')[1]; + }); + var xmin = Math.min.apply(null, x); + var xmax = Math.max.apply(null, x); + var ymin = Math.min.apply(null, y); + var ymax = Math.max.apply(null, y); + var bbox = { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + datum.bbox = bbox; + datum.center = { + x: (xmin + xmax) / 2, + y: (ymin + ymax) / 2 + }; + datum.totalLength = element.node().getTotalLength(); + } + if (tag == 'text') { + datum.center = { + x: element.attr('x'), + y: element.attr('y') + }; + } + if (tag == '#text') { + datum.text = element.text(); + } else if (tag == '#comment') { + datum.comment = element.text(); + } + return datum; + } + function extractAllElementsData(element) { + var datum = extractElementData(element); + datum.children = []; + var children = d3__namespace.selectAll(element.node().childNodes); + children.each(function () { + var childData = extractAllElementsData(d3__namespace.select(this)); + childData.parent = datum; + datum.children.push(childData); + }); + return datum; + } + function createElement(data) { + if (data.tag == '#text') { + return document.createTextNode(""); + } else if (data.tag == '#comment') { + return document.createComment(data.comment); + } else { + return document.createElementNS('http://www.w3.org/2000/svg', data.tag); + } + } + function createElementWithAttributes(data) { + var elementNode = createElement(data); + var element = d3__namespace.select(elementNode); + var attributes = data.attributes; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var attributeName = _Object$keys[_i]; + var attributeValue = attributes[attributeName]; + element.attr(attributeName, attributeValue); + } + return elementNode; + } + function replaceElement(element, data) { + var parent = d3__namespace.select(element.node().parentNode); + var newElementNode = createElementWithAttributes(data); + var newElement = parent.insert(function () { + return newElementNode; + }, function () { + return element.node(); + }); + element.remove(); + return newElement; + } + function insertElementData(element, datum) { + element.datum(datum); + element.data([datum], function (d) { + return d.key; + }); + } + function insertAllElementsData(element, datum) { + insertElementData(element, datum); + var children = d3__namespace.selectAll(element.node().childNodes); + children.each(function (d, i) { + insertAllElementsData(d3__namespace.select(this), datum.children[i]); + }); + } + function insertChildren(element, index) { + var children = element.selectAll(function () { + return element.node().childNodes; + }); + children = children.data(function (d) { + return d.children; + }, function (d) { + return d.tag + '-' + index; + }); + var childrenEnter = children.enter().append(function (d) { + return createElement(d); + }); + var childrenExit = children.exit(); + childrenExit = childrenExit.remove(); + children = childrenEnter.merge(children); + var childTagIndexes = {}; + children.each(function (childData) { + var childTag = childData.tag; + if (childTagIndexes[childTag] == null) { + childTagIndexes[childTag] = 0; + } + var childIndex = childTagIndexes[childTag]++; + attributeElement.call(this, childData, childIndex); + }); + } + function attributeElement(data) { + var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var element = d3__namespace.select(this); + data.tag; + var attributes = data.attributes; + var currentAttributes = element.node().attributes; + if (currentAttributes) { + for (var i = 0; i < currentAttributes.length; i++) { + var currentAttribute = currentAttributes[i]; + var name = currentAttribute.name; + if (name.split(':')[0] != 'xmlns' && currentAttribute.namespaceURI) { + var namespaceURIParts = currentAttribute.namespaceURI.split('/'); + var namespace = namespaceURIParts[namespaceURIParts.length - 1]; + name = namespace + ':' + name; + } + if (!(name in attributes)) { + attributes[name] = null; + } + } + } + for (var _i2 = 0, _Object$keys2 = Object.keys(attributes); _i2 < _Object$keys2.length; _i2++) { + var attributeName = _Object$keys2[_i2]; + element.attr(attributeName, attributes[attributeName]); + } + if (data.text) { + element.text(data.text); + } + insertChildren(element, index); + } + + function zoom (enable) { + this._options.zoom = enable; + if (this._options.zoom && !this._zoomBehavior) { + createZoomBehavior.call(this); + } else if (!this._options.zoom && this._zoomBehavior) { + this._zoomSelection.on(".zoom", null); + this._zoomBehavior = null; + } + return this; + } + function createZoomBehavior() { + var graphvizInstance = this; + function zoomed(event) { + var g = d3__namespace.select(svg.node().querySelector("g")); + g.attr('transform', event.transform); + graphvizInstance._dispatch.call('zoom', graphvizInstance); + } + var root = this._selection; + var svg = d3__namespace.select(root.node().querySelector("svg")); + if (svg.size() == 0) { + return this; + } + this._zoomSelection = svg; + var zoomBehavior = d3Zoom.zoom().scaleExtent(this._options.zoomScaleExtent).translateExtent(this._options.zoomTranslateExtent).interpolate(d3Interpolate.interpolate).on("zoom", zoomed); + this._zoomBehavior = zoomBehavior; + var g = d3__namespace.select(svg.node().querySelector("g")); + svg.call(zoomBehavior); + if (!this._active) { + translateZoomBehaviorTransform.call(this, g); + } + this._originalTransform = d3Zoom.zoomTransform(svg.node()); + return this; + } + function getTranslatedZoomTransform(selection) { + // Get the current zoom transform for the top level svg and + // translate it uniformly with the given selection, using the + // difference between the translation specified in the selection's + // data and it's saved previous translation. The selection is + // normally the top level g element of the graph. + var oldTranslation = this._translation; + var oldScale = this._scale; + var newTranslation = selection.datum().translation; + var newScale = selection.datum().scale; + var t = d3Zoom.zoomTransform(this._zoomSelection.node()); + if (oldTranslation) { + t = t.scale(1 / oldScale); + t = t.translate(-oldTranslation.x, -oldTranslation.y); + } + t = t.translate(newTranslation.x, newTranslation.y); + t = t.scale(newScale); + return t; + } + function translateZoomBehaviorTransform(selection) { + // Translate the current zoom transform for the top level svg + // uniformly with the given selection, using the difference + // between the translation specified in the selection's data and + // it's saved previous translation. The selection is normally the + // top level g element of the graph. + this._zoomBehavior.transform(this._zoomSelection, getTranslatedZoomTransform.call(this, selection)); + + // Save the selections's new translation and scale. + this._translation = selection.datum().translation; + this._scale = selection.datum().scale; + + // Set the original zoom transform to the translation and scale specified in + // the selection's data. + this._originalTransform = d3Zoom.zoomIdentity.translate(selection.datum().translation.x, selection.datum().translation.y).scale(selection.datum().scale); + } + function resetZoom(transition) { + // Reset the zoom transform to the original zoom transform. + var selection = this._zoomSelection; + if (transition) { + selection = selection.transition(transition); + } + selection.call(this._zoomBehavior.transform, this._originalTransform); + return this; + } + function zoomScaleExtent(extent) { + this._options.zoomScaleExtent = extent; + return this; + } + function zoomTranslateExtent(extent) { + this._options.zoomTranslateExtent = extent; + return this; + } + function zoomBehavior() { + return this._zoomBehavior || null; + } + function zoomSelection() { + return this._zoomSelection || null; + } + + function pathTween(points, d1) { + return function () { + var pointInterpolators = points.map(function (p) { + return d3Interpolate.interpolate([p[0][0], p[0][1]], [p[1][0], p[1][1]]); + }); + return function (t) { + return t < 1 ? "M" + pointInterpolators.map(function (p) { + return p(t); + }).join("L") : d1; + }; + }; + } + function pathTweenPoints(node, d1, precision, precisionIsRelative) { + var path0 = node; + var path1 = path0.cloneNode(); + var n0 = path0.getTotalLength(); + var n1 = (path1.setAttribute("d", d1), path1).getTotalLength(); + + // Uniform sampling of distance based on specified precision. + var distances = [0]; + var i = 0; + var dt = precisionIsRelative ? precision : precision / Math.max(n0, n1); + while ((i += dt) < 1) { + distances.push(i); + } + distances.push(1); + + // Compute point-interpolators at each distance. + var points = distances.map(function (t) { + var p0 = path0.getPointAtLength(t * n0); + var p1 = path1.getPointAtLength(t * n1); + return [[p0.x, p0.y], [p1.x, p1.y]]; + }); + return points; + } + + function data () { + return this._data || null; + } + function isEdgeElementParent(datum) { + return datum.attributes["class"] == 'edge' || datum.tag == 'a' && datum.parent.tag == 'g' && datum.parent.parent.attributes["class"] == 'edge'; + } + function isEdgeElement(datum) { + return datum.parent && isEdgeElementParent(datum.parent); + } + function getEdgeGroup(datum) { + if (datum.parent.attributes["class"] == 'edge') { + return datum.parent; + } else { + // datum.parent.tag == 'g' && datum.parent.parent.tag == 'g' && datum.parent.parent.parent.attributes.class == 'edge' + return datum.parent.parent.parent; + } + } + function getEdgeTitle(datum) { + return getEdgeGroup(datum).children.find(function (e) { + return e.tag == 'title'; + }); + } + + function render (callback) { + if (this._busy) { + this._queue.push(this.render.bind(this, callback)); + return this; + } + this._dispatch.call('renderStart', this); + if (this._transitionFactory) { + d3Timer.timeout(function () { + // Decouple from time spent. See https://github.com/d3/d3-timer/issues/27 + this._transition = d3Transition.transition(this._transitionFactory()); + _render.call(this, callback); + }.bind(this), 0); + } else { + _render.call(this, callback); + } + return this; + } + function _render(callback) { + var transitionInstance = this._transition; + var fade = this._options.fade && transitionInstance != null; + var tweenPaths = this._options.tweenPaths; + var tweenShapes = this._options.tweenShapes; + var convertEqualSidedPolygons = this._options.convertEqualSidedPolygons; + var growEnteringEdges = this._options.growEnteringEdges && transitionInstance != null; + var attributer = this._attributer; + var graphvizInstance = this; + function insertChildren(element) { + var children = element.selectAll(function () { + return element.node().childNodes; + }); + children = children.data(function (d) { + return d.children; + }, function (d) { + return d.key; + }); + var childrenEnter = children.enter().append(function (d) { + var element = createElement(d); + if (d.tag == '#text' && fade) { + element.nodeValue = d.text; + } + return element; + }); + if (fade || growEnteringEdges && isEdgeElementParent(element.datum())) { + var childElementsEnter = childrenEnter.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).each(function (d) { + var childEnter = d3__namespace.select(this); + for (var _i = 0, _Object$keys = Object.keys(d.attributes); _i < _Object$keys.length; _i++) { + var attributeName = _Object$keys[_i]; + var attributeValue = d.attributes[attributeName]; + childEnter.attr(attributeName, attributeValue); + } + }); + childElementsEnter.filter(function (d) { + return d.tag == 'svg' || d.tag == 'g' ? null : this; + }).style("opacity", 0.0); + } + var childrenExit = children.exit(); + if (attributer) { + childrenExit.each(attributer); + } + if (transitionInstance) { + childrenExit = childrenExit.transition(transitionInstance); + if (fade) { + childrenExit.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).style("opacity", 0.0); + } + } + childrenExit = childrenExit.remove(); + children = childrenEnter.merge(children).order(); + children.each(attributeElement); + } + function attributeElement(data) { + var element = d3__namespace.select(this); + if (data.tag == "svg") { + var options = graphvizInstance._options; + if (options.width != null || options.height != null) { + var width = options.width; + var height = options.height; + if (width == null) { + width = data.attributes.width.replace('pt', '') * 4 / 3; + } else { + element.attr("width", width); + data.attributes.width = width; + } + if (height == null) { + height = data.attributes.height.replace('pt', '') * 4 / 3; + } else { + element.attr("height", height); + data.attributes.height = height; + } + if (!options.fit) { + element.attr("viewBox", "0 0 ".concat(width * 3 / 4 / options.scale, " ").concat(height * 3 / 4 / options.scale)); + data.attributes.viewBox = "0 0 ".concat(width * 3 / 4 / options.scale, " ").concat(height * 3 / 4 / options.scale); + } + } + if (options.scale != 1 && (options.fit || options.width == null && options.height == null)) { + width = data.attributes.viewBox.split(' ')[2]; + height = data.attributes.viewBox.split(' ')[3]; + element.attr("viewBox", "0 0 ".concat(width / options.scale, " ").concat(height / options.scale)); + data.attributes.viewBox = "0 0 ".concat(width / options.scale, " ").concat(height / options.scale); + } + } + if (attributer) { + element.each(attributer); + } + var tag = data.tag; + var attributes = data.attributes; + var currentAttributes = element.node().attributes; + if (currentAttributes) { + for (var i = 0; i < currentAttributes.length; i++) { + var currentAttribute = currentAttributes[i]; + var name = currentAttribute.name; + if (name.split(':')[0] != 'xmlns' && currentAttribute.namespaceURI) { + var namespaceURIParts = currentAttribute.namespaceURI.split('/'); + var namespace = namespaceURIParts[namespaceURIParts.length - 1]; + name = namespace + ':' + name; + } + if (!(name in attributes)) { + attributes[name] = null; + } + } + } + var convertShape = false; + var convertPrevShape = false; + if (tweenShapes && transitionInstance) { + if ((this.nodeName == 'polygon' || this.nodeName == 'ellipse') && data.alternativeOld) { + convertPrevShape = true; + } + if ((tag == 'polygon' || tag == 'ellipse') && data.alternativeNew) { + convertShape = true; + } + if (this.nodeName == 'polygon' && tag == 'polygon' && data.alternativeOld) { + var prevData = extractElementData(element); + var prevPoints = prevData.attributes.points; + if (!convertEqualSidedPolygons) { + var nPrevPoints = prevPoints.split(' ').length; + var points = data.attributes.points; + var nPoints = points.split(' ').length; + if (nPoints == nPrevPoints) { + convertShape = false; + convertPrevShape = false; + } + } + } + if (convertPrevShape) { + var prevPathData = data.alternativeOld; + var pathElement = replaceElement(element, prevPathData); + pathElement.data([data], function () { + return data.key; + }); + element = pathElement; + } + if (convertShape) { + var newPathData = data.alternativeNew; + tag = 'path'; + attributes = newPathData.attributes; + } + } + var elementTransition = element; + if (transitionInstance) { + elementTransition = elementTransition.transition(transitionInstance); + if (fade) { + elementTransition.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).style("opacity", 1.0); + } + elementTransition.filter(function (d) { + return d.tag[0] == '#' ? null : this; + }).on("end", function (d) { + d3__namespace.select(this).attr('style', d && d.attributes && d.attributes.style || null); + }); + } + var growThisPath = growEnteringEdges && tag == 'path' && data.offset; + if (growThisPath) { + var totalLength = data.totalLength; + element.attr("stroke-dasharray", totalLength + " " + totalLength).attr("stroke-dashoffset", totalLength).attr('transform', 'translate(' + data.offset.x + ',' + data.offset.y + ')'); + attributes["stroke-dashoffset"] = 0; + attributes['transform'] = 'translate(0,0)'; + elementTransition.attr("stroke-dashoffset", attributes["stroke-dashoffset"]).attr('transform', attributes['transform']).on("start", function () { + d3__namespace.select(this).style('opacity', null); + }).on("end", function () { + d3__namespace.select(this).attr('stroke-dashoffset', null).attr('stroke-dasharray', null).attr('transform', null); + }); + } + var moveThisPolygon = growEnteringEdges && tag == 'polygon' && isEdgeElement(data) && data.offset && data.parent.children[3].tag == 'path'; + if (moveThisPolygon) { + var edgePath = d3__namespace.select(element.node().parentNode.querySelector("path")); + var p0 = edgePath.node().getPointAtLength(0); + var p1 = edgePath.node().getPointAtLength(data.totalLength); + var p2 = edgePath.node().getPointAtLength(data.totalLength - 1); + var angle1 = Math.atan2(p1.y - p2.y, p1.x - p2.x) * 180 / Math.PI; + var x = p0.x - p1.x + data.offset.x; + var y = p0.y - p1.y + data.offset.y; + element.attr('transform', 'translate(' + x + ',' + y + ')'); + elementTransition.attrTween("transform", function () { + return function (t) { + var p = edgePath.node().getPointAtLength(data.totalLength * t); + var p2 = edgePath.node().getPointAtLength(data.totalLength * t + 1); + var angle = Math.atan2(p2.y - p.y, p2.x - p.x) * 180 / Math.PI - angle1; + x = p.x - p1.x + data.offset.x * (1 - t); + y = p.y - p1.y + data.offset.y * (1 - t); + return 'translate(' + x + ',' + y + ') rotate(' + angle + ' ' + p1.x + ' ' + p1.y + ')'; + }; + }).on("start", function () { + d3__namespace.select(this).style('opacity', null); + }).on("end", function () { + d3__namespace.select(this).attr('transform', null); + }); + } + var tweenThisPath = tweenPaths && transitionInstance && tag == 'path' && element.attr('d') != null; + for (var _i2 = 0, _Object$keys2 = Object.keys(attributes); _i2 < _Object$keys2.length; _i2++) { + var attributeName = _Object$keys2[_i2]; + var attributeValue = attributes[attributeName]; + if (tweenThisPath && attributeName == 'd') { + var points = (data.alternativeOld || data).points; + if (points) { + elementTransition.attrTween("d", pathTween(points, attributeValue)); + } + } else { + if (attributeName == 'transform' && data.translation) { + if (transitionInstance) { + var onEnd = elementTransition.on("end"); + elementTransition.on("start", function () { + if (graphvizInstance._zoomBehavior) { + // Update the transform to transition to, just before the transition starts + // in order to catch changes between the transition scheduling to its start. + elementTransition.tween("attr.transform", function () { + var node = this; + return function (t) { + node.setAttribute("transform", d3Interpolate.interpolateTransformSvg(d3Zoom.zoomTransform(graphvizInstance._zoomSelection.node()).toString(), getTranslatedZoomTransform.call(graphvizInstance, element).toString())(t)); + }; + }); + } + }).on("end", function () { + onEnd.call(this); + // Update the zoom transform to the new translated transform + if (graphvizInstance._zoomBehavior) { + translateZoomBehaviorTransform.call(graphvizInstance, element); + } + }); + } else { + if (graphvizInstance._zoomBehavior) { + // Update the transform attribute to set with the current pan translation + translateZoomBehaviorTransform.call(graphvizInstance, element); + attributeValue = getTranslatedZoomTransform.call(graphvizInstance, element).toString(); + } + } + } + elementTransition.attr(attributeName, attributeValue); + } + } + if (convertShape) { + elementTransition.on("end", function (d, i, nodes) { + pathElement = d3__namespace.select(this); + var newElement = replaceElement(pathElement, d); + newElement.data([d], function () { + return d.key; + }); + }); + } + if (data.text) { + elementTransition.text(data.text); + } + insertChildren(element); + } + var root = this._selection; + if (transitionInstance != null) { + // Ensure original SVG shape elements are restored after transition before rendering new graph + var jobs = this._jobs; + if (graphvizInstance._active) { + jobs.push(null); + return this; + } else { + root.transition(transitionInstance).transition().duration(0).on("end", function () { + graphvizInstance._active = false; + if (jobs.length != 0) { + jobs.shift(); + graphvizInstance.render(); + } + }); + this._active = true; + } + } + if (transitionInstance != null) { + root.transition(transitionInstance).on("start", function () { + graphvizInstance._dispatch.call('transitionStart', graphvizInstance); + }).on("end", function () { + graphvizInstance._dispatch.call('transitionEnd', graphvizInstance); + }).transition().duration(0).on("start", function () { + graphvizInstance._dispatch.call('restoreEnd', graphvizInstance); + graphvizInstance._dispatch.call('end', graphvizInstance); + if (callback) { + callback.call(graphvizInstance); + } + }); + } + var data = this._data; + var svg = root.selectAll("svg").data([data], function (d) { + return d.key; + }); + svg = svg.enter().append("svg").merge(svg); + attributeElement.call(svg.node(), data); + if (this._options.zoom && !this._zoomBehavior) { + createZoomBehavior.call(this); + } + graphvizInstance._dispatch.call('renderEnd', graphvizInstance); + if (transitionInstance == null) { + this._dispatch.call('end', this); + if (callback) { + callback.call(this); + } + } + return this; + } + + function graphvizVersion () { + return this._graphvizVersion; + } + + var io=ArrayBuffer,H=Uint8Array,Qe=Uint16Array,so=Int16Array,qe=Int32Array,pr=function(p,c,d){if(H.prototype.slice)return H.prototype.slice.call(p,c,d);(c==null||c<0)&&(c=0),(d==null||d>p.length)&&(d=p.length);var s=new H(d-c);return s.set(p.subarray(c,d)),s},Ye=function(p,c,d,s){if(H.prototype.fill)return H.prototype.fill.call(p,c,d,s);for((d==null||d<0)&&(d=0),(s==null||s>p.length)&&(s=p.length);dp.length)&&(s=p.length);d2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],T=function(p,c,d){var s=new Error(c||po[p]);if(s.code=p,Error.captureStackTrace&&Error.captureStackTrace(s,T),!d)throw s;return s},jr=function(p,c,d){for(var s=0,f=0;s>>0},co=function(p,c){var d=p[0]|p[1]<<8|p[2]<<16;if(d==3126568&&p[3]==253){var s=p[4],f=s>>5&1,m=s>>2&1,_=s&3,h=s>>6;s&8&&T(0);var M=6-f,I=_==3?4:_,Q=jr(p,M,I);M+=I;var Z=h?1<>3);z=q+(q>>3)*(p[5]&7);}z>2145386496&&T(1);var X=new H((c==1?Y||z:c?0:z)+12);return X[0]=1,X[4]=4,X[8]=8,{b:M+Z,y:0,l:0,d:Q,w:c&&c!=1?c:X.subarray(12),e:z,o:new qe(X.buffer,0,3),u:Y,c:m,m:Math.min(131072,z)}}else if((d>>4|p[3]<<20)==25481893)return lo(p,4)+8;T(0);},Xe=function(p){for(var c=0;1<d&&T(3);for(var m=1<0;){var S=Xe(_+1),P=s>>3,ae=(1<>(s&7)&ae,w=(1<w&&(J-=j)),Y[++h]=--J,J==-1?(_+=J,V[--Q]=h):_-=J,!J)do{var ie=s>>3;M=(p[ie]|p[ie+1]<<8)>>(s&7)&3,s+=2,h+=M;}while(M==3)}(h>255||_)&&T(0);for(var b=0,k=(m>>1)+(m>>3)+3,se=m-1,oe=0;oe<=h;++oe){var K=Y[oe];if(K<1){z[oe]=-K;continue}for(I=0;I=Q)}}for(b&&T(0),I=0;I>3,{b:f,s:V,n:re,t:q}]},fo=function(p,c){var d=0,s=-1,f=new H(292),m=p[c],_=f.subarray(0,256),h=f.subarray(256,268),M=new Qe(f.buffer,268);if(m<128){var I=je(p,c+1,6),Q=I[0],Z=I[1];c+=m;var Y=Q<<3,z=p[c];z||T(0);for(var q=0,X=0,V=Z.b,re=V,S=(++c<<3)-8+Xe(z);S-=V,!(S>3;if(q+=(p[P]|p[P+1]<<8)>>(S&7)&(1<>3,X+=(p[P]|p[P+1]<<8)>>(S&7)&(1<255&&T(0);}else {for(s=m-127;d>4,_[d+1]=ae&15;}++c;}var J=0;for(d=0;d11&&T(0),J+=w&&1<0;--d){var oe=M[d];Ye(se,d,oe,M[d-1]=oe+h[d]*(1<h&&Z>3,z=(p[Y]|p[Y+1]<<8|p[Y+2]<<16)>>(Q&7);M=(M<>2,_=m<<1,h=m+_;Ze(p.subarray(s,s+=p[0]|p[1]<<8),c.subarray(0,m),d),Ze(p.subarray(s,s+=p[2]|p[3]<<8),c.subarray(m,_),d),Ze(p.subarray(s,s+=p[4]|p[5]<<8),c.subarray(_,h),d),Ze(p.subarray(s),c.subarray(h),d);},yo=function(p,c,d){var s,f=c.b,m=p[f],_=m>>1&3;c.l=m&1;var h=m>>3|p[f+1]<<5|p[f+2]<<13,M=(f+=3)+h;if(_==1)return f>=p.length?void 0:(c.b=f+1,d?(Ye(d,p[f],c.y,c.y+=h),d):Ye(new H(h),p[f]));if(!(M>p.length)){if(_==0)return c.b=M,d?(d.set(p.subarray(f,M),c.y),c.y+=h,d):pr(p,f,M);if(_==2){var I=p[f],Q=I&3,Z=I>>2&3,Y=I>>4,z=0,q=0;Q<2?Z&1?Y|=p[++f]<<4|(Z&2&&p[++f]<<12):Y=I>>3:(q=Z,Z<2?(Y|=(p[++f]&63)<<4,z=p[f]>>6|p[++f]<<2):Z==2?(Y|=p[++f]<<4|(p[++f]&3)<<12,z=p[f]>>2|p[++f]<<6):(Y|=p[++f]<<4|(p[++f]&63)<<12,z=p[f]>>6|p[++f]<<2|p[++f]<<10)),++f;var X=d?d.subarray(c.y,c.y+c.m):new H(c.m),V=X.length-Y;if(Q==0)X.set(p.subarray(f,f+=Y),V);else if(Q==1)Ye(X,p[f++],V);else {var re=c.h;if(Q==2){var S=fo(p,f);z+=f-(f=S[0]),c.h=re=S[1];}else re||T(0);(q?wo:Ze)(p.subarray(f,f+=z),X.subarray(V),re);}var P=p[f++];if(P){P==255?P=(p[f++]|p[f++]<<8)+32512:P>127&&(P=P-128<<8|p[f++]);var ae=p[f++];ae&3&&T(0);for(var J=[mo,_o,vo],w=2;w>-1;--w){var j=ae>>(w<<1)+2&3;if(j==1){var W=new H([0,0,p[f++]]);J[w]={s:W.subarray(2,3),n:W.subarray(0,1),t:new Qe(W.buffer,0,1),b:0};}else j==2?(s=je(p,f,9-(w&1)),f=s[0],J[w]=s[1]):j==3&&(c.t||T(0),J[w]=c.t[w]);}var ie=c.t=J,b=ie[0],k=ie[1],se=ie[2],oe=p[M-1];oe||T(0);var K=(M<<3)-8+Xe(oe)-se.b,L=K>>3,A=0,Le=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var Be=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var Re=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var $e=1<>>(K&7)&$e-1);L=(K-=dr[Ve])>>3;var me=ho[Ve]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<>3;var _e=go[Ne]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<>3,Le=se.t[Le]+((p[L]|p[L+1]<<8)>>(K&7)&(1<>3,Re=b.t[Re]+((p[L]|p[L+1]<<8)>>(K&7)&(1<>3,Be=k.t[Be]+((p[L]|p[L+1]<<8)>>(K&7)&(1<3)c.o[2]=c.o[1],c.o[1]=c.o[0],c.o[0]=ce-=3;else {var Ge=ce-(_e!=0);Ge?(ce=Ge==3?c.o[0]-1:c.o[Ge],Ge>1&&(c.o[2]=c.o[1]),c.o[1]=c.o[0],c.o[0]=ce):ce=c.o[0];}for(var w=0;w<_e;++w)X[A+w]=X[V+w];A+=_e,V+=_e;var Ee=A-ce;if(Ee<0){var De=-Ee,We=c.e+Ee;De>me&&(De=me);for(var w=0;w{typeof document<"u"?document.currentScript?.src:void 0;return function(c={}){var d,s=c,f,m,_=new Promise((e,r)=>{f=e,m=r;}),M=Object.assign({},s),I="./this.program",Q=(e,r)=>{throw r},Z="";function Y(e){return Z+e}var z,q,X=console.log.bind(console),V=console.error.bind(console);Object.assign(s,M),M=null;var re;s.wasmBinary&&(re=s.wasmBinary);var S,P=!1;function J(e,r){e||_e(r);}var w,j,W,b,k,oe;function K(){var e=S.buffer;s.HEAP8=w=new Int8Array(e),s.HEAP16=W=new Int16Array(e),s.HEAPU8=j=new Uint8Array(e),s.HEAPU16=new Uint16Array(e),s.HEAP32=b=new Int32Array(e),s.HEAPU32=k=new Uint32Array(e),s.HEAPF32=new Float32Array(e),s.HEAPF64=oe=new Float64Array(e);}var L=[],A=[],Le=[];function Re(){Ae(L);}function Ne(){!s.noFSInit&&!o.init.initialized&&o.init(),o.ignorePermissions=!1,Ae(A);}function Pe(){Ae(Le);}function Ve(e){A.unshift(e);}var ye=0,be=null;function ce(e){ye++;}function me(e){if(ye--,ye==0&&(be)){var r=be;be=null,r();}}function _e(e){e="Aborted("+e+")",V(e),P=!0,e+=". Build with -sASSERTIONS for more info.";var r=new WebAssembly.RuntimeError(e);throw m(r),r}var Ge="data:application/octet-stream;base64,",Ee=e=>e.startsWith(Ge),De=e=>e.startsWith("file://");function We(){var e="graphvizlib.wasm";return Ee(e)?e:Y(e)}var Je;function fr(e){if(e==Je&&re)return new Uint8Array(re);throw "both async and sync fetching of the wasm failed"}function Jr(e){return re?Promise.resolve().then(()=>fr(e)):z(e).then(r=>new Uint8Array(r),()=>fr(e))}function vr(e,r,t){return Jr(e).then(n=>WebAssembly.instantiate(n,r)).then(t,n=>{V(`failed to asynchronously prepare wasm: ${n}`),_e(n);})}function Sr(e,r,t,n){return !e&&typeof WebAssembly.instantiateStreaming=="function"&&!Ee(r)&&!De(r)&&typeof fetch=="function"?fetch(r,{credentials:"same-origin"}).then(a=>{var i=WebAssembly.instantiateStreaming(a,t);return i.then(n,function(u){return V(`wasm streaming compile failed: ${u}`),V("falling back to ArrayBuffer instantiation"),vr(r,t,n)})}):vr(r,t,n)}function Hr(){return {a:Qt}}function Tr(){var e=Hr();function r(n,a){return N=n.exports,S=N.B,K(),Ve(N.C),me(),N}ce();function t(n){r(n.instance);}return Je||(Je=We()),Sr(re,Je,e,t).catch(m),{}}var R,$,Qr={172808:(e,r)=>{var t=ue(e),n=ue(r);o.createPath("/",C.dirname(t)),o.writeFile(C.join("/",t),n);}};function qr(e){this.name="ExitStatus",this.message=`Program terminated with exit(${e})`,this.status=e;}var Ae=e=>{for(;e.length>0;)e.shift()(s);};class $r{constructor(r){this.excPtr=r,this.ptr=r-24;}set_type(r){k[this.ptr+4>>2]=r;}get_type(){return k[this.ptr+4>>2]}set_destructor(r){k[this.ptr+8>>2]=r;}get_destructor(){return k[this.ptr+8>>2]}set_caught(r){r=r?1:0,w[this.ptr+12]=r;}get_caught(){return w[this.ptr+12]!=0}set_rethrown(r){r=r?1:0,w[this.ptr+13]=r;}get_rethrown(){return w[this.ptr+13]!=0}init(r,t){this.set_adjusted_ptr(0),this.set_type(r),this.set_destructor(t);}set_adjusted_ptr(r){k[this.ptr+16>>2]=r;}get_adjusted_ptr(){return k[this.ptr+16>>2]}get_exception_ptr(){var r=Yr(this.get_type());if(r)return k[this.excPtr>>2];var t=this.get_adjusted_ptr();return t!==0?t:this.excPtr}}var mr=0,Ar=(e,r,t)=>{var n=new $r(e);throw n.init(r,t),mr=e,mr},C={isAbs:e=>e.charAt(0)==="/",splitPath:e=>{var r=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return r.exec(e).slice(1)},normalizeArray:(e,r)=>{for(var t=0,n=e.length-1;n>=0;n--){var a=e[n];a==="."?e.splice(n,1):a===".."?(e.splice(n,1),t++):t&&(e.splice(n,1),t--);}if(r)for(;t;t--)e.unshift("..");return e},normalize:e=>{var r=C.isAbs(e),t=e.substr(-1)==="/";return e=C.normalizeArray(e.split("/").filter(n=>!!n),!r).join("/"),!e&&!r&&(e="."),e&&t&&(e+="/"),(r?"/":"")+e},dirname:e=>{var r=C.splitPath(e),t=r[0],n=r[1];return !t&&!n?".":(n&&(n=n.substr(0,n.length-1)),t+n)},basename:e=>{if(e==="/")return "/";e=C.normalize(e),e=e.replace(/\/$/,"");var r=e.lastIndexOf("/");return r===-1?e:e.substr(r+1)},join:(...e)=>C.normalize(e.join("/")),join2:(e,r)=>C.normalize(e+"/"+r)},et=()=>{if(typeof crypto=="object"&&typeof crypto.getRandomValues=="function")return e=>crypto.getRandomValues(e);_e("initRandomDevice");},_r=e=>(_r=et())(e),he={resolve:(...e)=>{for(var r="",t=!1,n=e.length-1;n>=-1&&!t;n--){var a=n>=0?e[n]:o.cwd();if(typeof a!="string")throw new TypeError("Arguments to path.resolve must be strings");if(!a)return "";r=a+"/"+r,t=C.isAbs(a);}return r=C.normalizeArray(r.split("/").filter(i=>!!i),!t).join("/"),(t?"/":"")+r||"."},relative:(e,r)=>{e=he.resolve(e).substr(1),r=he.resolve(r).substr(1);function t(E){for(var G=0;G=0&&E[x]==="";x--);return G>x?[]:E.slice(G,x-G+1)}for(var n=t(e.split("/")),a=t(r.split("/")),i=Math.min(n.length,a.length),u=i,l=0;l{for(var n=r+t,a=r;e[a]&&!(a>=n);)++a;if(a-r>16&&e.buffer&&gr)return gr.decode(e.subarray(r,a));for(var i="";r>10,56320|E&1023);}}return i},er=[],rr=e=>{for(var r=0,t=0;t=55296&&n<=57343?(r+=4,++t):r+=3;}return r},tr=(e,r,t,n)=>{if(!(n>0))return 0;for(var a=t,i=t+n-1,u=0;u=55296&&l<=57343){var v=e.charCodeAt(++u);l=65536+((l&1023)<<10)|v&1023;}if(l<=127){if(t>=i)break;r[t++]=l;}else if(l<=2047){if(t+1>=i)break;r[t++]=192|l>>6,r[t++]=128|l&63;}else if(l<=65535){if(t+2>=i)break;r[t++]=224|l>>12,r[t++]=128|l>>6&63,r[t++]=128|l&63;}else {if(t+3>=i)break;r[t++]=240|l>>18,r[t++]=128|l>>12&63,r[t++]=128|l>>6&63,r[t++]=128|l&63;}}return r[t]=0,t-a};function or(e,r,t){var n=rr(e)+1,a=new Array(n),i=tr(e,a,0,a.length);return r&&(a.length=i),a}var rt=()=>{if(!er.length){var e=null;if(!e)return null;er=or(e,!0);}return er.shift()},Me={ttys:[],init(){},shutdown(){},register(e,r){Me.ttys[e]={input:[],output:[],ops:r},o.registerDevice(e,Me.stream_ops);},stream_ops:{open(e){var r=Me.ttys[e.node.rdev];if(!r)throw new o.ErrnoError(43);e.tty=r,e.seekable=!1;},close(e){e.tty.ops.fsync(e.tty);},fsync(e){e.tty.ops.fsync(e.tty);},read(e,r,t,n,a){if(!e.tty||!e.tty.ops.get_char)throw new o.ErrnoError(60);for(var i=0,u=0;u0&&(X(Fe(e.output,0)),e.output=[]);},ioctl_tcgets(e){return {c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(e,r,t){return 0},ioctl_tiocgwinsz(e){return [24,80]}},default_tty1_ops:{put_char(e,r){r===null||r===10?(V(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r);},fsync(e){e.output&&e.output.length>0&&(V(Fe(e.output,0)),e.output=[]);}}},tt=(e,r)=>(j.fill(0,e,e+r),e),hr=(e,r)=>Math.ceil(e/r)*r,wr=e=>{e=hr(e,65536);var r=Zr(65536,e);return r?tt(r,e):0},D={ops_table:null,mount(e){return D.createNode(null,"/",16895,0)},createNode(e,r,t,n){if(o.isBlkdev(t)||o.isFIFO(t))throw new o.ErrnoError(63);D.ops_table||={dir:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,lookup:D.node_ops.lookup,mknod:D.node_ops.mknod,rename:D.node_ops.rename,unlink:D.node_ops.unlink,rmdir:D.node_ops.rmdir,readdir:D.node_ops.readdir,symlink:D.node_ops.symlink},stream:{llseek:D.stream_ops.llseek}},file:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:{llseek:D.stream_ops.llseek,read:D.stream_ops.read,write:D.stream_ops.write,allocate:D.stream_ops.allocate,mmap:D.stream_ops.mmap,msync:D.stream_ops.msync}},link:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,readlink:D.node_ops.readlink},stream:{}},chrdev:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:o.chrdev_stream_ops}};var a=o.createNode(e,r,t,n);return o.isDir(a.mode)?(a.node_ops=D.ops_table.dir.node,a.stream_ops=D.ops_table.dir.stream,a.contents={}):o.isFile(a.mode)?(a.node_ops=D.ops_table.file.node,a.stream_ops=D.ops_table.file.stream,a.usedBytes=0,a.contents=null):o.isLink(a.mode)?(a.node_ops=D.ops_table.link.node,a.stream_ops=D.ops_table.link.stream):o.isChrdev(a.mode)&&(a.node_ops=D.ops_table.chrdev.node,a.stream_ops=D.ops_table.chrdev.stream),a.timestamp=Date.now(),e&&(e.contents[r]=a,e.timestamp=a.timestamp),a},getFileDataAsTypedArray(e){return e.contents?e.contents.subarray?e.contents.subarray(0,e.usedBytes):new Uint8Array(e.contents):new Uint8Array(0)},expandFileStorage(e,r){var t=e.contents?e.contents.length:0;if(!(t>=r)){var n=1048576;r=Math.max(r,t*(t>>0),t!=0&&(r=Math.max(r,256));var a=e.contents;e.contents=new Uint8Array(r),e.usedBytes>0&&e.contents.set(a.subarray(0,e.usedBytes),0);}},resizeFileStorage(e,r){if(e.usedBytes!=r)if(r==0)e.contents=null,e.usedBytes=0;else {var t=e.contents;e.contents=new Uint8Array(r),t&&e.contents.set(t.subarray(0,Math.min(r,e.usedBytes))),e.usedBytes=r;}},node_ops:{getattr(e){var r={};return r.dev=o.isChrdev(e.mode)?e.id:1,r.ino=e.id,r.mode=e.mode,r.nlink=1,r.uid=0,r.gid=0,r.rdev=e.rdev,o.isDir(e.mode)?r.size=4096:o.isFile(e.mode)?r.size=e.usedBytes:o.isLink(e.mode)?r.size=e.link.length:r.size=0,r.atime=new Date(e.timestamp),r.mtime=new Date(e.timestamp),r.ctime=new Date(e.timestamp),r.blksize=4096,r.blocks=Math.ceil(r.size/r.blksize),r},setattr(e,r){r.mode!==void 0&&(e.mode=r.mode),r.timestamp!==void 0&&(e.timestamp=r.timestamp),r.size!==void 0&&D.resizeFileStorage(e,r.size);},lookup(e,r){throw o.genericErrors[44]},mknod(e,r,t,n){return D.createNode(e,r,t,n)},rename(e,r,t){if(o.isDir(e.mode)){var n;try{n=o.lookupNode(r,t);}catch{}if(n)for(var a in n.contents)throw new o.ErrnoError(55)}delete e.parent.contents[e.name],e.parent.timestamp=Date.now(),e.name=t,r.contents[t]=e,r.timestamp=e.parent.timestamp;},unlink(e,r){delete e.contents[r],e.timestamp=Date.now();},rmdir(e,r){var t=o.lookupNode(e,r);for(var n in t.contents)throw new o.ErrnoError(55);delete e.contents[r],e.timestamp=Date.now();},readdir(e){var r=[".",".."];for(var t of Object.keys(e.contents))r.push(t);return r},symlink(e,r,t){var n=D.createNode(e,r,41471,0);return n.link=t,n},readlink(e){if(!o.isLink(e.mode))throw new o.ErrnoError(28);return e.link}},stream_ops:{read(e,r,t,n,a){var i=e.node.contents;if(a>=e.node.usedBytes)return 0;var u=Math.min(e.node.usedBytes-a,n);if(u>8&&i.subarray)r.set(i.subarray(a,a+u),t);else for(var l=0;l0||t+r{var a=`al ${e}`;z(e).then(i=>{r(new Uint8Array(i)),a&&me();},i=>{if(t)t();else throw `Loading data file "${e}" failed.`}),a&&ce();},nt=(e,r,t,n,a,i)=>{o.createDataFile(e,r,t,n,a,i);},at=[],it=(e,r,t,n)=>{typeof Browser<"u"&&Browser.init();var a=!1;return at.forEach(i=>{a||i.canHandle(r)&&(i.handle(e,r,t,n),a=!0);}),a},st=(e,r,t,n,a,i,u,l,v,E)=>{var G=r?he.resolve(C.join2(e,r)):e;function B(y){function O(te){E?.(),l||nt(e,r,te,n,a,v),i?.(),me();}it(y,G,O,()=>{u?.(),me();})||O(y);}ce(),typeof t=="string"?ot(t,B,u):B(t);},ut=e=>{var r={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090},t=r[e];if(typeof t>"u")throw new Error(`Unknown file open mode: ${e}`);return t},nr=(e,r)=>{var t=0;return e&&(t|=365),r&&(t|=146),t},o={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:!1,ignorePermissions:!0,ErrnoError:class{constructor(e){this.name="ErrnoError",this.errno=e;}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={};}get object(){return this.node}set object(e){this.node=e;}get isRead(){return (this.flags&2097155)!==1}get isWrite(){return (this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(e){this.shared.flags=e;}get position(){return this.shared.position}set position(e){this.shared.position=e;}},FSNode:class{constructor(e,r,t,n){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=o.nextInode++,this.name=r,this.mode=t,this.node_ops={},this.stream_ops={},this.rdev=n,this.readMode=365,this.writeMode=146;}get read(){return (this.mode&this.readMode)===this.readMode}set read(e){e?this.mode|=this.readMode:this.mode&=~this.readMode;}get write(){return (this.mode&this.writeMode)===this.writeMode}set write(e){e?this.mode|=this.writeMode:this.mode&=~this.writeMode;}get isFolder(){return o.isDir(this.mode)}get isDevice(){return o.isChrdev(this.mode)}},lookupPath(e,r={}){if(e=he.resolve(e),!e)return {path:"",node:null};var t={follow_mount:!0,recurse_count:0};if(r=Object.assign(t,r),r.recurse_count>8)throw new o.ErrnoError(32);for(var n=e.split("/").filter(x=>!!x),a=o.root,i="/",u=0;u40)throw new o.ErrnoError(32)}}return {path:i,node:a}},getPath(e){for(var r;;){if(o.isRoot(e)){var t=e.mount.mountpoint;return r?t[t.length-1]!=="/"?`${t}/${r}`:t+r:t}r=r?`${e.name}/${r}`:e.name,e=e.parent;}},hashName(e,r){for(var t=0,n=0;n>>0)%o.nameTable.length},hashAddNode(e){var r=o.hashName(e.parent.id,e.name);e.name_next=o.nameTable[r],o.nameTable[r]=e;},hashRemoveNode(e){var r=o.hashName(e.parent.id,e.name);if(o.nameTable[r]===e)o.nameTable[r]=e.name_next;else for(var t=o.nameTable[r];t;){if(t.name_next===e){t.name_next=e.name_next;break}t=t.name_next;}},lookupNode(e,r){var t=o.mayLookup(e);if(t)throw new o.ErrnoError(t);for(var n=o.hashName(e.id,r),a=o.nameTable[n];a;a=a.name_next){var i=a.name;if(a.parent.id===e.id&&i===r)return a}return o.lookup(e,r)},createNode(e,r,t,n){var a=new o.FSNode(e,r,t,n);return o.hashAddNode(a),a},destroyNode(e){o.hashRemoveNode(e);},isRoot(e){return e===e.parent},isMountpoint(e){return !!e.mounted},isFile(e){return (e&61440)===32768},isDir(e){return (e&61440)===16384},isLink(e){return (e&61440)===40960},isChrdev(e){return (e&61440)===8192},isBlkdev(e){return (e&61440)===24576},isFIFO(e){return (e&61440)===4096},isSocket(e){return (e&49152)===49152},flagsToPermissionString(e){var r=["r","w","rw"][e&3];return e&512&&(r+="w"),r},nodePermissions(e,r){return o.ignorePermissions?0:r.includes("r")&&!(e.mode&292)||r.includes("w")&&!(e.mode&146)||r.includes("x")&&!(e.mode&73)?2:0},mayLookup(e){if(!o.isDir(e.mode))return 54;var r=o.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate(e,r){try{var t=o.lookupNode(e,r);return 20}catch{}return o.nodePermissions(e,"wx")},mayDelete(e,r,t){var n;try{n=o.lookupNode(e,r);}catch(i){return i.errno}var a=o.nodePermissions(e,"wx");if(a)return a;if(t){if(!o.isDir(n.mode))return 54;if(o.isRoot(n)||o.getPath(n)===o.cwd())return 10}else if(o.isDir(n.mode))return 31;return 0},mayOpen(e,r){return e?o.isLink(e.mode)?32:o.isDir(e.mode)&&(o.flagsToPermissionString(r)!=="r"||r&512)?31:o.nodePermissions(e,o.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd(){for(var e=0;e<=o.MAX_OPEN_FDS;e++)if(!o.streams[e])return e;throw new o.ErrnoError(33)},getStreamChecked(e){var r=o.getStream(e);if(!r)throw new o.ErrnoError(8);return r},getStream:e=>o.streams[e],createStream(e,r=-1){return e=Object.assign(new o.FSStream,e),r==-1&&(r=o.nextfd()),e.fd=r,o.streams[r]=e,e},closeStream(e){o.streams[e]=null;},dupStream(e,r=-1){var t=o.createStream(e,r);return t.stream_ops?.dup?.(t),t},chrdev_stream_ops:{open(e){var r=o.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open?.(e);},llseek(){throw new o.ErrnoError(70)}},major:e=>e>>8,minor:e=>e&255,makedev:(e,r)=>e<<8|r,registerDevice(e,r){o.devices[e]={stream_ops:r};},getDevice:e=>o.devices[e],getMounts(e){for(var r=[],t=[e];t.length;){var n=t.pop();r.push(n),t.push(...n.mounts);}return r},syncfs(e,r){typeof e=="function"&&(r=e,e=!1),o.syncFSRequests++,o.syncFSRequests>1&&V(`warning: ${o.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);var t=o.getMounts(o.root.mount),n=0;function a(u){return o.syncFSRequests--,r(u)}function i(u){if(u)return i.errored?void 0:(i.errored=!0,a(u));++n>=t.length&&a(null);}t.forEach(u=>{if(!u.type.syncfs)return i(null);u.type.syncfs(u,e,i);});},mount(e,r,t){var n=t==="/",a=!t,i;if(n&&o.root)throw new o.ErrnoError(10);if(!n&&!a){var u=o.lookupPath(t,{follow_mount:!1});if(t=u.path,i=u.node,o.isMountpoint(i))throw new o.ErrnoError(10);if(!o.isDir(i.mode))throw new o.ErrnoError(54)}var l={type:e,opts:r,mountpoint:t,mounts:[]},v=e.mount(l);return v.mount=l,l.root=v,n?o.root=v:i&&(i.mounted=l,i.mount&&i.mount.mounts.push(l)),v},unmount(e){var r=o.lookupPath(e,{follow_mount:!1});if(!o.isMountpoint(r.node))throw new o.ErrnoError(28);var t=r.node,n=t.mounted,a=o.getMounts(n);Object.keys(o.nameTable).forEach(u=>{for(var l=o.nameTable[u];l;){var v=l.name_next;a.includes(l.mount)&&o.destroyNode(l),l=v;}}),t.mounted=null;var i=t.mount.mounts.indexOf(n);t.mount.mounts.splice(i,1);},lookup(e,r){return e.node_ops.lookup(e,r)},mknod(e,r,t){var n=o.lookupPath(e,{parent:!0}),a=n.node,i=C.basename(e);if(!i||i==="."||i==="..")throw new o.ErrnoError(28);var u=o.mayCreate(a,i);if(u)throw new o.ErrnoError(u);if(!a.node_ops.mknod)throw new o.ErrnoError(63);return a.node_ops.mknod(a,i,r,t)},create(e,r){return r=r!==void 0?r:438,r&=4095,r|=32768,o.mknod(e,r,0)},mkdir(e,r){return r=r!==void 0?r:511,r&=1023,r|=16384,o.mknod(e,r,0)},mkdirTree(e,r){for(var t=e.split("/"),n="",a=0;a"u"&&(t=r,r=438),r|=8192,o.mknod(e,r,t)},symlink(e,r){if(!he.resolve(e))throw new o.ErrnoError(44);var t=o.lookupPath(r,{parent:!0}),n=t.node;if(!n)throw new o.ErrnoError(44);var a=C.basename(r),i=o.mayCreate(n,a);if(i)throw new o.ErrnoError(i);if(!n.node_ops.symlink)throw new o.ErrnoError(63);return n.node_ops.symlink(n,a,e)},rename(e,r){var t=C.dirname(e),n=C.dirname(r),a=C.basename(e),i=C.basename(r),u,l,v;if(u=o.lookupPath(e,{parent:!0}),l=u.node,u=o.lookupPath(r,{parent:!0}),v=u.node,!l||!v)throw new o.ErrnoError(44);if(l.mount!==v.mount)throw new o.ErrnoError(75);var E=o.lookupNode(l,a),G=he.relative(e,n);if(G.charAt(0)!==".")throw new o.ErrnoError(28);if(G=he.relative(r,t),G.charAt(0)!==".")throw new o.ErrnoError(55);var x;try{x=o.lookupNode(v,i);}catch{}if(E!==x){var B=o.isDir(E.mode),y=o.mayDelete(l,a,B);if(y)throw new o.ErrnoError(y);if(y=x?o.mayDelete(v,i,B):o.mayCreate(v,i),y)throw new o.ErrnoError(y);if(!l.node_ops.rename)throw new o.ErrnoError(63);if(o.isMountpoint(E)||x&&o.isMountpoint(x))throw new o.ErrnoError(10);if(v!==l&&(y=o.nodePermissions(l,"w"),y))throw new o.ErrnoError(y);o.hashRemoveNode(E);try{l.node_ops.rename(E,v,i),E.parent=v;}catch(O){throw O}finally{o.hashAddNode(E);}}},rmdir(e){var r=o.lookupPath(e,{parent:!0}),t=r.node,n=C.basename(e),a=o.lookupNode(t,n),i=o.mayDelete(t,n,!0);if(i)throw new o.ErrnoError(i);if(!t.node_ops.rmdir)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.rmdir(t,n),o.destroyNode(a);},readdir(e){var r=o.lookupPath(e,{follow:!0}),t=r.node;if(!t.node_ops.readdir)throw new o.ErrnoError(54);return t.node_ops.readdir(t)},unlink(e){var r=o.lookupPath(e,{parent:!0}),t=r.node;if(!t)throw new o.ErrnoError(44);var n=C.basename(e),a=o.lookupNode(t,n),i=o.mayDelete(t,n,!1);if(i)throw new o.ErrnoError(i);if(!t.node_ops.unlink)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.unlink(t,n),o.destroyNode(a);},readlink(e){var r=o.lookupPath(e),t=r.node;if(!t)throw new o.ErrnoError(44);if(!t.node_ops.readlink)throw new o.ErrnoError(28);return he.resolve(o.getPath(t.parent),t.node_ops.readlink(t))},stat(e,r){var t=o.lookupPath(e,{follow:!r}),n=t.node;if(!n)throw new o.ErrnoError(44);if(!n.node_ops.getattr)throw new o.ErrnoError(63);return n.node_ops.getattr(n)},lstat(e){return o.stat(e,!0)},chmod(e,r,t){var n;if(typeof e=="string"){var a=o.lookupPath(e,{follow:!t});n=a.node;}else n=e;if(!n.node_ops.setattr)throw new o.ErrnoError(63);n.node_ops.setattr(n,{mode:r&4095|n.mode&-4096,timestamp:Date.now()});},lchmod(e,r){o.chmod(e,r,!0);},fchmod(e,r){var t=o.getStreamChecked(e);o.chmod(t.node,r);},chown(e,r,t,n){var a;if(typeof e=="string"){var i=o.lookupPath(e,{follow:!n});a=i.node;}else a=e;if(!a.node_ops.setattr)throw new o.ErrnoError(63);a.node_ops.setattr(a,{timestamp:Date.now()});},lchown(e,r,t){o.chown(e,r,t,!0);},fchown(e,r,t){var n=o.getStreamChecked(e);o.chown(n.node,r,t);},truncate(e,r){if(r<0)throw new o.ErrnoError(28);var t;if(typeof e=="string"){var n=o.lookupPath(e,{follow:!0});t=n.node;}else t=e;if(!t.node_ops.setattr)throw new o.ErrnoError(63);if(o.isDir(t.mode))throw new o.ErrnoError(31);if(!o.isFile(t.mode))throw new o.ErrnoError(28);var a=o.nodePermissions(t,"w");if(a)throw new o.ErrnoError(a);t.node_ops.setattr(t,{size:r,timestamp:Date.now()});},ftruncate(e,r){var t=o.getStreamChecked(e);if(!(t.flags&2097155))throw new o.ErrnoError(28);o.truncate(t.node,r);},utime(e,r,t){var n=o.lookupPath(e,{follow:!0}),a=n.node;a.node_ops.setattr(a,{timestamp:Math.max(r,t)});},open(e,r,t){if(e==="")throw new o.ErrnoError(44);r=typeof r=="string"?ut(r):r,r&64?(t=typeof t>"u"?438:t,t=t&4095|32768):t=0;var n;if(typeof e=="object")n=e;else {e=C.normalize(e);try{var a=o.lookupPath(e,{follow:!(r&131072)});n=a.node;}catch{}}var i=!1;if(r&64)if(n){if(r&128)throw new o.ErrnoError(20)}else n=o.mknod(e,t,0),i=!0;if(!n)throw new o.ErrnoError(44);if(o.isChrdev(n.mode)&&(r&=-513),r&65536&&!o.isDir(n.mode))throw new o.ErrnoError(54);if(!i){var u=o.mayOpen(n,r);if(u)throw new o.ErrnoError(u)}r&512&&!i&&o.truncate(n,0),r&=-131713;var l=o.createStream({node:n,path:o.getPath(n),flags:r,seekable:!0,position:0,stream_ops:n.stream_ops,ungotten:[],error:!1});return l.stream_ops.open&&l.stream_ops.open(l),s.logReadFiles&&!(r&1)&&(o.readFiles||(o.readFiles={}),e in o.readFiles||(o.readFiles[e]=1)),l},close(e){if(o.isClosed(e))throw new o.ErrnoError(8);e.getdents&&(e.getdents=null);try{e.stream_ops.close&&e.stream_ops.close(e);}catch(r){throw r}finally{o.closeStream(e.fd);}e.fd=null;},isClosed(e){return e.fd===null},llseek(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(!e.seekable||!e.stream_ops.llseek)throw new o.ErrnoError(70);if(t!=0&&t!=1&&t!=2)throw new o.ErrnoError(28);return e.position=e.stream_ops.llseek(e,r,t),e.ungotten=[],e.position},read(e,r,t,n,a){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if((e.flags&2097155)===1)throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.read)throw new o.ErrnoError(28);var i=typeof a<"u";if(!i)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var u=e.stream_ops.read(e,r,t,n,a);return i||(e.position+=u),u},write(e,r,t,n,a,i){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.write)throw new o.ErrnoError(28);e.seekable&&e.flags&1024&&o.llseek(e,0,2);var u=typeof a<"u";if(!u)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var l=e.stream_ops.write(e,r,t,n,a,i);return u||(e.position+=l),l},allocate(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(r<0||t<=0)throw new o.ErrnoError(28);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(!o.isFile(e.node.mode)&&!o.isDir(e.node.mode))throw new o.ErrnoError(43);if(!e.stream_ops.allocate)throw new o.ErrnoError(138);e.stream_ops.allocate(e,r,t);},mmap(e,r,t,n,a){if(n&2&&!(a&2)&&(e.flags&2097155)!==2)throw new o.ErrnoError(2);if((e.flags&2097155)===1)throw new o.ErrnoError(2);if(!e.stream_ops.mmap)throw new o.ErrnoError(43);return e.stream_ops.mmap(e,r,t,n,a)},msync(e,r,t,n,a){return e.stream_ops.msync?e.stream_ops.msync(e,r,t,n,a):0},ioctl(e,r,t){if(!e.stream_ops.ioctl)throw new o.ErrnoError(59);return e.stream_ops.ioctl(e,r,t)},readFile(e,r={}){if(r.flags=r.flags||0,r.encoding=r.encoding||"binary",r.encoding!=="utf8"&&r.encoding!=="binary")throw new Error(`Invalid encoding type "${r.encoding}"`);var t,n=o.open(e,r.flags),a=o.stat(e),i=a.size,u=new Uint8Array(i);return o.read(n,u,0,i,0),r.encoding==="utf8"?t=Fe(u,0):r.encoding==="binary"&&(t=u),o.close(n),t},writeFile(e,r,t={}){t.flags=t.flags||577;var n=o.open(e,t.flags,t.mode);if(typeof r=="string"){var a=new Uint8Array(rr(r)+1),i=tr(r,a,0,a.length);o.write(n,a,0,i,void 0,t.canOwn);}else if(ArrayBuffer.isView(r))o.write(n,r,0,r.byteLength,void 0,t.canOwn);else throw new Error("Unsupported data type");o.close(n);},cwd:()=>o.currentPath,chdir(e){var r=o.lookupPath(e,{follow:!0});if(r.node===null)throw new o.ErrnoError(44);if(!o.isDir(r.node.mode))throw new o.ErrnoError(54);var t=o.nodePermissions(r.node,"x");if(t)throw new o.ErrnoError(t);o.currentPath=r.path;},createDefaultDirectories(){o.mkdir("/tmp"),o.mkdir("/home"),o.mkdir("/home/web_user");},createDefaultDevices(){o.mkdir("/dev"),o.registerDevice(o.makedev(1,3),{read:()=>0,write:(n,a,i,u,l)=>u}),o.mkdev("/dev/null",o.makedev(1,3)),Me.register(o.makedev(5,0),Me.default_tty_ops),Me.register(o.makedev(6,0),Me.default_tty1_ops),o.mkdev("/dev/tty",o.makedev(5,0)),o.mkdev("/dev/tty1",o.makedev(6,0));var e=new Uint8Array(1024),r=0,t=()=>(r===0&&(r=_r(e).byteLength),e[--r]);o.createDevice("/dev","random",t),o.createDevice("/dev","urandom",t),o.mkdir("/dev/shm"),o.mkdir("/dev/shm/tmp");},createSpecialDirectories(){o.mkdir("/proc");var e=o.mkdir("/proc/self");o.mkdir("/proc/self/fd"),o.mount({mount(){var r=o.createNode(e,"fd",16895,73);return r.node_ops={lookup(t,n){var a=+n,i=o.getStreamChecked(a),u={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>i.path}};return u.parent=u,u}},r}},{},"/proc/self/fd");},createStandardStreams(){s.stdin?o.createDevice("/dev","stdin",s.stdin):o.symlink("/dev/tty","/dev/stdin"),s.stdout?o.createDevice("/dev","stdout",null,s.stdout):o.symlink("/dev/tty","/dev/stdout"),s.stderr?o.createDevice("/dev","stderr",null,s.stderr):o.symlink("/dev/tty1","/dev/stderr");o.open("/dev/stdin",0);o.open("/dev/stdout",1);o.open("/dev/stderr",1);},staticInit(){[44].forEach(e=>{o.genericErrors[e]=new o.ErrnoError(e),o.genericErrors[e].stack="";}),o.nameTable=new Array(4096),o.mount(D,{},"/"),o.createDefaultDirectories(),o.createDefaultDevices(),o.createSpecialDirectories(),o.filesystems={MEMFS:D};},init(e,r,t){o.init.initialized=!0,s.stdin=e||s.stdin,s.stdout=r||s.stdout,s.stderr=t||s.stderr,o.createStandardStreams();},quit(){o.init.initialized=!1;for(var e=0;ethis.length-1||y<0)){var O=y%this.chunkSize,te=y/this.chunkSize|0;return this.getter(te)[O]}}setDataGetter(y){this.getter=y;}cacheLength(){var y=new XMLHttpRequest;if(y.open("HEAD",t,!1),y.send(null),!(y.status>=200&&y.status<300||y.status===304))throw new Error("Couldn't load "+t+". Status: "+y.status);var O=Number(y.getResponseHeader("Content-length")),te,de=(te=y.getResponseHeader("Accept-Ranges"))&&te==="bytes",ne=(te=y.getResponseHeader("Content-Encoding"))&&te==="gzip",fe=1024*1024;de||(fe=O);var ve=(ge,xe)=>{if(ge>xe)throw new Error("invalid range ("+ge+", "+xe+") or no bytes requested!");if(xe>O-1)throw new Error("only "+O+" bytes available! programmer error!");var ee=new XMLHttpRequest;if(ee.open("GET",t,!1),O!==fe&&ee.setRequestHeader("Range","bytes="+ge+"-"+xe),ee.responseType="arraybuffer",ee.overrideMimeType&&ee.overrideMimeType("text/plain; charset=x-user-defined"),ee.send(null),!(ee.status>=200&&ee.status<300||ee.status===304))throw new Error("Couldn't load "+t+". Status: "+ee.status);return ee.response!==void 0?new Uint8Array(ee.response||[]):or(ee.responseText||"",!0)},Ie=this;Ie.setDataGetter(ge=>{var xe=ge*fe,ee=(ge+1)*fe-1;if(ee=Math.min(ee,O-1),typeof Ie.chunks[ge]>"u"&&(Ie.chunks[ge]=ve(xe,ee)),typeof Ie.chunks[ge]>"u")throw new Error("doXHR failed!");return Ie.chunks[ge]}),(ne||!O)&&(fe=O=1,O=this.getter(0).length,fe=O,X("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=O,this._chunkSize=fe,this.lengthKnown=!0;}get length(){return this.lengthKnown||this.cacheLength(),this._length}get chunkSize(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}if(typeof XMLHttpRequest<"u"){throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var u=new i,l={isDevice:!1,contents:u};}else var l={isDevice:!1,url:t};var v=o.createFile(e,r,l,n,a);l.contents?v.contents=l.contents:l.url&&(v.contents=null,v.url=l.url),Object.defineProperties(v,{usedBytes:{get:function(){return this.contents.length}}});var E={},G=Object.keys(v.stream_ops);G.forEach(B=>{var y=v.stream_ops[B];E[B]=(...O)=>(o.forceLoadFile(v),y(...O));});function x(B,y,O,te,de){var ne=B.node.contents;if(de>=ne.length)return 0;var fe=Math.min(ne.length-de,te);if(ne.slice)for(var ve=0;ve(o.forceLoadFile(v),x(B,y,O,te,de)),E.mmap=(B,y,O,te,de)=>{o.forceLoadFile(v);var ne=wr(y);if(!ne)throw new o.ErrnoError(48);return x(B,w,ne,y,O),{ptr:ne,allocated:!0}},v.stream_ops=E,v}},ue=(e,r)=>e?Fe(j,e,r):"",U={DEFAULT_POLLMASK:5,calculateAt(e,r,t){if(C.isAbs(r))return r;var n;if(e===-100)n=o.cwd();else {var a=U.getStreamFromFD(e);n=a.path;}if(r.length==0){if(!t)throw new o.ErrnoError(44);return n}return C.join2(n,r)},doStat(e,r,t){var n=e(r);b[t>>2]=n.dev,b[t+4>>2]=n.mode,k[t+8>>2]=n.nlink,b[t+12>>2]=n.uid,b[t+16>>2]=n.gid,b[t+20>>2]=n.rdev,$=[n.size>>>0,(R=n.size,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+24>>2]=$[0],b[t+28>>2]=$[1],b[t+32>>2]=4096,b[t+36>>2]=n.blocks;var a=n.atime.getTime(),i=n.mtime.getTime(),u=n.ctime.getTime();return $=[Math.floor(a/1e3)>>>0,(R=Math.floor(a/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+40>>2]=$[0],b[t+44>>2]=$[1],k[t+48>>2]=a%1e3*1e3,$=[Math.floor(i/1e3)>>>0,(R=Math.floor(i/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+56>>2]=$[0],b[t+60>>2]=$[1],k[t+64>>2]=i%1e3*1e3,$=[Math.floor(u/1e3)>>>0,(R=Math.floor(u/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+72>>2]=$[0],b[t+76>>2]=$[1],k[t+80>>2]=u%1e3*1e3,$=[n.ino>>>0,(R=n.ino,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+88>>2]=$[0],b[t+92>>2]=$[1],0},doMsync(e,r,t,n,a){if(!o.isFile(r.node.mode))throw new o.ErrnoError(43);if(n&2)return 0;var i=j.slice(e,e+t);o.msync(r,i,a,t,n);},getStreamFromFD(e){var r=o.getStreamChecked(e);return r},varargs:void 0,getStr(e){var r=ue(e);return r}};function pt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),t&-8)return -28;var a=o.lookupPath(r,{follow:!0}),i=a.node;if(!i)return -44;var u="";return t&4&&(u+="r"),t&2&&(u+="w"),t&1&&(u+="x"),u&&o.nodePermissions(i,u)?-2:0}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function Se(){var e=b[+U.varargs>>2];return U.varargs+=4,e}var Oe=Se;function lt(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 0:{var a=Se();if(a<0)return -28;for(;o.streams[a];)a++;var i;return i=o.dupStream(n,a),i.fd}case 1:case 2:return 0;case 3:return n.flags;case 4:{var a=Se();return n.flags|=a,0}case 12:{var a=Oe(),u=0;return W[a+u>>1]=2,0}case 13:case 14:return 0}return -28}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function ct(e,r){try{var t=U.getStreamFromFD(e);return U.doStat(o.stat,t.path,r)}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return -n.errno}}function dt(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 21509:return n.tty?0:-59;case 21505:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tcgets){var a=n.tty.ops.ioctl_tcgets(n),i=Oe();b[i>>2]=a.c_iflag||0,b[i+4>>2]=a.c_oflag||0,b[i+8>>2]=a.c_cflag||0,b[i+12>>2]=a.c_lflag||0;for(var u=0;u<32;u++)w[i+u+17]=a.c_cc[u]||0;return 0}return 0}case 21510:case 21511:case 21512:return n.tty?0:-59;case 21506:case 21507:case 21508:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tcsets){for(var i=Oe(),l=b[i>>2],v=b[i+4>>2],E=b[i+8>>2],G=b[i+12>>2],x=[],u=0;u<32;u++)x.push(w[i+u+17]);return n.tty.ops.ioctl_tcsets(n.tty,r,{c_iflag:l,c_oflag:v,c_cflag:E,c_lflag:G,c_cc:x})}return 0}case 21519:{if(!n.tty)return -59;var i=Oe();return b[i>>2]=0,0}case 21520:return n.tty?-28:-59;case 21531:{var i=Oe();return o.ioctl(n,r,i)}case 21523:{if(!n.tty)return -59;if(n.tty.ops.ioctl_tiocgwinsz){var B=n.tty.ops.ioctl_tiocgwinsz(n.tty),i=Oe();W[i>>1]=B[0],W[i+2>>1]=B[1];}return 0}case 21524:return n.tty?0:-59;case 21515:return n.tty?0:-59;default:return -28}}catch(y){if(typeof o>"u"||y.name!=="ErrnoError")throw y;return -y.errno}}function ft(e,r,t,n){try{r=U.getStr(r);var a=n&256,i=n&4096;return n=n&-6401,r=U.calculateAt(e,r,i),U.doStat(a?o.lstat:o.stat,r,t)}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return -u.errno}}function vt(e,r,t,n){U.varargs=n;try{r=U.getStr(r),r=U.calculateAt(e,r);var a=n?Se():0;return o.open(r,t,a).fd}catch(i){if(typeof o>"u"||i.name!=="ErrnoError")throw i;return -i.errno}}var Ke=(e,r,t)=>tr(e,j,r,t);function mt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),n<=0)return -28;var a=o.readlink(r),i=Math.min(n,rr(a)),u=w[t+i];return Ke(a,t,n+1),w[t+i]=u,i}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return -l.errno}}function _t(e){try{return e=U.getStr(e),o.rmdir(e),0}catch(r){if(typeof o>"u"||r.name!=="ErrnoError")throw r;return -r.errno}}function gt(e,r){try{return e=U.getStr(e),U.doStat(o.stat,e,r)}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return -t.errno}}function ht(e,r,t){try{return r=U.getStr(r),r=U.calculateAt(e,r),t===0?o.unlink(r):t===512?o.rmdir(r):_e("Invalid flags passed to unlinkat"),0}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return -n.errno}}var wt=()=>{_e("");},yt=1,bt=()=>yt,Et=(e,r,t)=>j.copyWithin(e,r,r+t),ar=(e,r)=>r+2097152>>>0<4194305-!!e?(e>>>0)+r*4294967296:NaN;function Mt(e,r,t,n,a,i,u,l){var v=ar(a,i);try{if(isNaN(v))return 61;var E=U.getStreamFromFD(n),G=o.mmap(E,e,v,r,t),x=G.ptr;return b[u>>2]=G.allocated,k[l>>2]=x,0}catch(B){if(typeof o>"u"||B.name!=="ErrnoError")throw B;return -B.errno}}function Dt(e,r,t,n,a,i,u){var l=ar(i,u);try{var v=U.getStreamFromFD(a);t&2&&U.doMsync(e,v,r,n,l);}catch(E){if(typeof o>"u"||E.name!=="ErrnoError")throw E;return -E.errno}}var Xt=(e,r,t,n)=>{var a=new Date().getFullYear(),i=new Date(a,0,1),u=new Date(a,6,1),l=i.getTimezoneOffset(),v=u.getTimezoneOffset(),E=Math.max(l,v);k[e>>2]=E*60,b[r>>2]=+(l!=v);var G=y=>{var O=y>=0?"-":"+",te=Math.abs(y),de=String(Math.floor(te/60)).padStart(2,"0"),ne=String(te%60).padStart(2,"0");return `UTC${O}${de}${ne}`},x=G(l),B=G(v);v{ir.length=0;for(var t;t=j[e++];){var n=t!=105;n&=t!=112,r+=n&&r%8?4:0,ir.push(t==112?k[r>>2]:t==105?b[r>>2]:oe[r>>3]),r+=n?8:4;}return ir},Bt=(e,r,t)=>{var n=Lt(r,t);return Qr[e](...n)},Rt=(e,r,t)=>Bt(e,r,t),kt=()=>Date.now();var Ft=()=>2147483648,Ot=e=>{var r=S.buffer,t=(e-r.byteLength+65535)/65536;try{return S.grow(t),K(),1}catch{}},xt=e=>{var r=j.length;e>>>=0;var t=Ft();if(e>t)return !1;for(var n=(v,E)=>v+(E-v%E)%E,a=1;a<=4;a*=2){var i=r*(1+.2/a);i=Math.min(i,e+100663296);var u=Math.min(t,n(Math.max(e,i),65536)),l=Ot(u);if(l)return !0}return !1},sr={},Ut=()=>I,Ce=()=>{if(!Ce.strings){var e=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",r={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:e,_:Ut()};for(var t in sr)sr[t]===void 0?delete r[t]:r[t]=sr[t];var n=[];for(var t in r)n.push(`${t}=${r[t]}`);Ce.strings=n;}return Ce.strings},Nt=(e,r)=>{for(var t=0;t{var t=0;return Ce().forEach((n,a)=>{var i=r+t;k[e+a*4>>2]=i,Nt(n,i),t+=n.length+1;}),0},Kt=(e,r)=>{var t=Ce();k[e>>2]=t.length;var n=0;return t.forEach(a=>n+=a.length+1),k[r>>2]=n,0},Zt=e=>{(P=!0),Q(e,new qr(e));},Yt=(e,r)=>{Zt(e);},zt=Yt;function jt(e){try{var r=U.getStreamFromFD(e);return o.close(r),0}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return t.errno}}var Pt=(e,r,t,n)=>{for(var a=0,i=0;i>2],l=k[r+4>>2];r+=8;var v=o.read(e,w,u,l,n);if(v<0)return -1;if(a+=v,v>2]=i,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}function St(e,r,t,n,a){var i=ar(r,t);try{if(isNaN(i))return 61;var u=U.getStreamFromFD(e);return o.llseek(u,i,n),$=[u.position>>>0,(R=u.position,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[a>>2]=$[0],b[a+4>>2]=$[1],u.getdents&&i===0&&n===0&&(u.getdents=null),0}catch(l){if(typeof o>"u"||l.name!=="ErrnoError")throw l;return l.errno}}var Ht=(e,r,t,n)=>{for(var a=0,i=0;i>2],l=k[r+4>>2];r+=8;var v=o.write(e,w,u,l,n);if(v<0)return -1;a+=v;}return a};function Tt(e,r,t,n){try{var a=U.getStreamFromFD(e),i=Ht(a,r,t);return k[n>>2]=i,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}o.createPreloadedFile=st,o.staticInit();var Qt={a:Ar,k:pt,h:lt,y:ct,z:dt,w:ft,d:vt,r:mt,s:_t,x:gt,t:ht,l:wt,i:bt,j:Et,m:Mt,n:Dt,p:Xt,A:Rt,b:kt,q:xt,u:Vt,v:Kt,e:zt,c:jt,f:Jt,o:St,g:Tt},N=Tr();s._webidl_free=e=>(s._webidl_free=N.D)(e);s._free=e=>(s._free=N.E)(e);s._webidl_malloc=e=>(s._webidl_malloc=N.F)(e);s._malloc=e=>(s._malloc=N.G)(e);var yr=s._emscripten_bind_VoidPtr___destroy___0=e=>(yr=s._emscripten_bind_VoidPtr___destroy___0=N.H)(e),br=s._emscripten_bind_Graphviz_Graphviz_2=(e,r)=>(br=s._emscripten_bind_Graphviz_Graphviz_2=N.I)(e,r),Er=s._emscripten_bind_Graphviz_version_0=()=>(Er=s._emscripten_bind_Graphviz_version_0=N.J)(),Mr=s._emscripten_bind_Graphviz_lastError_0=()=>(Mr=s._emscripten_bind_Graphviz_lastError_0=N.K)(),Dr=s._emscripten_bind_Graphviz_createFile_2=(e,r,t)=>(Dr=s._emscripten_bind_Graphviz_createFile_2=N.L)(e,r,t),Xr=s._emscripten_bind_Graphviz_layout_3=(e,r,t,n)=>(Xr=s._emscripten_bind_Graphviz_layout_3=N.M)(e,r,t,n),Lr=s._emscripten_bind_Graphviz_acyclic_3=(e,r,t,n)=>(Lr=s._emscripten_bind_Graphviz_acyclic_3=N.N)(e,r,t,n),Br=s._emscripten_bind_Graphviz_tred_3=(e,r,t,n)=>(Br=s._emscripten_bind_Graphviz_tred_3=N.O)(e,r,t,n),Rr=s._emscripten_bind_Graphviz_unflatten_4=(e,r,t,n,a)=>(Rr=s._emscripten_bind_Graphviz_unflatten_4=N.P)(e,r,t,n,a),kr=s._emscripten_bind_Graphviz_get_layout_result_0=e=>(kr=s._emscripten_bind_Graphviz_get_layout_result_0=N.Q)(e),Gr=s._emscripten_bind_Graphviz_set_layout_result_1=(e,r)=>(Gr=s._emscripten_bind_Graphviz_set_layout_result_1=N.R)(e,r),Fr=s._emscripten_bind_Graphviz_get_acyclic_outFile_0=e=>(Fr=s._emscripten_bind_Graphviz_get_acyclic_outFile_0=N.S)(e),Or=s._emscripten_bind_Graphviz_set_acyclic_outFile_1=(e,r)=>(Or=s._emscripten_bind_Graphviz_set_acyclic_outFile_1=N.T)(e,r),xr=s._emscripten_bind_Graphviz_get_acyclic_num_rev_0=e=>(xr=s._emscripten_bind_Graphviz_get_acyclic_num_rev_0=N.U)(e),Ur=s._emscripten_bind_Graphviz_set_acyclic_num_rev_1=(e,r)=>(Ur=s._emscripten_bind_Graphviz_set_acyclic_num_rev_1=N.V)(e,r),Nr=s._emscripten_bind_Graphviz_get_tred_out_0=e=>(Nr=s._emscripten_bind_Graphviz_get_tred_out_0=N.W)(e),Vr=s._emscripten_bind_Graphviz_set_tred_out_1=(e,r)=>(Vr=s._emscripten_bind_Graphviz_set_tred_out_1=N.X)(e,r),Kr=s._emscripten_bind_Graphviz_get_tred_err_0=e=>(Kr=s._emscripten_bind_Graphviz_get_tred_err_0=N.Y)(e),Cr=s._emscripten_bind_Graphviz_set_tred_err_1=(e,r)=>(Cr=s._emscripten_bind_Graphviz_set_tred_err_1=N.Z)(e,r),Ir=s._emscripten_bind_Graphviz___destroy___0=e=>(Ir=s._emscripten_bind_Graphviz___destroy___0=N._)(e),Zr=(e,r)=>(Zr=N.aa)(e,r),Yr=e=>(Yr=N.ba)(e);s.UTF8ToString=ue;var He;be=function e(){He||zr(),He||(be=e);};function zr(){if(ye>0||(Re(),ye>0))return;function e(){He||(He=!0,s.calledRun=!0,!P&&(Ne(),f(s),Pe()));}e();}zr();function pe(){}pe.prototype=Object.create(pe.prototype),pe.prototype.constructor=pe,pe.prototype.__class__=pe,pe.__cache__={},s.WrapperObject=pe;function Te(e){return (e||pe).__cache__}s.getCache=Te;function ur(e,r){var t=Te(r),n=t[e];return n||(n=Object.create((r||pe).prototype),n.ptr=e,t[e]=n)}s.wrapPointer=ur;function ro(e,r){return ur(e.ptr,r)}s.castObject=ro,s.NULL=ur(0);function to(e){if(!e.__destroy__)throw "Error: Cannot destroy object. (Did you create it yourself?)";e.__destroy__(),delete Te(e.__class__)[e.ptr];}s.destroy=to;function oo(e,r){return e.ptr===r.ptr}s.compare=oo;function no(e){return e.ptr}s.getPointer=no;function ao(e){return e.__class__}s.getClass=ao;var F={buffer:0,size:0,pos:0,temps:[],needed:0,prepare(){if(F.needed){for(var e=0;e=F.size?(J(n>0),F.needed+=n,a=s._webidl_malloc(n),F.temps.push(a)):(a=F.buffer+F.pos,F.pos+=n),a},copy(e,r,t){t/=r.BYTES_PER_ELEMENT;for(var n=0;n?@[]^_`{|}~"';function Lo(p){let c=p.length,d=[],s=0,f=0,m=-1;for(let _=0;_88?13:14;do d.push(s&255),s>>=8,f-=8;while(f>7);m=-1;}}return m>-1&&d.push((s|m< + +`}}function Fo(p){return p.map(Go)}function Oo(p,c){let d={images:[],files:[],...c};[...d.files,...Fo(d.images)].forEach(s=>p.createFile(s.path,s.data));}var xo=class Ue{constructor(c){this._module=c;}static load(){return Ro().then(c=>new Ue(c))}static unload(){ko();}version(){return this._module.Graphviz.prototype.version()}layout(c,d="svg",s="dot",f){if(!c)return "";let m=new this._module.Graphviz(f?.yInvert?1:0,f?.nop?f?.nop:0),_="",h="";try{Oo(m,f);try{_=m.layout(c,d,s);}catch(M){h=M.message;}h=m.lastError()||h;}finally{this._module.destroy(m);}if(!_&&h)throw Ue.unload(),new Error(h);return _}acyclic(c,d=!1,s=!1){if(!c)return {acyclic:!1,num_rev:0,outFile:""};let f=new this._module.Graphviz,m=!1,_=0,h="",M="";try{try{m=f.acyclic(c,d,s),_=f.acyclic_num_rev,h=f.acyclic_outFile;}catch(I){M=I.message;}M=f.lastError()||M;}finally{this._module.destroy(f);}if(M)throw Ue.unload(),new Error(M);return {acyclic:m,num_rev:_,outFile:h}}tred(c,d=!1,s=!1){if(!c)return {out:"",err:""};let f=new this._module.Graphviz,m="",_="",h="";try{try{f.tred(c,d,s),m=f.tred_out,_=f.tred_err;}catch(M){h=M.message;}h=f.lastError()||h;}finally{this._module.destroy(f);}if(!m&&h)throw Ue.unload(),new Error(h);return {out:m,err:_}}unflatten(c,d=0,s=!1,f=0){if(!c)return "";let m=new this._module.Graphviz,_="",h="";try{try{_=m.unflatten(c,d,s,f);}catch(M){h=M.message;}h=m.lastError()||h;}finally{this._module.destroy(m);}if(!_&&h)throw Ue.unload(),new Error(h);return _}circo(c,d="svg",s){return this.layout(c,d,"circo",s)}dot(c,d="svg",s){return this.layout(c,d,"dot",s)}fdp(c,d="svg",s){return this.layout(c,d,"fdp",s)}sfdp(c,d="svg",s){return this.layout(c,d,"sfdp",s)}neato(c,d="svg",s){return this.layout(c,d,"neato",s)}osage(c,d="svg",s){return this.layout(c,d,"osage",s)}patchwork(c,d="svg",s){return this.layout(c,d,"patchwork",s)}twopi(c,d="svg",s){return this.layout(c,d,"twopi",s)}nop(c){return this.layout(c,"dot","nop")}nop2(c){return this.layout(c,"dot","nop2")}}; + + function shallowCopyObject(obj) { + return Object.assign({}, obj); + } + function roundTo2Decimals(x) { + return Math.round(x * 100.0) / 100.0; + } + + function convertToPathData(originalData, guideData) { + if (originalData.tag == 'polygon') { + var newData = shallowCopyObject(originalData); + newData.tag = 'path'; + var originalAttributes = originalData.attributes; + var newAttributes = shallowCopyObject(originalAttributes); + var newPointsString = originalAttributes.points; + if (guideData.tag == 'polygon') { + var bbox = originalData.bbox; + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + var pointsString = originalAttributes.points; + var pointStrings = pointsString.split(' '); + var normPoints = pointStrings.map(function (p) { + var xy = p.split(','); + return [xy[0] - bbox.cx, xy[1] - bbox.cy]; + }); + var x0 = normPoints[normPoints.length - 1][0]; + var y0 = normPoints[normPoints.length - 1][1]; + for (var i = 0; i < normPoints.length; i++, x0 = x1, y0 = y1) { + var x1 = normPoints[i][0]; + var y1 = normPoints[i][1]; + var dx = x1 - x0; + var dy = y1 - y0; + if (dy == 0) { + continue; + } else { + var x2 = x0 - y0 * dx / dy; + } + if (0 <= x2 && x2 < Infinity && (x0 <= x2 && x2 <= x1 || x1 <= x2 && x2 <= x0)) { + break; + } + } + var newPointStrings = [[bbox.cx + x2, bbox.cy + 0].join(',')]; + newPointStrings = newPointStrings.concat(pointStrings.slice(i)); + newPointStrings = newPointStrings.concat(pointStrings.slice(0, i)); + newPointsString = newPointStrings.join(' '); + } + newAttributes['d'] = 'M' + newPointsString + 'z'; + delete newAttributes.points; + newData.attributes = newAttributes; + } else /* if (originalData.tag == 'ellipse') */{ + var newData = shallowCopyObject(originalData); + newData.tag = 'path'; + var originalAttributes = originalData.attributes; + var newAttributes = shallowCopyObject(originalAttributes); + var cx = originalAttributes.cx; + var cy = originalAttributes.cy; + var rx = originalAttributes.rx; + var ry = originalAttributes.ry; + if (guideData.tag == 'polygon') { + var bbox = guideData.bbox; + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + var p = guideData.attributes.points.split(' ')[0].split(','); + var sx = p[0]; + var sy = p[1]; + var dx = sx - bbox.cx; + var dy = sy - bbox.cy; + var l = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + var cosA = dx / l; + var sinA = -dy / l; + } else { + // if (guideData.tag == 'path') { + // FIXME: add support for getting start position from path + var cosA = 1; + var sinA = 0; + } + var x1 = rx * cosA; + var y1 = -ry * sinA; + var x2 = rx * -cosA; + var y2 = -ry * -sinA; + var dx = x2 - x1; + var dy = y2 - y1; + newAttributes['d'] = 'M ' + cx + ' ' + cy + ' m ' + x1 + ',' + y1 + ' a ' + rx + ',' + ry + ' 0 1,0 ' + dx + ',' + dy + ' a ' + rx + ',' + ry + ' 0 1,0 ' + -dx + ',' + -dy + 'z'; + delete newAttributes.cx; + delete newAttributes.cy; + delete newAttributes.rx; + delete newAttributes.ry; + newData.attributes = newAttributes; + } + return newData; + } + function translatePointsAttribute(pointsString, x, y) { + var pointStrings = pointsString.split(' '); + var points = pointStrings.map(function (p) { + return p.split(','); + }); + var points = pointStrings.map(function (p) { + return [roundTo2Decimals(+x + +p.split(',')[0]), roundTo2Decimals(+y + +p.split(',')[1])]; + }); + var pointStrings = points.map(function (p) { + return p.join(','); + }); + var pointsString = pointStrings.join(' '); + return pointsString; + } + function translateDAttribute(d, x, y) { + var pointStrings = d.split(/[A-Z ]/); + pointStrings.shift(); + var commands = d.split(/[^[A-Z ]+/); + var points = pointStrings.map(function (p) { + return p.split(','); + }); + var points = pointStrings.map(function (p) { + return [roundTo2Decimals(+x + +p.split(',')[0]), roundTo2Decimals(+y + +p.split(',')[1])]; + }); + var pointStrings = points.map(function (p) { + return p.join(','); + }); + d = commands.reduce(function (arr, v, i) { + return arr.concat(v, pointStrings[i]); + }, []).join(''); + return d; + } + + function initViz() { + var _this = this; + // force JIT compilation of @hpcc-js/wasm + try { + xo.load().then(function (graphviz) { + graphviz.layout("", "svg", "dot"); + _this.layoutSync = graphviz.layout.bind(graphviz); + if (_this._worker == null) { + _this._dispatch.call("initEnd", _this); + } + if (_this._afterInit) { + _this._afterInit(); + } + }); + // after the port to ESM modules, we don't know how to trigger this so + // we just disable it from coverage + /* c8 ignore start */ + } catch (error) { + // we end up here when the the script tag type used to load + // the "@hpcc-js/wasm" script is not "application/javascript" + // or "text/javascript", but typically "javascript/worker". In + // this case the browser does not load the script since it's + // unnecessary because it's loaded by the web worker + // instead. This is expected so we just ignore the error. + } + /* c8 ignore stop */ + if (this._worker != null) { + var vizURL = this._vizURL; + var graphvizInstance = this; + this._workerPort.onmessage = function (event) { + var callback = graphvizInstance._workerCallbacks.shift(); + callback.call(graphvizInstance, event); + }; + if (!vizURL.match(/^https?:\/\/|^\/\//i)) { + // Local URL. Prepend with local domain to be usable in web worker + vizURL = new window.URL(vizURL, document.location.href).href; + } + postMessage.call(this, { + type: "layout", + dot: "", + engine: 'dot', + vizURL: vizURL + }, function (event) { + switch (event.data.type) { + } + }); + postMessage.call(this, { + type: "version" + }, function (event) { + switch (event.data.type) { + case "version": + graphvizInstance._graphvizVersion = event.data.version; + graphvizInstance._dispatch.call("initEnd", this); + break; + } + }); + } + } + function postMessage(message, callback) { + this._workerCallbacks.push(callback); + this._workerPort.postMessage(message); + } + function layout(src, engine, vizOptions, callback) { + if (this._worker) { + postMessage.call(this, { + type: "layout", + dot: src, + engine: engine, + options: vizOptions + }, function (event) { + callback.call(this, event.data); + }); + } else { + try { + var svgDoc = this.layoutSync(src, "svg", engine, vizOptions); + callback.call(this, { + type: 'done', + svg: svgDoc + }); + } catch (error) { + callback.call(this, { + type: 'error', + error: error.message + }); + } + } + } + function dot (src, callback) { + var graphvizInstance = this; + this._worker; + var engine = this._options.engine; + var images = this._images; + this._dispatch.call("start", this); + this._busy = true; + this._dispatch.call("layoutStart", this); + var vizOptions = { + images: images + }; + if (!this._worker && this.layoutSync == null) { + this._afterInit = this.dot.bind(this, src, callback); + return this; + } + this.layout(src, engine, vizOptions, function (data) { + switch (data.type) { + case "error": + if (graphvizInstance._onerror) { + graphvizInstance._onerror(data.error); + } else { + throw data.error.message; + } + break; + case "done": + var svgDoc = data.svg; + layoutDone.call(this, svgDoc, callback); + break; + } + }); + return this; + } + function layoutDone(svgDoc, callback) { + var keyMode = this._options.keyMode; + var tweenPaths = this._options.tweenPaths; + var tweenShapes = this._options.tweenShapes; + if (typeof this._options.tweenPrecision == 'string' && this._options.tweenPrecision.includes('%')) { + var tweenPrecision = +this._options.tweenPrecision.split('%')[0] / 100; + var tweenPrecisionIsRelative = this._options.tweenPrecision.includes('%'); + } else { + var tweenPrecision = this._options.tweenPrecision; + var tweenPrecisionIsRelative = false; + } + var growEnteringEdges = this._options.growEnteringEdges; + var dictionary = {}; + var prevDictionary = this._dictionary || {}; + var nodeDictionary = {}; + var prevNodeDictionary = this._nodeDictionary || {}; + function setKey(datum, index) { + var tag = datum.tag; + if (keyMode == 'index') { + datum.key = index; + } else if (tag[0] != '#') { + if (keyMode == 'id') { + datum.key = datum.attributes.id; + } else if (keyMode == 'title') { + var title = datum.children.find(function (childData) { + return childData.tag == 'title'; + }); + if (title) { + if (title.children.length > 0) { + datum.key = title.children[0].text; + } else { + datum.key = ''; + } + } + } + } + if (datum.key == null) { + if (tweenShapes) { + if (tag == 'ellipse' || tag == 'polygon') { + tag = 'path'; + } + } + datum.key = tag + '-' + index; + } + } + function setId(datum, parentData) { + var id = (parentData ? parentData.id + '.' : '') + datum.key; + datum.id = id; + } + function addToDictionary(datum) { + dictionary[datum.id] = datum; + } + function calculateAlternativeShapeData(datum, prevDatum) { + if (tweenShapes && datum.id in prevDictionary) { + if ((prevDatum.tag == 'polygon' || prevDatum.tag == 'ellipse' || prevDatum.tag == 'path') && (prevDatum.tag != datum.tag || datum.tag == 'polygon')) { + if (prevDatum.tag != 'path') { + datum.alternativeOld = convertToPathData(prevDatum, datum); + } + if (datum.tag != 'path') { + datum.alternativeNew = convertToPathData(datum, prevDatum); + } + } + } + } + function calculatePathTweenPoints(datum, prevDatum) { + if (tweenPaths && prevDatum && (prevDatum.tag == 'path' || datum.alternativeOld && datum.alternativeOld.tag == 'path')) { + var attribute_d = (datum.alternativeNew || datum).attributes.d; + if (datum.alternativeOld) { + var oldNode = createElementWithAttributes(datum.alternativeOld); + } else { + var oldNode = createElementWithAttributes(prevDatum); + } + (datum.alternativeOld || (datum.alternativeOld = {})).points = pathTweenPoints(oldNode, attribute_d, tweenPrecision, tweenPrecisionIsRelative); + } + } + function postProcessDataPass1Local(datum) { + var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var parentData = arguments.length > 2 ? arguments[2] : undefined; + setKey(datum, index); + setId(datum, parentData); + var id = datum.id; + var prevDatum = prevDictionary[id]; + addToDictionary(datum); + calculateAlternativeShapeData(datum, prevDatum); + calculatePathTweenPoints(datum, prevDatum); + var childTagIndexes = {}; + datum.children.forEach(function (childData) { + var childTag = childData.tag; + if (childTag == 'ellipse' || childTag == 'polygon') { + childTag = 'path'; + } + if (childTagIndexes[childTag] == null) { + childTagIndexes[childTag] = 0; + } + var childIndex = childTagIndexes[childTag]++; + postProcessDataPass1Local(childData, childIndex, datum); + }); + } + function addToNodeDictionary(datum) { + var tag = datum.tag; + if (growEnteringEdges && datum.parent) { + if (datum.parent.attributes["class"] == 'node') { + if (tag == 'title') { + if (datum.children.length > 0) { + var child = datum.children[0]; + var nodeId = child.text; + } else { + var nodeId = ''; + } + nodeDictionary[nodeId] = datum.parent; + } + } + } + } + function extractGrowingEdgesData(datum) { + var id = datum.id; + var tag = datum.tag; + var prevDatum = prevDictionary[id]; + if (growEnteringEdges && !prevDatum && datum.parent) { + if (isEdgeElement(datum)) { + if (tag == 'path' || tag == 'polygon') { + if (tag == 'polygon') { + var path = datum.parent.children.find(function (e) { + return e.tag == 'path'; + }); + if (path) { + datum.totalLength = path.totalLength; + } + } + var title = getEdgeTitle(datum); + var child = title.children[0]; + var nodeIds = child.text.split('->'); + if (nodeIds.length != 2) { + nodeIds = child.text.split('--'); + } + var startNodeId = nodeIds[0]; + var startNode = nodeDictionary[startNodeId]; + if (Object.hasOwn(prevNodeDictionary, startNodeId)) { + var prevStartNode = prevNodeDictionary[startNodeId]; + var i = startNode.children.findIndex(function (element, index) { + return element.tag == 'g'; + }); + if (i >= 0) { + var j = startNode.children[i].children.findIndex(function (element, index) { + return element.tag == 'a'; + }); + startNode = startNode.children[i].children[j]; + } + var i = prevStartNode.children.findIndex(function (element, index) { + return element.tag == 'g'; + }); + if (i >= 0) { + var j = prevStartNode.children[i].children.findIndex(function (element, index) { + return element.tag == 'a'; + }); + prevStartNode = prevStartNode.children[i].children[j]; + } + var startShapes = startNode.children; + for (var i = 0; i < startShapes.length; i++) { + if (startShapes[i].tag == 'polygon' || startShapes[i].tag == 'ellipse' || startShapes[i].tag == 'path' || startShapes[i].tag == 'text') { + var startShape = startShapes[i]; + break; + } + } + var prevStartShapes = prevStartNode.children; + for (var i = 0; i < prevStartShapes.length; i++) { + if (prevStartShapes[i].tag == 'polygon' || prevStartShapes[i].tag == 'ellipse' || prevStartShapes[i].tag == 'path' || prevStartShapes[i].tag == 'text') { + var prevStartShape = prevStartShapes[i]; + break; + } + } + if (prevStartShape && startShape) { + datum.offset = { + x: prevStartShape.center.x - startShape.center.x, + y: prevStartShape.center.y - startShape.center.y + }; + } else { + datum.offset = { + x: 0, + y: 0 + }; + } + } + } + } + } + } + function postProcessDataPass2Global(datum) { + addToNodeDictionary(datum); + extractGrowingEdgesData(datum); + datum.children.forEach(function (childData) { + postProcessDataPass2Global(childData); + }); + } + this._dispatch.call("layoutEnd", this); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append('div'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + newDoc.append(function () { + return doc.documentElement; + }); + var newSvg = newDoc.select('svg'); + var data = extractAllElementsData(newSvg); + this._dispatch.call('dataExtractEnd', this); + postProcessDataPass1Local(data); + this._dispatch.call('dataProcessPass1End', this); + postProcessDataPass2Global(data); + this._dispatch.call('dataProcessPass2End', this); + this._data = data; + this._dictionary = dictionary; + this._nodeDictionary = nodeDictionary; + this._extractData = function (element, childIndex, parentData) { + var data = extractAllElementsData(element); + postProcessDataPass1Local(data, childIndex, parentData); + postProcessDataPass2Global(data); + return data; + }; + this._busy = false; + this._dispatch.call('dataProcessEnd', this); + if (callback) { + callback.call(this); + } + if (this._queue.length > 0) { + var job = this._queue.shift(); + job.call(this); + } + } + + function renderDot (src, callback) { + var graphvizInstance = this; + this.dot(src, render); + function render() { + graphvizInstance.render(callback); + } + return this; + } + + function transition (name) { + if (name instanceof Function) { + this._transitionFactory = name; + } else { + this._transition = d3Transition.transition(name); + } + return this; + } + function active(name) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + if (svg.size() != 0) { + return d3Transition.active(svg.node(), name); + } else { + return null; + } + } + + function options (options) { + if (typeof options == 'undefined') { + return Object.assign({}, this._options); + } else { + for (var _i = 0, _Object$keys = Object.keys(options); _i < _Object$keys.length; _i++) { + var option = _Object$keys[_i]; + this._options[option] = options[option]; + } + return this; + } + } + + function width (width) { + this._options.width = width; + return this; + } + + function height (height) { + this._options.height = height; + return this; + } + + function scale (scale) { + this._options.scale = scale; + return this; + } + + function fit (fit) { + this._options.fit = fit; + return this; + } + + function attributer (callback) { + this._attributer = callback; + return this; + } + + function engine (engine) { + this._options.engine = engine; + return this; + } + + function images (path, width, height) { + this._images.push({ + path: path, + width: width, + height: height + }); + return this; + } + + function keyMode (keyMode) { + if (!this._keyModes.has(keyMode)) { + throw Error('Illegal keyMode: ' + keyMode); + } + if (keyMode != this._options.keyMode && this._data != null) { + throw Error('Too late to change keyMode'); + } + this._options.keyMode = keyMode; + return this; + } + + function fade (enable) { + this._options.fade = enable; + return this; + } + + function tweenPaths (enable) { + this._options.tweenPaths = enable; + return this; + } + + function tweenShapes (enable) { + this._options.tweenShapes = enable; + if (enable) { + this._options.tweenPaths = true; + } + return this; + } + + function convertEqualSidedPolygons (enable) { + this._options.convertEqualSidedPolygons = enable; + return this; + } + + function tweenPrecision (precision) { + this._options.tweenPrecision = precision; + return this; + } + + function growEnteringEdges (enable) { + this._options.growEnteringEdges = enable; + return this; + } + + function on (typenames, callback) { + this._dispatch.on(typenames, callback); + return this; + } + + function onerror (callback) { + this._onerror = callback; + return this; + } + + function logEvents (enable) { + var _this = this; + var t0 = Date.now(); + var times = {}; + var eventTypes = this._eventTypes; + var maxEventTypeLength = Math.max.apply(Math, _toConsumableArray(eventTypes.map(function (eventType) { + return eventType.length; + }))); + var _loop = function _loop(i) { + var eventType = eventTypes[i]; + times[eventType] = []; + graphvizInstance = _this; + _this.on(eventType + '.log', enable ? function () { + var t = Date.now(); + var seqNo = times[eventType].length; + times[eventType].push(t); + var string = ''; + string += 'Event '; + string += d3Format.format(' >2')(i) + ' '; + string += eventType + ' '.repeat(maxEventTypeLength - eventType.length); + string += d3Format.format(' >5')(t - t0) + ' '; + if (eventType != 'initEnd') { + string += d3Format.format(' >5')(t - times['start'][seqNo]); + } + if (eventType == 'dataProcessEnd') { + string += ' prepare ' + d3Format.format(' >5')(t - times['layoutEnd'][seqNo]); + } + if (eventType == 'renderEnd' && graphvizInstance._transition) { + string += ' transition start margin ' + d3Format.format(' >5')(graphvizInstance._transition.delay() - (t - times['renderStart'][seqNo])); + expectedDelay = graphvizInstance._transition.delay(); + expectedDuration = graphvizInstance._transition.duration(); + } + if (eventType == 'transitionStart') { + var actualDelay = t - times['renderStart'][seqNo]; + string += ' transition delay ' + d3Format.format(' >5')(t - times['renderStart'][seqNo]); + string += ' expected ' + d3Format.format(' >5')(expectedDelay); + string += ' diff ' + d3Format.format(' >5')(actualDelay - expectedDelay); + } + if (eventType == 'transitionEnd') { + var actualDuration = t - times['transitionStart'][seqNo]; + string += ' transition duration ' + d3Format.format(' >5')(actualDuration); + string += ' expected ' + d3Format.format(' >5')(expectedDuration); + string += ' diff ' + d3Format.format(' >5')(actualDuration - expectedDuration); + } + console.log(string); + t0 = t; + } : null); + }, + graphvizInstance, + expectedDelay, + expectedDuration; + for (var i = 0; i < eventTypes.length; i++) { + _loop(i); + } + return this; + } + + function destroy () { + delete this._selection.node().__graphviz__; + if (this._worker) { + this._workerPortClose(); + } + return this; + } + + function rotate(x, y, cosA, sinA) { + // (x + j * y) * (cosA + j * sinA) = x * cosA - y * sinA + j * (x * sinA + y * cosA) + y = -y; + sinA = -sinA; + var _ref = [x * cosA - y * sinA, x * sinA + y * cosA]; + x = _ref[0]; + y = _ref[1]; + y = -y; + return [x, y]; + } + + function drawEdge(x1, y1, x2, y2, attributes) { + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + attributes = Object.assign({}, attributes); + if (attributes.style && attributes.style.includes('invis')) { + var newEdge = d3__namespace.select(null); + } else { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var newEdge0 = createEdge.call(this, attributes); + var edgeData = extractAllElementsData(newEdge0); + var newEdge = graph0.append('g').data([edgeData]); + attributeElement.call(newEdge.node(), edgeData); + _updateEdge.call(this, newEdge, x1, y1, x2, y2, attributes, options); + } + this._drawnEdge = { + g: newEdge, + x1: x1, + y1: y1, + x2: x2, + y2: y2, + attributes: attributes + }; + return this; + } + function updateDrawnEdge(x1, y1, x2, y2) { + var attributes = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + var options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + attributes = Object.assign(this._drawnEdge.attributes, attributes); + this._drawnEdge.x1 = x1; + this._drawnEdge.y1 = y1; + this._drawnEdge.x2 = x2; + this._drawnEdge.y2 = y2; + if (edge.empty() && !(attributes.style && attributes.style.includes('invis'))) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var edge = graph0.append('g'); + this._drawnEdge.g = edge; + } + if (!edge.empty()) { + _updateEdge.call(this, edge, x1, y1, x2, y2, attributes, options); + } + return this; + } + function _updateEdge(edge, x1, y1, x2, y2, attributes, options) { + var newEdge = createEdge.call(this, attributes); + var edgeData = extractAllElementsData(newEdge); + edge.data([edgeData]); + attributeElement.call(edge.node(), edgeData); + _moveEdge(edge, x1, y1, x2, y2, attributes, options); + } + function _moveEdge(edge, x1, y1, x2, y2, attributes, options) { + var shortening = options.shortening || 0; + var arrowHeadLength = 10; + var arrowHeadWidth = 7; + var margin = 0.1; + var arrowHeadPoints = [[0, -arrowHeadWidth / 2], [arrowHeadLength, 0], [0, arrowHeadWidth / 2], [0, -arrowHeadWidth / 2]]; + var dx = x2 - x1; + var dy = y2 - y1; + var length = Math.sqrt(dx * dx + dy * dy); + if (length == 0) { + var cosA = 1; + var sinA = 0; + } else { + var cosA = dx / length; + var sinA = dy / length; + } + x2 = x1 + (length - shortening - arrowHeadLength - margin) * cosA; + y2 = y1 + (length - shortening - arrowHeadLength - margin) * sinA; + if (attributes.URL || attributes.tooltip) { + var a = edge.selectWithoutDataPropagation("g").selectWithoutDataPropagation("a"); + var line = a.selectWithoutDataPropagation("path"); + var arrowHead = a.selectWithoutDataPropagation("polygon"); + } else { + var line = edge.selectWithoutDataPropagation("path"); + var arrowHead = edge.selectWithoutDataPropagation("polygon"); + } + var path1 = d3Path.path(); + path1.moveTo(x1, y1); + path1.lineTo(x2, y2); + line.attr("d", path1); + x2 = x1 + (length - shortening - arrowHeadLength) * cosA; + y2 = y1 + (length - shortening - arrowHeadLength) * sinA; + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + arrowHeadPoints[i] = rotate(point[0], point[1], cosA, sinA); + } + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + arrowHeadPoints[i] = [x2 + point[0], y2 + point[1]]; + } + var allPoints = []; + for (var i = 0; i < arrowHeadPoints.length; i++) { + var point = arrowHeadPoints[i]; + allPoints.push(point.join(',')); + } + var pointsAttr = allPoints.join(' '); + arrowHead.attr("points", pointsAttr); + return this; + } + function moveDrawnEdgeEndPoint(x2, y2) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + var x1 = this._drawnEdge.x1; + var y1 = this._drawnEdge.y1; + var attributes = this._drawnEdge.attributes; + this._drawnEdge.x2 = x2; + this._drawnEdge.y2 = y2; + _moveEdge(edge, x1, y1, x2, y2, attributes, options); + return this; + } + function removeDrawnEdge() { + if (!this._drawnEdge) { + return this; + } + var edge = this._drawnEdge.g; + edge.remove(); + this._drawnEdge = null; + return this; + } + function insertDrawnEdge(name) { + if (!this._drawnEdge) { + throw Error('No edge has been drawn'); + } + var edge = this._drawnEdge.g; + if (edge.empty()) { + return this; + } + this._drawnEdge.attributes; + var title = edge.selectWithoutDataPropagation("title"); + title.text(name); + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var graph0Datum = graph0.datum(); + var edgeData = this._extractData(edge, graph0Datum.children.length, graph0.datum()); + graph0Datum.children.push(edgeData); + insertAllElementsData(edge, edgeData); + this._drawnEdge = null; + return this; + } + function drawnEdgeSelection() { + if (this._drawnEdge) { + return this._drawnEdge.g; + } else { + return d3__namespace.select(null); + } + } + function createEdge(attributes) { + var attributesString = ''; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var name = _Object$keys[_i]; + if (attributes[name] != null) { + attributesString += ' "' + name + '"="' + attributes[name] + '"'; + } + } + var dotSrc = 'digraph {a -> b [' + attributesString + ']}'; + var svgDoc = this.layoutSync(dotSrc, 'svg', 'dot'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append(function () { + return doc.documentElement; + }); + var edge = newDoc.select('.edge'); + return edge; + } + + function drawNode(x, y, nodeId) { + var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + attributes = Object.assign({}, attributes); + if (attributes.style && attributes.style.includes('invis')) { + var newNode = d3__namespace.select(null); + } else { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var newNode0 = createNode.call(this, nodeId, attributes); + var nodeData = extractAllElementsData(newNode0); + var newNode = graph0.append('g').data([nodeData]); + attributeElement.call(newNode.node(), nodeData); + _updateNode.call(this, newNode, x, y, nodeId, attributes, options); + } + this._drawnNode = { + g: newNode, + nodeId: nodeId, + x: x, + y: y, + attributes: attributes + }; + return this; + } + function updateDrawnNode(x, y, nodeId) { + var attributes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + var node = this._drawnNode.g; + if (nodeId == null) { + nodeId = this._drawnNode.nodeId; + } + attributes = Object.assign(this._drawnNode.attributes, attributes); + this._drawnNode.nodeId = nodeId; + this._drawnNode.x = x; + this._drawnNode.y = y; + if (node.empty() && !(attributes.style && attributes.style.includes('invis'))) { + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var node = graph0.append('g'); + this._drawnNode.g = node; + } + if (!node.empty()) { + _updateNode.call(this, node, x, y, nodeId, attributes, options); + } + return this; + } + function _updateNode(node, x, y, nodeId, attributes, options) { + var newNode = createNode.call(this, nodeId, attributes); + var nodeData = extractAllElementsData(newNode); + node.data([nodeData]); + attributeElement.call(node.node(), nodeData); + _moveNode(node, x, y, attributes); + return this; + } + function _moveNode(node, x, y, attributes, options) { + if (attributes.URL || attributes.tooltip) { + var subParent = node.selectWithoutDataPropagation("g").selectWithoutDataPropagation("a"); + } else { + var subParent = node; + } + var svgElements = subParent.selectAll('ellipse,polygon,path,polyline'); + var text = node.selectWithoutDataPropagation("text"); + if (svgElements.size() != 0) { + var bbox = svgElements.node().getBBox(); + bbox.cx = bbox.x + bbox.width / 2; + bbox.cy = bbox.y + bbox.height / 2; + } else if (text.size() != 0) { + bbox = { + x: +text.attr('x'), + y: +text.attr('y'), + width: 0, + height: 0, + cx: +text.attr('x'), + cy: +text.attr('y') + }; + } + svgElements.each(function (data, index) { + var svgElement = d3__namespace.select(this); + if (svgElement.attr("cx")) { + svgElement.attr("cx", roundTo2Decimals(x)).attr("cy", roundTo2Decimals(y)); + } else if (svgElement.attr("points")) { + var pointsString = svgElement.attr('points').trim(); + svgElement.attr("points", translatePointsAttribute(pointsString, x - bbox.cx, y - bbox.cy)); + } else { + var d = svgElement.attr('d'); + svgElement.attr("d", translateDAttribute(d, x - bbox.cx, y - bbox.cy)); + } + }); + if (text.size() != 0) { + text.attr("x", roundTo2Decimals(+text.attr("x") + x - bbox.cx)).attr("y", roundTo2Decimals(+text.attr("y") + y - bbox.cy)); + } + return this; + } + function moveDrawnNode(x, y) { + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + var node = this._drawnNode.g; + var attributes = this._drawnNode.attributes; + this._drawnNode.x = x; + this._drawnNode.y = y; + if (!node.empty()) { + _moveNode(node, x, y, attributes); + } + return this; + } + function removeDrawnNode() { + if (!this._drawnNode) { + return this; + } + var node = this._drawnNode.g; + if (!node.empty()) { + node.remove(); + } + this._drawnNode = null; + return this; + } + function insertDrawnNode(nodeId) { + if (!this._drawnNode) { + throw Error('No node has been drawn'); + } + if (nodeId == null) { + nodeId = this._drawnNode.nodeId; + } + var node = this._drawnNode.g; + if (node.empty()) { + return this; + } + var attributes = this._drawnNode.attributes; + var title = node.selectWithoutDataPropagation("title"); + title.text(nodeId); + if (attributes.URL || attributes.tooltip) { + var ga = node.selectWithoutDataPropagation("g"); + var a = ga.selectWithoutDataPropagation("a"); + a.selectWithoutDataPropagation('ellipse,polygon,path,polyline'); + var text = a.selectWithoutDataPropagation('text'); + } else { + node.selectWithoutDataPropagation('ellipse,polygon,path,polyline'); + var text = node.selectWithoutDataPropagation('text'); + } + text.text(attributes.label || nodeId); + var root = this._selection; + var svg = root.selectWithoutDataPropagation("svg"); + var graph0 = svg.selectWithoutDataPropagation("g"); + var graph0Datum = graph0.datum(); + var nodeData = this._extractData(node, graph0Datum.children.length, graph0.datum()); + graph0Datum.children.push(nodeData); + insertAllElementsData(node, nodeData); + this._drawnNode = null; + return this; + } + function drawnNodeSelection() { + if (this._drawnNode) { + return this._drawnNode.g; + } else { + return d3__namespace.select(null); + } + } + function createNode(nodeId, attributes) { + var attributesString = ''; + for (var _i = 0, _Object$keys = Object.keys(attributes); _i < _Object$keys.length; _i++) { + var name = _Object$keys[_i]; + if (attributes[name] != null) { + attributesString += ' "' + name + '"="' + attributes[name] + '"'; + } + } + var dotSrc = 'graph {"' + nodeId + '" [' + attributesString + ']}'; + var svgDoc = this.layoutSync(dotSrc, 'svg', 'dot'); + var parser = new window.DOMParser(); + var doc = parser.parseFromString(svgDoc, "image/svg+xml"); + var newDoc = d3__namespace.select(document.createDocumentFragment()).append(function () { + return doc.documentElement; + }); + var node = newDoc.select('.node'); + return node; + } + + /* This file is excluded from coverage because the instrumented code + * translates "self" which gives a reference error. + */ + + /* c8 ignore start */ + + function workerCodeBody(port) { + self.document = {}; // Workaround for "ReferenceError: document is not defined" in hpccWasm + + port.addEventListener('message', function (event) { + var hpccWasm = self["@hpcc-js/wasm"]; + if (hpccWasm == undefined && event.data.vizURL) { + importScripts(event.data.vizURL); + hpccWasm = self["@hpcc-js/wasm"]; + // This is an alternative workaround where wasmFolder() is not needed + // document = {currentScript: {src: event.data.vizURL}}; + } + if (event.data.type == "version") { + hpccWasm.Graphviz.load().then(function (graphviz) { + port.postMessage({ + type: "version", + version: graphviz.version() + }); + }); + return; + } + hpccWasm.Graphviz.load().then(function (graphviz) { + var svg = graphviz.layout(event.data.dot, "svg", event.data.engine, event.data.options); + if (svg) { + port.postMessage({ + type: "done", + svg: svg + }); + } else if (event.data.vizURL) { + port.postMessage({ + type: "init" + }); + } else { + port.postMessage({ + type: "skip" + }); + } + })["catch"](function (error) { + port.postMessage({ + type: "error", + error: error.message + }); + }); + }); + } + function workerCode() { + var port = self; + workerCodeBody(port); + } + function sharedWorkerCode() { + self.onconnect = function (e) { + var port = e.ports[0]; + workerCodeBody(port); + port.start(); + }; + } + + /* c8 ignore stop */ + + var _graphviz$prototype; + function Graphviz(selection, options) { + var _this = this; + this._options = { + useWorker: true, + useSharedWorker: false, + engine: 'dot', + keyMode: 'title', + fade: true, + tweenPaths: true, + tweenShapes: true, + convertEqualSidedPolygons: true, + tweenPrecision: 1, + growEnteringEdges: true, + zoom: true, + zoomScaleExtent: [0.1, 10], + zoomTranslateExtent: [[-Infinity, -Infinity], [+Infinity, +Infinity]], + width: null, + height: null, + scale: 1, + fit: false + }; + if (options instanceof Object) { + for (var _i = 0, _Object$keys = Object.keys(options); _i < _Object$keys.length; _i++) { + var option = _Object$keys[_i]; + this._options[option] = options[option]; + } + } else if (typeof options == 'boolean') { + this._options.useWorker = options; + } + var useWorker = this._options.useWorker; + var useSharedWorker = this._options.useSharedWorker; + if (typeof Worker == 'undefined') { + useWorker = false; + } + if (typeof SharedWorker == 'undefined') { + useSharedWorker = false; + } + if (useWorker || useSharedWorker) { + var scripts = d3__namespace.selectAll('script'); + var vizScript = scripts.filter(function () { + return d3__namespace.select(this).attr('type') == 'javascript/worker' || d3__namespace.select(this).attr('src') && d3__namespace.select(this).attr('src').match(/.*\/@hpcc-js\/wasm/); + }); + if (vizScript.size() == 0) { + console.warn('No script tag of type "javascript/worker" was found and "useWorker" is true. Not using web worker.'); + useWorker = false; + useSharedWorker = false; + } else { + this._vizURL = vizScript.attr('src'); + if (!this._vizURL) { + console.warn('No "src" attribute of was found on the "javascript/worker" script tag and "useWorker" is true. Not using web worker.'); + useWorker = false; + useSharedWorker = false; + } + } + } + if (useSharedWorker) { + var url = 'data:application/javascript;base64,' + btoa(workerCodeBody.toString() + '(' + sharedWorkerCode.toString() + ')()'); + this._worker = this._worker = new SharedWorker(url); + this._workerPort = this._worker.port; + this._workerPortClose = this._worker.port.close.bind(this._workerPort); + this._worker.port.start(); + this._workerCallbacks = []; + } else if (useWorker) { + var blob = new Blob([workerCodeBody.toString() + '(' + workerCode.toString() + ')()']); + var blobURL = window.URL.createObjectURL(blob); + this._worker = new Worker(blobURL); + this._workerPort = this._worker; + this._workerPortClose = this._worker.terminate.bind(this._worker); + this._workerCallbacks = []; + } else { + xo.load().then(function (graphviz) { + _this._graphvizVersion = graphviz.version(); + }.bind(this)); + } + this._selection = selection; + this._active = false; + this._busy = false; + this._jobs = []; + this._queue = []; + this._keyModes = new Set(['title', 'id', 'tag-index', 'index']); + this._images = []; + this._translation = undefined; + this._scale = undefined; + this._eventTypes = ['initEnd', 'start', 'layoutStart', 'layoutEnd', 'dataExtractEnd', 'dataProcessPass1End', 'dataProcessPass2End', 'dataProcessEnd', 'renderStart', 'renderEnd', 'transitionStart', 'transitionEnd', 'restoreEnd', 'end', 'zoom']; + this._dispatch = d3Dispatch.dispatch.apply(void 0, _toConsumableArray(this._eventTypes)); + initViz.call(this); + selection.node().__graphviz__ = this; + } + function graphviz(selector, options) { + var g = d3__namespace.select(selector).graphviz(options); + return g; + } + Graphviz.prototype = graphviz.prototype = (_graphviz$prototype = { + constructor: Graphviz, + engine: engine, + addImage: images, + keyMode: keyMode, + fade: fade, + tweenPaths: tweenPaths, + tweenShapes: tweenShapes, + convertEqualSidedPolygons: convertEqualSidedPolygons, + tweenPrecision: tweenPrecision, + growEnteringEdges: growEnteringEdges, + zoom: zoom, + resetZoom: resetZoom, + zoomBehavior: zoomBehavior, + zoomSelection: zoomSelection, + zoomScaleExtent: zoomScaleExtent, + zoomTranslateExtent: zoomTranslateExtent, + render: render, + layout: layout, + dot: dot, + data: data, + renderDot: renderDot, + transition: transition, + active: active, + options: options, + width: width, + height: height, + scale: scale, + fit: fit, + attributer: attributer, + on: on, + onerror: onerror, + logEvents: logEvents, + destroy: destroy, + drawEdge: drawEdge, + updateDrawnEdge: updateDrawnEdge, + moveDrawnEdgeEndPoint: moveDrawnEdgeEndPoint, + insertDrawnEdge: insertDrawnEdge, + removeDrawnEdge: removeDrawnEdge + }, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_graphviz$prototype, "removeDrawnEdge", removeDrawnEdge), "drawnEdgeSelection", drawnEdgeSelection), "drawnEdgeSelection", drawnEdgeSelection), "drawNode", drawNode), "updateDrawnNode", updateDrawnNode), "moveDrawnNode", moveDrawnNode), "insertDrawnNode", insertDrawnNode), "removeDrawnNode", removeDrawnNode), "removeDrawnNode", removeDrawnNode), "drawnNodeSelection", drawnNodeSelection), _defineProperty(_defineProperty(_graphviz$prototype, "drawnNodeSelection", drawnNodeSelection), "graphvizVersion", graphvizVersion)); + + function selection_graphviz (options) { + var g = this.node().__graphviz__; + if (g) { + g.options(options); + // Ensure a possible new initEnd event handler is attached before calling it + d3Timer.timeout(function () { + g._dispatch.call("initEnd", this); + }.bind(this), 0); + } else { + g = new Graphviz(this, options); + } + return g; + } + + function selection_selectWithoutDataPropagation (name) { + return d3__namespace.select(this.size() > 0 ? this.node().querySelector(name) : null); + } + + d3.selection.prototype.graphviz = selection_graphviz; + d3.selection.prototype.selectWithoutDataPropagation = selection_selectWithoutDataPropagation; + + exports.graphviz = graphviz; + +})); +//# sourceMappingURL=d3-graphviz.js.map diff --git a/chapter21/docs/d3.v7.min.js b/chapter21/docs/d3.v7.min.js new file mode 100644 index 00000000..33bb8802 --- /dev/null +++ b/chapter21/docs/d3.v7.min.js @@ -0,0 +1,2 @@ +// https://d3js.org v7.9.0 Copyright 2010-2023 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return null==t||null==n?NaN:tn?1:t>=n?0:NaN}function e(t,n){return null==t||null==n?NaN:nt?1:n>=t?0:NaN}function r(t){let r,o,a;function u(t,n,e=0,i=t.length){if(e>>1;o(t[r],n)<0?e=r+1:i=r}while(en(t(e),r),a=(n,e)=>t(n)-e):(r=t===n||t===e?t:i,o=t,a=t),{left:u,center:function(t,n,e=0,r=t.length){const i=u(t,n,e,r-1);return i>e&&a(t[i-1],n)>-a(t[i],n)?i-1:i},right:function(t,n,e=0,i=t.length){if(e>>1;o(t[r],n)<=0?e=r+1:i=r}while(e{n(t,e,(r<<=2)+0,(i<<=2)+0,o<<=2),n(t,e,r+1,i+1,o),n(t,e,r+2,i+2,o),n(t,e,r+3,i+3,o)}}));function d(t){return function(n,e,r=e){if(!((e=+e)>=0))throw new RangeError("invalid rx");if(!((r=+r)>=0))throw new RangeError("invalid ry");let{data:i,width:o,height:a}=n;if(!((o=Math.floor(o))>=0))throw new RangeError("invalid width");if(!((a=Math.floor(void 0!==a?a:i.length/o))>=0))throw new RangeError("invalid height");if(!o||!a||!e&&!r)return n;const u=e&&t(e),c=r&&t(r),f=i.slice();return u&&c?(p(u,f,i,o,a),p(u,i,f,o,a),p(u,f,i,o,a),g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)):u?(p(u,i,f,o,a),p(u,f,i,o,a),p(u,i,f,o,a)):c&&(g(c,i,f,o,a),g(c,f,i,o,a),g(c,i,f,o,a)),n}}function p(t,n,e,r,i){for(let o=0,a=r*i;o{if(!((o-=a)>=i))return;let u=t*r[i];const c=a*t;for(let t=i,n=i+c;t{if(!((a-=u)>=o))return;let c=n*i[o];const f=u*n,s=f+u;for(let t=o,n=o+f;t=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function _(t){return 0|t.length}function b(t){return!(t>0)}function m(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function x(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function w(t,n){const e=x(t,n);return e?Math.sqrt(e):e}function M(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r=o&&(e=r=o):(e>o&&(e=o),r0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}class InternMap extends Map{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const[n,e]of t)this.set(n,e)}get(t){return super.get(A(this,t))}has(t){return super.has(A(this,t))}set(t,n){return super.set(S(this,t),n)}delete(t){return super.delete(E(this,t))}}class InternSet extends Set{constructor(t,n=N){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),null!=t)for(const n of t)this.add(n)}has(t){return super.has(A(this,t))}add(t){return super.add(S(this,t))}delete(t){return super.delete(E(this,t))}}function A({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):e}function S({_intern:t,_key:n},e){const r=n(e);return t.has(r)?t.get(r):(t.set(r,e),e)}function E({_intern:t,_key:n},e){const r=n(e);return t.has(r)&&(e=t.get(r),t.delete(r)),e}function N(t){return null!==t&&"object"==typeof t?t.valueOf():t}function k(t){return t}function C(t,...n){return F(t,k,k,n)}function P(t,...n){return F(t,Array.from,k,n)}function z(t,n){for(let e=1,r=n.length;et.pop().map((([n,e])=>[...t,n,e]))));return t}function $(t,n,...e){return F(t,k,n,e)}function D(t,n,...e){return F(t,Array.from,n,e)}function R(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function F(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new InternMap,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}function q(t,n){return Array.from(n,(n=>t[n]))}function U(t,...n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");t=Array.from(t);let[e]=n;if(e&&2!==e.length||n.length>1){const r=Uint32Array.from(t,((t,n)=>n));return n.length>1?(n=n.map((n=>t.map(n))),r.sort(((t,e)=>{for(const r of n){const n=O(r[t],r[e]);if(n)return n}}))):(e=t.map(e),r.sort(((t,n)=>O(e[t],e[n])))),q(t,r)}return t.sort(I(e))}function I(t=n){if(t===n)return O;if("function"!=typeof t)throw new TypeError("compare is not a function");return(n,e)=>{const r=t(n,e);return r||0===r?r:(0===t(e,e))-(0===t(n,n))}}function O(t,n){return(null==t||!(t>=t))-(null==n||!(n>=n))||(tn?1:0)}var B=Array.prototype.slice;function Y(t){return()=>t}const L=Math.sqrt(50),j=Math.sqrt(10),H=Math.sqrt(2);function X(t,n,e){const r=(n-t)/Math.max(0,e),i=Math.floor(Math.log10(r)),o=r/Math.pow(10,i),a=o>=L?10:o>=j?5:o>=H?2:1;let u,c,f;return i<0?(f=Math.pow(10,-i)/a,u=Math.round(t*f),c=Math.round(n*f),u/fn&&--c,f=-f):(f=Math.pow(10,i)*a,u=Math.round(t/f),c=Math.round(n/f),u*fn&&--c),c0))return[];if((t=+t)===(n=+n))return[t];const r=n=i))return[];const u=o-i+1,c=new Array(u);if(r)if(a<0)for(let t=0;t0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function K(t){return Math.max(1,Math.ceil(Math.log(v(t))/Math.LN2)+1)}function Q(){var t=k,n=M,e=K;function r(r){Array.isArray(r)||(r=Array.from(r));var i,o,a,u=r.length,c=new Array(u);for(i=0;i=h)if(t>=h&&n===M){const t=V(l,h,e);isFinite(t)&&(t>0?h=(Math.floor(h/t)+1)*t:t<0&&(h=(Math.ceil(h*-t)+1)/-t))}else d.pop()}for(var p=d.length,g=0,y=p;d[g]<=l;)++g;for(;d[y-1]>h;)--y;(g||y0?d[i-1]:l,v.x1=i0)for(i=0;i=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e=i)&&(e=i)}return e}function tt(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e=o)&&(e=o,r=i);return r}function nt(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function et(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function rt(t,n,e=0,r=1/0,i){if(n=Math.floor(n),e=Math.floor(Math.max(0,e)),r=Math.floor(Math.min(t.length-1,r)),!(e<=n&&n<=r))return t;for(i=void 0===i?O:I(i);r>e;){if(r-e>600){const o=r-e+1,a=n-e+1,u=Math.log(o),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(o-c)/o)*(a-o/2<0?-1:1);rt(t,n,Math.max(e,Math.floor(n-a*c/o+f)),Math.min(r,Math.floor(n+(o-a)*c/o+f)),i)}const o=t[n];let a=e,u=r;for(it(t,e,n),i(t[r],o)>0&&it(t,e,r);a0;)--u}0===i(t[e],o)?it(t,e,u):(++u,it(t,u,r)),u<=n&&(e=u+1),n<=u&&(r=u-1)}return t}function it(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function ot(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r}function at(t,n,e){if(t=Float64Array.from(function*(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}(t,e)),(r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return nt(t);if(n>=1)return J(t);var r,i=(r-1)*n,o=Math.floor(i),a=J(rt(t,o).subarray(0,o+1));return a+(nt(t.subarray(o+1))-a)*(i-o)}}function ut(t,n,e=o){if((r=t.length)&&!isNaN(n=+n)){if(n<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,a=Math.floor(i),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(i-a)}}function ct(t,n,e=o){if(!isNaN(n=+n)){if(r=Float64Array.from(t,((n,r)=>o(e(t[r],r,t)))),n<=0)return et(r);if(n>=1)return tt(r);var r,i=Uint32Array.from(t,((t,n)=>n)),a=r.length-1,u=Math.floor(a*n);return rt(i,u,0,a,((t,n)=>O(r[t],r[n]))),(u=ot(i.subarray(0,u+1),(t=>r[t])))>=0?u:-1}}function ft(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function st(t,n){return[t,n]}function lt(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r+t(n)}function kt(t,n){return n=Math.max(0,t.bandwidth()-2*n)/2,t.round()&&(n=Math.round(n)),e=>+t(e)+n}function Ct(){return!this.__axis}function Pt(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,f=t===xt||t===Tt?-1:1,s=t===Tt||t===wt?"x":"y",l=t===xt||t===Mt?St:Et;function h(h){var d=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,p=null==i?n.tickFormat?n.tickFormat.apply(n,e):mt:i,g=Math.max(o,0)+u,y=n.range(),v=+y[0]+c,_=+y[y.length-1]+c,b=(n.bandwidth?kt:Nt)(n.copy(),c),m=h.selection?h.selection():h,x=m.selectAll(".domain").data([null]),w=m.selectAll(".tick").data(d,n).order(),M=w.exit(),T=w.enter().append("g").attr("class","tick"),A=w.select("line"),S=w.select("text");x=x.merge(x.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),w=w.merge(T),A=A.merge(T.append("line").attr("stroke","currentColor").attr(s+"2",f*o)),S=S.merge(T.append("text").attr("fill","currentColor").attr(s,f*g).attr("dy",t===xt?"0em":t===Mt?"0.71em":"0.32em")),h!==m&&(x=x.transition(h),w=w.transition(h),A=A.transition(h),S=S.transition(h),M=M.transition(h).attr("opacity",At).attr("transform",(function(t){return isFinite(t=b(t))?l(t+c):this.getAttribute("transform")})),T.attr("opacity",At).attr("transform",(function(t){var n=this.parentNode.__axis;return l((n&&isFinite(n=n(t))?n:b(t))+c)}))),M.remove(),x.attr("d",t===Tt||t===wt?a?"M"+f*a+","+v+"H"+c+"V"+_+"H"+f*a:"M"+c+","+v+"V"+_:a?"M"+v+","+f*a+"V"+c+"H"+_+"V"+f*a:"M"+v+","+c+"H"+_),w.attr("opacity",1).attr("transform",(function(t){return l(b(t)+c)})),A.attr(s+"2",f*o),S.attr(s,f*g).text(p),m.filter(Ct).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===wt?"start":t===Tt?"end":"middle"),m.each((function(){this.__axis=b}))}return h.scale=function(t){return arguments.length?(n=t,h):n},h.ticks=function(){return e=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(e=null==t?[]:Array.from(t),h):e.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(c=+t,h):c},h}var zt={value:()=>{}};function $t(){for(var t,n=0,e=arguments.length,r={};n=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ut.hasOwnProperty(n)?{space:Ut[n],local:t}:t}function Ot(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===qt&&n.documentElement.namespaceURI===qt?n.createElement(t):n.createElementNS(e,t)}}function Bt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function Yt(t){var n=It(t);return(n.local?Bt:Ot)(n)}function Lt(){}function jt(t){return null==t?Lt:function(){return this.querySelector(t)}}function Ht(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function Xt(){return[]}function Gt(t){return null==t?Xt:function(){return this.querySelectorAll(t)}}function Vt(t){return function(){return this.matches(t)}}function Wt(t){return function(n){return n.matches(t)}}var Zt=Array.prototype.find;function Kt(){return this.firstElementChild}var Qt=Array.prototype.filter;function Jt(){return Array.from(this.children)}function tn(t){return new Array(t.length)}function nn(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function en(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;un?1:t>=n?0:NaN}function cn(t){return function(){this.removeAttribute(t)}}function fn(t){return function(){this.removeAttributeNS(t.space,t.local)}}function sn(t,n){return function(){this.setAttribute(t,n)}}function ln(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function hn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function dn(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function pn(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function gn(t){return function(){this.style.removeProperty(t)}}function yn(t,n,e){return function(){this.style.setProperty(t,n,e)}}function vn(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function _n(t,n){return t.style.getPropertyValue(n)||pn(t).getComputedStyle(t,null).getPropertyValue(n)}function bn(t){return function(){delete this[t]}}function mn(t,n){return function(){this[t]=n}}function xn(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function wn(t){return t.trim().split(/^|\s+/)}function Mn(t){return t.classList||new Tn(t)}function Tn(t){this._node=t,this._names=wn(t.getAttribute("class")||"")}function An(t,n){for(var e=Mn(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Gn=[null];function Vn(t,n){this._groups=t,this._parents=n}function Wn(){return new Vn([[document.documentElement]],Gn)}function Zn(t){return"string"==typeof t?new Vn([[document.querySelector(t)]],[document.documentElement]):new Vn([[t]],Gn)}Vn.prototype=Wn.prototype={constructor:Vn,select:function(t){"function"!=typeof t&&(t=jt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i=m&&(m=b+1);!(_=y[m])&&++m=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=un);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?gn:"function"==typeof n?vn:yn)(t,n,null==e?"":e)):_n(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?bn:"function"==typeof n?xn:mn)(t,n)):this.node()[t]},classed:function(t,n){var e=wn(t+"");if(arguments.length<2){for(var r=Mn(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?Ln:Yn,r=0;r()=>t;function fe(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function se(t){return!t.ctrlKey&&!t.button}function le(){return this.parentNode}function he(t,n){return null==n?{x:t.x,y:t.y}:n}function de(){return navigator.maxTouchPoints||"ontouchstart"in this}function pe(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function ge(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function ye(){}fe.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var ve=.7,_e=1/ve,be="\\s*([+-]?\\d+)\\s*",me="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",xe="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",we=/^#([0-9a-f]{3,8})$/,Me=new RegExp(`^rgb\\(${be},${be},${be}\\)$`),Te=new RegExp(`^rgb\\(${xe},${xe},${xe}\\)$`),Ae=new RegExp(`^rgba\\(${be},${be},${be},${me}\\)$`),Se=new RegExp(`^rgba\\(${xe},${xe},${xe},${me}\\)$`),Ee=new RegExp(`^hsl\\(${me},${xe},${xe}\\)$`),Ne=new RegExp(`^hsla\\(${me},${xe},${xe},${me}\\)$`),ke={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function Ce(){return this.rgb().formatHex()}function Pe(){return this.rgb().formatRgb()}function ze(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=we.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?$e(n):3===e?new qe(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?De(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?De(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Me.exec(t))?new qe(n[1],n[2],n[3],1):(n=Te.exec(t))?new qe(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ae.exec(t))?De(n[1],n[2],n[3],n[4]):(n=Se.exec(t))?De(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ee.exec(t))?Le(n[1],n[2]/100,n[3]/100,1):(n=Ne.exec(t))?Le(n[1],n[2]/100,n[3]/100,n[4]):ke.hasOwnProperty(t)?$e(ke[t]):"transparent"===t?new qe(NaN,NaN,NaN,0):null}function $e(t){return new qe(t>>16&255,t>>8&255,255&t,1)}function De(t,n,e,r){return r<=0&&(t=n=e=NaN),new qe(t,n,e,r)}function Re(t){return t instanceof ye||(t=ze(t)),t?new qe((t=t.rgb()).r,t.g,t.b,t.opacity):new qe}function Fe(t,n,e,r){return 1===arguments.length?Re(t):new qe(t,n,e,null==r?1:r)}function qe(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ue(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}`}function Ie(){const t=Oe(this.opacity);return`${1===t?"rgb(":"rgba("}${Be(this.r)}, ${Be(this.g)}, ${Be(this.b)}${1===t?")":`, ${t})`}`}function Oe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Be(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Ye(t){return((t=Be(t))<16?"0":"")+t.toString(16)}function Le(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Xe(t,n,e,r)}function je(t){if(t instanceof Xe)return new Xe(t.h,t.s,t.l,t.opacity);if(t instanceof ye||(t=ze(t)),!t)return new Xe;if(t instanceof Xe)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e0&&c<1?0:a,new Xe(a,u,c,t.opacity)}function He(t,n,e,r){return 1===arguments.length?je(t):new Xe(t,n,e,null==r?1:r)}function Xe(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ge(t){return(t=(t||0)%360)<0?t+360:t}function Ve(t){return Math.max(0,Math.min(1,t||0))}function We(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}pe(ye,ze,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Ce,formatHex:Ce,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return je(this).formatHsl()},formatRgb:Pe,toString:Pe}),pe(qe,Fe,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new qe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new qe(Be(this.r),Be(this.g),Be(this.b),Oe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ue,formatHex:Ue,formatHex8:function(){return`#${Ye(this.r)}${Ye(this.g)}${Ye(this.b)}${Ye(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Ie,toString:Ie})),pe(Xe,He,ge(ye,{brighter(t){return t=null==t?_e:Math.pow(_e,t),new Xe(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?ve:Math.pow(ve,t),new Xe(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new qe(We(t>=240?t-240:t+120,i,r),We(t,i,r),We(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new Xe(Ge(this.h),Ve(this.s),Ve(this.l),Oe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Oe(this.opacity);return`${1===t?"hsl(":"hsla("}${Ge(this.h)}, ${100*Ve(this.s)}%, ${100*Ve(this.l)}%${1===t?")":`, ${t})`}`}}));const Ze=Math.PI/180,Ke=180/Math.PI,Qe=.96422,Je=1,tr=.82521,nr=4/29,er=6/29,rr=3*er*er,ir=er*er*er;function or(t){if(t instanceof ur)return new ur(t.l,t.a,t.b,t.opacity);if(t instanceof pr)return gr(t);t instanceof qe||(t=Re(t));var n,e,r=lr(t.r),i=lr(t.g),o=lr(t.b),a=cr((.2225045*r+.7168786*i+.0606169*o)/Je);return r===i&&i===o?n=e=a:(n=cr((.4360747*r+.3850649*i+.1430804*o)/Qe),e=cr((.0139322*r+.0971045*i+.7141733*o)/tr)),new ur(116*a-16,500*(n-a),200*(a-e),t.opacity)}function ar(t,n,e,r){return 1===arguments.length?or(t):new ur(t,n,e,null==r?1:r)}function ur(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function cr(t){return t>ir?Math.pow(t,1/3):t/rr+nr}function fr(t){return t>er?t*t*t:rr*(t-nr)}function sr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function lr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function hr(t){if(t instanceof pr)return new pr(t.h,t.c,t.l,t.opacity);if(t instanceof ur||(t=or(t)),0===t.a&&0===t.b)return new pr(NaN,0=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r()=>t;function Cr(t,n){return function(e){return t+e*n}}function Pr(t,n){var e=n-t;return e?Cr(t,e>180||e<-180?e-360*Math.round(e/360):e):kr(isNaN(t)?n:t)}function zr(t){return 1==(t=+t)?$r:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):kr(isNaN(n)?e:n)}}function $r(t,n){var e=n-t;return e?Cr(t,e):kr(isNaN(t)?n:t)}var Dr=function t(n){var e=zr(n);function r(t,n){var r=e((t=Fe(t)).r,(n=Fe(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=$r(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Rr(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;eo&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:Yr(e,r)})),o=Hr.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Yr(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Yr(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Yr(t,e)},{i:u-2,x:Yr(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(void 0,t),n=n._next;--yi}function Ci(){xi=(mi=Mi.now())+wi,yi=vi=0;try{ki()}finally{yi=0,function(){var t,n,e=pi,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pi=n);gi=t,zi(r)}(),xi=0}}function Pi(){var t=Mi.now(),n=t-mi;n>bi&&(wi-=n,mi=t)}function zi(t){yi||(vi&&(vi=clearTimeout(vi)),t-xi>24?(t<1/0&&(vi=setTimeout(Ci,t-Mi.now()-wi)),_i&&(_i=clearInterval(_i))):(_i||(mi=Mi.now(),_i=setInterval(Pi,bi)),yi=1,Ti(Ci)))}function $i(t,n,e){var r=new Ei;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ei.prototype=Ni.prototype={constructor:Ei,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Ai():+e)+(null==n?0:+n),this._next||gi===this||(gi?gi._next=this:pi=this,gi=this),this._call=t,this._time=e,zi()},stop:function(){this._call&&(this._call=null,this._time=1/0,zi())}};var Di=$t("start","end","cancel","interrupt"),Ri=[],Fi=0,qi=1,Ui=2,Ii=3,Oi=4,Bi=5,Yi=6;function Li(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=qi,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(e.state!==qi)return c();for(f in i)if((h=i[f]).name===e.name){if(h.state===Ii)return $i(a);h.state===Oi?(h.state=Yi,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+fFi)throw new Error("too late; already scheduled");return e}function Hi(t,n){var e=Xi(t,n);if(e.state>Ii)throw new Error("too late; already running");return e}function Xi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Gi(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Ui&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?ji:Hi;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=It(t),r="transform"===e?ni:Ki;return this.attrTween(t,"function"==typeof n?(e.local?ro:eo)(e,r,Zi(this,"attr."+t,n)):null==n?(e.local?Ji:Qi)(e):(e.local?no:to)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=It(t);return this.tween(e,(r.local?io:oo)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?ti:Ki;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=_n(this,t),a=(this.style.removeProperty(t),_n(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,lo(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=_n(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=_n(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Zi(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Hi(this,t),f=c.on,s=null==c.value[a]?o||(o=lo(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=_n(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Zi(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Xi(this.node(),e).tween,o=0,a=i.length;o()=>t;function Qo(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function Jo(t){t.preventDefault(),t.stopImmediatePropagation()}var ta={name:"drag"},na={name:"space"},ea={name:"handle"},ra={name:"center"};const{abs:ia,max:oa,min:aa}=Math;function ua(t){return[+t[0],+t[1]]}function ca(t){return[ua(t[0]),ua(t[1])]}var fa={name:"x",handles:["w","e"].map(va),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},sa={name:"y",handles:["n","s"].map(va),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},la={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(va),input:function(t){return null==t?null:ca(t)},output:function(t){return t}},ha={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},da={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},pa={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},ga={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},ya={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function va(t){return{type:t}}function _a(t){return!t.ctrlKey&&!t.button}function ba(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function ma(){return navigator.maxTouchPoints||"ontouchstart"in this}function xa(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function wa(t){var n,e=ba,r=_a,i=ma,o=!0,a=$t("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([va("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",ha.overlay).merge(e).each((function(){var t=xa(this).extent;Zn(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([va("selection")]).enter().append("rect").attr("class","selection").attr("cursor",ha.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return ha[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=Zn(this),n=xa(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?ta:o&&e.altKey?ra:ea,x=t===sa?null:ga[b],w=t===fa?null:ya[b],M=xa(_),T=M.extent,A=M.selection,S=T[0][0],E=T[0][1],N=T[1][0],k=T[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,$=Array.from(e.touches||[e],(t=>{const n=t.identifier;return(t=ne(t,_)).point0=t.slice(),t.identifier=n,t}));Gi(_);var D=s(_,arguments,!0).beforestart();if("overlay"===b){A&&(g=!0);const n=[$[0],$[1]||$[0]];M.selection=A=[[i=t===sa?S:aa(n[0][0],n[1][0]),u=t===fa?E:aa(n[0][1],n[1][1])],[l=t===sa?N:oa(n[0][0],n[1][0]),d=t===fa?k:oa(n[0][1],n[1][1])]],$.length>1&&I(e)}else i=A[0][0],u=A[0][1],l=A[1][0],d=A[1][1];a=i,c=u,h=l,p=d;var R=Zn(_).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",ha[b]);if(e.touches)D.moved=U,D.ended=O;else{var q=Zn(e.view).on("mousemove.brush",U,!0).on("mouseup.brush",O,!0);o&&q.on("keydown.brush",(function(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===ea&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra,I(t));break;case 32:m!==ea&&m!==ra||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=na,F.attr("cursor",ha.selection),I(t));break;default:return}Jo(t)}),!0).on("keyup.brush",(function(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,I(t));break;case 18:m===ra&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea,I(t));break;case 32:m===na&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=ra):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=ea),F.attr("cursor",ha[b]),I(t));break;default:return}Jo(t)}),!0),ae(e.view)}f.call(_),D.start(e,m.name)}function U(t){for(const n of t.changedTouches||[t])for(const t of $)t.identifier===n.identifier&&(t.cur=ne(n,_));if(z&&!y&&!v&&1===$.length){const t=$[0];ia(t.cur[0]-t[0])>ia(t.cur[1]-t[1])?v=!0:y=!0}for(const t of $)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,Jo(t),I(t)}function I(t){const n=$[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case na:case ta:x&&(C=oa(S-i,aa(N-l,C)),a=i+C,h=l+C),w&&(P=oa(E-u,aa(k-d,P)),c=u+P,p=d+P);break;case ea:$[1]?(x&&(a=oa(S,aa(N,$[0][0])),h=oa(S,aa(N,$[1][0])),x=1),w&&(c=oa(E,aa(k,$[0][1])),p=oa(E,aa(k,$[1][1])),w=1)):(x<0?(C=oa(S-i,aa(N-i,C)),a=i+C,h=l):x>0&&(C=oa(S-l,aa(N-l,C)),a=i,h=l+C),w<0?(P=oa(E-u,aa(k-u,P)),c=u+P,p=d):w>0&&(P=oa(E-d,aa(k-d,P)),c=u,p=d+P));break;case ra:x&&(a=oa(S,aa(N,i-C*x)),h=oa(S,aa(N,l+C*x))),w&&(c=oa(E,aa(k,u-P*w)),p=oa(E,aa(k,d+P*w)))}ht+e))}function za(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=Pa(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;nr(f[t],f[n])));for(const e of s){const r=n;if(t){const t=Pa(1+~c,c).filter((t=>t<0?a[~t*c+e]:a[e*c+t]));i&&t.sort(((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n])));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=Pa(0,c).filter((t=>a[e*c+t]||a[t*c+e]));i&&t.sort(((t,n)=>i(a[e*c+t],a[e*c+n])));for(const r of t){let t;if(e=0))throw new Error(`invalid digits: ${t}`);if(n>15)return qa;const e=10**n;return function(t){this._+=t[0];for(let n=1,r=t.length;nRa)if(Math.abs(s*u-c*f)>Ra&&i){let h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan(($a-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>Ra&&this._append`L${t+b*f},${n+b*s}`,this._append`A${i},${i},0,0,${+(s*h>f*d)},${this._x1=t+m*u},${this._y1=n+m*c}`}else this._append`L${this._x1=t},${this._y1=n}`;else;}arc(t,n,e,r,i,o){if(t=+t,n=+n,o=!!o,(e=+e)<0)throw new Error(`negative radius: ${e}`);let a=e*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;null===this._x1?this._append`M${c},${f}`:(Math.abs(this._x1-c)>Ra||Math.abs(this._y1-f)>Ra)&&this._append`L${c},${f}`,e&&(l<0&&(l=l%Da+Da),l>Fa?this._append`A${e},${e},0,1,${s},${t-a},${n-u}A${e},${e},0,1,${s},${this._x1=c},${this._y1=f}`:l>Ra&&this._append`A${e},${e},0,${+(l>=$a)},${s},${this._x1=t+e*Math.cos(i)},${this._y1=n+e*Math.sin(i)}`)}rect(t,n,e,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${e=+e}v${+r}h${-e}Z`}toString(){return this._}};function Ia(){return new Ua}Ia.prototype=Ua.prototype;var Oa=Array.prototype.slice;function Ba(t){return function(){return t}}function Ya(t){return t.source}function La(t){return t.target}function ja(t){return t.radius}function Ha(t){return t.startAngle}function Xa(t){return t.endAngle}function Ga(){return 0}function Va(){return 10}function Wa(t){var n=Ya,e=La,r=ja,i=ja,o=Ha,a=Xa,u=Ga,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=Oa.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-Ea,y=a.apply(this,d)-Ea,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-Ea,b=a.apply(this,d)-Ea;if(c||(c=f=Ia()),h>Ca&&(Ma(y-g)>2*h+Ca?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,Ma(b-_)>2*h+Ca?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*Ta(g),p*Aa(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=v-+t.apply(this,arguments),x=(_+b)/2;c.quadraticCurveTo(0,0,m*Ta(_),m*Aa(_)),c.lineTo(v*Ta(x),v*Aa(x)),c.lineTo(m*Ta(b),m*Aa(b))}else c.quadraticCurveTo(0,0,v*Ta(_),v*Aa(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*Ta(g),p*Aa(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:Ba(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:Ba(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:Ba(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:Ba(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:Ba(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:Ba(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:Ba(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var Za=Array.prototype.slice;function Ka(t,n){return t-n}var Qa=t=>()=>t;function Ja(t,n){for(var e,r=-1,i=n.length;++rr!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function nu(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function eu(){}var ru=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function iu(){var t=1,n=1,e=K,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(Ka);else{const e=M(t,ou);for(n=G(...Z(e[0],e[1],n),n);n[n.length-1]>=e[1];)n.pop();for(;n[1]o(t,n)))}function o(e,i){const o=null==i?NaN:+i;if(isNaN(o))throw new Error(`invalid value: ${i}`);var u=[],c=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=au(e[0],r),ru[f<<1].forEach(p);for(;++o=r,ru[s<<2].forEach(p);for(;++o0?u.push([t]):c.push(t)})),c.forEach((function(t){for(var n,e=0,r=u.length;e0&&o0&&a=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:eu,i):r===u},i}function ou(t){return isFinite(t)?t:NaN}function au(t,n){return null!=t&&+t>=n}function uu(t){return null==t||isNaN(t=+t)?-1/0:t}function cu(t,n,e,r){const i=r-n,o=e-n,a=isFinite(i)||isFinite(o)?i/o:Math.sign(i)/Math.sign(o);return isNaN(a)?t:t+a-.5}function fu(t){return t[0]}function su(t){return t[1]}function lu(){return 1}const hu=134217729,du=33306690738754706e-32;function pu(t,n,e,r,i){let o,a,u,c,f=n[0],s=r[0],l=0,h=0;s>f==s>-f?(o=f,f=n[++l]):(o=s,s=r[++h]);let d=0;if(lf==s>-f?(a=f+o,u=o-(a-f),f=n[++l]):(a=s+o,u=o-(a-s),s=r[++h]),o=a,0!==u&&(i[d++]=u);lf==s>-f?(a=o+f,c=a-o,u=o-(a-c)+(f-c),f=n[++l]):(a=o+s,c=a-o,u=o-(a-c)+(s-c),s=r[++h]),o=a,0!==u&&(i[d++]=u);for(;l=33306690738754716e-32*f?c:-function(t,n,e,r,i,o,a){let u,c,f,s,l,h,d,p,g,y,v,_,b,m,x,w,M,T;const A=t-i,S=e-i,E=n-o,N=r-o;m=A*N,h=hu*A,d=h-(h-A),p=A-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=E*S,h=hu*E,d=h-(h-E),p=E-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,_u[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,_u[1]=b-(v+l)+(l-w),T=_+v,l=T-_,_u[2]=_-(T-l)+(v-l),_u[3]=T;let k=function(t,n){let e=n[0];for(let r=1;r=C||-k>=C)return k;if(l=t-A,u=t-(A+l)+(l-i),l=e-S,f=e-(S+l)+(l-i),l=n-E,c=n-(E+l)+(l-o),l=r-N,s=r-(N+l)+(l-o),0===u&&0===c&&0===f&&0===s)return k;if(C=vu*a+du*Math.abs(k),k+=A*s+N*u-(E*f+S*c),k>=C||-k>=C)return k;m=u*N,h=hu*u,d=h-(h-u),p=u-d,h=hu*N,g=h-(h-N),y=N-g,x=p*y-(m-d*g-p*g-d*y),w=c*S,h=hu*c,d=h-(h-c),p=c-d,h=hu*S,g=h-(h-S),y=S-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const P=pu(4,_u,4,wu,bu);m=A*s,h=hu*A,d=h-(h-A),p=A-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=E*f,h=hu*E,d=h-(h-E),p=E-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const z=pu(P,bu,4,wu,mu);m=u*s,h=hu*u,d=h-(h-u),p=u-d,h=hu*s,g=h-(h-s),y=s-g,x=p*y-(m-d*g-p*g-d*y),w=c*f,h=hu*c,d=h-(h-c),p=c-d,h=hu*f,g=h-(h-f),y=f-g,M=p*y-(w-d*g-p*g-d*y),v=x-M,l=x-v,wu[0]=x-(v+l)+(l-M),_=m+v,l=_-m,b=m-(_-l)+(v-l),v=b-w,l=b-v,wu[1]=b-(v+l)+(l-w),T=_+v,l=T-_,wu[2]=_-(T-l)+(v-l),wu[3]=T;const $=pu(z,mu,4,wu,xu);return xu[$-1]}(t,n,e,r,i,o,f)}const Tu=Math.pow(2,-52),Au=new Uint32Array(512);class Su{static from(t,n=zu,e=$u){const r=t.length,i=new Float64Array(2*r);for(let o=0;o>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;nc&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p;for(let n=0,e=1/0;n0&&(d=n,e=r)}let v=t[2*d],_=t[2*d+1],b=1/0;for(let n=0;nr&&(n[e++]=i,r=o)}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(Mu(g,y,v,_,m,x)<0){const t=d,n=v,e=_;d=p,v=m,_=x,p=t,m=n,x=e}const w=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=t+(f*s-u*l)*h,p=n+(a*l-c*s)*h;return{x:d,y:p}}(g,y,v,_,m,x);this._cx=w.x,this._cy=w.y;for(let n=0;n0&&Math.abs(f-o)<=Tu&&Math.abs(s-a)<=Tu)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t=0;)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,M++;let _=e[y];for(;g=e[_],Mu(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1])<0;)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,M--,_=g;if(y===l)for(;g=n[y],Mu(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1])<0;)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,M--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(M);for(let t=0,n=this._hullStart;t0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=Au[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(Nu(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;Pu(t,e+r>>1,i),n[t[e]]>n[t[r]]&&Pu(t,e,r),n[t[i]]>n[t[r]]&&Pu(t,i,r),n[t[e]]>n[t[i]]&&Pu(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]u);if(o=o-e?(Cu(t,n,i,r),Cu(t,n,e,o-1)):(Cu(t,n,e,o-1),Cu(t,n,i,r))}}function Pu(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function zu(t){return t[0]}function $u(t){return t[1]}const Du=1e-6;class Ru{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>Du||Math.abs(this._y1-i)>Du)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class Fu{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class qu{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this;let i,o;const a=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let r,u,c=0,f=0,s=e.length;c1;)i-=2;for(let t=2;t0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)this.xmax?2:0)|(nthis.ymax?8:0)}_simplify(t){if(t&&t.length>4){for(let n=0;n2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},((t,n)=>n)).sort(((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]));const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],o[r[0]]=1,2===r.length&&(o[r[1]]=0,this.triangles[1]=r[1],this.triangles[2]=r[1]))}voronoi(t){return new qu(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=Iu(n-c[2*t],2)+Iu(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=Iu(n-c[2*r],2)+Iu(e-c[2*r+1],2);if(l9999?"+"+Ku(n,6):Ku(n,4))+"-"+Ku(t.getUTCMonth()+1,2)+"-"+Ku(t.getUTCDate(),2)+(o?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"."+Ku(o,3)+"Z":i?"T"+Ku(e,2)+":"+Ku(r,2)+":"+Ku(i,2)+"Z":r||e?"T"+Ku(e,2)+":"+Ku(r,2)+"Z":"")}function Ju(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Hu;if(f)return f=!1,ju;var n,r,i=a;if(t.charCodeAt(i)===Xu){for(;a++=o?c=!0:(r=t.charCodeAt(a++))===Gu?f=!0:r===Vu&&(f=!0,t.charCodeAt(a)===Gu&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;amc(n,e).then((n=>(new DOMParser).parseFromString(n,t)))}var Sc=Ac("application/xml"),Ec=Ac("text/html"),Nc=Ac("image/svg+xml");function kc(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function Cc(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function Pc(t){return t[0]}function zc(t){return t[1]}function $c(t,n,e){var r=new Dc(null==n?Pc:n,null==e?zc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Dc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Rc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Fc=$c.prototype=Dc.prototype;function qc(t){return function(){return t}}function Uc(t){return 1e-6*(t()-.5)}function Ic(t){return t.x+t.vx}function Oc(t){return t.y+t.vy}function Bc(t){return t.index}function Yc(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}Fc.copy=function(){var t,n,e=new Dc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Rc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Rc(n));return e},Fc.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return kc(this.cover(n,e),n,e,t)},Fc.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;es&&(s=r),il&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;et||t>=i||r>n||n>=o;)switch(u=(nh||(o=c.y0)>d||(a=c.x1)=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Fc.removeAll=function(t){for(var n=0,e=t.length;n1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Zc(t){return(t=Wc(Math.abs(t)))?t[1]:NaN}var Kc,Qc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Jc(t){if(!(n=Qc.exec(t)))throw new Error("invalid format: "+t);var n;return new tf({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function tf(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function nf(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Jc.prototype=tf.prototype,tf.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var ef={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>nf(100*t,n),r:nf,s:function(t,n){var e=Wc(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Kc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Wc(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function rf(t){return t}var of,af=Array.prototype.map,uf=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function cf(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?rf:(n=af.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?rf:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(af.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Jc(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):ef[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=ef[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),T&&0==+t&&"+"!==l&&(T=!1),h=(T?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?uf[8+Kc/3]:"")+M+(T&&"("===l?")":""),w)for(i=-1,o=t.length;++i(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,S=A>1)+h+t+M+S.slice(A);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Jc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3))),i=Math.pow(10,-r),o=uf[8+r/3];return function(t){return e(i*t)+o}}}}function ff(n){return of=cf(n),t.format=of.format,t.formatPrefix=of.formatPrefix,of}function sf(t){return Math.max(0,-Zc(Math.abs(t)))}function lf(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Zc(n)/3)))-Zc(Math.abs(t)))}function hf(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Zc(n)-Zc(t))+1}t.format=void 0,t.formatPrefix=void 0,ff({thousands:",",grouping:[3],currency:["$",""]});var df=1e-6,pf=1e-12,gf=Math.PI,yf=gf/2,vf=gf/4,_f=2*gf,bf=180/gf,mf=gf/180,xf=Math.abs,wf=Math.atan,Mf=Math.atan2,Tf=Math.cos,Af=Math.ceil,Sf=Math.exp,Ef=Math.hypot,Nf=Math.log,kf=Math.pow,Cf=Math.sin,Pf=Math.sign||function(t){return t>0?1:t<0?-1:0},zf=Math.sqrt,$f=Math.tan;function Df(t){return t>1?0:t<-1?gf:Math.acos(t)}function Rf(t){return t>1?yf:t<-1?-yf:Math.asin(t)}function Ff(t){return(t=Cf(t/2))*t}function qf(){}function Uf(t,n){t&&Of.hasOwnProperty(t.type)&&Of[t.type](t,n)}var If={Feature:function(t,n){Uf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r=0?1:-1,i=r*e,o=Tf(n=(n*=mf)/2+vf),a=Cf(n),u=Vf*a,c=Gf*o+u*Tf(i),f=u*r*Cf(i);as.add(Mf(f,c)),Xf=t,Gf=o,Vf=a}function ds(t){return[Mf(t[1],t[0]),Rf(t[2])]}function ps(t){var n=t[0],e=t[1],r=Tf(e);return[r*Tf(n),r*Cf(n),Cf(e)]}function gs(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function ys(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function vs(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function _s(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function bs(t){var n=zf(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var ms,xs,ws,Ms,Ts,As,Ss,Es,Ns,ks,Cs,Ps,zs,$s,Ds,Rs,Fs={point:qs,lineStart:Is,lineEnd:Os,polygonStart:function(){Fs.point=Bs,Fs.lineStart=Ys,Fs.lineEnd=Ls,rs=new T,cs.polygonStart()},polygonEnd:function(){cs.polygonEnd(),Fs.point=qs,Fs.lineStart=Is,Fs.lineEnd=Os,as<0?(Wf=-(Kf=180),Zf=-(Qf=90)):rs>df?Qf=90:rs<-df&&(Zf=-90),os[0]=Wf,os[1]=Kf},sphere:function(){Wf=-(Kf=180),Zf=-(Qf=90)}};function qs(t,n){is.push(os=[Wf=t,Kf=t]),nQf&&(Qf=n)}function Us(t,n){var e=ps([t*mf,n*mf]);if(es){var r=ys(es,e),i=ys([r[1],-r[0],0],r);bs(i),i=ds(i);var o,a=t-Jf,u=a>0?1:-1,c=i[0]*bf*u,f=xf(a)>180;f^(u*JfQf&&(Qf=o):f^(u*Jf<(c=(c+360)%360-180)&&cQf&&(Qf=n)),f?tjs(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t):Kf>=Wf?(tKf&&(Kf=t)):t>Jf?js(Wf,t)>js(Wf,Kf)&&(Kf=t):js(t,Kf)>js(Wf,Kf)&&(Wf=t)}else is.push(os=[Wf=t,Kf=t]);nQf&&(Qf=n),es=e,Jf=t}function Is(){Fs.point=Us}function Os(){os[0]=Wf,os[1]=Kf,Fs.point=qs,es=null}function Bs(t,n){if(es){var e=t-Jf;rs.add(xf(e)>180?e+(e>0?360:-360):e)}else ts=t,ns=n;cs.point(t,n),Us(t,n)}function Ys(){cs.lineStart()}function Ls(){Bs(ts,ns),cs.lineEnd(),xf(rs)>df&&(Wf=-(Kf=180)),os[0]=Wf,os[1]=Kf,es=null}function js(t,n){return(n-=t)<0?n+360:n}function Hs(t,n){return t[0]-n[0]}function Xs(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:ngf&&(t-=Math.round(t/_f)*_f),[t,n]}function ul(t,n,e){return(t%=_f)?n||e?ol(fl(t),sl(n,e)):fl(t):n||e?sl(n,e):al}function cl(t){return function(n,e){return xf(n+=t)>gf&&(n-=Math.round(n/_f)*_f),[n,e]}}function fl(t){var n=cl(t);return n.invert=cl(-t),n}function sl(t,n){var e=Tf(t),r=Cf(t),i=Tf(n),o=Cf(n);function a(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*e+u*r;return[Mf(c*i-s*o,u*e-f*r),Rf(s*i+c*o)]}return a.invert=function(t,n){var a=Tf(n),u=Tf(t)*a,c=Cf(t)*a,f=Cf(n),s=f*i-c*o;return[Mf(c*i+f*o,u*e+s*r),Rf(s*e-u*r)]},a}function ll(t){function n(n){return(n=t(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n}return t=ul(t[0]*mf,t[1]*mf,t.length>2?t[2]*mf:0),n.invert=function(n){return(n=t.invert(n[0]*mf,n[1]*mf))[0]*=bf,n[1]*=bf,n},n}function hl(t,n,e,r,i,o){if(e){var a=Tf(n),u=Cf(n),c=r*e;null==i?(i=n+r*_f,o=n-c/2):(i=dl(a,i),o=dl(a,o),(r>0?io)&&(i+=r*_f));for(var f,s=i;r>0?s>o:s1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function gl(t,n){return xf(t[0]-n[0])=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function _l(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r=0?1:-1,E=S*A,N=E>gf,k=y*w;if(c.add(Mf(k*S*Cf(E),v*M+k*Tf(E))),a+=N?A+S*_f:A,N^p>=e^m>=e){var C=ys(ps(d),ps(b));bs(C);var P=ys(o,C);bs(P);var z=(N^A>=0?-1:1)*Rf(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=N^A>=0?1:-1)}}return(a<-df||a0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(wl))}return h}}function wl(t){return t.length>1}function Ml(t,n){return((t=t.x)[0]<0?t[1]-yf-df:yf-t[1])-((n=n.x)[0]<0?n[1]-yf-df:yf-n[1])}al.invert=al;var Tl=xl((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?gf:-gf,c=xf(o-e);xf(c-gf)0?yf:-yf),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=gf&&(xf(e-i)df?wf((Cf(n)*(o=Tf(r))*Cf(e)-Cf(r)*(i=Tf(n))*Cf(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*yf,r.point(-gf,i),r.point(0,i),r.point(gf,i),r.point(gf,0),r.point(gf,-i),r.point(0,-i),r.point(-gf,-i),r.point(-gf,0),r.point(-gf,i);else if(xf(t[0]-n[0])>df){var o=t[0]0,i=xf(n)>df;function o(t,e){return Tf(t)*Tf(e)>n}function a(t,e,r){var i=[1,0,0],o=ys(ps(t),ps(e)),a=gs(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=ys(i,o),h=_s(i,f);vs(h,_s(o,s));var d=l,p=gs(h,d),g=gs(d,d),y=p*p-g*(gs(h,h)-1);if(!(y<0)){var v=zf(y),_=_s(d,(-p-v)/g);if(vs(_,h),_=ds(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x0^_[1]<(xf(_[0]-m)gf^(m<=_[0]&&_[0]<=x)){var S=_s(d,(-p+v)/g);return vs(S,h),[_,ds(S)]}}}function u(n,e){var i=r?t:gf-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return xl(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?gf:-gf),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||gl(n,d)||gl(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&gl(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){hl(o,t,e,i,n,r)}),r?[0,-t]:[-gf,t-gf])}var Sl,El,Nl,kl,Cl=1e9,Pl=-Cl;function zl(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return xf(r[0]-t)0?0:3:xf(r[0]-e)0?2:1:xf(r[1]-n)0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=pl(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;er&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=ft(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&vl(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(Pl,Math.min(Cl,p)),g=Math.max(Pl,Math.min(Cl,g))],m=[o=Math.max(Pl,Math.min(Cl,o)),a=Math.max(Pl,Math.min(Cl,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a0)){if(a/=h,h<0){if(a0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var $l={sphere:qf,point:qf,lineStart:function(){$l.point=Rl,$l.lineEnd=Dl},lineEnd:qf,polygonStart:qf,polygonEnd:qf};function Dl(){$l.point=$l.lineEnd=qf}function Rl(t,n){El=t*=mf,Nl=Cf(n*=mf),kl=Tf(n),$l.point=Fl}function Fl(t,n){t*=mf;var e=Cf(n*=mf),r=Tf(n),i=xf(t-El),o=Tf(i),a=r*Cf(i),u=kl*e-Nl*r*o,c=Nl*e+kl*r*o;Sl.add(Mf(zf(a*a+u*u),c)),El=t,Nl=e,kl=r}function ql(t){return Sl=new T,Lf(t,$l),+Sl}var Ul=[null,null],Il={type:"LineString",coordinates:Ul};function Ol(t,n){return Ul[0]=t,Ul[1]=n,ql(Il)}var Bl={Feature:function(t,n){return Ll(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r0&&(i=Ol(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))df})).map(c)).concat(lt(Af(o/d)*d,i,d).filter((function(t){return xf(t%g)>df})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Wl(o,i,90),f=Zl(n,t,y),s=Wl(u,a,90),l=Zl(r,e,y),v):y},v.extentMajor([[-180,-90+df],[180,90-df]]).extentMinor([[-180,-80-df],[180,80+df]])}var Ql,Jl,th,nh,eh=t=>t,rh=new T,ih=new T,oh={point:qf,lineStart:qf,lineEnd:qf,polygonStart:function(){oh.lineStart=ah,oh.lineEnd=fh},polygonEnd:function(){oh.lineStart=oh.lineEnd=oh.point=qf,rh.add(xf(ih)),ih=new T},result:function(){var t=rh/2;return rh=new T,t}};function ah(){oh.point=uh}function uh(t,n){oh.point=ch,Ql=th=t,Jl=nh=n}function ch(t,n){ih.add(nh*t-th*n),th=t,nh=n}function fh(){ch(Ql,Jl)}var sh=oh,lh=1/0,hh=lh,dh=-lh,ph=dh,gh={point:function(t,n){tdh&&(dh=t);nph&&(ph=n)},lineStart:qf,lineEnd:qf,polygonStart:qf,polygonEnd:qf,result:function(){var t=[[lh,hh],[dh,ph]];return dh=ph=-(hh=lh=1/0),t}};var yh,vh,_h,bh,mh=gh,xh=0,wh=0,Mh=0,Th=0,Ah=0,Sh=0,Eh=0,Nh=0,kh=0,Ch={point:Ph,lineStart:zh,lineEnd:Rh,polygonStart:function(){Ch.lineStart=Fh,Ch.lineEnd=qh},polygonEnd:function(){Ch.point=Ph,Ch.lineStart=zh,Ch.lineEnd=Rh},result:function(){var t=kh?[Eh/kh,Nh/kh]:Sh?[Th/Sh,Ah/Sh]:Mh?[xh/Mh,wh/Mh]:[NaN,NaN];return xh=wh=Mh=Th=Ah=Sh=Eh=Nh=kh=0,t}};function Ph(t,n){xh+=t,wh+=n,++Mh}function zh(){Ch.point=$h}function $h(t,n){Ch.point=Dh,Ph(_h=t,bh=n)}function Dh(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Ph(_h=t,bh=n)}function Rh(){Ch.point=Ph}function Fh(){Ch.point=Uh}function qh(){Ih(yh,vh)}function Uh(t,n){Ch.point=Ih,Ph(yh=_h=t,vh=bh=n)}function Ih(t,n){var e=t-_h,r=n-bh,i=zf(e*e+r*r);Th+=i*(_h+t)/2,Ah+=i*(bh+n)/2,Sh+=i,Eh+=(i=bh*t-_h*n)*(_h+t),Nh+=i*(bh+n),kh+=3*i,Ph(_h=t,bh=n)}var Oh=Ch;function Bh(t){this._context=t}Bh.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,_f)}},result:qf};var Yh,Lh,jh,Hh,Xh,Gh=new T,Vh={point:qf,lineStart:function(){Vh.point=Wh},lineEnd:function(){Yh&&Zh(Lh,jh),Vh.point=qf},polygonStart:function(){Yh=!0},polygonEnd:function(){Yh=null},result:function(){var t=+Gh;return Gh=new T,t}};function Wh(t,n){Vh.point=Zh,Lh=Hh=t,jh=Xh=n}function Zh(t,n){Hh-=t,Xh-=n,Gh.add(zf(Hh*Hh+Xh*Xh)),Hh=t,Xh=n}var Kh=Vh;let Qh,Jh,td,nd;class ed{constructor(t){this._append=null==t?rd:function(t){const n=Math.floor(t);if(!(n>=0))throw new RangeError(`invalid digits: ${t}`);if(n>15)return rd;if(n!==Qh){const t=10**n;Qh=n,Jh=function(n){let e=1;this._+=n[0];for(const r=n.length;e4*n&&g--){var m=a+h,x=u+d,w=c+p,M=zf(m*m+x*x+w*w),T=Rf(w/=M),A=xf(xf(w)-1)n||xf((v*k+_*C)/b-.5)>.3||a*h+u*d+c*p2?t[2]%360*mf:0,k()):[y*bf,v*bf,_*bf]},E.angle=function(t){return arguments.length?(b=t%360*mf,k()):b*bf},E.reflectX=function(t){return arguments.length?(m=t?-1:1,k()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,k()):x<0},E.precision=function(t){return arguments.length?(a=dd(u,S=t*t),C()):zf(S)},E.fitExtent=function(t,n){return ud(E,t,n)},E.fitSize=function(t,n){return cd(E,t,n)},E.fitWidth=function(t,n){return fd(E,t,n)},E.fitHeight=function(t,n){return sd(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&N,k()}}function _d(t){var n=0,e=gf/3,r=vd(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*mf,e=t[1]*mf):[n*bf,e*bf]},i}function bd(t,n){var e=Cf(t),r=(e+Cf(n))/2;if(xf(r)0?n<-yf+df&&(n=-yf+df):n>yf-df&&(n=yf-df);var e=i/kf(Nd(n),r);return[e*Cf(r*t),i-e*Tf(r*t)]}return o.invert=function(t,n){var e=i-n,o=Pf(r)*zf(t*t+e*e),a=Mf(t,xf(e))*Pf(e);return e*r<0&&(a-=gf*Pf(t)*Pf(e)),[a/r,2*wf(kf(i/o,1/r))-yf]},o}function Cd(t,n){return[t,n]}function Pd(t,n){var e=Tf(t),r=t===n?Cf(t):(e-Tf(n))/(n-t),i=e/r+t;if(xf(r)=0;)n+=e[r].value;else n=1;t.value=n}function Gd(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Wd)):void 0===n&&(n=Vd);for(var e,r,i,o,a,u=new Qd(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Qd(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Kd)}function Vd(t){return t.children}function Wd(t){return Array.isArray(t)?t[1]:null}function Zd(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Kd(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Qd(t){this.data=t,this.depth=this.height=0,this.parent=null}function Jd(t){return null==t?null:tp(t)}function tp(t){if("function"!=typeof t)throw new Error;return t}function np(){return 0}function ep(t){return function(){return t}}qd.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(zd+$d*i+o*(Dd+Rd*i))-n)/(zd+3*$d*i+o*(7*Dd+9*Rd*i)))*r)*i*i,!(xf(e)df&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},Od.invert=Md(Rf),Bd.invert=Md((function(t){return 2*wf(t)})),Yd.invert=function(t,n){return[-n,2*wf(Sf(t))-yf]},Qd.prototype=Gd.prototype={constructor:Qd,count:function(){return this.eachAfter(Xd)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Gd(this).eachBefore(Zd)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e(t=(rp*t+ip)%op)/op}function up(t,n){for(var e,r,i=0,o=(t=function(t,n){let e,r,i=t.length;for(;i;)r=n()*i--|0,e=t[i],t[i]=t[r],t[r]=e;return t}(Array.from(t),n)).length,a=[];i0&&e*e>r*r+i*i}function lp(t,n){for(var e=0;e1e-6?(E+Math.sqrt(E*E-4*S*N))/(2*S):N/E);return{x:r+w+M*k,y:i+T+A*k,r:k}}function gp(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function yp(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function vp(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function _p(t){this._=t,this.next=null,this.previous=null}function bp(t,n){if(!(o=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var e,r,i,o,a,u,c,f,s,l,h;if((e=t[0]).x=0,e.y=0,!(o>1))return e.r;if(r=t[1],e.x=-r.r,r.x=e.r,r.y=0,!(o>2))return e.r+r.r;gp(r,e,i=t[2]),e=new _p(e),r=new _p(r),i=new _p(i),e.next=i.previous=r,r.next=e.previous=i,i.next=r.previous=e;t:for(c=3;c1&&!zp(t,n););return t.slice(0,n)}function zp(t,n){if("/"===t[n]){let e=0;for(;n>0&&"\\"===t[--n];)++e;if(!(1&e))return!0}return!1}function $p(t,n){return t.parent===n.parent?1:2}function Dp(t){var n=t.children;return n?n[0]:t.t}function Rp(t){var n=t.children;return n?n[n.length-1]:t.t}function Fp(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qp(t,n,e){return t.a.parent===n.parent?t.a:e}function Up(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Ip(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++uh&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c1?n:1)},e}(Op);var Lp=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l1?n:1)},e}(Op);function jp(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function Hp(t,n){return t[0]-n[0]||t[1]-n[1]}function Xp(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r1&&jp(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var Gp=Math.random,Vp=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Gp),Wp=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(Gp),Zp=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Gp),Kp=function t(n){var e=Zp.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(Gp),Qp=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(Gp),Jp=function t(n){var e=Qp.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(Gp),tg=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(Gp),ng=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(Gp),eg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(Gp),rg=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(Gp),ig=function t(n){var e=Zp.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(Gp),og=function t(n){var e=ig.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(Gp),ag=function t(n){var e=rg.source(n),r=og.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(Gp),ug=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(Gp),cg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(Gp),fg=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(Gp),sg=function t(n){var e=ig.source(n),r=ag.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(Gp);const lg=1/4294967296;function hg(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function dg(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const pg=Symbol("implicit");function gg(){var t=new InternMap,n=[],e=[],r=pg;function i(i){let o=t.get(i);if(void 0===o){if(r!==pg)return r;t.set(i,o=n.push(i)-1)}return e[o%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new InternMap;for(const r of e)t.has(r)||t.set(r,n.push(r)-1);return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return gg(n,e).unknown(r)},hg.apply(i,arguments),i}function yg(){var t,n,e=gg().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=an&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?Mg:wg,i=o=null,l}function l(n){return null==n||isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),Yr)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,_g),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=Vr,s()},l.clamp=function(t){return arguments.length?(f=!!t||mg,s()):f!==mg},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Sg(){return Ag()(mg,mg)}function Eg(n,e,r,i){var o,a=W(n,e,r);switch((i=Jc(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=lf(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=hf(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=sf(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function Ng(t){var n=t.domain;return t.ticks=function(t){var e=n();return G(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Eg(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f0;){if((i=V(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function kg(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a-t(-n,e)}function Fg(n){const e=n(Cg,Pg),r=e.domain;let i,o,a=10;function u(){return i=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),n=>Math.log(n)/t)}(a),o=function(t){return 10===t?Dg:t===Math.E?Math.exp:n=>Math.pow(t,n)}(a),r()[0]<0?(i=Rg(i),o=Rg(o),n(zg,$g)):n(Cg,Pg),e}return e.base=function(t){return arguments.length?(a=+t,u()):a},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=t=>{const n=r();let e=n[0],u=n[n.length-1];const c=u0){for(;l<=h;++l)for(f=1;fu)break;p.push(s)}}else for(;l<=h;++l)for(f=a-1;f>=1;--f)if(s=l>0?f/o(-l):f*o(l),!(su)break;p.push(s)}2*p.length{if(null==n&&(n=10),null==r&&(r=10===a?"s":","),"function"!=typeof r&&(a%1||null!=(r=Jc(r)).precision||(r.trim=!0),r=t.format(r)),n===1/0)return r;const u=Math.max(1,a*n/e.ticks().length);return t=>{let n=t/o(Math.round(i(t)));return n*ar(kg(r(),{floor:t=>o(Math.floor(i(t))),ceil:t=>o(Math.ceil(i(t)))})),e}function qg(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function Ug(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function Ig(t){var n=1,e=t(qg(n),Ug(n));return e.constant=function(e){return arguments.length?t(qg(n=+e),Ug(n)):n},Ng(e)}function Og(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function Bg(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function Yg(t){return t<0?-t*t:t*t}function Lg(t){var n=t(mg,mg),e=1;return n.exponent=function(n){return arguments.length?1===(e=+n)?t(mg,mg):.5===e?t(Bg,Yg):t(Og(e),Og(1/e)):e},Ng(n)}function jg(){var t=Lg(Ag());return t.copy=function(){return Tg(t,jg()).exponent(t.exponent())},hg.apply(t,arguments),t}function Hg(t){return Math.sign(t)*t*t}const Xg=new Date,Gg=new Date;function Vg(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=n=>(t(n=new Date(+n)),n),i.ceil=e=>(t(e=new Date(e-1)),n(e,1),t(e),e),i.round=t=>{const n=i(t),e=i.ceil(t);return t-n(n(t=new Date(+t),null==e?1:Math.floor(e)),t),i.range=(e,r,o)=>{const a=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e0))return a;let u;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(uVg((n=>{if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),((t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})),e&&(i.count=(n,r)=>(Xg.setTime(+n),Gg.setTime(+r),t(Xg),t(Gg),Math.floor(e(Xg,Gg))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?n=>r(n)%t==0:n=>i.count(0,n)%t==0):i:null)),i}const Wg=Vg((()=>{}),((t,n)=>{t.setTime(+t+n)}),((t,n)=>n-t));Wg.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?Vg((n=>{n.setTime(Math.floor(n/t)*t)}),((n,e)=>{n.setTime(+n+e*t)}),((n,e)=>(e-n)/t)):Wg:null);const Zg=Wg.range,Kg=1e3,Qg=6e4,Jg=36e5,ty=864e5,ny=6048e5,ey=2592e6,ry=31536e6,iy=Vg((t=>{t.setTime(t-t.getMilliseconds())}),((t,n)=>{t.setTime(+t+n*Kg)}),((t,n)=>(n-t)/Kg),(t=>t.getUTCSeconds())),oy=iy.range,ay=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getMinutes())),uy=ay.range,cy=Vg((t=>{t.setUTCSeconds(0,0)}),((t,n)=>{t.setTime(+t+n*Qg)}),((t,n)=>(n-t)/Qg),(t=>t.getUTCMinutes())),fy=cy.range,sy=Vg((t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Kg-t.getMinutes()*Qg)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getHours())),ly=sy.range,hy=Vg((t=>{t.setUTCMinutes(0,0,0)}),((t,n)=>{t.setTime(+t+n*Jg)}),((t,n)=>(n-t)/Jg),(t=>t.getUTCHours())),dy=hy.range,py=Vg((t=>t.setHours(0,0,0,0)),((t,n)=>t.setDate(t.getDate()+n)),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ty),(t=>t.getDate()-1)),gy=py.range,yy=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>t.getUTCDate()-1)),vy=yy.range,_y=Vg((t=>{t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+n)}),((t,n)=>(n-t)/ty),(t=>Math.floor(t/ty))),by=_y.range;function my(t){return Vg((n=>{n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),((t,n)=>{t.setDate(t.getDate()+7*n)}),((t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Qg)/ny))}const xy=my(0),wy=my(1),My=my(2),Ty=my(3),Ay=my(4),Sy=my(5),Ey=my(6),Ny=xy.range,ky=wy.range,Cy=My.range,Py=Ty.range,zy=Ay.range,$y=Sy.range,Dy=Ey.range;function Ry(t){return Vg((n=>{n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCDate(t.getUTCDate()+7*n)}),((t,n)=>(n-t)/ny))}const Fy=Ry(0),qy=Ry(1),Uy=Ry(2),Iy=Ry(3),Oy=Ry(4),By=Ry(5),Yy=Ry(6),Ly=Fy.range,jy=qy.range,Hy=Uy.range,Xy=Iy.range,Gy=Oy.range,Vy=By.range,Wy=Yy.range,Zy=Vg((t=>{t.setDate(1),t.setHours(0,0,0,0)}),((t,n)=>{t.setMonth(t.getMonth()+n)}),((t,n)=>n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())),(t=>t.getMonth())),Ky=Zy.range,Qy=Vg((t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCMonth(t.getUTCMonth()+n)}),((t,n)=>n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())),(t=>t.getUTCMonth())),Jy=Qy.range,tv=Vg((t=>{t.setMonth(0,1),t.setHours(0,0,0,0)}),((t,n)=>{t.setFullYear(t.getFullYear()+n)}),((t,n)=>n.getFullYear()-t.getFullYear()),(t=>t.getFullYear()));tv.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),((n,e)=>{n.setFullYear(n.getFullYear()+e*t)})):null;const nv=tv.range,ev=Vg((t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),((t,n)=>{t.setUTCFullYear(t.getUTCFullYear()+n)}),((t,n)=>n.getUTCFullYear()-t.getUTCFullYear()),(t=>t.getUTCFullYear()));ev.every=t=>isFinite(t=Math.floor(t))&&t>0?Vg((n=>{n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),((n,e)=>{n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null;const rv=ev.range;function iv(t,n,e,i,o,a){const u=[[iy,1,Kg],[iy,5,5e3],[iy,15,15e3],[iy,30,3e4],[a,1,Qg],[a,5,3e5],[a,15,9e5],[a,30,18e5],[o,1,Jg],[o,3,108e5],[o,6,216e5],[o,12,432e5],[i,1,ty],[i,2,1728e5],[e,1,ny],[n,1,ey],[n,3,7776e6],[t,1,ry]];function c(n,e,i){const o=Math.abs(e-n)/i,a=r((([,,t])=>t)).right(u,o);if(a===u.length)return t.every(W(n/ry,e/ry,i));if(0===a)return Wg.every(Math.max(W(n,e,i),1));const[c,f]=u[o/u[a-1][2]=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:k_,s:C_,S:Zv,u:Kv,U:Qv,V:t_,w:n_,W:e_,x:null,X:null,y:r_,Y:o_,Z:u_,"%":N_},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:c_,e:c_,f:d_,g:T_,G:S_,H:f_,I:s_,j:l_,L:h_,m:p_,M:g_,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:k_,s:C_,S:y_,u:v_,U:__,V:m_,w:x_,W:w_,x:null,X:null,y:M_,Y:A_,Z:E_,"%":N_},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return T(t,n,e,r)},d:zv,e:zv,f:Uv,g:Nv,G:Ev,H:Dv,I:Dv,j:$v,L:qv,m:Pv,M:Rv,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:Cv,Q:Ov,s:Bv,S:Fv,u:Mv,U:Tv,V:Av,w:wv,W:Sv,x:function(t,n,r){return T(t,e,n,r)},X:function(t,n,e){return T(t,r,n,e)},y:Nv,Y:Ev,Z:kv,"%":Iv};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=sv(lv(o.y,0,1))).getUTCDay(),r=i>4||0===i?qy.ceil(r):qy(r),r=yy.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=fv(lv(o.y,0,1))).getDay(),r=i>4||0===i?wy.ceil(r):wy(r),r=py.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?sv(lv(o.y,0,1)).getUTCDay():fv(lv(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,sv(o)):fv(o)}}function T(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in pv?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var dv,pv={"-":"",_:" ",0:"0"},gv=/^\s*\d+/,yv=/^%/,vv=/[\\^$*+?|[\]().{}]/g;function _v(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o[t.toLowerCase(),n])))}function wv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Mv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Tv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Av(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Sv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Ev(t,n,e){var r=gv.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Nv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function kv(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Cv(t,n,e){var r=gv.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function Pv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function zv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function $v(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Dv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Rv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Fv(t,n,e){var r=gv.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function qv(t,n,e){var r=gv.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Uv(t,n,e){var r=gv.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Iv(t,n,e){var r=yv.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Ov(t,n,e){var r=gv.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Bv(t,n,e){var r=gv.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Yv(t,n){return _v(t.getDate(),n,2)}function Lv(t,n){return _v(t.getHours(),n,2)}function jv(t,n){return _v(t.getHours()%12||12,n,2)}function Hv(t,n){return _v(1+py.count(tv(t),t),n,3)}function Xv(t,n){return _v(t.getMilliseconds(),n,3)}function Gv(t,n){return Xv(t,n)+"000"}function Vv(t,n){return _v(t.getMonth()+1,n,2)}function Wv(t,n){return _v(t.getMinutes(),n,2)}function Zv(t,n){return _v(t.getSeconds(),n,2)}function Kv(t){var n=t.getDay();return 0===n?7:n}function Qv(t,n){return _v(xy.count(tv(t)-1,t),n,2)}function Jv(t){var n=t.getDay();return n>=4||0===n?Ay(t):Ay.ceil(t)}function t_(t,n){return t=Jv(t),_v(Ay.count(tv(t),t)+(4===tv(t).getDay()),n,2)}function n_(t){return t.getDay()}function e_(t,n){return _v(wy.count(tv(t)-1,t),n,2)}function r_(t,n){return _v(t.getFullYear()%100,n,2)}function i_(t,n){return _v((t=Jv(t)).getFullYear()%100,n,2)}function o_(t,n){return _v(t.getFullYear()%1e4,n,4)}function a_(t,n){var e=t.getDay();return _v((t=e>=4||0===e?Ay(t):Ay.ceil(t)).getFullYear()%1e4,n,4)}function u_(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+_v(n/60|0,"0",2)+_v(n%60,"0",2)}function c_(t,n){return _v(t.getUTCDate(),n,2)}function f_(t,n){return _v(t.getUTCHours(),n,2)}function s_(t,n){return _v(t.getUTCHours()%12||12,n,2)}function l_(t,n){return _v(1+yy.count(ev(t),t),n,3)}function h_(t,n){return _v(t.getUTCMilliseconds(),n,3)}function d_(t,n){return h_(t,n)+"000"}function p_(t,n){return _v(t.getUTCMonth()+1,n,2)}function g_(t,n){return _v(t.getUTCMinutes(),n,2)}function y_(t,n){return _v(t.getUTCSeconds(),n,2)}function v_(t){var n=t.getUTCDay();return 0===n?7:n}function __(t,n){return _v(Fy.count(ev(t)-1,t),n,2)}function b_(t){var n=t.getUTCDay();return n>=4||0===n?Oy(t):Oy.ceil(t)}function m_(t,n){return t=b_(t),_v(Oy.count(ev(t),t)+(4===ev(t).getUTCDay()),n,2)}function x_(t){return t.getUTCDay()}function w_(t,n){return _v(qy.count(ev(t)-1,t),n,2)}function M_(t,n){return _v(t.getUTCFullYear()%100,n,2)}function T_(t,n){return _v((t=b_(t)).getUTCFullYear()%100,n,2)}function A_(t,n){return _v(t.getUTCFullYear()%1e4,n,4)}function S_(t,n){var e=t.getUTCDay();return _v((t=e>=4||0===e?Oy(t):Oy.ceil(t)).getUTCFullYear()%1e4,n,4)}function E_(){return"+0000"}function N_(){return"%"}function k_(t){return+t}function C_(t){return Math.floor(+t/1e3)}function P_(n){return dv=hv(n),t.timeFormat=dv.format,t.timeParse=dv.parse,t.utcFormat=dv.utcFormat,t.utcParse=dv.utcParse,dv}t.timeFormat=void 0,t.timeParse=void 0,t.utcFormat=void 0,t.utcParse=void 0,P_({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var z_="%Y-%m-%dT%H:%M:%S.%LZ";var $_=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat(z_),D_=$_;var R_=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse(z_),F_=R_;function q_(t){return new Date(t)}function U_(t){return t instanceof Date?+t:+new Date(+t)}function I_(t,n,e,r,i,o,a,u,c,f){var s=Sg(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y");function x(t){return(c(t)Fr(t[t.length-1]),ib=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(H_),ob=rb(ib),ab=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(H_),ub=rb(ab),cb=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(H_),fb=rb(cb),sb=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(H_),lb=rb(sb),hb=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(H_),db=rb(hb),pb=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(H_),gb=rb(pb),yb=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(H_),vb=rb(yb),_b=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(H_),bb=rb(_b),mb=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(H_),xb=rb(mb),wb=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(H_),Mb=rb(wb),Tb=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(H_),Ab=rb(Tb),Sb=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(H_),Eb=rb(Sb),Nb=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(H_),kb=rb(Nb),Cb=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(H_),Pb=rb(Cb),zb=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(H_),$b=rb(zb),Db=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(H_),Rb=rb(Db),Fb=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(H_),qb=rb(Fb),Ub=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(H_),Ib=rb(Ub),Ob=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(H_),Bb=rb(Ob),Yb=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(H_),Lb=rb(Yb),jb=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(H_),Hb=rb(jb),Xb=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(H_),Gb=rb(Xb),Vb=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(H_),Wb=rb(Vb),Zb=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(H_),Kb=rb(Zb),Qb=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(H_),Jb=rb(Qb),tm=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(H_),nm=rb(tm),em=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(H_),rm=rb(em);var im=hi(Tr(300,.5,0),Tr(-240,.5,1)),om=hi(Tr(-100,.75,.35),Tr(80,1.5,.8)),am=hi(Tr(260,.75,.35),Tr(80,1.5,.8)),um=Tr();var cm=Fe(),fm=Math.PI/3,sm=2*Math.PI/3;function lm(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var hm=lm(H_("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),dm=lm(H_("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),pm=lm(H_("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),gm=lm(H_("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function ym(t){return function(){return t}}const vm=Math.abs,_m=Math.atan2,bm=Math.cos,mm=Math.max,xm=Math.min,wm=Math.sin,Mm=Math.sqrt,Tm=1e-12,Am=Math.PI,Sm=Am/2,Em=2*Am;function Nm(t){return t>=1?Sm:t<=-1?-Sm:Math.asin(t)}function km(t){let n=3;return t.digits=function(e){if(!arguments.length)return n;if(null==e)n=null;else{const t=Math.floor(e);if(!(t>=0))throw new RangeError(`invalid digits: ${e}`);n=t}return t},()=>new Ua(n)}function Cm(t){return t.innerRadius}function Pm(t){return t.outerRadius}function zm(t){return t.startAngle}function $m(t){return t.endAngle}function Dm(t){return t&&t.padAngle}function Rm(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/Mm(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*Mm(mm(0,x*x*m-w*w)),T=(w*b-_*M)/m,A=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,N=T-y,k=A-v,C=S-y,P=E-v;return N*N+k*k>C*C+P*P&&(T=S,A=E),{cx:T,cy:A,x01:-s,y01:-l,x11:T*(i/x-1),y11:A*(i/x-1)}}var Fm=Array.prototype.slice;function qm(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function Um(t){this._context=t}function Im(t){return new Um(t)}function Om(t){return t[0]}function Bm(t){return t[1]}function Ym(t,n){var e=ym(!0),r=null,i=Im,o=null,a=km(u);function u(u){var c,f,s,l=(u=qm(u)).length,h=!1;for(null==r&&(o=i(s=a())),c=0;c<=l;++c)!(c=l;--h)u.point(v[h],_[h]);u.lineEnd(),u.areaEnd()}y&&(v[s]=+t(d,s,f),_[s]=+n(d,s,f),u.point(r?+r(d,s,f):v[s],e?+e(d,s,f):_[s]))}if(p)return u=null,p+""||null}function s(){return Ym().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Om:ym(+t),n="function"==typeof n?n:ym(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?Bm:ym(+e),f.x=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),r=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),f):t},f.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ym(+t),f):r},f.y=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),e=null,f):n},f.y0=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),f):n},f.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:ym(+t),f):e},f.lineX0=f.lineY0=function(){return s().x(t).y(n)},f.lineY1=function(){return s().x(t).y(e)},f.lineX1=function(){return s().x(r).y(n)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:ym(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function jm(t,n){return nt?1:n>=t?0:NaN}function Hm(t){return t}Um.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Xm=Vm(Im);function Gm(t){this._curve=t}function Vm(t){function n(n){return new Gm(t(n))}return n._curve=t,n}function Wm(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Zm(){return Wm(Ym().curve(Xm))}function Km(){var t=Lm().curve(Xm),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Wm(e())},delete t.lineX0,t.lineEndAngle=function(){return Wm(r())},delete t.lineX1,t.lineInnerRadius=function(){return Wm(i())},delete t.lineY0,t.lineOuterRadius=function(){return Wm(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Vm(t)):n()._curve},t}function Qm(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Gm.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class Jm{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class tx{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0===this._point)this._point=1;else{const e=Qm(this._x0,this._y0),r=Qm(this._x0,this._y0=(this._y0+n)/2),i=Qm(t,this._y0),o=Qm(t,n);this._context.moveTo(...e),this._context.bezierCurveTo(...r,...i,...o)}this._x0=t,this._y0=n}}function nx(t){return new Jm(t,!0)}function ex(t){return new Jm(t,!1)}function rx(t){return new tx(t)}function ix(t){return t.source}function ox(t){return t.target}function ax(t){let n=ix,e=ox,r=Om,i=Bm,o=null,a=null,u=km(c);function c(){let c;const f=Fm.call(arguments),s=n.apply(this,f),l=e.apply(this,f);if(null==o&&(a=t(c=u())),a.lineStart(),f[0]=s,a.point(+r.apply(this,f),+i.apply(this,f)),f[0]=l,a.point(+r.apply(this,f),+i.apply(this,f)),a.lineEnd(),c)return a=null,c+""||null}return c.source=function(t){return arguments.length?(n=t,c):n},c.target=function(t){return arguments.length?(e=t,c):e},c.x=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),c):r},c.y=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),c):i},c.context=function(n){return arguments.length?(null==n?o=a=null:a=t(o=n),c):o},c}const ux=Mm(3);var cx={draw(t,n){const e=.59436*Mm(n+xm(n/28,.75)),r=e/2,i=r*ux;t.moveTo(0,e),t.lineTo(0,-e),t.moveTo(-i,-r),t.lineTo(i,r),t.moveTo(-i,r),t.lineTo(i,-r)}},fx={draw(t,n){const e=Mm(n/Am);t.moveTo(e,0),t.arc(0,0,e,0,Em)}},sx={draw(t,n){const e=Mm(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}};const lx=Mm(1/3),hx=2*lx;var dx={draw(t,n){const e=Mm(n/hx),r=e*lx;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},px={draw(t,n){const e=.62625*Mm(n);t.moveTo(0,-e),t.lineTo(e,0),t.lineTo(0,e),t.lineTo(-e,0),t.closePath()}},gx={draw(t,n){const e=.87559*Mm(n-xm(n/7,2));t.moveTo(-e,0),t.lineTo(e,0),t.moveTo(0,e),t.lineTo(0,-e)}},yx={draw(t,n){const e=Mm(n),r=-e/2;t.rect(r,r,e,e)}},vx={draw(t,n){const e=.4431*Mm(n);t.moveTo(e,e),t.lineTo(e,-e),t.lineTo(-e,-e),t.lineTo(-e,e),t.closePath()}};const _x=wm(Am/10)/wm(7*Am/10),bx=wm(Em/10)*_x,mx=-bm(Em/10)*_x;var xx={draw(t,n){const e=Mm(.8908130915292852*n),r=bx*e,i=mx*e;t.moveTo(0,-e),t.lineTo(r,i);for(let n=1;n<5;++n){const o=Em*n/5,a=bm(o),u=wm(o);t.lineTo(u*e,-a*e),t.lineTo(a*r-u*i,u*r+a*i)}t.closePath()}};const wx=Mm(3);var Mx={draw(t,n){const e=-Mm(n/(3*wx));t.moveTo(0,2*e),t.lineTo(-wx*e,-e),t.lineTo(wx*e,-e),t.closePath()}};const Tx=Mm(3);var Ax={draw(t,n){const e=.6824*Mm(n),r=e/2,i=e*Tx/2;t.moveTo(0,-e),t.lineTo(i,r),t.lineTo(-i,r),t.closePath()}};const Sx=-.5,Ex=Mm(3)/2,Nx=1/Mm(12),kx=3*(Nx/2+1);var Cx={draw(t,n){const e=Mm(n/kx),r=e/2,i=e*Nx,o=r,a=e*Nx+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(Sx*r-Ex*i,Ex*r+Sx*i),t.lineTo(Sx*o-Ex*a,Ex*o+Sx*a),t.lineTo(Sx*u-Ex*c,Ex*u+Sx*c),t.lineTo(Sx*r+Ex*i,Sx*i-Ex*r),t.lineTo(Sx*o+Ex*a,Sx*a-Ex*o),t.lineTo(Sx*u+Ex*c,Sx*c-Ex*u),t.closePath()}},Px={draw(t,n){const e=.6189*Mm(n-xm(n/6,1.7));t.moveTo(-e,-e),t.lineTo(e,e),t.moveTo(-e,e),t.lineTo(e,-e)}};const zx=[fx,sx,dx,yx,xx,Mx,Cx],$x=[fx,gx,Px,Ax,cx,vx,px];function Dx(){}function Rx(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Fx(t){this._context=t}function qx(t){this._context=t}function Ux(t){this._context=t}function Ix(t,n){this._basis=new Fx(t),this._beta=n}Fx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Rx(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},qx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ux.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Rx(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Ix.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Ox=function t(n){function e(t){return 1===n?new Fx(t):new Ix(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function Bx(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Yx(t,n){this._context=t,this._k=(1-n)/6}Yx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Bx(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Lx=function t(n){function e(t){return new Yx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function jx(t,n){this._context=t,this._k=(1-n)/6}jx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Hx=function t(n){function e(t){return new jx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Xx(t,n){this._context=t,this._k=(1-n)/6}Xx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Bx(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gx=function t(n){function e(t){return new Xx(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Vx(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Tm){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>Tm){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Wx(t,n){this._context=t,this._alpha=n}Wx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zx=function t(n){function e(t){return n?new Wx(t,n):new Yx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Kx(t,n){this._context=t,this._alpha=n}Kx.prototype={areaStart:Dx,areaEnd:Dx,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Qx=function t(n){function e(t){return n?new Kx(t,n):new jx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Jx(t,n){this._context=t,this._alpha=n}Jx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Vx(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var tw=function t(n){function e(t){return n?new Jx(t,n):new Xx(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function nw(t){this._context=t}function ew(t){return t<0?-1:1}function rw(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(ew(o)+ew(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function iw(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function ow(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function aw(t){this._context=t}function uw(t){this._context=new cw(t)}function cw(t){this._context=t}function fw(t){this._context=t}function sw(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o=0;)e[n]=n;return e}function pw(t,n){return t[n]}function gw(t){const n=[];return n.key=t,n}function yw(t){var n=t.map(vw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function vw(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++eo&&(o=n,r=e);return r}function _w(t){var n=t.map(bw);return dw(t).sort((function(t,e){return n[t]-n[e]}))}function bw(t){for(var n,e=0,r=-1,i=t.length;++r=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var mw=t=>()=>t;function xw(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function ww(t,n,e){this.k=t,this.x=n,this.y=e}ww.prototype={constructor:ww,scale:function(t){return 1===t?this:new ww(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ww(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Mw=new ww(1,0,0);function Tw(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Mw;return t.__zoom}function Aw(t){t.stopImmediatePropagation()}function Sw(t){t.preventDefault(),t.stopImmediatePropagation()}function Ew(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Nw(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function kw(){return this.__zoom||Mw}function Cw(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Pw(){return navigator.maxTouchPoints||"ontouchstart"in this}function zw(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Tw.prototype=ww.prototype,t.Adder=T,t.Delaunay=Lu,t.FormatSpecifier=tf,t.InternMap=InternMap,t.InternSet=InternSet,t.Node=Qd,t.Path=Ua,t.Voronoi=qu,t.ZoomTransform=ww,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>qi&&e.name===n)return new po([[t]],Zo,n,+r);return null},t.arc=function(){var t=Cm,n=Pm,e=ym(0),r=null,i=zm,o=$m,a=Dm,u=null,c=km(f);function f(){var f,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Sm,p=o.apply(this,arguments)-Sm,g=vm(p-d),y=p>d;if(u||(u=f=c()),hTm)if(g>Em-Tm)u.moveTo(h*bm(d),h*wm(d)),u.arc(0,0,h,d,p,!y),l>Tm&&(u.moveTo(l*bm(p),l*wm(p)),u.arc(0,0,l,p,d,y));else{var v,_,b=d,m=p,x=d,w=p,M=g,T=g,A=a.apply(this,arguments)/2,S=A>Tm&&(r?+r.apply(this,arguments):Mm(l*l+h*h)),E=xm(vm(h-l)/2,+e.apply(this,arguments)),N=E,k=E;if(S>Tm){var C=Nm(S/l*wm(A)),P=Nm(S/h*wm(A));(M-=2*C)>Tm?(x+=C*=y?1:-1,w-=C):(M=0,x=w=(d+p)/2),(T-=2*P)>Tm?(b+=P*=y?1:-1,m-=P):(T=0,b=m=(d+p)/2)}var z=h*bm(b),$=h*wm(b),D=l*bm(w),R=l*wm(w);if(E>Tm){var F,q=h*bm(m),U=h*wm(m),I=l*bm(x),O=l*wm(x);if(g1?0:t<-1?Am:Math.acos(t)}((B*L+Y*j)/(Mm(B*B+Y*Y)*Mm(L*L+j*j)))/2),X=Mm(F[0]*F[0]+F[1]*F[1]);N=xm(E,(l-X)/(H-1)),k=xm(E,(h-X)/(H+1))}else N=k=0}T>Tm?k>Tm?(v=Rm(I,O,z,$,h,k,y),_=Rm(q,U,D,R,h,k,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),kTm&&M>Tm?N>Tm?(v=Rm(D,R,q,U,l,-N,y),_=Rm(z,$,I,O,l,-N,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),N=0))throw new RangeError("invalid r");let e=t.length;if(!((e=Math.floor(e))>=0))throw new RangeError("invalid length");if(!e||!n)return t;const r=y(n),i=t.slice();return r(t,i,0,e,1),r(i,t,0,e,1),r(t,i,0,e,1),t},t.blur2=l,t.blurImage=h,t.brush=function(){return wa(la)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return wa(fa)},t.brushY=function(){return wa(sa)},t.buffer=function(t,n){return fetch(t,n).then(_c)},t.chord=function(){return za(!1,!1)},t.chordDirected=function(){return za(!0,!1)},t.chordTranspose=function(){return za(!1,!0)},t.cluster=function(){var t=Ld,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(jd,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Hd,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=ze,t.contourDensity=function(){var t=fu,n=su,e=lu,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=Qa(20);function h(r){var i=new Float32Array(c*f),s=Math.pow(2,-a),h=-1;for(const o of r){var d=(t(o,++h,r)+u)*s,p=(n(o,h,r)+u)*s,g=+e(o,h,r);if(g&&d>=0&&d=0&&pt*r)))(n).map(((t,n)=>(t.value=+e[n],p(t))))}function p(t){return t.coordinates.forEach(g),t}function g(t){t.forEach(y)}function y(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function _(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,d}return d.contours=function(t){var n=h(t),e=iu().size([c,f]),r=Math.pow(2,2*a),i=t=>{t=+t;var i=p(e.contour(n,t*r));return i.value=t,i};return Object.defineProperty(i,"max",{get:()=>J(n)/r}),i},d.x=function(n){return arguments.length?(t="function"==typeof n?n:Qa(+n),d):t},d.y=function(t){return arguments.length?(n="function"==typeof t?t:Qa(+t),d):n},d.weight=function(t){return arguments.length?(e="function"==typeof t?t:Qa(+t),d):e},d.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,_()},d.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),_()},d.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?Qa(Za.call(t)):Qa(t),d):s},d.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=(Math.sqrt(4*t*t+1)-1)/2,_()},d},t.contours=iu,t.count=v,t.create=function(t){return Zn(Yt(t).call(document.documentElement))},t.creator=Yt,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(m)).map(_),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(b))return o;for(;;){o.push(i.map(((n,e)=>t[e][n])));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=wc,t.csvFormat=rc,t.csvFormatBody=ic,t.csvFormatRow=ac,t.csvFormatRows=oc,t.csvFormatValue=uc,t.csvParse=nc,t.csvParseRows=ec,t.cubehelix=Tr,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new Fx(t)},t.curveBasisClosed=function(t){return new qx(t)},t.curveBasisOpen=function(t){return new Ux(t)},t.curveBumpX=nx,t.curveBumpY=ex,t.curveBundle=Ox,t.curveCardinal=Lx,t.curveCardinalClosed=Hx,t.curveCardinalOpen=Gx,t.curveCatmullRom=Zx,t.curveCatmullRomClosed=Qx,t.curveCatmullRomOpen=tw,t.curveLinear=Im,t.curveLinearClosed=function(t){return new nw(t)},t.curveMonotoneX=function(t){return new aw(t)},t.curveMonotoneY=function(t){return new uw(t)},t.curveNatural=function(t){return new fw(t)},t.curveStep=function(t){return new lw(t,.5)},t.curveStepAfter=function(t){return new lw(t,1)},t.curveStepBefore=function(t){return new lw(t,0)},t.descending=e,t.deviation=w,t.difference=function(t,...n){t=new InternSet(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new InternSet;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=$t,t.drag=function(){var t,n,e,r,i=se,o=le,a=he,u=de,c={},f=$t("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,ee).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(Zn(a.view).on("mousemove.drag",p,re).on("mouseup.drag",g,re),ae(a.view),ie(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(oe(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){Zn(t.view).on("mousemove.drag mouseup.drag",null),ue(t.view,e),oe(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e+t,t.easePoly=wo,t.easePolyIn=mo,t.easePolyInOut=wo,t.easePolyOut=xo,t.easeQuad=_o,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=_o,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Ao,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*To)},t.easeSinInOut=Ao,t.easeSinOut=function(t){return Math.sin(t*To)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=M,t.fcumsum=function(t,n){const e=new T;let r=-1;return Float64Array.from(t,void 0===n?t=>e.add(+t||0):i=>e.add(+n(i,++r,t)||0))},t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.flatGroup=function(t,...n){return z(P(t,...n),n)},t.flatRollup=function(t,n,...e){return z(D(t,n,...e),e)},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;if+p||os+p||ac.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;vt.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r[u(t,n,r),t])));for(a=0,i=new Array(f);a=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=Uc(e))*l),0===h&&(p+=(h=Uc(e))*h),p(t=(Lc*t+jc)%Hc)/Hc}();function l(){h(),f.call("tick",n),e1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=qc(.1);function o(t){for(var i,o=0,a=n.length;o=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++ejs(r[0],r[1])&&(r[1]=i[1]),js(i[0],r[1])>js(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=js(r[1],i[0]))>a&&(a=u,Wf=i[0],Kf=r[1])}return is=os=null,Wf===1/0||Zf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Wf,Zf],[Kf,Qf]]},t.geoCentroid=function(t){ms=xs=ws=Ms=Ts=As=Ss=Es=0,Ns=new T,ks=new T,Cs=new T,Lf(t,Gs);var n=+Ns,e=+ks,r=+Cs,i=Ef(n,e,r);return i=0))throw new RangeError(`invalid digits: ${t}`);i=n}return null===n&&(r=new ed(i)),a},a.projection(t).digits(i).context(n)},t.geoProjection=yd,t.geoProjectionMutator=vd,t.geoRotation=ll,t.geoStereographic=function(){return yd(Bd).scale(250).clipAngle(142)},t.geoStereographicRaw=Bd,t.geoStream=Lf,t.geoTransform=function(t){return{stream:id(t)}},t.geoTransverseMercator=function(){var t=Ed(Yd),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Yd,t.gray=function(t,n){return new ur(t,0,0,null==n?1:n)},t.greatest=ot,t.greatestIndex=function(t,e=n){if(1===e.length)return tt(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=C,t.groupSort=function(t,e,r){return(2!==e.length?U($(t,e,r),(([t,e],[r,i])=>n(e,i)||n(t,r))):U(C(t,r),(([t,r],[i,o])=>e(r,o)||n(t,i)))).map((([t])=>t))},t.groups=P,t.hcl=dr,t.hierarchy=Gd,t.histogram=Q,t.hsl=He,t.html=Ec,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return F(t,k,R,n)},t.indexes=function(t,...n){return F(t,Array.from,R,n)},t.interpolate=Gr,t.interpolateArray=function(t,n){return(Ir(n)?Ur:Or)(t,n)},t.interpolateBasis=Er,t.interpolateBasisClosed=Nr,t.interpolateBlues=Gb,t.interpolateBrBG=ob,t.interpolateBuGn=Mb,t.interpolateBuPu=Ab,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=am,t.interpolateCubehelix=li,t.interpolateCubehelixDefault=im,t.interpolateCubehelixLong=hi,t.interpolateDate=Br,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Eb,t.interpolateGreens=Wb,t.interpolateGreys=Kb,t.interpolateHcl=ci,t.interpolateHclLong=fi,t.interpolateHsl=oi,t.interpolateHslLong=ai,t.interpolateHue=function(t,n){var e=Pr(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=pm,t.interpolateLab=function(t,n){var e=$r((t=ar(t)).l,(n=ar(n)).l),r=$r(t.a,n.a),i=$r(t.b,n.b),o=$r(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=dm,t.interpolateNumber=Yr,t.interpolateNumberArray=Ur,t.interpolateObject=Lr,t.interpolateOrRd=kb,t.interpolateOranges=rm,t.interpolatePRGn=ub,t.interpolatePiYG=fb,t.interpolatePlasma=gm,t.interpolatePuBu=$b,t.interpolatePuBuGn=Pb,t.interpolatePuOr=lb,t.interpolatePuRd=Rb,t.interpolatePurples=Jb,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return um.h=360*t-100,um.s=1.5-1.5*n,um.l=.8-.9*n,um+""},t.interpolateRdBu=db,t.interpolateRdGy=gb,t.interpolateRdPu=qb,t.interpolateRdYlBu=vb,t.interpolateRdYlGn=bb,t.interpolateReds=nm,t.interpolateRgb=Dr,t.interpolateRgbBasis=Fr,t.interpolateRgbBasisClosed=qr,t.interpolateRound=Vr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,cm.r=255*(n=Math.sin(t))*n,cm.g=255*(n=Math.sin(t+fm))*n,cm.b=255*(n=Math.sin(t+sm))*n,cm+""},t.interpolateSpectral=xb,t.interpolateString=Xr,t.interpolateTransformCss=ti,t.interpolateTransformSvg=ni,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=hm,t.interpolateWarm=om,t.interpolateYlGn=Bb,t.interpolateYlGnBu=Ib,t.interpolateYlOrBr=Lb,t.interpolateYlOrRd=Hb,t.interpolateZoom=ri,t.interrupt=Gi,t.intersection=function(t,...n){t=new InternSet(t),n=n.map(vt);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Ei,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?Ai():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=D_,t.isoParse=F_,t.json=function(t,n){return fetch(t,n).then(Tc)},t.lab=ar,t.lch=function(t,n,e,r){return 1===arguments.length?hr(t):new pr(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=ht,t.line=Ym,t.lineRadial=Zm,t.link=ax,t.linkHorizontal=function(){return ax(nx)},t.linkRadial=function(){const t=ax(rx);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return ax(ex)},t.local=Qn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,((e,r)=>n(e,r,t)))},t.matcher=Vt,t.max=J,t.maxIndex=tt,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return at(t,.5,n)},t.medianIndex=function(t,n){return ct(t,.5,n)},t.merge=ft,t.min=nt,t.minIndex=et,t.mode=function(t,n){const e=new InternMap;if(void 0===n)for(let n of t)null!=n&&n>=n&&e.set(n,(e.get(n)||0)+1);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&i>=i&&e.set(i,(e.get(i)||0)+1)}let r,i=0;for(const[t,n]of e)n>i&&(i=n,r=t);return r},t.namespace=It,t.namespaces=Ut,t.nice=Z,t.now=Ai,t.pack=function(){var t=null,n=1,e=1,r=np;function i(i){const o=ap();return i.x=n/2,i.y=e/2,t?i.eachBefore(xp(t)).eachAfter(wp(r,.5,o)).eachBefore(Mp(1)):i.eachBefore(xp(mp)).eachAfter(wp(np,1,o)).eachAfter(wp(r,i.r/Math.min(n,e),o)).eachBefore(Mp(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Jd(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:ep(+t),i):r},i},t.packEnclose=function(t){return up(t,ap())},t.packSiblings=function(t){return bp(t,ap()),t},t.pairs=function(t,n=st){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Ap(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:ym(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:ym(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:ym(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:ym(+t),a):o},a},t.piecewise=di,t.pointRadial=Qm,t.pointer=ne,t.pointers=function(t,n){return t.target&&(t=te(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,(t=>ne(t,n)))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++eu!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n(n=1664525*n+1013904223|0,lg*(n>>>0))},t.randomLogNormal=Kp,t.randomLogistic=fg,t.randomNormal=Zp,t.randomPareto=ng,t.randomPoisson=sg,t.randomUniform=Vp,t.randomWeibull=ug,t.range=lt,t.rank=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");let r=Array.from(t);const i=new Float64Array(r.length);2!==e.length&&(r=r.map(e),e=n);const o=(t,n)=>e(r[t],r[n]);let a,u;return(t=Uint32Array.from(r,((t,n)=>n))).sort(e===n?(t,n)=>O(r[t],r[n]):I(o)),t.forEach(((t,n)=>{const e=o(t,void 0===a?t:a);e>=0?((void 0===a||e>0)&&(a=t,u=n),i[t]=u):i[t]=NaN})),i},t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=Fe,t.ribbon=function(){return Wa()},t.ribbonArrow=function(){return Wa(Va)},t.rollup=$,t.rollups=D,t.scaleBand=yg,t.scaleDiverging=function t(){var n=Ng(L_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=Fg(L_()).domain([.1,1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleDivergingPow=j_,t.scaleDivergingSqrt=function(){return j_.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=Ig(L_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return null==t||isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,_g),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,_g):[0,1],Ng(r)},t.scaleImplicit=pg,t.scaleLinear=function t(){var n=Sg();return n.copy=function(){return Tg(n,t())},hg.apply(n,arguments),Ng(n)},t.scaleLog=function t(){const n=Fg(Ag()).domain([1,10]);return n.copy=()=>Tg(n,t()).base(n.base()),hg.apply(n,arguments),n},t.scaleOrdinal=gg,t.scalePoint=function(){return vg(yg.apply(null,arguments).paddingInner(1))},t.scalePow=jg,t.scaleQuantile=function t(){var e,r=[],i=[],o=[];function a(){var t=0,n=Math.max(1,i.length);for(o=new Array(n-1);++t0?o[n-1]:r[0],n=i?[o[i-1],r]:[o[n-1],o[n]]},u.unknown=function(t){return arguments.length?(n=t,u):u},u.thresholds=function(){return o.slice()},u.copy=function(){return t().domain([e,r]).range(a).unknown(n)},hg.apply(Ng(u),arguments)},t.scaleRadial=function t(){var n,e=Sg(),r=[0,1],i=!1;function o(t){var r=function(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(Hg(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,_g)).map(Hg)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},hg.apply(o,arguments),Ng(o)},t.scaleSequential=function t(){var n=Ng(O_()(mg));return n.copy=function(){return B_(n,t())},dg.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=Fg(O_()).domain([1,10]);return n.copy=function(){return B_(n,t()).base(n.base())},dg.apply(n,arguments)},t.scaleSequentialPow=Y_,t.scaleSequentialQuantile=function t(){var e=[],r=mg;function i(t){if(null!=t&&!isNaN(t=+t))return r((s(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map(((t,n)=>r(n/(e.length-1))))},i.quantiles=function(t){return Array.from({length:t+1},((n,r)=>at(e,r/t)))},i.copy=function(){return t(r).domain(e)},dg.apply(i,arguments)},t.scaleSequentialSqrt=function(){return Y_.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=Ig(O_());return n.copy=function(){return B_(n,t()).constant(n.constant())},dg.apply(n,arguments)},t.scaleSqrt=function(){return jg.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=Ig(Ag());return n.copy=function(){return Tg(n,t()).constant(n.constant())},hg.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function o(t){return null!=t&&t<=t?r[s(e,t,0,i)]:n}return o.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),o):e.slice()},o.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),o):r.slice()},o.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t().domain(e).range(r).unknown(n)},hg.apply(o,arguments)},t.scaleTime=function(){return hg.apply(I_(uv,cv,tv,Zy,xy,py,sy,ay,iy,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return hg.apply(I_(ov,av,ev,Qy,Fy,yy,hy,cy,iy,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=ht(t,n);return e<0?void 0:e},t.schemeAccent=G_,t.schemeBlues=Xb,t.schemeBrBG=ib,t.schemeBuGn=wb,t.schemeBuPu=Tb,t.schemeCategory10=X_,t.schemeDark2=V_,t.schemeGnBu=Sb,t.schemeGreens=Vb,t.schemeGreys=Zb,t.schemeObservable10=W_,t.schemeOrRd=Nb,t.schemeOranges=em,t.schemePRGn=ab,t.schemePaired=Z_,t.schemePastel1=K_,t.schemePastel2=Q_,t.schemePiYG=cb,t.schemePuBu=zb,t.schemePuBuGn=Cb,t.schemePuOr=sb,t.schemePuRd=Db,t.schemePurples=Qb,t.schemeRdBu=hb,t.schemeRdGy=pb,t.schemeRdPu=Fb,t.schemeRdYlBu=yb,t.schemeRdYlGn=_b,t.schemeReds=tm,t.schemeSet1=J_,t.schemeSet2=tb,t.schemeSet3=nb,t.schemeSpectral=mb,t.schemeTableau10=eb,t.schemeYlGn=Ob,t.schemeYlGnBu=Ub,t.schemeYlOrBr=Yb,t.schemeYlOrRd=jb,t.select=Zn,t.selectAll=function(t){return"string"==typeof t?new Vn([document.querySelectorAll(t)],[document.documentElement]):new Vn([Ht(t)],Gn)},t.selection=Wn,t.selector=jt,t.selectorAll=Gt,t.shuffle=dt,t.shuffler=pt,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=U,t.stack=function(){var t=ym([]),n=dw,e=hw,r=pw;function i(i){var o,a,u=Array.from(t.apply(this,arguments),gw),c=u.length,f=-1;for(const t of i)for(o=0,++f;o0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o0){for(var e,r=0,i=t[n[0]],o=i.length;r0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;afunction(t){t=`${t}`;let n=t.length;zp(t,n-1)&&!zp(t,n-2)&&(t=t.slice(0,-1));return"/"===t[0]?t:`/${t}`}(t(n,e,r)))),e=n.map(Pp),i=new Set(n).add("");for(const t of e)i.has(t)||(i.add(t),n.push(t),e.push(Pp(t)),h.push(Np));d=(t,e)=>n[e],p=(t,n)=>e[n]}for(a=0,i=h.length;a=0&&(f=h[t]).data===Np;--t)f.data=null}if(u.parent=Sp,u.eachBefore((function(t){t.depth=t.parent.depth+1,--i})).eachBefore(Kd),u.parent=null,i>0)throw new Error("cycle");return u}return r.id=function(t){return arguments.length?(n=Jd(t),r):n},r.parentId=function(t){return arguments.length?(e=Jd(t),r):e},r.path=function(n){return arguments.length?(t=Jd(n),r):t},r},t.style=_n,t.subset=function(t,n){return _t(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=_t,t.svg=Nc,t.symbol=function(t,n){let e=null,r=km(i);function i(){let i;if(e||(e=i=r()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),i)return e=null,i+""||null}return t="function"==typeof t?t:ym(t||fx),n="function"==typeof n?n:ym(void 0===n?64:+n),i.type=function(n){return arguments.length?(t="function"==typeof n?n:ym(n),i):t},i.size=function(t){return arguments.length?(n="function"==typeof t?t:ym(+t),i):n},i.context=function(t){return arguments.length?(e=null==t?null:t,i):e},i},t.symbolAsterisk=cx,t.symbolCircle=fx,t.symbolCross=sx,t.symbolDiamond=dx,t.symbolDiamond2=px,t.symbolPlus=gx,t.symbolSquare=yx,t.symbolSquare2=vx,t.symbolStar=xx,t.symbolTimes=Px,t.symbolTriangle=Mx,t.symbolTriangle2=Ax,t.symbolWye=Cx,t.symbolX=Px,t.symbols=zx,t.symbolsFill=zx,t.symbolsStroke=$x,t.text=mc,t.thresholdFreedmanDiaconis=function(t,n,e){const r=v(t),i=at(t,.75)-at(t,.25);return r&&i?Math.ceil((e-n)/(2*i*Math.pow(r,-1/3))):1},t.thresholdScott=function(t,n,e){const r=v(t),i=w(t);return r&&i?Math.ceil((e-n)*Math.cbrt(r)/(3.49*i)):1},t.thresholdSturges=K,t.tickFormat=Eg,t.tickIncrement=V,t.tickStep=W,t.ticks=G,t.timeDay=py,t.timeDays=gy,t.timeFormatDefaultLocale=P_,t.timeFormatLocale=hv,t.timeFriday=Sy,t.timeFridays=$y,t.timeHour=sy,t.timeHours=ly,t.timeInterval=Vg,t.timeMillisecond=Wg,t.timeMilliseconds=Zg,t.timeMinute=ay,t.timeMinutes=uy,t.timeMonday=wy,t.timeMondays=ky,t.timeMonth=Zy,t.timeMonths=Ky,t.timeSaturday=Ey,t.timeSaturdays=Dy,t.timeSecond=iy,t.timeSeconds=oy,t.timeSunday=xy,t.timeSundays=Ny,t.timeThursday=Ay,t.timeThursdays=zy,t.timeTickInterval=cv,t.timeTicks=uv,t.timeTuesday=My,t.timeTuesdays=Cy,t.timeWednesday=Ty,t.timeWednesdays=Py,t.timeWeek=xy,t.timeWeeks=Ny,t.timeYear=tv,t.timeYears=nv,t.timeout=$i,t.timer=Ni,t.timerFlush=ki,t.transition=go,t.transpose=gt,t.tree=function(){var t=$p,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new Up(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Up(r[i],i)),e.parent=n;return(a.parent=new Up(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.xs.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=Rp(u),o=Dp(o),u&&o;)c=Dp(c),(a=Rp(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(Fp(qp(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!Rp(a)&&(a.t=u,a.m+=l-s),o&&!Dp(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Yp,n=!1,e=1,r=1,i=[0],o=np,a=np,u=np,c=np,f=np;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Tp),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d>>1;f[g]c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Ap,t.treemapResquarify=Lp,t.treemapSlice=Ip,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Ip:Ap)(t,n,e,r,i)},t.treemapSquarify=Yp,t.tsv=Mc,t.tsvFormat=lc,t.tsvFormatBody=hc,t.tsvFormatRow=pc,t.tsvFormatRows=dc,t.tsvFormatValue=gc,t.tsvParse=fc,t.tsvParseRows=sc,t.union=function(...t){const n=new InternSet;for(const e of t)for(const t of e)n.add(t);return n},t.unixDay=_y,t.unixDays=by,t.utcDay=yy,t.utcDays=vy,t.utcFriday=By,t.utcFridays=Vy,t.utcHour=hy,t.utcHours=dy,t.utcMillisecond=Wg,t.utcMilliseconds=Zg,t.utcMinute=cy,t.utcMinutes=fy,t.utcMonday=qy,t.utcMondays=jy,t.utcMonth=Qy,t.utcMonths=Jy,t.utcSaturday=Yy,t.utcSaturdays=Wy,t.utcSecond=iy,t.utcSeconds=oy,t.utcSunday=Fy,t.utcSundays=Ly,t.utcThursday=Oy,t.utcThursdays=Gy,t.utcTickInterval=av,t.utcTicks=ov,t.utcTuesday=Uy,t.utcTuesdays=Hy,t.utcWednesday=Iy,t.utcWednesdays=Xy,t.utcWeek=Fy,t.utcWeeks=Ly,t.utcYear=ev,t.utcYears=rv,t.variance=x,t.version="7.9.0",t.window=pn,t.xml=Sc,t.zip=function(){return gt(arguments)},t.zoom=function(){var t,n,e,r=Ew,i=Nw,o=zw,a=Cw,u=Pw,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=ri,h=$t("start","zoom","end"),d=500,p=150,g=0,y=10;function v(t){t.property("__zoom",kw).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",A).on("dblclick.zoom",S).filter(u).on("touchstart.zoom",E).on("touchmove.zoom",N).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new ww(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ww(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e,r){t.on("start.zoom",(function(){w(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){w(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=w(t,o).event(r),u=i.apply(t,o),c=null==e?m(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new ww(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function w(t,n,e){return!e&&t.__zooming||new M(t,n)}function M(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function T(t,...n){if(r.apply(this,arguments)){var e=w(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=ne(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],Gi(this),e.start()}Sw(t),e.wheel=setTimeout((function(){e.wheel=null,e.end()}),p),e.zoom("mouse",o(b(_(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=w(this,n,!0).event(t),u=Zn(t.view).on("mousemove.zoom",(function(t){if(Sw(t),!a.moved){var n=t.clientX-s,e=t.clientY-l;a.moved=n*n+e*e>g}a.event(t).zoom("mouse",o(b(a.that.__zoom,a.mouse[0]=ne(t,i),a.mouse[1]),a.extent,f))}),!0).on("mouseup.zoom",(function(t){u.on("mousemove.zoom mouseup.zoom",null),ue(t.view,a.moved),Sw(t),a.event(t).end()}),!0),c=ne(t,i),s=t.clientX,l=t.clientY;ae(t.view),Aw(t),a.mouse=[c,this.__zoom.invert(c)],Gi(this),a.start()}}function S(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=ne(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(b(_(e,c),a,u),i.apply(this,n),f);Sw(t),s>0?Zn(this).transition().duration(s).call(x,l,a,t):Zn(this).call(v.transform,l,a,t)}}function E(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=w(this,i,e.changedTouches.length===s).event(e);for(Aw(e),a=0;a{for(var d in l)pr(p,d,{get:l[d],enumerable:!0})},co=(p,l,d,i)=>{if(l&&typeof l=="object"||typeof l=="function")for(let f of uo(l))!po.call(p,f)&&f!==d&&pr(p,f,{get:()=>l[f],enumerable:!(i=so(l,f))||i.enumerable});return p};var fo=p=>co(pr({},"__esModule",{value:!0}),p);var Yo={};lo(Yo,{Graphviz:()=>Zo});module.exports=fo(Yo);var vo=ArrayBuffer,H=Uint8Array,Qe=Uint16Array,mo=Int16Array,qe=Int32Array,lr=function(p,l,d){if(H.prototype.slice)return H.prototype.slice.call(p,l,d);(l==null||l<0)&&(l=0),(d==null||d>p.length)&&(d=p.length);var i=new H(d-l);return i.set(p.subarray(l,d)),i},Ye=function(p,l,d,i){if(H.prototype.fill)return H.prototype.fill.call(p,l,d,i);for((d==null||d<0)&&(d=0),(i==null||i>p.length)&&(i=p.length);dp.length)&&(i=p.length);d2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],T=function(p,l,d){var i=new Error(l||go[p]);if(i.code=p,Error.captureStackTrace&&Error.captureStackTrace(i,T),!d)throw i;return i},Pr=function(p,l,d){for(var i=0,f=0;i>>0},wo=function(p,l){var d=p[0]|p[1]<<8|p[2]<<16;if(d==3126568&&p[3]==253){var i=p[4],f=i>>5&1,m=i>>2&1,_=i&3,h=i>>6;i&8&&T(0);var M=6-f,I=_==3?4:_,Q=Pr(p,M,I);M+=I;var Z=h?1<>3);z=q+(q>>3)*(p[5]&7)}z>2145386496&&T(1);var X=new H((l==1?Y||z:l?0:z)+12);return X[0]=1,X[4]=4,X[8]=8,{b:M+Z,y:0,l:0,d:Q,w:l&&l!=1?l:X.subarray(12),e:z,o:new qe(X.buffer,0,3),u:Y,c:m,m:Math.min(131072,z)}}else if((d>>4|p[3]<<20)==25481893)return ho(p,4)+8;T(0)},Xe=function(p){for(var l=0;1<d&&T(3);for(var m=1<0;){var S=Xe(_+1),P=i>>3,ae=(1<>(i&7)&ae,w=(1<w&&(J-=j)),Y[++h]=--J,J==-1?(_+=J,V[--Q]=h):_-=J,!J)do{var ie=i>>3;M=(p[ie]|p[ie+1]<<8)>>(i&7)&3,i+=2,h+=M}while(M==3)}(h>255||_)&&T(0);for(var b=0,k=(m>>1)+(m>>3)+3,se=m-1,oe=0;oe<=h;++oe){var K=Y[oe];if(K<1){z[oe]=-K;continue}for(I=0;I=Q)}}for(b&&T(0),I=0;I>3,{b:f,s:V,n:re,t:q}]},yo=function(p,l){var d=0,i=-1,f=new H(292),m=p[l],_=f.subarray(0,256),h=f.subarray(256,268),M=new Qe(f.buffer,268);if(m<128){var I=je(p,l+1,6),Q=I[0],Z=I[1];l+=m;var Y=Q<<3,z=p[l];z||T(0);for(var q=0,X=0,V=Z.b,re=V,S=(++l<<3)-8+Xe(z);S-=V,!(S>3;if(q+=(p[P]|p[P+1]<<8)>>(S&7)&(1<>3,X+=(p[P]|p[P+1]<<8)>>(S&7)&(1<255&&T(0)}else{for(i=m-127;d>4,_[d+1]=ae&15}++l}var J=0;for(d=0;d11&&T(0),J+=w&&1<0;--d){var oe=M[d];Ye(se,d,oe,M[d-1]=oe+h[d]*(1<h&&Z>3,z=(p[Y]|p[Y+1]<<8|p[Y+2]<<16)>>(Q&7);M=(M<>2,_=m<<1,h=m+_;Ze(p.subarray(i,i+=p[0]|p[1]<<8),l.subarray(0,m),d),Ze(p.subarray(i,i+=p[2]|p[3]<<8),l.subarray(m,_),d),Ze(p.subarray(i,i+=p[4]|p[5]<<8),l.subarray(_,h),d),Ze(p.subarray(i),l.subarray(h),d)},Bo=function(p,l,d){var i,f=l.b,m=p[f],_=m>>1&3;l.l=m&1;var h=m>>3|p[f+1]<<5|p[f+2]<<13,M=(f+=3)+h;if(_==1)return f>=p.length?void 0:(l.b=f+1,d?(Ye(d,p[f],l.y,l.y+=h),d):Ye(new H(h),p[f]));if(!(M>p.length)){if(_==0)return l.b=M,d?(d.set(p.subarray(f,M),l.y),l.y+=h,d):lr(p,f,M);if(_==2){var I=p[f],Q=I&3,Z=I>>2&3,Y=I>>4,z=0,q=0;Q<2?Z&1?Y|=p[++f]<<4|(Z&2&&p[++f]<<12):Y=I>>3:(q=Z,Z<2?(Y|=(p[++f]&63)<<4,z=p[f]>>6|p[++f]<<2):Z==2?(Y|=p[++f]<<4|(p[++f]&3)<<12,z=p[f]>>2|p[++f]<<6):(Y|=p[++f]<<4|(p[++f]&63)<<12,z=p[f]>>6|p[++f]<<2|p[++f]<<10)),++f;var X=d?d.subarray(l.y,l.y+l.m):new H(l.m),V=X.length-Y;if(Q==0)X.set(p.subarray(f,f+=Y),V);else if(Q==1)Ye(X,p[f++],V);else{var re=l.h;if(Q==2){var S=yo(p,f);z+=f-(f=S[0]),l.h=re=S[1]}else re||T(0);(q?Lo:Ze)(p.subarray(f,f+=z),X.subarray(V),re)}var P=p[f++];if(P){P==255?P=(p[f++]|p[f++]<<8)+32512:P>127&&(P=P-128<<8|p[f++]);var ae=p[f++];ae&3&&T(0);for(var J=[Eo,Mo,bo],w=2;w>-1;--w){var j=ae>>(w<<1)+2&3;if(j==1){var W=new H([0,0,p[f++]]);J[w]={s:W.subarray(2,3),n:W.subarray(0,1),t:new Qe(W.buffer,0,1),b:0}}else j==2?(i=je(p,f,9-(w&1)),f=i[0],J[w]=i[1]):j==3&&(l.t||T(0),J[w]=l.t[w])}var ie=l.t=J,b=ie[0],k=ie[1],se=ie[2],oe=p[M-1];oe||T(0);var K=(M<<3)-8+Xe(oe)-se.b,L=K>>3,A=0,Le=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var Be=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var Re=(p[L]|p[L+1]<<8)>>(K&7)&(1<>3;var $e=1<>>(K&7)&$e-1);L=(K-=fr[Ve])>>3;var me=Xo[Ve]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<>3;var _e=Do[Ne]+((p[L]|p[L+1]<<8|p[L+2]<<16)>>(K&7)&(1<>3,Le=se.t[Le]+((p[L]|p[L+1]<<8)>>(K&7)&(1<>3,Re=b.t[Re]+((p[L]|p[L+1]<<8)>>(K&7)&(1<>3,Be=k.t[Be]+((p[L]|p[L+1]<<8)>>(K&7)&(1<3)l.o[2]=l.o[1],l.o[1]=l.o[0],l.o[0]=ce-=3;else{var Ge=ce-(_e!=0);Ge?(ce=Ge==3?l.o[0]-1:l.o[Ge],Ge>1&&(l.o[2]=l.o[1]),l.o[1]=l.o[0],l.o[0]=ce):ce=l.o[0]}for(var w=0;w<_e;++w)X[A+w]=X[V+w];A+=_e,V+=_e;var Ee=A-ce;if(Ee<0){var De=-Ee,We=l.e+Ee;De>me&&(De=me);for(var w=0;w{var p=typeof document<"u"?document.currentScript?.src:void 0;return function(l={}){var d,i=l,f,m,_=new Promise((e,r)=>{f=e,m=r}),h=!1,M=Object.assign({},i),I="./this.program",Q=(e,r)=>{throw r},Z="";function Y(e){return Z+e}var z,q,X=console.log.bind(console),V=console.error.bind(console);Object.assign(i,M),M=null;var re;i.wasmBinary&&(re=i.wasmBinary);var S,P=!1,ae;function J(e,r){e||_e(r)}var w,j,W,ie,b,k,se,oe;function K(){var e=S.buffer;i.HEAP8=w=new Int8Array(e),i.HEAP16=W=new Int16Array(e),i.HEAPU8=j=new Uint8Array(e),i.HEAPU16=ie=new Uint16Array(e),i.HEAP32=b=new Int32Array(e),i.HEAPU32=k=new Uint32Array(e),i.HEAPF32=se=new Float32Array(e),i.HEAPF64=oe=new Float64Array(e)}var L=[],A=[],Le=[],Be=!1;function Re(){Ae(L)}function Ne(){Be=!0,!i.noFSInit&&!o.init.initialized&&o.init(),o.ignorePermissions=!1,Me.init(),Ae(A)}function Pe(){Ae(Le)}function Ve(e){A.unshift(e)}var ye=0,ke=null,be=null;function $e(e){return e}function ce(e){ye++}function me(e){if(ye--,ye==0&&(ke!==null&&(clearInterval(ke),ke=null),be)){var r=be;be=null,r()}}function _e(e){e="Aborted("+e+")",V(e),P=!0,ae=1,e+=". Build with -sASSERTIONS for more info.";var r=new WebAssembly.RuntimeError(e);throw m(r),r}var Ge="data:application/octet-stream;base64,",Ee=e=>e.startsWith(Ge),De=e=>e.startsWith("file://");function We(){var e="graphvizlib.wasm";return Ee(e)?e:Y(e)}var Je;function vr(e){if(e==Je&&re)return new Uint8Array(re);if(q)return q(e);throw"both async and sync fetching of the wasm failed"}function Sr(e){return re?Promise.resolve().then(()=>vr(e)):z(e).then(r=>new Uint8Array(r),()=>vr(e))}function mr(e,r,t){return Sr(e).then(n=>WebAssembly.instantiate(n,r)).then(t,n=>{V(`failed to asynchronously prepare wasm: ${n}`),_e(n)})}function Hr(e,r,t,n){return!e&&typeof WebAssembly.instantiateStreaming=="function"&&!Ee(r)&&!De(r)&&typeof fetch=="function"?fetch(r,{credentials:"same-origin"}).then(a=>{var s=WebAssembly.instantiateStreaming(a,t);return s.then(n,function(u){return V(`wasm streaming compile failed: ${u}`),V("falling back to ArrayBuffer instantiation"),mr(r,t,n)})}):mr(r,t,n)}function Tr(){return{a:qt}}function Qr(){var e=Tr();function r(n,a){return N=n.exports,S=N.B,K(),Ve(N.C),me("wasm-instantiate"),N}ce("wasm-instantiate");function t(n){r(n.instance)}return Je||(Je=We()),Hr(re,Je,e,t).catch(m),{}}var R,$,qr={172808:(e,r)=>{var t=ue(e),n=ue(r);o.createPath("/",C.dirname(t)),o.writeFile(C.join("/",t),n)}};function $r(e){this.name="ExitStatus",this.message=`Program terminated with exit(${e})`,this.status=e}var Ae=e=>{for(;e.length>0;)e.shift()(i)};class Wr{constructor(r){this.excPtr=r,this.ptr=r-24}set_type(r){k[this.ptr+4>>2]=r}get_type(){return k[this.ptr+4>>2]}set_destructor(r){k[this.ptr+8>>2]=r}get_destructor(){return k[this.ptr+8>>2]}set_caught(r){r=r?1:0,w[this.ptr+12]=r}get_caught(){return w[this.ptr+12]!=0}set_rethrown(r){r=r?1:0,w[this.ptr+13]=r}get_rethrown(){return w[this.ptr+13]!=0}init(r,t){this.set_adjusted_ptr(0),this.set_type(r),this.set_destructor(t)}set_adjusted_ptr(r){k[this.ptr+16>>2]=r}get_adjusted_ptr(){return k[this.ptr+16>>2]}get_exception_ptr(){var r=zr(this.get_type());if(r)return k[this.excPtr>>2];var t=this.get_adjusted_ptr();return t!==0?t:this.excPtr}}var _r=0,Ar=0,et=(e,r,t)=>{var n=new Wr(e);throw n.init(r,t),_r=e,Ar++,_r},C={isAbs:e=>e.charAt(0)==="/",splitPath:e=>{var r=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return r.exec(e).slice(1)},normalizeArray:(e,r)=>{for(var t=0,n=e.length-1;n>=0;n--){var a=e[n];a==="."?e.splice(n,1):a===".."?(e.splice(n,1),t++):t&&(e.splice(n,1),t--)}if(r)for(;t;t--)e.unshift("..");return e},normalize:e=>{var r=C.isAbs(e),t=e.substr(-1)==="/";return e=C.normalizeArray(e.split("/").filter(n=>!!n),!r).join("/"),!e&&!r&&(e="."),e&&t&&(e+="/"),(r?"/":"")+e},dirname:e=>{var r=C.splitPath(e),t=r[0],n=r[1];return!t&&!n?".":(n&&(n=n.substr(0,n.length-1)),t+n)},basename:e=>{if(e==="/")return"/";e=C.normalize(e),e=e.replace(/\/$/,"");var r=e.lastIndexOf("/");return r===-1?e:e.substr(r+1)},join:(...e)=>C.normalize(e.join("/")),join2:(e,r)=>C.normalize(e+"/"+r)},rt=()=>{if(typeof crypto=="object"&&typeof crypto.getRandomValues=="function")return e=>crypto.getRandomValues(e);_e("initRandomDevice")},gr=e=>(gr=rt())(e),he={resolve:(...e)=>{for(var r="",t=!1,n=e.length-1;n>=-1&&!t;n--){var a=n>=0?e[n]:o.cwd();if(typeof a!="string")throw new TypeError("Arguments to path.resolve must be strings");if(!a)return"";r=a+"/"+r,t=C.isAbs(a)}return r=C.normalizeArray(r.split("/").filter(s=>!!s),!t).join("/"),(t?"/":"")+r||"."},relative:(e,r)=>{e=he.resolve(e).substr(1),r=he.resolve(r).substr(1);function t(E){for(var G=0;G=0&&E[x]==="";x--);return G>x?[]:E.slice(G,x-G+1)}for(var n=t(e.split("/")),a=t(r.split("/")),s=Math.min(n.length,a.length),u=s,c=0;c{for(var n=r+t,a=r;e[a]&&!(a>=n);)++a;if(a-r>16&&e.buffer&&hr)return hr.decode(e.subarray(r,a));for(var s="";r>10,56320|E&1023)}}return s},er=[],rr=e=>{for(var r=0,t=0;t=55296&&n<=57343?(r+=4,++t):r+=3}return r},tr=(e,r,t,n)=>{if(!(n>0))return 0;for(var a=t,s=t+n-1,u=0;u=55296&&c<=57343){var v=e.charCodeAt(++u);c=65536+((c&1023)<<10)|v&1023}if(c<=127){if(t>=s)break;r[t++]=c}else if(c<=2047){if(t+1>=s)break;r[t++]=192|c>>6,r[t++]=128|c&63}else if(c<=65535){if(t+2>=s)break;r[t++]=224|c>>12,r[t++]=128|c>>6&63,r[t++]=128|c&63}else{if(t+3>=s)break;r[t++]=240|c>>18,r[t++]=128|c>>12&63,r[t++]=128|c>>6&63,r[t++]=128|c&63}}return r[t]=0,t-a};function or(e,r,t){var n=t>0?t:rr(e)+1,a=new Array(n),s=tr(e,a,0,a.length);return r&&(a.length=s),a}var tt=()=>{if(!er.length){var e=null;if(!e)return null;er=or(e,!0)}return er.shift()},Me={ttys:[],init(){},shutdown(){},register(e,r){Me.ttys[e]={input:[],output:[],ops:r},o.registerDevice(e,Me.stream_ops)},stream_ops:{open(e){var r=Me.ttys[e.node.rdev];if(!r)throw new o.ErrnoError(43);e.tty=r,e.seekable=!1},close(e){e.tty.ops.fsync(e.tty)},fsync(e){e.tty.ops.fsync(e.tty)},read(e,r,t,n,a){if(!e.tty||!e.tty.ops.get_char)throw new o.ErrnoError(60);for(var s=0,u=0;u0&&(X(Fe(e.output,0)),e.output=[])},ioctl_tcgets(e){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(e,r,t){return 0},ioctl_tiocgwinsz(e){return[24,80]}},default_tty1_ops:{put_char(e,r){r===null||r===10?(V(Fe(e.output,0)),e.output=[]):r!=0&&e.output.push(r)},fsync(e){e.output&&e.output.length>0&&(V(Fe(e.output,0)),e.output=[])}}},ot=(e,r)=>(j.fill(0,e,e+r),e),wr=(e,r)=>Math.ceil(e/r)*r,yr=e=>{e=wr(e,65536);var r=Yr(65536,e);return r?ot(r,e):0},D={ops_table:null,mount(e){return D.createNode(null,"/",16895,0)},createNode(e,r,t,n){if(o.isBlkdev(t)||o.isFIFO(t))throw new o.ErrnoError(63);D.ops_table||={dir:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,lookup:D.node_ops.lookup,mknod:D.node_ops.mknod,rename:D.node_ops.rename,unlink:D.node_ops.unlink,rmdir:D.node_ops.rmdir,readdir:D.node_ops.readdir,symlink:D.node_ops.symlink},stream:{llseek:D.stream_ops.llseek}},file:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:{llseek:D.stream_ops.llseek,read:D.stream_ops.read,write:D.stream_ops.write,allocate:D.stream_ops.allocate,mmap:D.stream_ops.mmap,msync:D.stream_ops.msync}},link:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr,readlink:D.node_ops.readlink},stream:{}},chrdev:{node:{getattr:D.node_ops.getattr,setattr:D.node_ops.setattr},stream:o.chrdev_stream_ops}};var a=o.createNode(e,r,t,n);return o.isDir(a.mode)?(a.node_ops=D.ops_table.dir.node,a.stream_ops=D.ops_table.dir.stream,a.contents={}):o.isFile(a.mode)?(a.node_ops=D.ops_table.file.node,a.stream_ops=D.ops_table.file.stream,a.usedBytes=0,a.contents=null):o.isLink(a.mode)?(a.node_ops=D.ops_table.link.node,a.stream_ops=D.ops_table.link.stream):o.isChrdev(a.mode)&&(a.node_ops=D.ops_table.chrdev.node,a.stream_ops=D.ops_table.chrdev.stream),a.timestamp=Date.now(),e&&(e.contents[r]=a,e.timestamp=a.timestamp),a},getFileDataAsTypedArray(e){return e.contents?e.contents.subarray?e.contents.subarray(0,e.usedBytes):new Uint8Array(e.contents):new Uint8Array(0)},expandFileStorage(e,r){var t=e.contents?e.contents.length:0;if(!(t>=r)){var n=1048576;r=Math.max(r,t*(t>>0),t!=0&&(r=Math.max(r,256));var a=e.contents;e.contents=new Uint8Array(r),e.usedBytes>0&&e.contents.set(a.subarray(0,e.usedBytes),0)}},resizeFileStorage(e,r){if(e.usedBytes!=r)if(r==0)e.contents=null,e.usedBytes=0;else{var t=e.contents;e.contents=new Uint8Array(r),t&&e.contents.set(t.subarray(0,Math.min(r,e.usedBytes))),e.usedBytes=r}},node_ops:{getattr(e){var r={};return r.dev=o.isChrdev(e.mode)?e.id:1,r.ino=e.id,r.mode=e.mode,r.nlink=1,r.uid=0,r.gid=0,r.rdev=e.rdev,o.isDir(e.mode)?r.size=4096:o.isFile(e.mode)?r.size=e.usedBytes:o.isLink(e.mode)?r.size=e.link.length:r.size=0,r.atime=new Date(e.timestamp),r.mtime=new Date(e.timestamp),r.ctime=new Date(e.timestamp),r.blksize=4096,r.blocks=Math.ceil(r.size/r.blksize),r},setattr(e,r){r.mode!==void 0&&(e.mode=r.mode),r.timestamp!==void 0&&(e.timestamp=r.timestamp),r.size!==void 0&&D.resizeFileStorage(e,r.size)},lookup(e,r){throw o.genericErrors[44]},mknod(e,r,t,n){return D.createNode(e,r,t,n)},rename(e,r,t){if(o.isDir(e.mode)){var n;try{n=o.lookupNode(r,t)}catch{}if(n)for(var a in n.contents)throw new o.ErrnoError(55)}delete e.parent.contents[e.name],e.parent.timestamp=Date.now(),e.name=t,r.contents[t]=e,r.timestamp=e.parent.timestamp},unlink(e,r){delete e.contents[r],e.timestamp=Date.now()},rmdir(e,r){var t=o.lookupNode(e,r);for(var n in t.contents)throw new o.ErrnoError(55);delete e.contents[r],e.timestamp=Date.now()},readdir(e){var r=[".",".."];for(var t of Object.keys(e.contents))r.push(t);return r},symlink(e,r,t){var n=D.createNode(e,r,41471,0);return n.link=t,n},readlink(e){if(!o.isLink(e.mode))throw new o.ErrnoError(28);return e.link}},stream_ops:{read(e,r,t,n,a){var s=e.node.contents;if(a>=e.node.usedBytes)return 0;var u=Math.min(e.node.usedBytes-a,n);if(u>8&&s.subarray)r.set(s.subarray(a,a+u),t);else for(var c=0;c0||t+r{var a=n?"":`al ${e}`;z(e).then(s=>{r(new Uint8Array(s)),a&&me(a)},s=>{if(t)t();else throw`Loading data file "${e}" failed.`}),a&&ce(a)},at=(e,r,t,n,a,s)=>{o.createDataFile(e,r,t,n,a,s)},it=[],st=(e,r,t,n)=>{typeof Browser<"u"&&Browser.init();var a=!1;return it.forEach(s=>{a||s.canHandle(r)&&(s.handle(e,r,t,n),a=!0)}),a},ut=(e,r,t,n,a,s,u,c,v,E)=>{var G=r?he.resolve(C.join2(e,r)):e,x=`cp ${G}`;function B(y){function O(te){E?.(),c||at(e,r,te,n,a,v),s?.(),me(x)}st(y,G,O,()=>{u?.(),me(x)})||O(y)}ce(x),typeof t=="string"?nt(t,B,u):B(t)},pt=e=>{var r={r:0,"r+":2,w:577,"w+":578,a:1089,"a+":1090},t=r[e];if(typeof t>"u")throw new Error(`Unknown file open mode: ${e}`);return t},nr=(e,r)=>{var t=0;return e&&(t|=365),r&&(t|=146),t},o={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:!1,ignorePermissions:!0,ErrnoError:class{constructor(e){this.name="ErrnoError",this.errno=e}},genericErrors:{},filesystems:null,syncFSRequests:0,FSStream:class{constructor(){this.shared={}}get object(){return this.node}set object(e){this.node=e}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(e){this.shared.flags=e}get position(){return this.shared.position}set position(e){this.shared.position=e}},FSNode:class{constructor(e,r,t,n){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=o.nextInode++,this.name=r,this.mode=t,this.node_ops={},this.stream_ops={},this.rdev=n,this.readMode=365,this.writeMode=146}get read(){return(this.mode&this.readMode)===this.readMode}set read(e){e?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(e){e?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return o.isDir(this.mode)}get isDevice(){return o.isChrdev(this.mode)}},lookupPath(e,r={}){if(e=he.resolve(e),!e)return{path:"",node:null};var t={follow_mount:!0,recurse_count:0};if(r=Object.assign(t,r),r.recurse_count>8)throw new o.ErrnoError(32);for(var n=e.split("/").filter(x=>!!x),a=o.root,s="/",u=0;u40)throw new o.ErrnoError(32)}}return{path:s,node:a}},getPath(e){for(var r;;){if(o.isRoot(e)){var t=e.mount.mountpoint;return r?t[t.length-1]!=="/"?`${t}/${r}`:t+r:t}r=r?`${e.name}/${r}`:e.name,e=e.parent}},hashName(e,r){for(var t=0,n=0;n>>0)%o.nameTable.length},hashAddNode(e){var r=o.hashName(e.parent.id,e.name);e.name_next=o.nameTable[r],o.nameTable[r]=e},hashRemoveNode(e){var r=o.hashName(e.parent.id,e.name);if(o.nameTable[r]===e)o.nameTable[r]=e.name_next;else for(var t=o.nameTable[r];t;){if(t.name_next===e){t.name_next=e.name_next;break}t=t.name_next}},lookupNode(e,r){var t=o.mayLookup(e);if(t)throw new o.ErrnoError(t);for(var n=o.hashName(e.id,r),a=o.nameTable[n];a;a=a.name_next){var s=a.name;if(a.parent.id===e.id&&s===r)return a}return o.lookup(e,r)},createNode(e,r,t,n){var a=new o.FSNode(e,r,t,n);return o.hashAddNode(a),a},destroyNode(e){o.hashRemoveNode(e)},isRoot(e){return e===e.parent},isMountpoint(e){return!!e.mounted},isFile(e){return(e&61440)===32768},isDir(e){return(e&61440)===16384},isLink(e){return(e&61440)===40960},isChrdev(e){return(e&61440)===8192},isBlkdev(e){return(e&61440)===24576},isFIFO(e){return(e&61440)===4096},isSocket(e){return(e&49152)===49152},flagsToPermissionString(e){var r=["r","w","rw"][e&3];return e&512&&(r+="w"),r},nodePermissions(e,r){return o.ignorePermissions?0:r.includes("r")&&!(e.mode&292)||r.includes("w")&&!(e.mode&146)||r.includes("x")&&!(e.mode&73)?2:0},mayLookup(e){if(!o.isDir(e.mode))return 54;var r=o.nodePermissions(e,"x");return r||(e.node_ops.lookup?0:2)},mayCreate(e,r){try{var t=o.lookupNode(e,r);return 20}catch{}return o.nodePermissions(e,"wx")},mayDelete(e,r,t){var n;try{n=o.lookupNode(e,r)}catch(s){return s.errno}var a=o.nodePermissions(e,"wx");if(a)return a;if(t){if(!o.isDir(n.mode))return 54;if(o.isRoot(n)||o.getPath(n)===o.cwd())return 10}else if(o.isDir(n.mode))return 31;return 0},mayOpen(e,r){return e?o.isLink(e.mode)?32:o.isDir(e.mode)&&(o.flagsToPermissionString(r)!=="r"||r&512)?31:o.nodePermissions(e,o.flagsToPermissionString(r)):44},MAX_OPEN_FDS:4096,nextfd(){for(var e=0;e<=o.MAX_OPEN_FDS;e++)if(!o.streams[e])return e;throw new o.ErrnoError(33)},getStreamChecked(e){var r=o.getStream(e);if(!r)throw new o.ErrnoError(8);return r},getStream:e=>o.streams[e],createStream(e,r=-1){return e=Object.assign(new o.FSStream,e),r==-1&&(r=o.nextfd()),e.fd=r,o.streams[r]=e,e},closeStream(e){o.streams[e]=null},dupStream(e,r=-1){var t=o.createStream(e,r);return t.stream_ops?.dup?.(t),t},chrdev_stream_ops:{open(e){var r=o.getDevice(e.node.rdev);e.stream_ops=r.stream_ops,e.stream_ops.open?.(e)},llseek(){throw new o.ErrnoError(70)}},major:e=>e>>8,minor:e=>e&255,makedev:(e,r)=>e<<8|r,registerDevice(e,r){o.devices[e]={stream_ops:r}},getDevice:e=>o.devices[e],getMounts(e){for(var r=[],t=[e];t.length;){var n=t.pop();r.push(n),t.push(...n.mounts)}return r},syncfs(e,r){typeof e=="function"&&(r=e,e=!1),o.syncFSRequests++,o.syncFSRequests>1&&V(`warning: ${o.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);var t=o.getMounts(o.root.mount),n=0;function a(u){return o.syncFSRequests--,r(u)}function s(u){if(u)return s.errored?void 0:(s.errored=!0,a(u));++n>=t.length&&a(null)}t.forEach(u=>{if(!u.type.syncfs)return s(null);u.type.syncfs(u,e,s)})},mount(e,r,t){var n=t==="/",a=!t,s;if(n&&o.root)throw new o.ErrnoError(10);if(!n&&!a){var u=o.lookupPath(t,{follow_mount:!1});if(t=u.path,s=u.node,o.isMountpoint(s))throw new o.ErrnoError(10);if(!o.isDir(s.mode))throw new o.ErrnoError(54)}var c={type:e,opts:r,mountpoint:t,mounts:[]},v=e.mount(c);return v.mount=c,c.root=v,n?o.root=v:s&&(s.mounted=c,s.mount&&s.mount.mounts.push(c)),v},unmount(e){var r=o.lookupPath(e,{follow_mount:!1});if(!o.isMountpoint(r.node))throw new o.ErrnoError(28);var t=r.node,n=t.mounted,a=o.getMounts(n);Object.keys(o.nameTable).forEach(u=>{for(var c=o.nameTable[u];c;){var v=c.name_next;a.includes(c.mount)&&o.destroyNode(c),c=v}}),t.mounted=null;var s=t.mount.mounts.indexOf(n);t.mount.mounts.splice(s,1)},lookup(e,r){return e.node_ops.lookup(e,r)},mknod(e,r,t){var n=o.lookupPath(e,{parent:!0}),a=n.node,s=C.basename(e);if(!s||s==="."||s==="..")throw new o.ErrnoError(28);var u=o.mayCreate(a,s);if(u)throw new o.ErrnoError(u);if(!a.node_ops.mknod)throw new o.ErrnoError(63);return a.node_ops.mknod(a,s,r,t)},create(e,r){return r=r!==void 0?r:438,r&=4095,r|=32768,o.mknod(e,r,0)},mkdir(e,r){return r=r!==void 0?r:511,r&=1023,r|=16384,o.mknod(e,r,0)},mkdirTree(e,r){for(var t=e.split("/"),n="",a=0;a"u"&&(t=r,r=438),r|=8192,o.mknod(e,r,t)},symlink(e,r){if(!he.resolve(e))throw new o.ErrnoError(44);var t=o.lookupPath(r,{parent:!0}),n=t.node;if(!n)throw new o.ErrnoError(44);var a=C.basename(r),s=o.mayCreate(n,a);if(s)throw new o.ErrnoError(s);if(!n.node_ops.symlink)throw new o.ErrnoError(63);return n.node_ops.symlink(n,a,e)},rename(e,r){var t=C.dirname(e),n=C.dirname(r),a=C.basename(e),s=C.basename(r),u,c,v;if(u=o.lookupPath(e,{parent:!0}),c=u.node,u=o.lookupPath(r,{parent:!0}),v=u.node,!c||!v)throw new o.ErrnoError(44);if(c.mount!==v.mount)throw new o.ErrnoError(75);var E=o.lookupNode(c,a),G=he.relative(e,n);if(G.charAt(0)!==".")throw new o.ErrnoError(28);if(G=he.relative(r,t),G.charAt(0)!==".")throw new o.ErrnoError(55);var x;try{x=o.lookupNode(v,s)}catch{}if(E!==x){var B=o.isDir(E.mode),y=o.mayDelete(c,a,B);if(y)throw new o.ErrnoError(y);if(y=x?o.mayDelete(v,s,B):o.mayCreate(v,s),y)throw new o.ErrnoError(y);if(!c.node_ops.rename)throw new o.ErrnoError(63);if(o.isMountpoint(E)||x&&o.isMountpoint(x))throw new o.ErrnoError(10);if(v!==c&&(y=o.nodePermissions(c,"w"),y))throw new o.ErrnoError(y);o.hashRemoveNode(E);try{c.node_ops.rename(E,v,s),E.parent=v}catch(O){throw O}finally{o.hashAddNode(E)}}},rmdir(e){var r=o.lookupPath(e,{parent:!0}),t=r.node,n=C.basename(e),a=o.lookupNode(t,n),s=o.mayDelete(t,n,!0);if(s)throw new o.ErrnoError(s);if(!t.node_ops.rmdir)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.rmdir(t,n),o.destroyNode(a)},readdir(e){var r=o.lookupPath(e,{follow:!0}),t=r.node;if(!t.node_ops.readdir)throw new o.ErrnoError(54);return t.node_ops.readdir(t)},unlink(e){var r=o.lookupPath(e,{parent:!0}),t=r.node;if(!t)throw new o.ErrnoError(44);var n=C.basename(e),a=o.lookupNode(t,n),s=o.mayDelete(t,n,!1);if(s)throw new o.ErrnoError(s);if(!t.node_ops.unlink)throw new o.ErrnoError(63);if(o.isMountpoint(a))throw new o.ErrnoError(10);t.node_ops.unlink(t,n),o.destroyNode(a)},readlink(e){var r=o.lookupPath(e),t=r.node;if(!t)throw new o.ErrnoError(44);if(!t.node_ops.readlink)throw new o.ErrnoError(28);return he.resolve(o.getPath(t.parent),t.node_ops.readlink(t))},stat(e,r){var t=o.lookupPath(e,{follow:!r}),n=t.node;if(!n)throw new o.ErrnoError(44);if(!n.node_ops.getattr)throw new o.ErrnoError(63);return n.node_ops.getattr(n)},lstat(e){return o.stat(e,!0)},chmod(e,r,t){var n;if(typeof e=="string"){var a=o.lookupPath(e,{follow:!t});n=a.node}else n=e;if(!n.node_ops.setattr)throw new o.ErrnoError(63);n.node_ops.setattr(n,{mode:r&4095|n.mode&-4096,timestamp:Date.now()})},lchmod(e,r){o.chmod(e,r,!0)},fchmod(e,r){var t=o.getStreamChecked(e);o.chmod(t.node,r)},chown(e,r,t,n){var a;if(typeof e=="string"){var s=o.lookupPath(e,{follow:!n});a=s.node}else a=e;if(!a.node_ops.setattr)throw new o.ErrnoError(63);a.node_ops.setattr(a,{timestamp:Date.now()})},lchown(e,r,t){o.chown(e,r,t,!0)},fchown(e,r,t){var n=o.getStreamChecked(e);o.chown(n.node,r,t)},truncate(e,r){if(r<0)throw new o.ErrnoError(28);var t;if(typeof e=="string"){var n=o.lookupPath(e,{follow:!0});t=n.node}else t=e;if(!t.node_ops.setattr)throw new o.ErrnoError(63);if(o.isDir(t.mode))throw new o.ErrnoError(31);if(!o.isFile(t.mode))throw new o.ErrnoError(28);var a=o.nodePermissions(t,"w");if(a)throw new o.ErrnoError(a);t.node_ops.setattr(t,{size:r,timestamp:Date.now()})},ftruncate(e,r){var t=o.getStreamChecked(e);if(!(t.flags&2097155))throw new o.ErrnoError(28);o.truncate(t.node,r)},utime(e,r,t){var n=o.lookupPath(e,{follow:!0}),a=n.node;a.node_ops.setattr(a,{timestamp:Math.max(r,t)})},open(e,r,t){if(e==="")throw new o.ErrnoError(44);r=typeof r=="string"?pt(r):r,r&64?(t=typeof t>"u"?438:t,t=t&4095|32768):t=0;var n;if(typeof e=="object")n=e;else{e=C.normalize(e);try{var a=o.lookupPath(e,{follow:!(r&131072)});n=a.node}catch{}}var s=!1;if(r&64)if(n){if(r&128)throw new o.ErrnoError(20)}else n=o.mknod(e,t,0),s=!0;if(!n)throw new o.ErrnoError(44);if(o.isChrdev(n.mode)&&(r&=-513),r&65536&&!o.isDir(n.mode))throw new o.ErrnoError(54);if(!s){var u=o.mayOpen(n,r);if(u)throw new o.ErrnoError(u)}r&512&&!s&&o.truncate(n,0),r&=-131713;var c=o.createStream({node:n,path:o.getPath(n),flags:r,seekable:!0,position:0,stream_ops:n.stream_ops,ungotten:[],error:!1});return c.stream_ops.open&&c.stream_ops.open(c),i.logReadFiles&&!(r&1)&&(o.readFiles||(o.readFiles={}),e in o.readFiles||(o.readFiles[e]=1)),c},close(e){if(o.isClosed(e))throw new o.ErrnoError(8);e.getdents&&(e.getdents=null);try{e.stream_ops.close&&e.stream_ops.close(e)}catch(r){throw r}finally{o.closeStream(e.fd)}e.fd=null},isClosed(e){return e.fd===null},llseek(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(!e.seekable||!e.stream_ops.llseek)throw new o.ErrnoError(70);if(t!=0&&t!=1&&t!=2)throw new o.ErrnoError(28);return e.position=e.stream_ops.llseek(e,r,t),e.ungotten=[],e.position},read(e,r,t,n,a){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if((e.flags&2097155)===1)throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.read)throw new o.ErrnoError(28);var s=typeof a<"u";if(!s)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var u=e.stream_ops.read(e,r,t,n,a);return s||(e.position+=u),u},write(e,r,t,n,a,s){if(n<0||a<0)throw new o.ErrnoError(28);if(o.isClosed(e))throw new o.ErrnoError(8);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(o.isDir(e.node.mode))throw new o.ErrnoError(31);if(!e.stream_ops.write)throw new o.ErrnoError(28);e.seekable&&e.flags&1024&&o.llseek(e,0,2);var u=typeof a<"u";if(!u)a=e.position;else if(!e.seekable)throw new o.ErrnoError(70);var c=e.stream_ops.write(e,r,t,n,a,s);return u||(e.position+=c),c},allocate(e,r,t){if(o.isClosed(e))throw new o.ErrnoError(8);if(r<0||t<=0)throw new o.ErrnoError(28);if(!(e.flags&2097155))throw new o.ErrnoError(8);if(!o.isFile(e.node.mode)&&!o.isDir(e.node.mode))throw new o.ErrnoError(43);if(!e.stream_ops.allocate)throw new o.ErrnoError(138);e.stream_ops.allocate(e,r,t)},mmap(e,r,t,n,a){if(n&2&&!(a&2)&&(e.flags&2097155)!==2)throw new o.ErrnoError(2);if((e.flags&2097155)===1)throw new o.ErrnoError(2);if(!e.stream_ops.mmap)throw new o.ErrnoError(43);return e.stream_ops.mmap(e,r,t,n,a)},msync(e,r,t,n,a){return e.stream_ops.msync?e.stream_ops.msync(e,r,t,n,a):0},ioctl(e,r,t){if(!e.stream_ops.ioctl)throw new o.ErrnoError(59);return e.stream_ops.ioctl(e,r,t)},readFile(e,r={}){if(r.flags=r.flags||0,r.encoding=r.encoding||"binary",r.encoding!=="utf8"&&r.encoding!=="binary")throw new Error(`Invalid encoding type "${r.encoding}"`);var t,n=o.open(e,r.flags),a=o.stat(e),s=a.size,u=new Uint8Array(s);return o.read(n,u,0,s,0),r.encoding==="utf8"?t=Fe(u,0):r.encoding==="binary"&&(t=u),o.close(n),t},writeFile(e,r,t={}){t.flags=t.flags||577;var n=o.open(e,t.flags,t.mode);if(typeof r=="string"){var a=new Uint8Array(rr(r)+1),s=tr(r,a,0,a.length);o.write(n,a,0,s,void 0,t.canOwn)}else if(ArrayBuffer.isView(r))o.write(n,r,0,r.byteLength,void 0,t.canOwn);else throw new Error("Unsupported data type");o.close(n)},cwd:()=>o.currentPath,chdir(e){var r=o.lookupPath(e,{follow:!0});if(r.node===null)throw new o.ErrnoError(44);if(!o.isDir(r.node.mode))throw new o.ErrnoError(54);var t=o.nodePermissions(r.node,"x");if(t)throw new o.ErrnoError(t);o.currentPath=r.path},createDefaultDirectories(){o.mkdir("/tmp"),o.mkdir("/home"),o.mkdir("/home/web_user")},createDefaultDevices(){o.mkdir("/dev"),o.registerDevice(o.makedev(1,3),{read:()=>0,write:(n,a,s,u,c)=>u}),o.mkdev("/dev/null",o.makedev(1,3)),Me.register(o.makedev(5,0),Me.default_tty_ops),Me.register(o.makedev(6,0),Me.default_tty1_ops),o.mkdev("/dev/tty",o.makedev(5,0)),o.mkdev("/dev/tty1",o.makedev(6,0));var e=new Uint8Array(1024),r=0,t=()=>(r===0&&(r=gr(e).byteLength),e[--r]);o.createDevice("/dev","random",t),o.createDevice("/dev","urandom",t),o.mkdir("/dev/shm"),o.mkdir("/dev/shm/tmp")},createSpecialDirectories(){o.mkdir("/proc");var e=o.mkdir("/proc/self");o.mkdir("/proc/self/fd"),o.mount({mount(){var r=o.createNode(e,"fd",16895,73);return r.node_ops={lookup(t,n){var a=+n,s=o.getStreamChecked(a),u={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>s.path}};return u.parent=u,u}},r}},{},"/proc/self/fd")},createStandardStreams(){i.stdin?o.createDevice("/dev","stdin",i.stdin):o.symlink("/dev/tty","/dev/stdin"),i.stdout?o.createDevice("/dev","stdout",null,i.stdout):o.symlink("/dev/tty","/dev/stdout"),i.stderr?o.createDevice("/dev","stderr",null,i.stderr):o.symlink("/dev/tty1","/dev/stderr");var e=o.open("/dev/stdin",0),r=o.open("/dev/stdout",1),t=o.open("/dev/stderr",1)},staticInit(){[44].forEach(e=>{o.genericErrors[e]=new o.ErrnoError(e),o.genericErrors[e].stack=""}),o.nameTable=new Array(4096),o.mount(D,{},"/"),o.createDefaultDirectories(),o.createDefaultDevices(),o.createSpecialDirectories(),o.filesystems={MEMFS:D}},init(e,r,t){o.init.initialized=!0,i.stdin=e||i.stdin,i.stdout=r||i.stdout,i.stderr=t||i.stderr,o.createStandardStreams()},quit(){o.init.initialized=!1;for(var e=0;ethis.length-1||y<0)){var O=y%this.chunkSize,te=y/this.chunkSize|0;return this.getter(te)[O]}}setDataGetter(y){this.getter=y}cacheLength(){var y=new XMLHttpRequest;if(y.open("HEAD",t,!1),y.send(null),!(y.status>=200&&y.status<300||y.status===304))throw new Error("Couldn't load "+t+". Status: "+y.status);var O=Number(y.getResponseHeader("Content-length")),te,de=(te=y.getResponseHeader("Accept-Ranges"))&&te==="bytes",ne=(te=y.getResponseHeader("Content-Encoding"))&&te==="gzip",fe=1024*1024;de||(fe=O);var ve=(ge,xe)=>{if(ge>xe)throw new Error("invalid range ("+ge+", "+xe+") or no bytes requested!");if(xe>O-1)throw new Error("only "+O+" bytes available! programmer error!");var ee=new XMLHttpRequest;if(ee.open("GET",t,!1),O!==fe&&ee.setRequestHeader("Range","bytes="+ge+"-"+xe),ee.responseType="arraybuffer",ee.overrideMimeType&&ee.overrideMimeType("text/plain; charset=x-user-defined"),ee.send(null),!(ee.status>=200&&ee.status<300||ee.status===304))throw new Error("Couldn't load "+t+". Status: "+ee.status);return ee.response!==void 0?new Uint8Array(ee.response||[]):or(ee.responseText||"",!0)},Ie=this;Ie.setDataGetter(ge=>{var xe=ge*fe,ee=(ge+1)*fe-1;if(ee=Math.min(ee,O-1),typeof Ie.chunks[ge]>"u"&&(Ie.chunks[ge]=ve(xe,ee)),typeof Ie.chunks[ge]>"u")throw new Error("doXHR failed!");return Ie.chunks[ge]}),(ne||!O)&&(fe=O=1,O=this.getter(0).length,fe=O,X("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=O,this._chunkSize=fe,this.lengthKnown=!0}get length(){return this.lengthKnown||this.cacheLength(),this._length}get chunkSize(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}if(typeof XMLHttpRequest<"u"){if(!h)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var u=new s,c={isDevice:!1,contents:u}}else var c={isDevice:!1,url:t};var v=o.createFile(e,r,c,n,a);c.contents?v.contents=c.contents:c.url&&(v.contents=null,v.url=c.url),Object.defineProperties(v,{usedBytes:{get:function(){return this.contents.length}}});var E={},G=Object.keys(v.stream_ops);G.forEach(B=>{var y=v.stream_ops[B];E[B]=(...O)=>(o.forceLoadFile(v),y(...O))});function x(B,y,O,te,de){var ne=B.node.contents;if(de>=ne.length)return 0;var fe=Math.min(ne.length-de,te);if(ne.slice)for(var ve=0;ve(o.forceLoadFile(v),x(B,y,O,te,de)),E.mmap=(B,y,O,te,de)=>{o.forceLoadFile(v);var ne=yr(y);if(!ne)throw new o.ErrnoError(48);return x(B,w,ne,y,O),{ptr:ne,allocated:!0}},v.stream_ops=E,v}},ue=(e,r)=>e?Fe(j,e,r):"",U={DEFAULT_POLLMASK:5,calculateAt(e,r,t){if(C.isAbs(r))return r;var n;if(e===-100)n=o.cwd();else{var a=U.getStreamFromFD(e);n=a.path}if(r.length==0){if(!t)throw new o.ErrnoError(44);return n}return C.join2(n,r)},doStat(e,r,t){var n=e(r);b[t>>2]=n.dev,b[t+4>>2]=n.mode,k[t+8>>2]=n.nlink,b[t+12>>2]=n.uid,b[t+16>>2]=n.gid,b[t+20>>2]=n.rdev,$=[n.size>>>0,(R=n.size,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+24>>2]=$[0],b[t+28>>2]=$[1],b[t+32>>2]=4096,b[t+36>>2]=n.blocks;var a=n.atime.getTime(),s=n.mtime.getTime(),u=n.ctime.getTime();return $=[Math.floor(a/1e3)>>>0,(R=Math.floor(a/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+40>>2]=$[0],b[t+44>>2]=$[1],k[t+48>>2]=a%1e3*1e3,$=[Math.floor(s/1e3)>>>0,(R=Math.floor(s/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+56>>2]=$[0],b[t+60>>2]=$[1],k[t+64>>2]=s%1e3*1e3,$=[Math.floor(u/1e3)>>>0,(R=Math.floor(u/1e3),+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+72>>2]=$[0],b[t+76>>2]=$[1],k[t+80>>2]=u%1e3*1e3,$=[n.ino>>>0,(R=n.ino,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[t+88>>2]=$[0],b[t+92>>2]=$[1],0},doMsync(e,r,t,n,a){if(!o.isFile(r.node.mode))throw new o.ErrnoError(43);if(n&2)return 0;var s=j.slice(e,e+t);o.msync(r,s,a,t,n)},getStreamFromFD(e){var r=o.getStreamChecked(e);return r},varargs:void 0,getStr(e){var r=ue(e);return r}};function lt(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),t&-8)return-28;var a=o.lookupPath(r,{follow:!0}),s=a.node;if(!s)return-44;var u="";return t&4&&(u+="r"),t&2&&(u+="w"),t&1&&(u+="x"),u&&o.nodePermissions(s,u)?-2:0}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function Se(){var e=b[+U.varargs>>2];return U.varargs+=4,e}var Oe=Se;function ct(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 0:{var a=Se();if(a<0)return-28;for(;o.streams[a];)a++;var s;return s=o.dupStream(n,a),s.fd}case 1:case 2:return 0;case 3:return n.flags;case 4:{var a=Se();return n.flags|=a,0}case 12:{var a=Oe(),u=0;return W[a+u>>1]=2,0}case 13:case 14:return 0}return-28}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function dt(e,r){try{var t=U.getStreamFromFD(e);return U.doStat(o.stat,t.path,r)}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return-n.errno}}function ft(e,r,t){U.varargs=t;try{var n=U.getStreamFromFD(e);switch(r){case 21509:return n.tty?0:-59;case 21505:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tcgets){var a=n.tty.ops.ioctl_tcgets(n),s=Oe();b[s>>2]=a.c_iflag||0,b[s+4>>2]=a.c_oflag||0,b[s+8>>2]=a.c_cflag||0,b[s+12>>2]=a.c_lflag||0;for(var u=0;u<32;u++)w[s+u+17]=a.c_cc[u]||0;return 0}return 0}case 21510:case 21511:case 21512:return n.tty?0:-59;case 21506:case 21507:case 21508:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tcsets){for(var s=Oe(),c=b[s>>2],v=b[s+4>>2],E=b[s+8>>2],G=b[s+12>>2],x=[],u=0;u<32;u++)x.push(w[s+u+17]);return n.tty.ops.ioctl_tcsets(n.tty,r,{c_iflag:c,c_oflag:v,c_cflag:E,c_lflag:G,c_cc:x})}return 0}case 21519:{if(!n.tty)return-59;var s=Oe();return b[s>>2]=0,0}case 21520:return n.tty?-28:-59;case 21531:{var s=Oe();return o.ioctl(n,r,s)}case 21523:{if(!n.tty)return-59;if(n.tty.ops.ioctl_tiocgwinsz){var B=n.tty.ops.ioctl_tiocgwinsz(n.tty),s=Oe();W[s>>1]=B[0],W[s+2>>1]=B[1]}return 0}case 21524:return n.tty?0:-59;case 21515:return n.tty?0:-59;default:return-28}}catch(y){if(typeof o>"u"||y.name!=="ErrnoError")throw y;return-y.errno}}function vt(e,r,t,n){try{r=U.getStr(r);var a=n&256,s=n&4096;return n=n&-6401,r=U.calculateAt(e,r,s),U.doStat(a?o.lstat:o.stat,r,t)}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return-u.errno}}function mt(e,r,t,n){U.varargs=n;try{r=U.getStr(r),r=U.calculateAt(e,r);var a=n?Se():0;return o.open(r,t,a).fd}catch(s){if(typeof o>"u"||s.name!=="ErrnoError")throw s;return-s.errno}}var Ke=(e,r,t)=>tr(e,j,r,t);function _t(e,r,t,n){try{if(r=U.getStr(r),r=U.calculateAt(e,r),n<=0)return-28;var a=o.readlink(r),s=Math.min(n,rr(a)),u=w[t+s];return Ke(a,t,n+1),w[t+s]=u,s}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return-c.errno}}function gt(e){try{return e=U.getStr(e),o.rmdir(e),0}catch(r){if(typeof o>"u"||r.name!=="ErrnoError")throw r;return-r.errno}}function ht(e,r){try{return e=U.getStr(e),U.doStat(o.stat,e,r)}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return-t.errno}}function wt(e,r,t){try{return r=U.getStr(r),r=U.calculateAt(e,r),t===0?o.unlink(r):t===512?o.rmdir(r):_e("Invalid flags passed to unlinkat"),0}catch(n){if(typeof o>"u"||n.name!=="ErrnoError")throw n;return-n.errno}}var yt=()=>{_e("")},bt=1,Et=()=>bt,Mt=(e,r,t)=>j.copyWithin(e,r,r+t),ar=(e,r)=>r+2097152>>>0<4194305-!!e?(e>>>0)+r*4294967296:NaN;function Dt(e,r,t,n,a,s,u,c){var v=ar(a,s);try{if(isNaN(v))return 61;var E=U.getStreamFromFD(n),G=o.mmap(E,e,v,r,t),x=G.ptr;return b[u>>2]=G.allocated,k[c>>2]=x,0}catch(B){if(typeof o>"u"||B.name!=="ErrnoError")throw B;return-B.errno}}function Xt(e,r,t,n,a,s,u){var c=ar(s,u);try{var v=U.getStreamFromFD(a);t&2&&U.doMsync(e,v,r,n,c)}catch(E){if(typeof o>"u"||E.name!=="ErrnoError")throw E;return-E.errno}}var Lt=(e,r,t,n)=>{var a=new Date().getFullYear(),s=new Date(a,0,1),u=new Date(a,6,1),c=s.getTimezoneOffset(),v=u.getTimezoneOffset(),E=Math.max(c,v);k[e>>2]=E*60,b[r>>2]=+(c!=v);var G=y=>{var O=y>=0?"-":"+",te=Math.abs(y),de=String(Math.floor(te/60)).padStart(2,"0"),ne=String(te%60).padStart(2,"0");return`UTC${O}${de}${ne}`},x=G(c),B=G(v);v{ir.length=0;for(var t;t=j[e++];){var n=t!=105;n&=t!=112,r+=n&&r%8?4:0,ir.push(t==112?k[r>>2]:t==105?b[r>>2]:oe[r>>3]),r+=n?8:4}return ir},Rt=(e,r,t)=>{var n=Bt(r,t);return qr[e](...n)},kt=(e,r,t)=>Rt(e,r,t),Gt=()=>Date.now(),Ft;Ft=()=>performance.now();var Ot=()=>2147483648,xt=e=>{var r=S.buffer,t=(e-r.byteLength+65535)/65536;try{return S.grow(t),K(),1}catch{}},Ut=e=>{var r=j.length;e>>>=0;var t=Ot();if(e>t)return!1;for(var n=(v,E)=>v+(E-v%E)%E,a=1;a<=4;a*=2){var s=r*(1+.2/a);s=Math.min(s,e+100663296);var u=Math.min(t,n(Math.max(e,s),65536)),c=xt(u);if(c)return!0}return!1},sr={},Nt=()=>I||"./this.program",Ce=()=>{if(!Ce.strings){var e=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",r={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:e,_:Nt()};for(var t in sr)sr[t]===void 0?delete r[t]:r[t]=sr[t];var n=[];for(var t in r)n.push(`${t}=${r[t]}`);Ce.strings=n}return Ce.strings},Vt=(e,r)=>{for(var t=0;t{var t=0;return Ce().forEach((n,a)=>{var s=r+t;k[e+a*4>>2]=s,Vt(n,s),t+=n.length+1}),0},Ct=(e,r)=>{var t=Ce();k[e>>2]=t.length;var n=0;return t.forEach(a=>n+=a.length+1),k[r>>2]=n,0},It=0,Zt=()=>It>0,Yt=e=>{ae=e,Zt()||(P=!0),Q(e,new $r(e))},zt=(e,r)=>{ae=e,Yt(e)},jt=zt;function Pt(e){try{var r=U.getStreamFromFD(e);return o.close(r),0}catch(t){if(typeof o>"u"||t.name!=="ErrnoError")throw t;return t.errno}}var Jt=(e,r,t,n)=>{for(var a=0,s=0;s>2],c=k[r+4>>2];r+=8;var v=o.read(e,w,u,c,n);if(v<0)return-1;if(a+=v,v>2]=s,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}function Ht(e,r,t,n,a){var s=ar(r,t);try{if(isNaN(s))return 61;var u=U.getStreamFromFD(e);return o.llseek(u,s,n),$=[u.position>>>0,(R=u.position,+Math.abs(R)>=1?R>0?+Math.floor(R/4294967296)>>>0:~~+Math.ceil((R-+(~~R>>>0))/4294967296)>>>0:0)],b[a>>2]=$[0],b[a+4>>2]=$[1],u.getdents&&s===0&&n===0&&(u.getdents=null),0}catch(c){if(typeof o>"u"||c.name!=="ErrnoError")throw c;return c.errno}}var Tt=(e,r,t,n)=>{for(var a=0,s=0;s>2],c=k[r+4>>2];r+=8;var v=o.write(e,w,u,c,n);if(v<0)return-1;a+=v,typeof n<"u"&&(n+=v)}return a};function Qt(e,r,t,n){try{var a=U.getStreamFromFD(e),s=Tt(a,r,t);return k[n>>2]=s,0}catch(u){if(typeof o>"u"||u.name!=="ErrnoError")throw u;return u.errno}}o.createPreloadedFile=ut,o.staticInit();var qt={a:et,k:lt,h:ct,y:dt,z:ft,w:vt,d:mt,r:_t,s:gt,x:ht,t:wt,l:yt,i:Et,j:Mt,m:Dt,n:Xt,p:Lt,A:kt,b:Gt,q:Ut,u:Kt,v:Ct,e:jt,c:Pt,f:St,o:Ht,g:Qt},N=Qr(),$t=()=>($t=N.C)(),Wt=i._webidl_free=e=>(Wt=i._webidl_free=N.D)(e),At=i._free=e=>(At=i._free=N.E)(e),eo=i._webidl_malloc=e=>(eo=i._webidl_malloc=N.F)(e),ro=i._malloc=e=>(ro=i._malloc=N.G)(e),br=i._emscripten_bind_VoidPtr___destroy___0=e=>(br=i._emscripten_bind_VoidPtr___destroy___0=N.H)(e),Er=i._emscripten_bind_Graphviz_Graphviz_2=(e,r)=>(Er=i._emscripten_bind_Graphviz_Graphviz_2=N.I)(e,r),Mr=i._emscripten_bind_Graphviz_version_0=()=>(Mr=i._emscripten_bind_Graphviz_version_0=N.J)(),Dr=i._emscripten_bind_Graphviz_lastError_0=()=>(Dr=i._emscripten_bind_Graphviz_lastError_0=N.K)(),Xr=i._emscripten_bind_Graphviz_createFile_2=(e,r,t)=>(Xr=i._emscripten_bind_Graphviz_createFile_2=N.L)(e,r,t),Lr=i._emscripten_bind_Graphviz_layout_3=(e,r,t,n)=>(Lr=i._emscripten_bind_Graphviz_layout_3=N.M)(e,r,t,n),Br=i._emscripten_bind_Graphviz_acyclic_3=(e,r,t,n)=>(Br=i._emscripten_bind_Graphviz_acyclic_3=N.N)(e,r,t,n),Rr=i._emscripten_bind_Graphviz_tred_3=(e,r,t,n)=>(Rr=i._emscripten_bind_Graphviz_tred_3=N.O)(e,r,t,n),kr=i._emscripten_bind_Graphviz_unflatten_4=(e,r,t,n,a)=>(kr=i._emscripten_bind_Graphviz_unflatten_4=N.P)(e,r,t,n,a),Gr=i._emscripten_bind_Graphviz_get_layout_result_0=e=>(Gr=i._emscripten_bind_Graphviz_get_layout_result_0=N.Q)(e),Fr=i._emscripten_bind_Graphviz_set_layout_result_1=(e,r)=>(Fr=i._emscripten_bind_Graphviz_set_layout_result_1=N.R)(e,r),Or=i._emscripten_bind_Graphviz_get_acyclic_outFile_0=e=>(Or=i._emscripten_bind_Graphviz_get_acyclic_outFile_0=N.S)(e),xr=i._emscripten_bind_Graphviz_set_acyclic_outFile_1=(e,r)=>(xr=i._emscripten_bind_Graphviz_set_acyclic_outFile_1=N.T)(e,r),Ur=i._emscripten_bind_Graphviz_get_acyclic_num_rev_0=e=>(Ur=i._emscripten_bind_Graphviz_get_acyclic_num_rev_0=N.U)(e),Nr=i._emscripten_bind_Graphviz_set_acyclic_num_rev_1=(e,r)=>(Nr=i._emscripten_bind_Graphviz_set_acyclic_num_rev_1=N.V)(e,r),Vr=i._emscripten_bind_Graphviz_get_tred_out_0=e=>(Vr=i._emscripten_bind_Graphviz_get_tred_out_0=N.W)(e),Kr=i._emscripten_bind_Graphviz_set_tred_out_1=(e,r)=>(Kr=i._emscripten_bind_Graphviz_set_tred_out_1=N.X)(e,r),Cr=i._emscripten_bind_Graphviz_get_tred_err_0=e=>(Cr=i._emscripten_bind_Graphviz_get_tred_err_0=N.Y)(e),Ir=i._emscripten_bind_Graphviz_set_tred_err_1=(e,r)=>(Ir=i._emscripten_bind_Graphviz_set_tred_err_1=N.Z)(e,r),Zr=i._emscripten_bind_Graphviz___destroy___0=e=>(Zr=i._emscripten_bind_Graphviz___destroy___0=N._)(e),Yr=(e,r)=>(Yr=N.aa)(e,r),zr=e=>(zr=N.ba)(e);i.UTF8ToString=ue;var He;be=function e(){He||jr(),He||(be=e)};function jr(){if(ye>0||(Re(),ye>0))return;function e(){He||(He=!0,i.calledRun=!0,!P&&(Ne(),f(i),Pe()))}e()}jr();function pe(){}pe.prototype=Object.create(pe.prototype),pe.prototype.constructor=pe,pe.prototype.__class__=pe,pe.__cache__={},i.WrapperObject=pe;function Te(e){return(e||pe).__cache__}i.getCache=Te;function ur(e,r){var t=Te(r),n=t[e];return n||(n=Object.create((r||pe).prototype),n.ptr=e,t[e]=n)}i.wrapPointer=ur;function to(e,r){return ur(e.ptr,r)}i.castObject=to,i.NULL=ur(0);function oo(e){if(!e.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";e.__destroy__(),delete Te(e.__class__)[e.ptr]}i.destroy=oo;function no(e,r){return e.ptr===r.ptr}i.compare=no;function ao(e){return e.ptr}i.getPointer=ao;function io(e){return e.__class__}i.getClass=io;var F={buffer:0,size:0,pos:0,temps:[],needed:0,prepare(){if(F.needed){for(var e=0;e=F.size?(J(n>0),F.needed+=n,a=i._webidl_malloc(n),F.temps.push(a)):(a=F.buffer+F.pos,F.pos+=n),a},copy(e,r,t){t/=r.BYTES_PER_ELEMENT;for(var n=0;n?@[]^_`{|}~"';function xo(p){let l=p.length,d=[],i=0,f=0,m=-1;for(let _=0;_88?13:14;do d.push(i&255),i>>=8,f-=8;while(f>7);m=-1}}return m>-1&&d.push((i|m< + +`}}function Co(p){return p.map(Ko)}function Io(p,l){let d={images:[],files:[],...l};[...d.files,...Co(d.images)].forEach(i=>p.createFile(i.path,i.data))}var Zo=class Ue{constructor(l){this._module=l}static load(){return No().then(l=>new Ue(l))}static unload(){Vo()}version(){return this._module.Graphviz.prototype.version()}layout(l,d="svg",i="dot",f){if(!l)return"";let m=new this._module.Graphviz(f?.yInvert?1:0,f?.nop?f?.nop:0),_="",h="";try{Io(m,f);try{_=m.layout(l,d,i)}catch(M){h=M.message}h=m.lastError()||h}finally{this._module.destroy(m)}if(!_&&h)throw Ue.unload(),new Error(h);return _}acyclic(l,d=!1,i=!1){if(!l)return{acyclic:!1,num_rev:0,outFile:""};let f=new this._module.Graphviz,m=!1,_=0,h="",M="";try{try{m=f.acyclic(l,d,i),_=f.acyclic_num_rev,h=f.acyclic_outFile}catch(I){M=I.message}M=f.lastError()||M}finally{this._module.destroy(f)}if(M)throw Ue.unload(),new Error(M);return{acyclic:m,num_rev:_,outFile:h}}tred(l,d=!1,i=!1){if(!l)return{out:"",err:""};let f=new this._module.Graphviz,m="",_="",h="";try{try{f.tred(l,d,i),m=f.tred_out,_=f.tred_err}catch(M){h=M.message}h=f.lastError()||h}finally{this._module.destroy(f)}if(!m&&h)throw Ue.unload(),new Error(h);return{out:m,err:_}}unflatten(l,d=0,i=!1,f=0){if(!l)return"";let m=new this._module.Graphviz,_="",h="";try{try{_=m.unflatten(l,d,i,f)}catch(M){h=M.message}h=m.lastError()||h}finally{this._module.destroy(m)}if(!_&&h)throw Ue.unload(),new Error(h);return _}circo(l,d="svg",i){return this.layout(l,d,"circo",i)}dot(l,d="svg",i){return this.layout(l,d,"dot",i)}fdp(l,d="svg",i){return this.layout(l,d,"fdp",i)}sfdp(l,d="svg",i){return this.layout(l,d,"sfdp",i)}neato(l,d="svg",i){return this.layout(l,d,"neato",i)}osage(l,d="svg",i){return this.layout(l,d,"osage",i)}patchwork(l,d="svg",i){return this.layout(l,d,"patchwork",i)}twopi(l,d="svg",i){return this.layout(l,d,"twopi",i)}nop(l){return this.layout(l,"dot","nop")}nop2(l){return this.layout(l,"dot","nop2")}}; + +if(__exports != exports)module.exports = exports;return module.exports})); +//# sourceMappingURL=graphviz.umd.js.map diff --git a/chapter21/docs/ifg_trim.pdf b/chapter21/docs/ifg_trim.pdf new file mode 100644 index 00000000..d952fd4f Binary files /dev/null and b/chapter21/docs/ifg_trim.pdf differ diff --git a/chapter21/docs/index.html b/chapter21/docs/index.html new file mode 100644 index 00000000..06e19e2c --- /dev/null +++ b/chapter21/docs/index.html @@ -0,0 +1,218 @@ + + +Simple Viewer + + + + + + +
+
+
Simple Program:
+ +
+
+
+ +
+ + +
0
+ +
0
+ +
+
+ + + + diff --git a/chapter21/docs/lattice.gv b/chapter21/docs/lattice.gv new file mode 100644 index 00000000..8661082d --- /dev/null +++ b/chapter21/docs/lattice.gv @@ -0,0 +1,203 @@ +digraph Lattice { + compound = true; + // Define nodes + splines=false; + node [shape=circle, style=filled]; + nodesep=0.2; + ranksep=0.2; + + TOP [label=<⊤>, fillcolor=black, fontcolor=white]; + BOT [label=<⊥>, fillcolor=black, fontcolor=white]; + + // ---------------------- + // Control + XCTRL [label=<⊤:ctrl>, fillcolor=yellow, shape=oval]; + CTRL [label=<⊥:ctrl>, fillcolor=yellow, shape=oval]; + + TOP -> XCTRL; + XCTRL -> CTRL; + CTRL -> BOT; + + // ---------------------- + // Integers + INT_TOP [label=<⊤:int>, fillcolor=lightblue, shape=oval]; + INT_BOT [label=<⊥:int>, fillcolor=lightblue, shape=oval]; + + INT_HI [label="[min>max]" , fillcolor=lightblue, shape=oval]; + INT_XBOOL [label="[1...0]", fillcolor=lightblue, shape=oval]; + INT_CON [label="constants", fillcolor=lightblue, shape=oval]; + INT_CON0 [label="0", fillcolor=lightblue]; + INT_CON1 [label="1", fillcolor=lightblue]; + INT_BOOL [label="[0...1]", fillcolor=lightblue,shape=oval]; + INT_LO [label="[min INT_TOP; + INT_TOP -> INT_HI; + INT_HI -> INT_XBOOL; + INT_XBOOL -> INT_CON0; + INT_XBOOL -> INT_CON1; + INT_HI -> INT_CON; + INT_CON0 -> INT_BOOL; + INT_CON1 -> INT_BOOL; + INT_BOOL -> INT_LO; + INT_CON -> INT_LO; + INT_LO -> INT_BOT; + INT_BOT -> BOT; + + INT_CON0 -> INT_CON1 -> INT_CON [style=invis]; + + // ---------------------- + // Floats + FLT_TOP [label=<⊤:flt>, fillcolor=aqua, shape=oval]; + FLT_BOT [label=<⊥:flt>, fillcolor=aqua, shape=oval]; + + FLT_CON64 [label="64b consts\n[excludes\n32b consts]" , fillcolor=aqua, shape=oval]; + FLT_CON32 [label="32b consts", fillcolor=aqua, shape=oval]; + FLT_CONPI [label="3.14159...", fillcolor=aqua, shape=oval]; + FLT_X32 [label="~f32", fillcolor=aqua]; + FLT_CON0 [label="0." , fillcolor=aqua]; + FLT_32 [label="f32" , fillcolor=aqua]; + + TOP -> FLT_TOP; + FLT_TOP -> FLT_CON64 + FLT_TOP -> FLT_CONPI + FLT_CON64 -> FLT_BOT + FLT_CONPI -> FLT_BOT + + FLT_TOP -> FLT_X32; + FLT_X32 -> FLT_CON0; + FLT_X32 -> FLT_CON32; + FLT_CON0 -> FLT_32; + FLT_CON32 -> FLT_32; + FLT_32 -> FLT_BOT + + FLT_BOT -> BOT; + + FLT_CON0 -> FLT_CON32 -> FLT_CONPI -> FLT_CON64 [style=invis]; + + + // ---------------------- + // Pointers, just a boolean nil/not and a struct + PTR [shape=none, fillcolor=none, label=< + + + +
*ptr
struct
+ >]; + PTR0 [shape=none, fillcolor=none, label=< + + + +
*ptr?
struct
+ >]; + + TOP -> PTR; + PTR -> PTR0; + PTR0 -> BOT; + + // ---------------------- + // Structs + STRUCT_TOP [label=<⊤:struct>, fillcolor=lightgreen, shape=oval]; + STRUCT_BOT [label=<⊥:struct>, fillcolor=lightgreen, shape=oval]; + + STRUCT_S1 [shape=none, fillcolor=none, label=< + + +
fieldint/ptr
+ >]; + STRUCT_S2 [shape=none, fillcolor=none, label=< + + + +
fieldint/ptr
fieldint/ptr
+ >]; + STRUCT_SN [shape=none, fillcolor=none, label=< + + + + +
fieldint/ptr
... int/ptr
fieldint/ptr
+ >]; + + + TOP -> STRUCT_TOP; + STRUCT_TOP -> STRUCT_S1; + STRUCT_TOP -> STRUCT_S2; + STRUCT_TOP -> STRUCT_SN; + STRUCT_S1 -> STRUCT_BOT; + STRUCT_S2 -> STRUCT_BOT; + STRUCT_SN -> STRUCT_BOT; + STRUCT_BOT -> BOT; + + STRUCT_S1 -> STRUCT_S2 -> STRUCT_SN [style=invis]; + + // ---------------------- + // Memory + MEM_TOP [label=<⊤:mem>, fillcolor=blue, fontcolor=white, shape=oval]; + MEM_BOT [label=<⊥:mem>, fillcolor=blue, fontcolor=white, shape=oval]; + MEM_ALIAS1 [label="#1" , fillcolor=blue, fontcolor=white]; + MEM_ALIASDOTS [label="..." , fillcolor=blue, fontcolor=white, shape=oval]; + MEM_ALIASN [label="#n" , fillcolor=blue, fontcolor=white]; + + TOP -> MEM_TOP; + MEM_TOP -> MEM_ALIAS1; + MEM_TOP -> MEM_ALIASDOTS; + MEM_TOP -> MEM_ALIASN; + MEM_ALIAS1 -> MEM_BOT; + MEM_ALIASDOTS -> MEM_BOT; + MEM_ALIASN -> MEM_BOT; + MEM_BOT -> BOT; + + MEM_ALIAS1 -> MEM_ALIASDOTS -> MEM_ALIASN [style=invis]; + + // ---------------------- + // Tuples + + TUPLE_TOP [label=<⊤:tuple>, fillcolor=pink, shape=oval]; + TUPLE_BOT [label=<⊥:tuple>, fillcolor=pink, shape=oval]; + + TUPLE1 [shape=none, fillcolor=none, label=< + + + +
Tuple
type
+ >]; + TUPLE2 [shape=none, fillcolor=none, label=< + + + + +
Tuple
type
type
+ >]; + TUPLEN [shape=none, fillcolor=none, label=< + + + + + +
Tuple
type
...
type
+ >]; + + + TOP -> TUPLE_TOP; + TUPLE_TOP -> TUPLE1; + TUPLE_TOP -> TUPLE2; + TUPLE_TOP -> TUPLEN; + TUPLE1 -> TUPLE_BOT; + TUPLE2 -> TUPLE_BOT; + TUPLEN -> TUPLE_BOT; + TUPLE_BOT -> BOT; + + // ---------------------- + // Additional customization + {rank=same; TOP;} + {rank=same; INT_TOP; FLT_TOP; XCTRL; PTR; STRUCT_TOP; MEM_TOP; TUPLE_TOP} + {rank=same; INT_CON; INT_CON0; INT_CON1; + FLT_CON32; FLT_CON64; FLT_CON0; FLT_CONPI; + STRUCT_S1; STRUCT_S2; STRUCT_SN; + MEM_ALIAS1; MEM_ALIASDOTS; MEM_ALIASN; + TUPLE1; TUPLE2; TUPLEN; + } + {rank=same; INT_BOT; FLT_BOT; CTRL; PTR0; STRUCT_BOT; MEM_BOT; TUPLE_BOT} + {rank=same; BOT;} +} diff --git a/chapter21/docs/lattice.svg b/chapter21/docs/lattice.svg new file mode 100644 index 00000000..e72b473b --- /dev/null +++ b/chapter21/docs/lattice.svg @@ -0,0 +1,691 @@ + + + + + + +Lattice + + + +TOP + +⊤ + + + +XCTRL + +⊤ +:ctrl + + + +TOP->XCTRL + + + + + +INT_TOP + +⊤ +:int + + + +TOP->INT_TOP + + + + + +FLT_TOP + +⊤ +:flt + + + +TOP->FLT_TOP + + + + + +PTR + + + +*ptr + + +struct + + + +TOP->PTR + + + + + +STRUCT_TOP + +⊤ +:struct + + + +TOP->STRUCT_TOP + + + + + +MEM_TOP + +⊤ +:mem + + + +TOP->MEM_TOP + + + + + +TUPLE_TOP + +⊤ +:tuple + + + +TOP->TUPLE_TOP + + + + + +BOT + +⊥ + + + +CTRL + +⊥ +:ctrl + + + +XCTRL->CTRL + + + + + +CTRL->BOT + + + + + +INT_HI + +[min>max] + + + +INT_TOP->INT_HI + + + + + +INT_BOT + +⊥ +:int + + + +INT_BOT->BOT + + + + + +INT_XBOOL + +[1...0] + + + +INT_HI->INT_XBOOL + + + + + +INT_CON + +constants + + + +INT_HI->INT_CON + + + + + +INT_CON0 + +0 + + + +INT_XBOOL->INT_CON0 + + + + + +INT_CON1 + +1 + + + +INT_XBOOL->INT_CON1 + + + + + +INT_LO + +[min<max] + + + +INT_CON->INT_LO + + + + + + +INT_BOOL + +[0...1] + + + +INT_CON0->INT_BOOL + + + + + + +INT_CON1->INT_BOOL + + + + + +INT_BOOL->INT_LO + + + + + +INT_LO->INT_BOT + + + + + +FLT_CON64 + +64b consts +[excludes +32b consts] + + + +FLT_TOP->FLT_CON64 + + + + + +FLT_CONPI + +3.14159... + + + +FLT_TOP->FLT_CONPI + + + + + +FLT_X32 + +~f32 + + + +FLT_TOP->FLT_X32 + + + + + +FLT_BOT + +⊥ +:flt + + + +FLT_BOT->BOT + + + + + +FLT_CON64->FLT_BOT + + + + + +FLT_CON32 + +32b consts + + + + +FLT_32 + +f32 + + + +FLT_CON32->FLT_32 + + + + + +FLT_CONPI->FLT_BOT + + + + + + +FLT_X32->FLT_CON32 + + + + + +FLT_CON0 + +0. + + + +FLT_X32->FLT_CON0 + + + + + + +FLT_CON0->FLT_32 + + + + + +FLT_32->FLT_BOT + + + + + +PTR0 + + + +*ptr? + + +struct + + + +PTR->PTR0 + + + + + +PTR0->BOT + + + + + +STRUCT_S1 + + + +field + + + + + + + + +int/ptr + + + +STRUCT_TOP->STRUCT_S1 + + + + + +STRUCT_S2 + + + +field + + + + + + + + +int/ptr + + +field + + + + + + + + +int/ptr + + + +STRUCT_TOP->STRUCT_S2 + + + + + +STRUCT_SN + + + +field + + + + + + + + +int/ptr + + +...   + + + + + + + + +int/ptr + + +field + + + + + + + + +int/ptr + + + +STRUCT_TOP->STRUCT_SN + + + + + +STRUCT_BOT + +⊥ +:struct + + + +STRUCT_BOT->BOT + + + + + +STRUCT_S1->STRUCT_BOT + + + + + + +STRUCT_S2->STRUCT_BOT + + + + + + +STRUCT_SN->STRUCT_BOT + + + + + +MEM_ALIAS1 + +#1 + + + +MEM_TOP->MEM_ALIAS1 + + + + + +MEM_ALIASDOTS + +... + + + +MEM_TOP->MEM_ALIASDOTS + + + + + +MEM_ALIASN + +#n + + + +MEM_TOP->MEM_ALIASN + + + + + +MEM_BOT + +⊥ +:mem + + + +MEM_BOT->BOT + + + + + +MEM_ALIAS1->MEM_BOT + + + + + + +MEM_ALIASDOTS->MEM_BOT + + + + + + +MEM_ALIASN->MEM_BOT + + + + + +TUPLE1 + + + +Tuple + + +type + + + +TUPLE_TOP->TUPLE1 + + + + + +TUPLE2 + + + +Tuple + + +type + + +type + + + +TUPLE_TOP->TUPLE2 + + + + + +TUPLEN + + + +Tuple + + +type + + +... + + +type + + + +TUPLE_TOP->TUPLEN + + + + + +TUPLE_BOT + +⊥ +:tuple + + + +TUPLE_BOT->BOT + + + + + +TUPLE1->TUPLE_BOT + + + + + +TUPLE2->TUPLE_BOT + + + + + +TUPLEN->TUPLE_BOT + + + + + diff --git a/chapter21/docs/lattice2.gv b/chapter21/docs/lattice2.gv new file mode 100644 index 00000000..6aa37fa0 --- /dev/null +++ b/chapter21/docs/lattice2.gv @@ -0,0 +1,85 @@ +digraph Lattice { + compound = true; + // Define nodes + splines=false; + node [shape=oval, style=filled]; + nodesep=0.2; + ranksep=0.4; + + TOP [label="~scalar\n+int+tmp+0", fillcolor=black, fontcolor=white, group=center]; + + // ------------------------ + PTRHQ [label="~tmp\n+tmp+0", fillcolor=green, fontcolor=white, group=left]; + TOP -> PTRHQ + + VALH_ [label="~nscalar\n+int+tmp", fillcolor=white, group=center]; + TOP -> VALH_ + + INTHQ [label="~int\n+int+0", fillcolor=lightblue, group=right]; + TOP -> INTHQ + + LEFTHI [label="junk", style=invis, group=junkleft] + + + PTRHQ -> LEFTHI-> VALH_ -> INTHQ [style=invis]; + { rank=same; PTRHQ; LEFTHI; VALH_; INTHQ } + + // ------------------------ + PTRH_ [label="~ntmp\n+tmp", fillcolor=green, fontcolor=white, group=left]; + VALH_ -> PTRH_ + PTRHQ -> PTRH_ + + INTH_ [label="~nint\n+int", fillcolor=lightblue, group=right]; + VALH_ -> INTH_ + INTHQ -> INTH_ + { rank=same; PTRH_; INTH_ } + + // ------------------------ + NILX_ [label="~nil\n[int,tmp]+0", fillcolor=aqua, group=junkleft]; + INTHQ -> NILX_ + PTRHQ -> NILX_ + + NIL__ [label="nil\n[+int+tmp],0", fillcolor=pink]; + VALH_ -> NIL__; + + NILX_ -> NIL__ [style=invis]; + { rank=same; NIL__; NILX_ } + + // ------------------------ + PTRL_ [label="ntmp\ntmp", fillcolor=green, fontcolor=white, group=left]; + PTRH_ -> PTRL_ + + INTL_ [label="nint\nint", fillcolor=lightblue, group=right]; + INTH_ -> INTL_ + { rank=same; PTRL_; INTL_ } + + // ------------------------ + PTRL0 [label="tmp\ntmp,0", fillcolor=green, fontcolor=white, group=left]; + PTRL_ -> PTRL0 + NIL__ -> PTRL0 + + VALL_ [label="nscalar\nint,tmp", fillcolor=white, group=center]; + PTRL_ -> VALL_ + INTL_ -> VALL_ + NILX_ -> VALL_ + + INTL0 [label="int\nint,0", fillcolor=lightblue, group=right]; + INTL_ -> INTL0 + NIL__ -> INTL0 + + PTRL0 -> VALL_ -> INTL0 [style=invis]; + { rank=same; PTRL0; VALL_; INTL0 } + + // ------------------------ + BOT [label="scalar\nint,tmp,0", fillcolor=black, fontcolor=white, group=center]; + PTRL0 -> BOT + INTL0 -> BOT + VALL_ -> BOT + + // ------------------------ + // Verticle alignment + TOP -> VALH_ -> VALL_ -> BOT [style=invis]; + PTRHQ -> PTRH_ -> PTRL_ -> PTRL0 [style=invis]; + INTHQ -> INTH_ -> INTL_ -> INTL0 [style=invis]; + LEFTHI -> NILX_ [style=invis] +} diff --git a/chapter21/docs/lattice2.svg b/chapter21/docs/lattice2.svg new file mode 100644 index 00000000..8b682aa7 --- /dev/null +++ b/chapter21/docs/lattice2.svg @@ -0,0 +1,260 @@ + + + + + + +Lattice + + + +TOP + +~scalar ++int+tmp+0 + + + +PTRHQ + +~tmp ++tmp+0 + + + +TOP->PTRHQ + + + + + +VALH_ + +~nscalar ++int+tmp + + + +TOP->VALH_ + + + + + + +INTHQ + +~int ++int+0 + + + +TOP->INTHQ + + + + + + + +PTRH_ + +~ntmp ++tmp + + + +PTRHQ->PTRH_ + + + + + + +NILX_ + +~nil +[int,tmp]+0 + + + +PTRHQ->NILX_ + + + + + + +VALH_->PTRH_ + + + + + +INTH_ + +~nint ++int + + + +VALH_->INTH_ + + + + + +NIL__ + +nil +[+int+tmp],0 + + + +VALH_->NIL__ + + + + + +VALL_ + +nscalar +int,tmp + + + + +INTHQ->INTH_ + + + + + + +INTHQ->NILX_ + + + + + + + +PTRL_ + +ntmp +tmp + + + +PTRH_->PTRL_ + + + + + + +INTL_ + +nint +int + + + +INTH_->INTL_ + + + + + + + +NILX_->VALL_ + + + + + +PTRL0 + +tmp +tmp,0 + + + +NIL__->PTRL0 + + + + + +INTL0 + +int +int,0 + + + +NIL__->INTL0 + + + + + +PTRL_->PTRL0 + + + + + + +PTRL_->VALL_ + + + + + +INTL_->VALL_ + + + + + +INTL_->INTL0 + + + + + + + +BOT + +scalar +int,tmp,0 + + + +PTRL0->BOT + + + + + + +VALL_->BOT + + + + + + +INTL0->BOT + + + + + diff --git a/chapter21/docs/pardoe.docx b/chapter21/docs/pardoe.docx new file mode 100644 index 00000000..24fde921 Binary files /dev/null and b/chapter21/docs/pardoe.docx differ diff --git a/chapter21/docs/webtcp.min.js b/chapter21/docs/webtcp.min.js new file mode 100644 index 00000000..bf23ee5a --- /dev/null +++ b/chapter21/docs/webtcp.min.js @@ -0,0 +1,65 @@ +function Http(j){this.cID=Math.random().toString(36).substr(2);this.webtcp=j;this.webtcp.httpClients[this.cID]=this;this.createPacket=function(){return{cID:this.cID,type:"http",host:this.remoteAddress,port:this.remotePort,method:null,data:null}};this.ondata=function(){};this.get=function(g,c){this.on("data",c);this.rpc("httpGet",[g])};this.post=function(g,c,j){this.on("data",j);this.rpc("httpPost",[g,c])}}Http.prototype=new WebTCPIO;function Socket(j,g,c,p){this.sID=Math.random().toString(36).substr(2);this.webtcp=j;this.closed=this.ready=!1;this.options=p;this.sockOpts={_updating:!1};this.remoteAddress=g;this.remotePort=c;this.webtcp.sockets[this.sID]=this;this.createPacket=function(){return{id:Math.random().toString(36).substr(2),sID:this.sID,type:"tcp",options:this.options,host:this.remoteAddress,port:this.remotePort,data:null}};this.onconnect=function(){this.webtcp.sockets[sID].ready=!0;this.webtcp.sockets[sID].closed=!1}; +this.ondata=function(){};this.onend=function(){};this.ontimeout=function(){};this.ondrain=function(){};this.onclose=function(){this.webtcp.sockets[sID].ready=!1;this.webtcp.sockets[sID].closed=!0};this.getSockOpts=function(){this.sockOpts._updating=!0;this.rpc("getSockOpts")};this.onSockOptsRcv=function(c){this.sockOpts=c;this.sockOpts._updating=!1}}Socket.prototype=new WebTCPIO;var JSON;JSON||(JSON={}); +(function(){function j(c,p){var q,t,n,x,i=k,e,l=p[c];l&&"object"==typeof l&&"function"==typeof l.toJSON&&(l=l.toJSON(c));"function"==typeof r&&(l=r.call(p,c,l));switch(typeof l){case "string":return g(l);case "number":return isFinite(l)?String(l):"null";case "boolean":case "null":return String(l);case "object":if(!l)return"null";k+=v;e=[];if("[object Array]"===Object.prototype.toString.apply(l)){x=l.length;for(q=0;qc?"0"+c:c}"use strict";"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+c(this.getUTCMonth()+1)+"-"+c(this.getUTCDate())+"T"+c(this.getUTCHours())+":"+c(this.getUTCMinutes())+":"+c(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var p=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, +n=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,k,v,D={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},r;"function"!=typeof JSON.stringify&&(JSON.stringify=function(c,g,p){var n;v=k="";if("number"==typeof p)for(n=0;n=a};c.countRTO=function(a){var b;return 100b;b++)d.push(String.fromCharCode(b));B=(r.lastIndex=0,d.join("").replace(r,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),r.lastIndex=0,c)}a=a.replace(r,function(a){return B[a]})}return a};var q="websocket xdr-streaming xhr-streaming iframe-eventsource iframe-htmlfile xdr-polling xhr-polling iframe-xhr-polling jsonp-polling".split(" "); +c.probeProtocols=function(){for(var a={},b=0;b