summaryrefslogtreecommitdiff
path: root/chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-19 14:56:14 -0700
committerCliff Click <cliffc@acm.org>2026-10-19 14:56:14 -0700
commit7edca9823ec8ef0aed10c88fa07ef969792aab77 (patch)
treed95e308cac7a9c5039a59be636d881982a9b4878 /chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java
parent3617495d8efbcce23bbc9f1754c7d27d34d30a52 (diff)
downloadSimple-main.tar.gz
Simple-main.zip
Split from ch25, SCCP and interprocedural SCCPmain
Diffstat (limited to 'chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java')
-rw-r--r--chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java217
1 files changed, 217 insertions, 0 deletions
diff --git a/chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java b/chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java
new file mode 100644
index 00000000..20d6fe71
--- /dev/null
+++ b/chapter-interprocedural-sccp/src/test/java/com/seaofnodes/simple/Simple.java
@@ -0,0 +1,217 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.CodeGen.Phase;
+import com.seaofnodes.simple.print.*;
+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.stream.Collectors;
+
+public class Simple {
+ public static final String PORTS = "com.seaofnodes.simple.node.cpus";
+
+ static final int DUMP_AFTER_PARSE = 1<<Phase.Parse.ordinal();
+ static final int DUMP_AFTER_ITER = 1<<Phase.Iter.ordinal();
+ static final int DUMP_AFTER_OPTO = 1<<Phase.Opto.ordinal();
+ static final int DUMP_AFTER_ITER_POST_OPTO = 1<<Phase.IterPostOpto.ordinal();
+ static final int DUMP_AFTER_FINALIZE_IR = 1<<Phase.FinalizeIR.ordinal();
+ static final int DUMP_AFTER_TYPE_CHECK = 1<<Phase.TypeCheck.ordinal();
+ static final int DUMP_AFTER_LOOP_TREE = 1<<Phase.LoopTree.ordinal();
+ static final int DUMP_AFTER_SELECT = 1<<Phase.Select.ordinal();
+ static final int DUMP_AFTER_GCM = 1<<Phase.Schedule.ordinal();
+ static final int DUMP_AFTER_LOCAL_SCHED = 1<<Phase.LocalSched.ordinal();
+ static final int DUMP_AFTER_REG_ALLOC = 1<<Phase.RegAlloc.ordinal();
+ static final int DUMP_AFTER_ENCODE = 1<<Phase.Encoding.ordinal();
+
+ static final int DUMP_FINAL = 1<<16;
+
+ static final int DUMP_PASS_NAME = 1<<30;
+ static final int DUMP_AFTER_ALL = ((1<<Phase.values().length)-1) | DUMP_PASS_NAME;
+
+ static final int DUMP_DISASSEMBLE = 1<<31;
+
+ static void usage() {
+ System.out.println(
+"""
+simple [options] <input-file> ...args...
+Options:
+ --dump - dump final intermediate representation
+ --dump-after-parse - dump intermediate representation after parsing
+ --dump-after-iter - dump intermediate representation after Iter
+ --dump-after-opto - dump intermediate representation after Opto
+ --dump-after-iter-post-opto - dump intermediate representation after IterPostOpto
+ --dump-after-finalize-ir - dump intermediate representation after FinalizeIR
+ --dump-after-type-check - dump intermediate representation after type checking
+ --dump-after-loop-tree - dump intermediate representation after loop-tree construction
+ --dump-after-select - dump intermediate representation after instruction selection
+ --dump-after-gcm - dump intermediate representation after GCM
+ --dump-after-local-sched - dump intermediate representation after local scheduling
+ --dump-after-reg-alloc - dump intermediate representation after register allocation
+ --dump-after-encode - dump intermediate representation after encoding
+ --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
+"""
+);
+ System.exit(0);
+ }
+
+ 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() {
+ System.out.print(TestC.CPU_PORT);
+ System.out.print("-");
+ System.out.println(TestC.CALL_CONVENTION);
+ }
+
+ static void dump(CodeGen code, int dump, int pass) {
+ if( (dump & pass)==0 ) return;
+ if( (dump & DUMP_PASS_NAME)!=0 ) System.err.println("Final:");
+ System.err.println(code);
+ }
+
+ static void print_compilation_times(CodeGen code) {
+ long total=0;
+ for( Phase phase : Phase.values() ) {
+ long time=code._times[phase.ordinal()];
+ total+=time;
+ System.out.printf("%-24s %.3f sec%n",phase+" Time:",time/1e3);
+ }
+ System.out.printf("TOTAL COMPILATION TIME: %.3f sec%n",total/1e3);
+ }
+
+ static String getInput() throws IOException {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
+ return reader.lines().collect(Collectors.joining("\n"));
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ 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;
+ int dump = 0;
+ int first_arg = 0;
+ String src = null;
+ String cpu = null;
+ String abi = null;
+
+ // Parse command line
+ int i; for( i = 0; i < args.length; i++ ) {
+ String arg = args[i];
+ if( arg.charAt(0) != '-' ) {
+ input_filename = arg;
+ break;
+ }
+
+ switch (arg) {
+ case "-": input_filename=""; break;
+ case "--dump": dump |= DUMP_FINAL; break;
+ case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break;
+ case "--dump-after-finalize-ir": dump |= DUMP_AFTER_FINALIZE_IR; break;
+ case "--dump-after-iter-post-opto": dump |= DUMP_AFTER_ITER_POST_OPTO; break;
+ case "--dump-after-iter": dump |= DUMP_AFTER_ITER; 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 "--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 = TestC.CPU_PORT;
+ if (abi == null) abi = TestC.CALL_CONVENTION;
+ do_codegen = true;
+ }
+
+ // Read input file
+ try {
+ 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);
+
+ code.driver(do_codegen ? Phase.Encoding : Phase.LocalSched,
+ do_codegen ? cpu : null, abi, dump);
+ if( do_codegen ) code.exportELF(base+".o");
+
+ dump(code, dump, DUMP_FINAL);
+
+ if (do_codegen && (dump & DUMP_DISASSEMBLE) != 0) {
+ System.out.println(code.asm());
+ }
+
+ if (do_print_size) {
+ System.out.printf( "Code Size: %d%n", code._encoding._bits.size());
+ }
+
+ if (do_print_time) {
+ print_compilation_times(code);
+ }
+
+ 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 (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);
+ System.out.print(result);
+ }
+ }
+}