diff options
Diffstat (limited to 'src/test/java/com/seaofnodes/simple/Simple.java')
| -rw-r--r-- | src/test/java/com/seaofnodes/simple/Simple.java | 285 |
1 files changed, 135 insertions, 150 deletions
diff --git a/src/test/java/com/seaofnodes/simple/Simple.java b/src/test/java/com/seaofnodes/simple/Simple.java index 18804ebd..b7e10122 100644 --- a/src/test/java/com/seaofnodes/simple/Simple.java +++ b/src/test/java/com/seaofnodes/simple/Simple.java @@ -1,66 +1,65 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.codegen.CompUnit; +import com.seaofnodes.simple.codegen.CodeGen.Phase; import com.seaofnodes.simple.print.*; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.Ary; import com.seaofnodes.simple.util.Utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.stream.Collectors; public class Simple { - public static final String PORTS = "com.seaofnodes.simple.node.cpus"; - - static final int DUMP_AFTER_PARSE = 1<<0; - 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_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; - static final int DUMP_AFTER_ENCODE = 1<<8; - - static final int DUMP_FINAL = 1<<16; - - static final int DUMP_PASS_NAME = 1<<30; - static final int DUMP_AFTER_ALL = 0xff | DUMP_PASS_NAME; - - static final int DUMP_DISASSEMBLE = 1<<31; - static void usage() { System.out.println( """ -simple [options] <input-file> ...args... +simple [options] input-file.smp ...program args... +Options are applied in-order. Options: - --dump - dump final intermediate representation + --help - This text + + --root root/ - Project root directory; this must end in a '/' and input + files are relative paths to this. If missing, the one input + file path is treated as its own root directory. + + -o output - Project output directory; similar to --root, if 'output' ends in a + '/', then all result files use relative paths to 'output', using a input file + root-relative path. If --root is missing, the one result file is named 'output' + + -L path - add an external Simple object search path + --eval - (slowly) evaluate the compiled code in emulator + --run - run the compiled code natively; this is the default + --main - export the top-level initializer as C `main` + --cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm) + --abi <abi-name> - use specific ABI variant (SystemV) + --target - print native CPU and ABI + --version + -S - dump generated assembler code + --dump-size - print the size of generated code + --dump-time - print compilation and execution times --dump-after-parse - dump intermediate representation after parse + --dump-after-iter - dump intermediate representation after pessimistic iter pass --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-select - dump intermediate representation after instruction 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 - -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 + --dump - dump final intermediate representation only """ ); System.exit(0); } - static void bad_usage() { bad("Invalid usage (use --help)"); } + static void bad_usage() { throw bad("Invalid usage (use --help)"); } static RuntimeException bad(String err) { System.err.println("ERROR: "+err); System.exit(1); @@ -73,71 +72,34 @@ Options: System.out.println(TestC.CALL_CONVENTION); } - static void dump(CodeGen code, int dump, int pass) { - if ((dump & pass) != 0) { - if ((dump & DUMP_PASS_NAME) != 0) { - System.err.println(switch (pass) { - case DUMP_AFTER_PARSE -> "After Parse:"; - 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_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 Encoding:"; - case DUMP_FINAL -> "Final:"; - default -> throw Utils.TODO(); - }); - } - - System.err.println(IRPrinter.prettyPrint(code._stop, 9999)); - - } - } - static void print_compilation_times(CodeGen code) { - double t, total = 0; - - total += t = code._tParse / 1e3; - System.out.printf( "Parsing Time: %.3f sec%n", t); - total += t = code._tOpto / 1e3; - System.out.printf( "Optimization Time: %.3f sec%n", t); - total += t = code._tTypeCheck / 1e3; - System.out.printf( "Type Checking Time: %.3f sec%n", t); - total += t = code._tLoopTree / 1e3; - System.out.printf( "Loop Tree Time: %.3f sec%n", t); - total += t = code._tInsSel / 1e3; - System.out.printf( "Code Selection Time: %.3f sec%n", t); - total += t = code._tGCM / 1e3; - System.out.printf( "GCM Time: %.3f sec%n", t); - total += t = code._tLocal / 1e3; - System.out.printf( "Local Scheduling Time: %.3f sec%n", t); - total += t = code._tRegAlloc / 1e3; - System.out.printf( "Register Allocation Time: %.3f sec%n", t); - total += t = code._tEncode / 1e3; - System.out.printf( "Encoding Time: %.3f sec%n", t); - System.out.printf( "TOTAL COMPILATION TIME: %.3f sec%n", total); + long[] times = code._times; + for( int i=0; i<code._times.length; i++ ) + System.out.printf("%20s %.3f sec%n", Phase.values()[i], times[i]); } - static String getInput() throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { - return reader.lines().collect(Collectors.joining("\n")); - } + static String getInput() { + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + return reader.lines().collect(Collectors.joining("\n")); } public static void main(String[] args) throws Exception { + String root = null; String input_filename = null; boolean do_eval = false; boolean do_run = true; boolean do_codegen = false; - boolean do_print_size = false; - boolean do_print_time = false; + boolean emit_main = false; + boolean print_time = false; + boolean print_size = false; + boolean print_asm = false; int dump = 0; int first_arg = 0; String src = null; String cpu = null; String abi = null; + String out = null; + ArrayList<String> libPaths = new ArrayList<>(); // Parse command line int i; for( i = 0; i < args.length; i++ ) { @@ -149,23 +111,32 @@ Options: 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 "-S": dump |= DUMP_DISASSEMBLE; break; + case "--dump-after-parse": dump |= 1<<Phase.Parse .ordinal() ; break; + case "--dump-after-iter": dump |= 1<<Phase.Iter .ordinal() ; break; + case "--dump-after-opto": dump |= 1<<Phase.Opto .ordinal() ; break; + case "--dump-after-type-check": dump |= 1<<Phase.TypeCheck .ordinal() ; break; + case "--dump-after-loop-tree": dump |= 1<<Phase.LoopTree .ordinal() ; break; + case "--dump-after-select": dump |= 1<<Phase.Select .ordinal() ; break; + case "--dump-after-gcm": dump |= 1<<Phase.Schedule .ordinal() ; break; + case "--dump-after-local-sched": dump |= 1<<Phase.LocalSched.ordinal() ; break; + case "--dump-after-reg-alloc": dump |= 1<<Phase.RegAlloc .ordinal() ; break; + case "--dump-after-encode": dump |= 1<<Phase.Encoding .ordinal() ; break; + case "--dump-after-export": dump |= 1<<Phase.Export .ordinal() ; break; + case "--dump": dump |= 1<<Phase.LastPhase .ordinal() ; break; + case "--dump-after-all": dump |= (2<<Phase.LastPhase .ordinal())-1; break; + case "-S": print_asm = true; 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 "--main": emit_main = true; break; + case "--dump-size": print_size = true; break; + case "--dump-time": print_time = true; break; + case "-o": if (out != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + out = args[++i]; do_codegen=true; + break; + case "-L": if (i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); + libPaths.add(args[++i]); + break; case "--cpu": if (cpu != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage(); cpu = args[++i]; break; @@ -179,16 +150,68 @@ Options: } } + // Break the paths into these parts: + // - A module path, given from "--root" or inferred from the one input file + // - Some sources [modpath/relpath/file.smp]*, all relative to the module path. + // - A build path, given from "-o" or inferred from the one input file + // + // All the sources are compiled, with outputs in [buildpath/relpath/file.o]* + 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); + Path inPath = Path.of(input_filename); + + // Figure out the module path + Path modPath; + if( root == null ) { + modPath = inPath.getParent(); + if( modPath == null ) + modPath = Path.of("."); + } else { + throw Utils.TODO(); + } + + // Compute the module-relative paths for all sources + Path srcRelPath = modPath.relativize(inPath); + int n = srcRelPath.getNameCount(); + Path relPath = n==1 ? null : srcRelPath.subpath(0,n-1); + // Compute source/class name + String srcNameExt = srcRelPath.getName(n-1).toString(); + String srcName = srcNameExt.substring(0,srcNameExt.length()-4); + + // Compute the build path. + Path outPath; + if( out == null ) { + // If no output given, the build dir is the modPath + outPath = modPath; + } else { + // If the output is a directory, that is our out path + outPath = Path.of(out); + if( !out.endsWith("/") ) { + // If the output is a file, the directory is our outPath + Path fullOut = outPath; + outPath = outPath.getParent(); + if( outPath == null ) + outPath = Path.of("."); + Path foo = outPath.relativize(fullOut); + if( !foo.toString().equals(srcName+".o") ) + throw bad("Output path needs to be of the form "+srcName+".o"); + } + } + String outBase = outPath.resolve(srcName).toString(); - if (do_run || (dump & DUMP_DISASSEMBLE) != 0 || do_print_size) { + if( do_run || print_asm || print_size ) { if (cpu == null) cpu = TestC.CPU_PORT; if (abi == null) abi = TestC.CALL_CONVENTION; do_codegen = true; } + if( cpu == null ) cpu = TestC.CPU_PORT; + if( abi == null ) abi = TestC.CALL_CONVENTION; + + String simpleHome = System.getenv("SIMPLE_HOME"); + if( simpleHome != null && !simpleHome.isEmpty() ) + libPaths.add(Path.of(simpleHome,cpu+"_"+abi).toString()); // Read input file try { @@ -196,70 +219,32 @@ Options: } catch( IOException e ) { throw bad("Cannot read input file: "+input_filename); } // Compilation pipeline - CodeGen code = new CodeGen(src); - - code.parse(); - dump(code, dump, DUMP_AFTER_PARSE); - - code.opto(); - dump(code, dump, DUMP_AFTER_OPTO); - - code.typeCheck(); - dump(code, dump, DUMP_AFTER_TYPE_CHECK); - - code.loopTree(); - dump(code, dump, DUMP_AFTER_LOOP_TREE); + Ary<String> externPaths = libPaths.isEmpty() ? null : new Ary<>(libPaths.toArray(new String[0])); + CodeGen code = new CodeGen(modPath.toString(), outPath.toString(), externPaths, srcName, src, 456, true, TypeInteger.BOT ); + code.driver(Phase.LastPhase,cpu,abi, false, emit_main || do_run || do_eval, dump); - if (do_codegen) { - code.instSelect(cpu, abi, PORTS); - dump(code, dump, DUMP_AFTER_SELECT); - } - - code.GCM(); - dump(code, dump, DUMP_AFTER_GCM); - - code.localSched(); - dump(code, dump, DUMP_AFTER_LOCAL_SCHED); - - if (do_codegen) { - code.regAlloc(); - dump(code, dump, DUMP_AFTER_REG_ALLOC); - - code.encode(); - dump(code, dump, DUMP_AFTER_ENCODE); - - code.exportELF(base+".o"); - } - - dump(code, dump, DUMP_FINAL); - - if (do_codegen && (dump & DUMP_DISASSEMBLE) != 0) { + if( do_codegen && print_asm ) System.out.println(code.asm()); - } - if (do_print_size) { - System.out.printf( "Code Size: %d%n", code._encoding._bits.size()); - } + if( print_size ) + System.out.printf( "Code Size: %d%n", code._encoding._bits.size()); - if (do_print_time) { + if( print_time ) print_compilation_times(code); - } - if (do_eval) { + if( do_eval ) { // TODO: Support for evaluation of functions with different argument numbers and types long t = System.currentTimeMillis(); 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.printf( "EXECUTION TIME: %.3f sec%n", - (System.currentTimeMillis() - t) / 1e3); - } + if( print_time ) + System.out.printf( "EXECUTION TIME: %.3f sec%n", (System.currentTimeMillis() - t) / 1e3); } - if (do_run) { + 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 = TestC.gcc(base+".o", null, null, true, exe); + String exe = TestC.OS.startsWith("Windows") ? outBase+".exe" : outBase; + String result = TestC.gcc(outBase+".o", null, null, "", TestC.linkObjs(externPaths), exe); System.out.print(result); } } |
