diff options
| author | Cliff Click <cliffc@acm.org> | 2025-05-08 13:38:45 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-05-08 13:38:45 -0700 |
| commit | f1c1c070f0491cba8b18f3169e72e9a1df8f1a2a (patch) | |
| tree | d6b3a7c903daf0d3f953e40f877030d86b690377 /chapter22/src/test | |
| parent | a174b75edab35f078455b4b9a737f383a3be55a3 (diff) | |
| download | Simple-f1c1c070f0491cba8b18f3169e72e9a1df8f1a2a.tar.gz Simple-f1c1c070f0491cba8b18f3169e72e9a1df8f1a2a.zip | |
Work on a cmd-line driver for Simple
Diffstat (limited to 'chapter22/src/test')
4 files changed, 153 insertions, 168 deletions
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java index 8ad72eaa..86f0e9db 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java @@ -289,9 +289,9 @@ public abstract class Eval2 { // Fetch without unboxing, searching up-Frame static Object val( Node n ) { return F.get(n); } // Fetch and unbox as primitive long - static long x( Node n ) { Object d = F.get(n); return d==null ? 0 : (Long) F.get(n); } + static long x( Node n ) { Object d = F.get(n); return d==null ? 0 : (Long)d; } // Fetch and unbox as primitive double - static double d( Node n ) { Object d = F.get(n); return d==null ? 0 : (Double)F.get(n); } + static double d( Node n ) { Object d = F.get(n); return d==null ? 0 : (Double)d; } // Fetch and unbox a function constant static TypeFunPtr tfp(Node n) { return (TypeFunPtr)F.get(n); } // Fetch and unbox a closure @@ -347,10 +347,19 @@ public abstract class Eval2 { } private static Object load( LoadNode ld ) { - TypeMemPtr tmp = (TypeMemPtr)ld.ptr()._type; - Object[] fs = (Object[])val(ld.ptr()); + Object f = val(ld.ptr()); + // Check for dense constant array + if( f instanceof TypeMemPtr tmp ) { + assert tmp._obj._con != TypeConAry.BOT; + if( ld._name.equals("#") ) + return (long)tmp._obj._con.len(); + int idx = offToIdx(x(ld.off()),tmp._obj); + return tmp._obj._con.at(idx); + } + Object[] fs = (Object[])f; if( ld._name.equals("#") ) return (long)fs.length; + TypeMemPtr tmp = (TypeMemPtr)ld.ptr()._type; int idx = tmp._obj.isAry() ? offToIdx(x(ld.off()),tmp._obj) : tmp._obj.find(ld._name); diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Simple.java b/chapter22/src/test/java/com/seaofnodes/simple/Simple.java index 9b1e2827..1465aa6d 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Simple.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Simple.java @@ -17,7 +17,7 @@ public class Simple { static final int DUMP_AFTER_OPTO = 1<<1; static final int DUMP_AFTER_TYPE_CHECK = 1<<2; static final int DUMP_AFTER_LOOP_TREE = 1<<3; - static final int DUMP_AFTER_INSTR_SELECT = 1<<4; + static final int DUMP_AFTER_SELECT = 1<<4; static final int DUMP_AFTER_GCM = 1<<5; static final int DUMP_AFTER_LOCAL_SCHED = 1<<6; static final int DUMP_AFTER_REG_ALLOC = 1<<7; @@ -32,33 +32,30 @@ public class Simple { static final int DUMP_DISASSEMBLE = 1<<31; - static String system_cpu = null; - static String system_abi = null; - static void usage() { System.out.println( """ -simple <input-file> [options] [--eval|--run ...] +simple [options] <input-file> ...args... Options: - --dump - dump final intermediate representation - --dump-after-parse - dump intermediate representation after parse - --dump-after-opto - dump intermediate representation after opto pass - --dump-after-type-check - dump intermediate representation after type check pass - --dump-after-instr-select - dump intermediate representation after instrution selection pass - --dump-after-gcm - dump intermediate representation after GCM pass - --dump-after-local-sched - dump intermediate representation after local scheduling pass - --dump-after-reg-alloc - dump intermediate representation after register allocation pass - --dump-after-encode - dump intermediate representation after encoding pass - --dump-after-all - dump intermediate representation after all passes - --dot - dump grapical representation of intermediate code into *.dot file(s) - -S - dump generated assembler code - --eval ... - evaluate the compiled code in emulator - --run ... - run the compiled code natively - --dump-size - print the size of generated code - --dump-time - print compilation and execution times - --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm) - --abi <abi-name> - use speific ABI variant (SystemV) - --target - print native CPU and ABI + --dump - dump final intermediate representation + --dump-after-parse - dump intermediate representation after parse + --dump-after-opto - dump intermediate representation after opto pass + --dump-after-type-check - dump intermediate representation after type check pass + --dump-after-select - dump intermediate representation after instrution selection pass + --dump-after-gcm - dump intermediate representation after GCM pass + --dump-after-local-sched - dump intermediate representation after local scheduling pass + --dump-after-reg-alloc - dump intermediate representation after register allocation pass + --dump-after-encode - dump intermediate representation after encoding pass + --dump-after-all - dump intermediate representation after all passes + --dot - dump grapical representation of intermediate code into *.dot file(s) + -S - dump generated assembler code + --eval - evaluate the compiled code in emulator + --run - run the compiled code natively; this is the default + --dump-size - print the size of generated code + --dump-time - print compilation and execution times + --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm) + --abi <abi-name> - use speific ABI variant (SystemV) + --target - print native CPU and ABI --version --help """ @@ -66,46 +63,40 @@ Options: System.exit(0); } - static void bad_usage() { - System.err.println("ERROR: Invalid usage (use --help)"); + static void bad_usage() { bad("Invalid usage (use --help)"); } + static RuntimeException bad(String err) { + System.err.println("ERROR: "+err); System.exit(1); + return new RuntimeException(err); } static void target() { - if (system_cpu == null || system_abi == null) { - System.err.println("ERROR: Unknown target"); - System.exit(1); - } - System.out.print(system_cpu); + System.out.print(TestC.CPU_PORT); System.out.print("-"); - System.out.println(system_abi); - System.exit(0); + System.out.println(TestC.CALL_CONVENTION); } static void dump(CodeGen code, int dump, int pass) { if ((dump & pass) != 0) { if ((dump & DUMP_DOT) != 0) { String fn = switch (pass) { - case DUMP_AFTER_PARSE -> "01-parse.dot"; - case DUMP_AFTER_OPTO -> "02-opto.dot"; - case DUMP_AFTER_TYPE_CHECK -> "03-type_check.dot"; - case DUMP_AFTER_LOOP_TREE -> "04-loop_tree.dot"; - case DUMP_AFTER_INSTR_SELECT -> "05-instr_select.dot"; - case DUMP_AFTER_GCM -> "06-gcm.dot"; - case DUMP_AFTER_LOCAL_SCHED -> "07-local_sched.dot"; - case DUMP_AFTER_REG_ALLOC -> "08-reg_allos.dot"; - case DUMP_AFTER_ENCODE -> "09-local_sched.dot"; - case DUMP_FINAL -> "10-final.dot"; - default -> throw Utils.TODO(); + case DUMP_AFTER_PARSE -> "01-parse.dot"; + case DUMP_AFTER_OPTO -> "02-opto.dot"; + case DUMP_AFTER_TYPE_CHECK -> "03-type_check.dot"; + case DUMP_AFTER_LOOP_TREE -> "04-loop_tree.dot"; + case DUMP_AFTER_SELECT -> "05-instr_select.dot"; + case DUMP_AFTER_GCM -> "06-gcm.dot"; + case DUMP_AFTER_LOCAL_SCHED -> "07-local_sched.dot"; + case DUMP_AFTER_REG_ALLOC -> "08-reg_allos.dot"; + case DUMP_AFTER_ENCODE -> "09-local_sched.dot"; + case DUMP_FINAL -> "10-final.dot"; + default -> throw Utils.TODO(); }; try { Files.writeString(Path.of(fn), - new GraphVisualizer().generateDotOutput(code._stop, null, null)); - } catch(IOException e) { - System.err.println("ERROR: Cannot write DOT file"); - System.exit(1); - } + new GraphVisualizer().generateDotOutput(code._stop, null, null)); + } catch(IOException e) { throw bad("Cannot write DOT file"); } } else { if ((dump & DUMP_PASS_NAME) != 0) { System.err.println(switch (pass) { @@ -113,11 +104,11 @@ Options: case DUMP_AFTER_OPTO -> "After OPTO:"; case DUMP_AFTER_TYPE_CHECK -> "After Type Check:"; case DUMP_AFTER_LOOP_TREE -> "After Loop Tree:"; - case DUMP_AFTER_INSTR_SELECT -> "After Instruction Selection:"; + case DUMP_AFTER_SELECT -> "After Code Selection:"; case DUMP_AFTER_GCM -> "After GCM:"; case DUMP_AFTER_LOCAL_SCHED -> "After Local Scheduling:"; case DUMP_AFTER_REG_ALLOC -> "After Register Allocation:"; - case DUMP_AFTER_ENCODE -> "After Instruction Encoding:"; + case DUMP_AFTER_ENCODE -> "After Encoding:"; case DUMP_FINAL -> "Final:"; default -> throw Utils.TODO(); }); @@ -132,24 +123,24 @@ Options: double t, total = 0; total += t = code._tParse / 1e3; - System.out.println(String.format("Parsing Time: %.3f sec", t)); + System.out.printf( "Parsing Time: %.3f sec%n", t); total += t = code._tOpto / 1e3; - System.out.println(String.format("Optimization Time: %.3f sec", t)); + System.out.printf( "Optimization Time: %.3f sec%n", t); total += t = code._tTypeCheck / 1e3; - System.out.println(String.format("Type Checking Time: %.3f sec", t)); + System.out.printf( "Type Checking Time: %.3f sec%n", t); total += t = code._tLoopTree / 1e3; - System.out.println(String.format("Loop Tree Time: %.3f sec", t)); + System.out.printf( "Loop Tree Time: %.3f sec%n", t); total += t = code._tInsSel / 1e3; - System.out.println(String.format("Instruction Selection Time: %.3f sec", t)); + System.out.printf( "Code Selection Time: %.3f sec%n", t); total += t = code._tGCM / 1e3; - System.out.println(String.format("GCM Time: %.3f sec", t)); + System.out.printf( "GCM Time: %.3f sec%n", t); total += t = code._tLocal / 1e3; - System.out.println(String.format("Local Scheduling Time: %.3f sec", t)); + System.out.printf( "Local Scheduling Time: %.3f sec%n", t); total += t = code._tRegAlloc / 1e3; - System.out.println(String.format("Register Allocation Time: %.3f sec", t)); + System.out.printf( "Register Allocation Time: %.3f sec%n", t); total += t = code._tEncode / 1e3; - System.out.println(String.format("Instruction Encoding Time: %.3f sec", t)); - System.out.println(String.format("TOTAL COMPILATION TIME: %.3f sec", total)); + System.out.printf( "Encoding Time: %.3f sec%n", t); + System.out.printf( "TOTAL COMPILATION TIME: %.3f sec%n", total); } static String getInput() { @@ -159,9 +150,8 @@ Options: public static void main(String[] args) throws Exception { String input_filename = null; - boolean use_stdin = false; boolean do_eval = false; - boolean do_run = false; + boolean do_run = true; boolean do_codegen = false; boolean do_print_size = false; boolean do_print_time = false; @@ -171,78 +161,62 @@ Options: String cpu = null; String abi = null; - // TODO: autodetect - system_cpu = "x86_64_v2"; - system_abi = "SystemV"; - // Parse command line -loop: for (int i = 0; i < args.length; i++) { + int i; for( i = 0; i < args.length; i++ ) { String arg = args[i]; - if (arg.charAt(0) == '-') { - switch (arg) { - case "-": use_stdin = true; break; - case "--dump": dump |= DUMP_FINAL; break; - case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break; - case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break; - case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break; - case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break; - case "--dump-after-instr-select": dump |= DUMP_AFTER_INSTR_SELECT; break; - case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break; - case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break; - case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break; - case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break; - case "--dump-after-all": dump |= DUMP_AFTER_ALL; break; - case "--dot": dump |= DUMP_DOT; break; - case "-S": dump |= DUMP_DISASSEMBLE; break; - case "--eval": do_eval = true; first_arg = i + 1; break loop; - case "--run": do_run = true; first_arg = i + 1; break loop; - case "--dump-size": do_print_size = true; break; - case "--dump-time": do_print_time = true; break; - case "--cpu": if (cpu != null - || i + 1 >= args.length - || args[i + 1].charAt(0) == '-') bad_usage(); - cpu = args[i + 1]; - i++; - break; - case "--abi": if (abi != null - || i + 1 >= args.length - || args[i + 1].charAt(0) == '-') bad_usage(); - abi = args[i + 1]; - i++; - break; - case "--target": target(); - case "--version": throw Utils.TODO(); - case "--help": usage(); - default: bad_usage(); - } - } else { - if (input_filename != null || use_stdin) bad_usage(); + if( arg.charAt(0) != '-' ) { input_filename = arg; + break; } - } - if (input_filename == null && !use_stdin) { - System.err.println("ERROR: no input file' (use --help)"); - System.exit(1); + switch (arg) { + case "-": input_filename=""; break; + case "--dump": dump |= DUMP_FINAL; break; + case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break; + case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break; + case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break; + case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break; + case "--dump-after-select": dump |= DUMP_AFTER_SELECT; break; + case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break; + case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break; + case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break; + case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break; + case "--dump-after-all": dump |= DUMP_AFTER_ALL; break; + case "--dot": dump |= DUMP_DOT; break; + case "-S": dump |= DUMP_DISASSEMBLE; break; + case "--eval": do_eval = true ; do_run = false; break; + case "--run": do_run = true ; break; + case "--norun": do_run = false; break; + case "--dump-size": do_print_size = true; break; + case "--dump-time": do_print_time = true; break; + case "--cpu": if (cpu != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + cpu = args[++i]; + break; + case "--abi": if (abi != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + abi = args[++i]; + break; + case "--target": target(); break; + case "--version": throw Utils.TODO(); + case "--help": usage(); + default: bad_usage(); + } } + if (input_filename == null) throw bad("no input file' (use --help)"); + if( !input_filename.isEmpty() && !input_filename.endsWith(".smp") ) + throw bad("File extension must be .smp"); + String base = input_filename.substring(0,input_filename.length()-4); + if (do_run || (dump & DUMP_DISASSEMBLE) != 0 || do_print_size) { - if (cpu == null) cpu = system_cpu; - if (abi == null) abi = system_abi; - if (cpu == null || abi == null) { - System.err.println("ERROR: Cannot compile for unknown target"); - System.exit(1); - } + if (cpu == null) cpu = TestC.CPU_PORT; + if (abi == null) abi = TestC.CALL_CONVENTION; do_codegen = true; } // Read input file try { - src = use_stdin ? getInput() : Files.readString(Path.of(input_filename)); - } catch(IOException e) { - System.err.println("ERROR: Cannot read input file"); - System.exit(1); - } + src = input_filename.isEmpty() ? getInput() : Files.readString(Path.of(input_filename)); + } catch( IOException e ) { throw bad("Cannot read input file: "+input_filename); } // Compilation pipeline CodeGen code = new CodeGen(src); @@ -260,8 +234,8 @@ loop: for (int i = 0; i < args.length; i++) { dump(code, dump, DUMP_AFTER_LOOP_TREE); if (do_codegen) { - code.instSelect(PORTS, cpu, abi); - dump(code, dump, DUMP_AFTER_INSTR_SELECT); + code.instSelect(cpu, abi, PORTS); + dump(code, dump, DUMP_AFTER_SELECT); } code.GCM(); @@ -276,6 +250,8 @@ loop: for (int i = 0; i < args.length; i++) { code.encode(); dump(code, dump, DUMP_AFTER_ENCODE); + + code.exportELF(base+".o"); } dump(code, dump, DUMP_FINAL); @@ -285,7 +261,7 @@ loop: for (int i = 0; i < args.length; i++) { } if (do_print_size) { - System.out.println(String.format("Code Size: %d", code._encoding._bits.size())); + System.out.printf( "Code Size: %d%n", code._encoding._bits.size()); } if (do_print_time) { @@ -295,19 +271,19 @@ loop: for (int i = 0; i < args.length; i++) { if (do_eval) { // TODO: Support for evaluation of functions with different argument numbers and types long t = System.currentTimeMillis(); - long arg = (first_arg < args.length) ? Integer.valueOf(args[first_arg]) : 0; + long arg = (i+1 < args.length) ? Integer.parseInt(args[i+1]) : 0; System.out.println(Eval2.eval(code, arg, 100000)); if (do_print_time) { - System.out.println(String.format("EXECUTION TIME: %.3f sec", - (System.currentTimeMillis() - t) / 1e3)); - } - } else if (do_run) { - if (cpu != system_cpu || abi != system_abi) { - System.err.println("ERROR: cannot run code on not native target"); - System.exit(1); + System.out.printf( "EXECUTION TIME: %.3f sec%n", + (System.currentTimeMillis() - t) / 1e3); } - - throw Utils.TODO(); + } + if (do_run) { + if ( !TestC.CPU_PORT.equals( cpu ) || !TestC.CALL_CONVENTION.equals( abi ) ) + throw bad("cannot run code on not native target"); + String exe = TestC.OS.startsWith("Windows") ? base+".exe" : base; + String result = com.seaofnodes.simple.TestC.gcc(base+".o", null, null, true, exe); + System.out.print(result); } } } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/TestC.java b/chapter22/src/test/java/com/seaofnodes/simple/TestC.java index 2e68a029..93fa9b66 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/TestC.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/TestC.java @@ -41,8 +41,20 @@ public abstract class TestC { public static void run( String src, String simple_conv, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException { String bin = efile+xtn; String obj = bin+".o"; + String exe = OS.startsWith("Windows") ? bin+".exe" : bin; // Compile simple, emit ELF CodeGen code = new CodeGen(src).driver( CPU_PORT, simple_conv, obj); + String result = gcc(obj, c_conv, cfile, false, exe ); + assertEquals(expected,result); + + // Allocation quality not degraded + int delta = spills>>3; + if( delta==0 ) delta = 1; + if( spills != -1 ) + assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); + } + + public static String gcc( String obj, String c_conv, String cfile, boolean stdin, String... args ) throws IOException { // Compile the C program. Compiling code and constants in the low // 2Gig. Pointers are 64b BUT since always in the low 2G all the @@ -56,7 +68,7 @@ public abstract class TestC { "-lm", // Picks up 'sqrt' for newtonFloat tests to compare "-g", "-o", - bin, + args[0], }); // Calling convention for C calls, if any if( cfile!=null ) { @@ -64,6 +76,7 @@ public abstract class TestC { params.add("CALL_CONV="+c_conv); } + // Run GCC to link (optionally compile C driver code) Process gcc = new ProcessBuilder(params.asAry()).redirectErrorStream(true).start(); int exit; try { @@ -81,21 +94,13 @@ public abstract class TestC { //assertTrue(result.isEmpty()); // No data in error stream // Execute results - Process smp = new ProcessBuilder(bin).redirectErrorStream(true).start(); - try { exit = (byte)smp.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); } - result = new String(smp.getInputStream().readAllBytes()); - if( exit!=0 ) { + ProcessBuilder smp = new ProcessBuilder(args); + if( stdin ) smp.redirectInput(ProcessBuilder.Redirect.INHERIT); + Process p = smp.start(); + try { exit = (byte)p.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); } + result = new String(p.getInputStream().readAllBytes()); + if( exit!=0 ) System.err.println("exec exit code: "+exit); - System.err.println(result); - } - assertEquals( 0, exit ); - assertEquals(expected,result); - - // Allocation quality not degraded - int delta = spills>>3; - if( delta==0 ) delta = 1; - if( spills != -1 ) - assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta); - + return result; } } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/progs/jig.smp b/chapter22/src/test/java/com/seaofnodes/simple/progs/jig.smp index 2d8d375b..ae0b57aa 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/progs/jig.smp +++ b/chapter22/src/test/java/com/seaofnodes/simple/progs/jig.smp @@ -1,15 +1,10 @@ // -*- mode: java; -*- -// theory: conservative approx to a CG will link all target fcsn. -// unlinked *local* fcns with *no* TFP constants can be declared unreachable and removed. - -// 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; - } +//7599136877341746241 +//========= Reduced ========= +struct s0 { + Zvbjf? Ia; + i32 v0; }; -int cast_int = arg+2; -return sqrt(arg) + sqrt(cast_int); +s0 !Z1_=new s0; +while(new s0.v0) { + Z1_.Ia=Z1_.Ia; |
