summaryrefslogtreecommitdiff
path: root/chapter20/src/test/java/com/seaofnodes
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-03-08 09:59:31 -0800
committerGitHub <noreply@github.com>2025-03-08 09:59:31 -0800
commit2370fb29d4538479af9eb94fc666a5ce09fcb492 (patch)
treef21ed94228e23c6786a175741b785ab85888fadb /chapter20/src/test/java/com/seaofnodes
parent53452331d8e69dc3bcd40a56a4f00f9380140e73 (diff)
downloadSimple-2370fb29d4538479af9eb94fc666a5ce09fcb492.tar.gz
Simple-2370fb29d4538479af9eb94fc666a5ce09fcb492.zip
Ch20 reg (#166)
* READMEs * Update README.md * Update README.md * Move printing into print dir * Move codegen into codegen * Framework for Reg Alloc * First cut BuildLRG RegMask.EMPTY -> null * Setup for first simple split * First cut split code for mismatch regs * 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. * Next cut regalloc Building IFG. Coloring. Some nested spilling Optimize divf/con -> mul times inverse * 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 <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 --------- Co-authored-by: Cliff Click <cliffc@acm.org> * 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 * 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 * README updates * Fix ch19 mis-merge? * x86 call args, risc5 load/store regs * Push RISC WMASK avoid writing to RSP * 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 * 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. * 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 * remove jukn files * minimal "make release" * 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 * 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 * Push l,ast change, unbreak branch * 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 * Bunch of minor arm, risc fixes small constants not cloning * 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 * 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 * Cleanup call ABI presentation Everybody uses the same names, same code shapes * Caller save regs ...not callee save yet * Expose caller save regs * 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 * 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 * 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 * yank MulIRISC * fix arg flags reg Arm split op can spill flags bugfix RegAlloc 1st real >=64bit reg num * Update Chapter20Test.java * Turn off transpile tests which are broken for some time now * A lot more readme * better flags ListScheduler stalls cmp/jmp in the same block; avoids some flags spills. Make CmpIX86/ARM rematieralize. Bugfix: remove some include x86/risc/arm in other dirs. Canonicalize boilerplate fcn order * regalloc improves Use FltRISC, not clonable requires a spill from int->flt regs. new splits track origin LRG, so later splits in the same pass know what lrg a spilled input is. * RA improvements & fixes Bugfix on split loop-depth computation. Track killmask kills, which are always capacity kills and require more spilling. Rename the riscv registers canonically, so I can tell them part! Definitely no GP or TP in Simple. Node insertAfter bypass a little more conservative. * RA bugfix remove unified failed live ranges * easier access for remote ports debug support * Lots more comments * bugfix infinite peep cycle on (17 ^ 3.14), i.e. bad program * Fix imm12 shift --------- Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Diffstat (limited to 'chapter20/src/test/java/com/seaofnodes')
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/BrainFuckTest.java14
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter01Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter02Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter03Test.java2
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter05Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter06Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter07Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter08Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter09Test.java2
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter10Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter11Test.java3
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java5
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter13Test.java14
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter14Test.java4
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter15Test.java13
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter16Test.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter17Test.java7
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter18Test.java13
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter19Test.java88
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter20Test.java185
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Eval2.java4
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Main.java2
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/MergeSortTest.java12
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/SchedulerTest.java1
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java2
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java2
27 files changed, 298 insertions, 84 deletions
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter20/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 8f09cb3d..c23bb301 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.evaluator.Evaluator;
+import com.seaofnodes.simple.codegen.CodeGen;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static com.seaofnodes.simple.Main.PORTS;
public class BrainFuckTest {
@@ -17,8 +18,7 @@ public class BrainFuckTest {
encoded.append("program[").append(i).append("] = ").append(value).append(";");
}
- CodeGen code = new CodeGen(
- encoded + """
+ String src = encoded + """
int d = 0;
u8[] !output = new u8[0];
@@ -62,8 +62,10 @@ for( int pc = 0; pc < program#; pc++ ) {
}
}
return output;
- """);
- code.parse().opto().typeCheck()/*.instSelect("x86_64_v2", "SystemV")*/.GCM().localSched();
- assertEquals("Hello World!\n", Eval2.eval(code, 0, 10000));
+""";
+ Chapter20Test.testCPU(src,"x86_64_v2", "SystemV",28,null);
+ Chapter20Test.testCPU(src,"riscv" , "SystemV",18,null);
+ Chapter20Test.testCPU(src,"arm" , "SystemV",12,null);
+ //assertEquals("Hello World!\n", Eval2.eval(code, 0, 10000));
}
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index 934eda76..cddbdfcf 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter02Test.java
index d8607c32..631e1487 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter02Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter03Test.java
index 4f9b2490..c4e4c91e 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter03Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
-
import static org.junit.Assert.*;
public class Chapter03Test {
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java
index d09b1748..c6199193 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 86ec4136..a584ad5a 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index 117531f0..24d12921 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index 6d6a3ce7..88554323 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter08Test.java
index 350df18b..7e90d484 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter08Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter08Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import org.junit.Assert;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter09Test.java
index 10f4a78b..401f346f 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter09Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter09Test.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.evaluator.Evaluator;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import org.junit.Assert;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index 02029b3f..1253e4a6 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter11Test.java
index 0b24bd5d..c2b9a86d 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter11Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter11Test.java
@@ -1,8 +1,7 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
-
-
import static org.junit.Assert.assertEquals;
public class Chapter11Test {
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index 21df8205..8069ddaa 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -1,8 +1,7 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.evaluator.Evaluator;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.StopNode;
-import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -43,7 +42,7 @@ while( 1 ) {
return guess;
""");
code.parse().opto();
- assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0f));", code.print());
+ assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)*0.5f));", code.print());
assertEquals("3.0", Eval2.eval(code, 9));
assertEquals("1.414213562373095", Eval2.eval(code, 2));
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter13Test.java
index d05fd7d8..977595cb 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter13Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter13Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -128,6 +129,19 @@ return n.i;
}
@Test
+ public void testNullRef4() {
+ CodeGen code = new CodeGen("-null-5/null-5;");
+ try { code.parse().opto().typeCheck(); fail(); }
+ catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); }
+ }
+
+ @Test public void testNullRef5() {
+ CodeGen code = new CodeGen("return null+42;");
+ try { code.parse().opto().typeCheck(); fail(); }
+ catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); }
+ }
+
+ @Test
public void testEmpty() {
CodeGen code = new CodeGen(
"""
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter14Test.java
index 17708c37..b83516e3 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter14Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter14Test.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.StopNode;
import org.junit.Test;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -174,7 +174,7 @@ while(v1) break;
return v1;
""");
code.parse().opto();
- assertEquals("return Phi(Loop,(((1<<arg)&1)&Shl),0);", code.print());
+ assertEquals("return (Phi(Loop,((1<<arg)&1),0)&Phi(Loop,Shl,4294967295));", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index 546eb0e9..7dd0710a 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -300,18 +301,20 @@ return is[1];
@Test
public void testBad3() {
- CodeGen code = new CodeGen(
-"""
+ CodeGen code = new CodeGen("""
int[] is = new int[arg];
return is[1];
""");
code.parse().opto();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 4));
- try { Eval2.eval(code,0); }
- catch( ArrayIndexOutOfBoundsException e ) { assertEquals("Array index 1 out of bounds for array length 0",e.getMessage()); }
- try { Eval2.eval(code,-1); }
+ try { Eval2.eval(code,-1); fail(); }
catch( NegativeArraySizeException e ) { assertEquals("-1",e.getMessage()); }
+ // This test will not pass (i.e., failed range-check) until we have range checks.
+ // Without the range check, the load `is[1]` optimizes against the `new int[]`
+ // and assumes it loads a zero then folds away, and the Eval2 never sees an OOB load.
+ //try { Eval2.eval(code,0); fail(); }
+ //catch( ArrayIndexOutOfBoundsException e ) { assertEquals("Array index 1 out of bounds for array length 0",e.getMessage()); }
}
@Test
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index ad3dc690..930624e5 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.evaluator.Evaluator;
import com.seaofnodes.simple.node.StopNode;
import org.junit.Test;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index a1d0f8b9..6e43dbc8 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -10,11 +11,9 @@ public class Chapter17Test {
public void testJig() {
CodeGen code = new CodeGen(
"""
-int i = 0;
-i=i=1;
-return i;
+return 1;
""");
- code.parse().opto();
+ code.parse().opto().typeCheck();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index db970f60..d0623d12 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
+import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
-import org.junit.Ignore;
public class Chapter18Test {
@@ -77,7 +78,7 @@ var sq = { int x ->
return sq(arg)+sq(3);
""");
code.parse().opto().typeCheck().GCM().localSched();
- assertEquals("Stop[ return (sq( 3)+sq( arg)); return (Parm_x(sq,int,3,arg)*x); ]", code._stop.toString());
+ assertEquals("Stop[ return (#2+#2); return (Parm_x(sq,int)*x); ]", code._stop.toString());
assertEquals("13", Eval2.eval(code, 2));
}
@@ -115,7 +116,7 @@ var fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(3);
""");
code.parse().opto();
- assertEquals("Stop[ return Phi(Region,{ int -> int #1},{ int -> int #2})( 3); return (Parm_x($fun,int,3)*x); return (Parm_x($fun,int,3)<<1); ]", code._stop.toString());
+ assertEquals("Stop[ return #2; return (Parm_x($fun1,int,3)*x); return (Parm_x($fun2,int,3)<<1); ]", code._stop.toString());
assertEquals("6", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
}
@@ -125,7 +126,7 @@ return fcn(3);
public void testFcn5() {
CodeGen code = new CodeGen("val fact = { int x -> x <= 1 ? 1 : x*fact(x-1); }; return fact(arg);");
code.parse().opto().typeCheck();
- assertEquals("Stop[ return fact( arg); return Phi(Region,1,(Parm_x(fact,int,arg,(x-1))*fact( Sub))); ]", code._stop.toString());
+ assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,int,arg,(x-1))*#2)); ]", code._stop.toString());
assertEquals( "1", Eval2.eval(code, 0));
assertEquals( "1", Eval2.eval(code, 1));
assertEquals( "2", Eval2.eval(code, 2));
@@ -175,7 +176,7 @@ for(;;) {
}
""");
code.parse().opto().typeCheck().GCM().localSched();
- assertEquals("Stop[ return x( Phi(Loop,arg,x( 3))); return Parm_i(x,int,3,Phi_arg); ]", code._stop.toString());
+ assertEquals("Stop[ return #2; return Parm_i(x,int); ]", code._stop.toString());
assertEquals("3", Eval2.eval(code, 0));
}
@@ -346,7 +347,7 @@ if (i2i) return i2i(arg);
return f2f(o)(1);
""");
code.parse().opto().typeCheck().GCM().localSched();
- assertEquals("Stop[ return Phi(Region,o( arg),o( 1)); return Parm_i(o,int,arg,1); ]", code._stop.toString());
+ assertEquals("Stop[ return Phi(Region,#2,#2); return Parm_i(o,int); ]", code._stop.toString());
assertEquals("1", Eval2.eval(code, 2));
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter19Test.java
index a4857a01..bb7e8716 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter19Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter19Test.java
@@ -1,9 +1,11 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
+import org.junit.Ignore;
import org.junit.Test;
+import static com.seaofnodes.simple.Main.PORTS;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
-import org.junit.Ignore;
public class Chapter19Test {
@@ -55,107 +57,107 @@ val _hashCodeString = { String self ->
String !s = new String { cs = new u8[17]; };
s.cs[0] = 67; // C
s.cs[1] = 108; // l
-hashCode(s);""");
+hashCode(s)+hashCode(s);""");
code.parse().opto().typeCheck().GCM().localSched();
- assertEquals("Stop[ return Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash)))); return Phi(Region,1,0,0,1); ]", code._stop.toString());
- assertEquals("-2449306563677080489", Eval2.eval(code, 2));
+ assertEquals("Stop[ return (#2+#2); return Phi(Region,1,0,0,1); return Phi(Region,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code._stop.toString());
+ assertEquals("-4898613127354160978", Eval2.eval(code, 2));
}
@Test
public void testBasic0() {
- CodeGen code = new CodeGen("return 0;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return 0;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return 0;", code._stop.toString());
}
@Test
public void testBasic1() {
- CodeGen code = new CodeGen("return arg+1;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg+1;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (inc,arg);", code._stop.toString());
}
@Test
public void testBasic2() {
- CodeGen code = new CodeGen("return -17;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return -17;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return -17;", code._stop.toString());
}
@Test
public void testBasic3() {
- CodeGen code = new CodeGen("return arg==1;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg==1;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (set==,(cmp,arg));", code._stop.toString());
}
@Test
public void testBasic4() {
- CodeGen code = new CodeGen("return arg<<1;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg<<1;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (shli,arg);", code._stop.toString());
}
@Test
public void testBasic5() {
- CodeGen code = new CodeGen("return arg >> 1;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg >> 1;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (sari,arg);", code._stop.toString());
}
@Test
public void testBasic6() {
- CodeGen code = new CodeGen("return arg >>> 1;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg >>> 1;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (shri,arg);", code._stop.toString());
}
@Test
public void testBasic7() {
- CodeGen code = new CodeGen("return arg / 2;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg / 2;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (div,arg,2);", code._stop.toString());
}
@Test
public void testBasic8() {
- CodeGen code = new CodeGen("return arg * 6;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg * 6;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (muli,arg);", code._stop.toString());
}
@Test
public void testBasic9() {
- CodeGen code = new CodeGen("return arg & 2;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg & 2;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (andi,arg);", code._stop.toString());
}
@Test
public void testBasic10() {
- CodeGen code = new CodeGen("return arg | 2;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg | 2;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (ori,arg);", code._stop.toString());
}
@Test
public void testBasic11() {
- CodeGen code = new CodeGen("return arg ^ 2;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg ^ 2;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (xori,arg);", code._stop.toString());
}
@Test
public void testBasic12() {
- CodeGen code = new CodeGen("return arg + 2.0;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg + 2.0;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (addf,(i2f8,arg),2.0f);", code._stop.toString());
}
@Test
public void testBasic13() {
- CodeGen code = new CodeGen("return arg - 2.0;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg - 2.0;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (subf,(i2f8,arg),2.0f);", code._stop.toString());
}
@Test
public void testBasic14() {
- CodeGen code = new CodeGen("return arg * 2.0;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ CodeGen code = new CodeGen("return arg * 2.0;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (mulf,(i2f8,arg),2.0f);", code._stop.toString());
}
@Test
public void testBasic15() {
- CodeGen code = new CodeGen("return arg / 2.0;").parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
- assertEquals("return (divf,(i2f8,arg),2.0f);", code._stop.toString());
+ CodeGen code = new CodeGen("return arg / 2.0;").parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
+ assertEquals("return (mulf,(i2f8,arg),0.5f);", code._stop.toString());
}
@Test
@@ -164,7 +166,7 @@ hashCode(s);""");
"""
int arg1 = arg + 1;
return arg1 / arg;""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (div,(inc,arg),arg);", code._stop.toString());
}
@@ -175,7 +177,7 @@ return arg1 / arg;""");
int arg1 = arg + 1;
return arg1 * arg;
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (mul,(inc,arg),arg);", code._stop.toString());
}
@@ -185,7 +187,7 @@ return arg1 * arg;
int a = arg;
return a + 2.0;
"""
- ).parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ ).parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (addf,(i2f8,arg),2.0f);", code._stop.toString());
}
@@ -200,7 +202,7 @@ else {
a = arg-3;
}
return a;""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return Phi(Region,(addi,arg),(addi,arg));", code.print());
}
@@ -215,7 +217,7 @@ if( arg==1 )
else
a=b+1;
return a+b;""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (add,(add,Phi(Region,(shli,arg),arg),arg),Phi(Region,4,5));", code.print());
}
@@ -227,7 +229,7 @@ int sum=0;
for( int i=0; i<arg; i++ )
sum += i;
return sum;""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return Phi(Loop,0,(add,Phi_sum,Phi(Loop,0,(inc,Phi_i))));", code.print());
}
@@ -237,42 +239,42 @@ return sum;""");
"""
struct S { int a; S? c; };
return new S;""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return S;", code.print());
}
@Test
public void testLea1() {
CodeGen code = new CodeGen("int x = arg/3; return arg+x+7;");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (lea,arg,(div,arg,3));", code.print());
}
@Test
public void testLea2() {
CodeGen code = new CodeGen("int x = arg/3; return arg+x*4+7;");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (lea,arg,(div,arg,3));", code.print());
}
@Test
public void testLea3() {
CodeGen code = new CodeGen("int x = arg/3; return x*4+arg;");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return (lea,arg,(div,arg,3));", code.print());
}
@Test
public void testAlloc2() {
CodeGen code = new CodeGen("int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return .[];", code.print());
}
@Test
public void testAlloc3() {
CodeGen code = new CodeGen("int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1]+3;");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return .[];", code.print());
}
@@ -289,7 +291,7 @@ for( int i=0; i<ary#-1; i++ )
ary[i+1] += ary[i];
return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return .[];", code.print());
}
@@ -304,7 +306,7 @@ for( int i=0; i<A#; i++ )
for( int i=0; i<A#; i++ )
B[i] += A[i];
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return 0;", code.print());
}
@@ -317,7 +319,7 @@ for( int i=0; i<A#; i++ )
A[i]++;
return A[1];
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return .[];", code.print());
}
@@ -337,8 +339,8 @@ val sqrt = { flt x ->
flt farg = arg;
return sqrt(farg);
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
- assertEquals("return Phi(Loop,(i2f8,arg),(divf,(addf,(divf,i2f8,Phi_guess),Phi_guess),2.0f));", code.print());
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
+ assertEquals("return Phi(Loop,(i2f8,arg),(mulf,(addf,(divf,i2f8,Phi_guess),Phi_guess),0.5f));", code.print());
};
@@ -368,7 +370,7 @@ for( int j=0; j<nprimes; j++ )
rez[j] = primes[j];
return rez;
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
assertEquals("return [int];", code.print());
//assertEquals("int[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20));
}
@@ -381,8 +383,8 @@ return rez;
val fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(2)*10 + fcn(3);
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
- assertEquals("Stop[ return (add,Phi(Region,{ int -> int #1},{ int -> int #2})( 3),(muli,Phi_( 2))); return (mul,Parm_x($fun,int,3,2),x); return (shli,Parm_x($fun,int,3,2)); ]", code.print());
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
+ assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun1,int),x); return (shli,Parm_x($fun2,int)); ]", code.print());
}
@Test
@@ -392,7 +394,7 @@ return fcn(2)*10 + fcn(3);
val sq = { int x -> x*x; };
return sq(arg) + sq(3);
""");
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched();
- assertEquals("Stop[ return (add,sq(),sq()); return (mul,Parm_x(sq,int,3,arg),x); ]", code.print());
+ code.parse().opto().typeCheck().instSelect(PORTS,"x86_64_v2", "SystemV").GCM().localSched();
+ assertEquals("Stop[ return (add,#2,#2); return (mul,Parm_x(sq,int),x); ]", code.print());
}
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 48458f95..008f5e0c 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -1,17 +1,196 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.print.ASMPrinter;
+import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
+import static com.seaofnodes.simple.Main.PORTS;
import static org.junit.Assert.*;
public class Chapter20Test {
@Test
public void testJig() {
- CodeGen code = new CodeGen("""
-return 0;
-""");
+ CodeGen code = new CodeGen("return 0;");
code.parse().opto().typeCheck();
assertEquals("return 0;", code._stop.toString());
assertEquals("0", Eval2.eval(code, 2));
}
+
+ static void testCPU( String src, String cpu, String os, int spills, String stop ) {
+ CodeGen code = new CodeGen(src);
+ code.parse().opto().typeCheck().instSelect(PORTS,cpu,os).GCM().localSched().regAlloc().encode();
+ int delta = spills>>3;
+ if( delta==0 ) delta = 1;
+ assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);
+ if( stop != null )
+ assertEquals(stop, code._stop.toString());
+ }
+
+ private static void testAllCPUs( String src, int spills, String stop ) {
+ testCPU(src,"x86_64_v2", "SystemV",spills,stop);
+ testCPU(src,"riscv" , "SystemV",spills,stop);
+ testCPU(src,"arm" , "SystemV",spills,stop);
+ }
+
+ @Test public void testAlloc0() {
+ testAllCPUs("return new u8[arg];", 1, "return [u8];");
+ }
+
+ @Test public void testBasic1() {
+ String src = "return arg | 2;";
+ testCPU(src,"x86_64_v2", "SystemV",1,"return (ori,mov(arg));");
+ testCPU(src,"riscv" , "SystemV",0,"return ( arg | #2 );");
+ testCPU(src,"arm" , "SystemV",0,"return (ori,arg);");
+ }
+
+ @Test
+ public void testNewtonInteger() {
+ String src =
+"""
+// Newtons approximation to the square root
+val sqrt = { int x ->
+ int guess = x;
+ while( 1 ) {
+ int next = (x/guess + guess)/2;
+ if( next == guess ) return guess;
+ guess = next;
+ }
+};
+return sqrt(arg) + sqrt(arg+2);
+""";
+ testCPU(src,"x86_64_v2", "SystemV",26,null);
+ testCPU(src,"riscv" , "SystemV",19,null);
+ testCPU(src,"arm" , "SystemV",26,null);
+ }
+
+ @Test
+ public void testNewtonFloat() {
+ String src =
+"""
+// Newtons approximation to the square root
+val sqrt = { flt x ->
+ flt guess = x;
+ while( 1 ) {
+ flt next = (x/guess + guess)/2;
+ if( next == guess ) return guess;
+ guess = next;
+ }
+};
+flt farg = arg;
+return sqrt(farg) + sqrt(farg+2.0);
+""";
+ testCPU(src,"x86_64_v2", "SystemV",25,null);
+ testCPU(src,"riscv" , "SystemV",21,null);
+ testCPU(src,"arm" , "SystemV",18,null);
+ }
+
+ @Test
+ public void testAlloc2() {
+ String src = "int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];";
+ testAllCPUs(src,1,"return .[];");
+ }
+
+ @Test
+ public void testArray1() {
+ String src =
+"""
+int[] !ary = new int[arg];
+// Fill [0,1,2,3,4,...]
+for( int i=0; i<ary#; i++ )
+ ary[i] = i;
+// Fill [0,1,3,6,10,...]
+for( int i=0; i<ary#-1; i++ )
+ ary[i+1] += ary[i];
+return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
+""";
+ testCPU(src,"x86_64_v2", "SystemV",3,"return .[];");
+ testCPU(src,"riscv" , "SystemV",1,"return (add,.[],(mul,.[],1000));");
+ testCPU(src,"arm" , "SystemV",1,"return (add,.[],(muli,.[]));");
+ }
+
+ @Test
+ public void testString() {
+ String src = """
+struct String {
+ u8[] cs;
+ int _hashCode;
+};
+
+val equals = { String self, String s ->
+ if( self == s ) return true;
+ if( self.cs# != s.cs# ) return false;
+ for( int i=0; i< self.cs#; i++ )
+ if( self.cs[i] != s.cs[i] )
+ return false;
+ return true;
+};
+
+val hashCode = { String self ->
+ self._hashCode
+ ? self._hashCode
+ : (self._hashCode = _hashCodeString(self));
+};
+
+val _hashCodeString = { String self ->
+ int hash=0;
+ if( self.cs ) {
+ for( int i=0; i< self.cs#; i++ )
+ hash = hash*31 + self.cs[i];
+ }
+ if( !hash ) hash = 123456789;
+ return hash;
+};
+
+String !s = new String { cs = new u8[17]; };
+s.cs[0] = 67; // C
+s.cs[1] = 108; // l
+hashCode(s);
+""";
+ testCPU(src,"x86_64_v2", "SystemV",18,null);
+ testCPU(src,"riscv" , "SystemV", 3,null);
+ testCPU(src,"arm" , "SystemV", 3,null);
+ }
+
+ @Test
+ public void testCast() {
+ String src = "struct Bar { int x; }; var b = arg ? new Bar; return b ? b.x++ + b.x++ : -1;";
+ testAllCPUs(src,0,null);
+ }
+
+ @Test
+ public void testFltArg() {
+ String src = "return {int i, flt f, int j->return i+f+j;};";
+ testAllCPUs(src,0,null);
+ }
+
+ @Test
+ public void testFlags1() {
+ String src = """
+bool b1 = arg == 1;
+bool b2 = arg == 2;
+if (b2) if (b1) return 1;
+if (b1) return 2;
+return 0;
+""";
+ testCPU(src,"x86_64_v2", "SystemV",0,"return Phi(Region,1,2,0);");
+ testCPU(src,"riscv" , "SystemV",0,"return Phi(Region,1,2,0);");
+ testCPU(src,"arm" , "SystemV",0,"return Phi(Region,1,2,0);");
+ }
+
+ @Test
+ public void testFlags2() {
+ String src = """
+bool b1 = arg == 1;
+while (arg > 0) {
+ arg--;
+ if (b1) arg--;
+}
+return arg;
+""";
+ testCPU(src,"x86_64_v2", "SystemV",3,null);
+ testCPU(src,"riscv" , "SystemV",2,null);
+ testCPU(src,"arm" , "SystemV",2,null);
+ }
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter20/src/test/java/com/seaofnodes/simple/Eval2.java
index 6ae8427c..ecea97dd 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Eval2.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Eval2.java
@@ -1,7 +1,9 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.print.IRPrinter;
+import com.seaofnodes.simple.type.*;
import java.util.*;
public abstract class Eval2 {
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Main.java b/chapter20/src/test/java/com/seaofnodes/simple/Main.java
index 523bd306..f3a6784c 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/Main.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/Main.java
@@ -1,9 +1,11 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
+ public static final String PORTS = "com.seaofnodes.simple.node.cpus";
// Compile and run a simple program
public static void main( String[] args ) throws Exception {
// First arg is file, 2nd+ args are program args
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/MergeSortTest.java b/chapter20/src/test/java/com/seaofnodes/simple/MergeSortTest.java
index d48449d5..c83fe089 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/MergeSortTest.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/MergeSortTest.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -8,7 +9,7 @@ public class MergeSortTest {
@Test
public void testMergeSort() {
- CodeGen code = new CodeGen(
+ String src =
"""
// based on the top-down version from https://en.wikipedia.org/wiki/Merge_sort
@@ -56,10 +57,11 @@ for (int i = 0; i < a#; i++)
merge_sort(a, b, a#);
return a;
-""");
- code.parse().opto();
- assertEquals("Stop[ return [int]; return 0; ]", code._stop.toString());
- assertEquals("int[ 1,2,3,4,5,6,7,8,9,10,11]", Eval2.eval(code, 11));
+""";
+ Chapter20Test.testCPU(src,"x86_64_v2", "SystemV",46,"Stop[ return mov(mov([int])); return 0; ]");
+ Chapter20Test.testCPU(src,"riscv" , "SystemV",36,"Stop[ return mov(mov([int])); return 0; ]");
+ Chapter20Test.testCPU(src,"arm" , "SystemV",37,"Stop[ return mov(mov([int])); return 0; ]");
+//assertEquals("int[ 1,2,3,4,5,6,7,8,9,10,11]", Eval2.eval(code, 11));
}
}
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/chapter20/src/test/java/com/seaofnodes/simple/SchedulerTest.java
index d50c302a..ca29bf84 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/SchedulerTest.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/SchedulerTest.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.evaluator.Evaluator;
import com.seaofnodes.simple.node.StopNode;
import org.junit.Assert;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
index f7e0c4ad..30a548ad 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
@@ -2,7 +2,7 @@ package com.seaofnodes.simple.fuzzer;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Eval2;
-import com.seaofnodes.simple.CodeGen;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.Node;
import java.util.ArrayList;
import java.util.Objects;
diff --git a/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java b/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java
index 0781ad67..669a1e6a 100644
--- a/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java
+++ b/chapter20/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.fuzzer;
-import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.IterPeeps;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StopNode;
import com.seaofnodes.simple.type.TypeInteger;