diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-19 14:56:14 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-19 14:56:14 -0700 |
| commit | 7edca9823ec8ef0aed10c88fa07ef969792aab77 (patch) | |
| tree | d95e308cac7a9c5039a59be636d881982a9b4878 /chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java | |
| parent | 3617495d8efbcce23bbc9f1754c7d27d34d30a52 (diff) | |
| download | Simple-main.tar.gz Simple-main.zip | |
Split from ch25, SCCP and interprocedural SCCPmain
Diffstat (limited to 'chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java')
| -rw-r--r-- | chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java b/chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java new file mode 100644 index 00000000..3b3aabc0 --- /dev/null +++ b/chapter-sccp/src/test/java/com/seaofnodes/simple/TestC.java @@ -0,0 +1,137 @@ +package com.seaofnodes.simple; + +import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import static org.junit.Assert.*; + +// Call a C driver program, which calls a Simple-generated .o, and self-checks. +// Expects GCC from the default CLI, compiles C, compiles Simple, links and runs. +public abstract class TestC { + + public static final String OS = System.getProperty("os.name"); + public static final String CPU = System.getProperty("os.arch"); + + public static final String CALL_CONVENTION = OS.startsWith("Windows") ? "Win64" : "SystemV"; + public static final String CPU_PORT = switch( CPU ) { + case "amd64" -> "x86_64_v2"; + default -> throw Utils.TODO("Map Yer CPU Port Here"); + }; + + public static void run( String file, int spills ) throws IOException { run(file,"",spills); } + + public static void run( String file, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs",file,expected,spills); + } + + // Compile and run a simple program + public static void run( String dir, String file, TypeInteger arg, String expected, int spills, boolean standalone) throws IOException { + // Files + String cfile = dir+"/"+file+".c" ; + String sfile = dir+"/"+file+".smp"; + String efile = "build/objs/"+file; + + // Compile and export Simple + String src = Files.readString(Path.of(sfile)); + run(src,CALL_CONVENTION,arg, "",standalone? null: cfile,efile,"S",expected,spills); + } + + // link with c and also inline + public static void run(String src, String file, TypeInteger arg, String expected, int spills) throws IOException { + String dir = "src/test/java/com/seaofnodes/simple/progs"; + String cfile = dir+"/"+file+".c"; + String efile = "build/objs/"+file; + run(src, CALL_CONVENTION, arg, "", cfile, efile, "S", expected, spills); + } + + public static void run(String dir, String file, String expected, int spills ) throws IOException { + run(dir, file,null, expected, spills, false); + } + + // Do not link with c file - no inline. + public static void runS(String file, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs", file, null, expected, spills, true); + } + + + // Do not link with c file - just inline with source. + public static void runSF(String name, String src, TypeInteger arg, String expected, int spills ) throws IOException { + String efile = "build/objs/"+name; + run(src,CALL_CONVENTION,arg, "",null,efile,"S",expected,spills); + } + + public static void runS(String file, TypeInteger arg, String expected, int spills ) throws IOException { + run("src/test/java/com/seaofnodes/simple/progs", file, arg, expected, spills, true); + } + + + public static void run( String src, String simple_conv, TypeInteger arg, 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 CheckedCodeGen(src, arg).driver( CPU_PORT, simple_conv, obj); + SpillStats.recordNative(code,CPU_PORT,simple_conv); + + String result = gcc(obj, c_conv, cfile, false, exe ); + assertEquals(expected,result); + + // Allocation quality not degraded + SpillStats.checkSpills(spills,code._regAlloc._spillScaled); + } + + 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 + // high bits are zero - and Simple code can be emitted treating + // pointers as 4bytes. + var params = new Ary<>(String.class); + params.add("gcc"); + if( cfile!=null ) params.add(cfile); // Associated C driver, usually has a `main` + params.addAll(new String[] { + obj, + "-lm", // Picks up 'sqrt' for newtonFloat tests to compare + "-g", + "-o", + args[0], + }); + // Calling convention for C calls, if any + if( cfile!=null ) { + params.add("-D"); + 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 { + boolean normal = gcc.waitFor(2, TimeUnit.SECONDS); + exit = normal ? gcc.exitValue() : -1; // no exit??? + } catch( InterruptedException e ) { + throw new IOException("interrupted"); + } + String result = new String(gcc.getInputStream().readAllBytes()); + if( exit!=0 ) { + System.err.println("gcc error code: "+exit); + System.err.println(result); + } + assertEquals( 0, exit ); + //assertTrue(result.isEmpty()); // No data in error stream + + // Execute results + ProcessBuilder smp = new ProcessBuilder(args); + if( stdin ) smp.redirectInput(ProcessBuilder.Redirect.INHERIT); + Process p = smp.start(); + try { exit = p.waitFor(); } catch( InterruptedException e ) { throw new IOException("interrupted"); } + result = new String(p.getInputStream().readAllBytes()); + assertEquals("Program exit status",0,exit); + return result; + } +} |
