summaryrefslogtreecommitdiff
path: root/ASimpleReply
diff options
context:
space:
mode:
authorTamás Hadházy <85063808+Hels15@users.noreply.github.com>2025-04-15 22:46:50 +0100
committerGitHub <noreply@github.com>2025-04-15 14:46:50 -0700
commit2fb0ec312d76f22534331023c86e68b7a62b98e6 (patch)
tree06d1bac2db8a8c124a202fe35500762775b6846e /ASimpleReply
parentb74f35618c087e4e6634707c6e03ca669315bcc9 (diff)
downloadSimple-2fb0ec312d76f22534331023c86e68b7a62b98e6.tar.gz
Simple-2fb0ec312d76f22534331023c86e68b7a62b98e6.zip
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 <cliffc@acm.org> * 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 <cliffc@acm.org> * 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 <cliffc@acm.org> * 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 <cliffc@acm.org> Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com>
Diffstat (limited to 'ASimpleReply')
-rw-r--r--ASimpleReply/ASimpleReply2.md123
-rw-r--r--ASimpleReply/ASimpleReply3.md127
-rw-r--r--ASimpleReply/ASimpleReplyChain.md16
-rw-r--r--ASimpleReply/DadalReply2.md58
-rw-r--r--ASimpleReply/DadalReply3.md25
5 files changed, 338 insertions, 11 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
diff --git a/ASimpleReply/ASimpleReply3.md b/ASimpleReply/ASimpleReply3.md
new file mode 100644
index 00000000..395f4b77
--- /dev/null
+++ b/ASimpleReply/ASimpleReply3.md
@@ -0,0 +1,127 @@
+# 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
diff --git a/ASimpleReply/ASimpleReplyChain.md b/ASimpleReply/ASimpleReplyChain.md
index 2d53a8ee..eb0bc80e 100644
--- a/ASimpleReply/ASimpleReplyChain.md
+++ b/ASimpleReply/ASimpleReplyChain.md
@@ -17,10 +17,22 @@ 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
+### 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/ASimpleReply3.md
+
+### Dadal's Reply(3)
+
+https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/DadalReply3.md
+
[room for more conversations]
diff --git a/ASimpleReply/DadalReply2.md b/ASimpleReply/DadalReply2.md
new file mode 100644
index 00000000..bb30e155
--- /dev/null
+++ b/ASimpleReply/DadalReply2.md
@@ -0,0 +1,58 @@
+
+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
+
+The whole replace chain:
+
+https://github.com/SeaOfNodes/Simple/blob/main/ASimpleReply/ASimpleReplyChain.md
+
+
+
+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 :)
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")