From 1e28b27ec2d1129d4a219a57ec0c661c74720493 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sun, 13 Apr 2025 10:23:18 -0700 Subject: Handle infinite loops Loop tree building (and breaking infinite loops) needs to happen *before* instruction selection, which is optional. Best done as a new compiler phase... which now wants a driver. Add a compiler driver; adjust tests to use. Add "never-branch" handling to the 3 CPU port main branch ops. --- .../java/com/seaofnodes/simple/Chapter11Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter18Test.java | 15 ++--- .../java/com/seaofnodes/simple/Chapter19Test.java | 71 +++++++++++----------- .../java/com/seaofnodes/simple/Chapter20Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter21Test.java | 13 ++-- .../test/java/com/seaofnodes/simple/Simple.java | 31 ++++++---- .../src/test/java/com/seaofnodes/simple/TestC.java | 2 +- .../test/java/com/seaofnodes/simple/TestRisc5.java | 2 +- .../com/seaofnodes/simple/fuzzer/FuzzerUtils.java | 2 +- .../test/java/com/seaofnodes/simple/progs/jig.smp | 17 ++++++ 10 files changed, 92 insertions(+), 65 deletions(-) create mode 100644 chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp (limited to 'chapter21/src/test') diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java index c2b9a86d..7e88b60e 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -289,7 +289,7 @@ else { } """); code.parse().opto().typeCheck().GCM(); - assertEquals("return Phi(Region,9,Top,Top,Top,Top);", code.print()); + assertEquals("return 9;", code.print()); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java index 99daae7d..c0e28412 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -1,5 +1,6 @@ package com.seaofnodes.simple; +import com.seaofnodes.simple.codegen.CodeGen.Phase; import com.seaofnodes.simple.codegen.CodeGen; import org.junit.Ignore; import org.junit.Test; @@ -14,7 +15,7 @@ public class Chapter18Test { """ return 0; """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("return 0;", code._stop.toString()); assertEquals("0", Eval2.eval(code, 2)); } @@ -76,7 +77,7 @@ var sq = { int x -> }; return sq(arg)+sq(3); """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("Stop[ return (#2+#2); return (Parm_x(sq,int)*x); ]", code._stop.toString()); assertEquals("13", Eval2.eval(code, 2)); } @@ -174,7 +175,7 @@ for(;;) { i2i = id(x); } """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("Stop[ return #2; return Parm_i(x,int); ]", code._stop.toString()); assertEquals("3", Eval2.eval(code, 0)); } @@ -190,7 +191,7 @@ for(;;) { arg = x(3); } """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("return Top;", code._stop.toString()); assertEquals("null", Eval2.eval(code, 0)); } @@ -215,7 +216,7 @@ ps[0] = new Person; ps[1] = new Person; fcn(ps,1); """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("return 0;", code._stop.toString()); assertEquals("0", Eval2.eval(code, 0)); } @@ -345,7 +346,7 @@ if (arg) i2i = null; if (i2i) return i2i(arg); return f2f(o)(1); """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("Stop[ return Phi(Region,#2,#2); return Parm_i(o,int); ]", code._stop.toString()); assertEquals("1", Eval2.eval(code, 2)); } @@ -361,7 +362,7 @@ Person !p = new Person; p.coffee_count += 1; return p.coffee_count; """); - code.parse().opto().typeCheck().GCM().localSched(); + code.driver(Phase.LocalSched); assertEquals("return 1;", code._stop.toString()); assertEquals("1", Eval2.eval(code, 2)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java index 9ba8e972..787dfd4c 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java @@ -1,5 +1,6 @@ package com.seaofnodes.simple; +import com.seaofnodes.simple.codegen.CodeGen.Phase; import com.seaofnodes.simple.codegen.CodeGen; import java.io.IOException; import java.nio.file.Files; @@ -32,98 +33,98 @@ return 0; @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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); 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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (addf,(cvtf,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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (subf,(cvtf,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;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (mulf,(cvtf,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(); + CodeGen code = new CodeGen("return arg / 2.0;").driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (mulf,(cvtf,arg),0.5f);", code._stop.toString()); } @@ -133,7 +134,7 @@ return 0; """ int arg1 = arg + 1; return arg1 / arg;"""); - code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (div,(inc,arg),arg);", code._stop.toString()); } @@ -144,7 +145,7 @@ return arg1 / arg;"""); int arg1 = arg + 1; return arg1 * arg; """); - code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (mul,(inc,arg),arg);", code._stop.toString()); } @@ -154,7 +155,7 @@ return arg1 * arg; int a = arg; return a + 2.0; """ - ).parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + ).driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (addf,(cvtf,arg),2.0f);", code._stop.toString()); } @@ -169,7 +170,7 @@ else { a = arg-3; } return a;"""); - code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return Phi(Region,(addi,arg),(addi,arg));", code.print()); } @@ -184,7 +185,7 @@ if( arg==1 ) else a=b+1; return a+b;"""); - code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("return (add,(add,Phi(Region,(shli,arg),arg),arg),Phi(Region,4,5));", code.print()); } @@ -196,7 +197,7 @@ int sum=0; for( int i=0; i x*x; } : { int x -> x+x; }; return fcn(2)*10 + fcn(3); """); - code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun1,int),x); return (shli,Parm_x($fun2,int)); ]", code.print()); } @@ -326,7 +327,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(); + code.driver(Phase.LocalSched,"x86_64_v2", "SystemV"); assertEquals("Stop[ return (add,#2,#2); return (mul,Parm_x(sq,int),x); ]", code.print()); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java index 8b7136ab..664620a8 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -23,7 +23,7 @@ public class Chapter20Test { static void testCPU( String src, String cpu, String os, int spills, String stop ) { CodeGen code = new CodeGen(src); - code.parse().opto().typeCheck().instSelect(cpu,os).GCM().localSched().regAlloc(); + code.driver(CodeGen.Phase.RegAlloc,cpu,os); int delta = spills>>3; if( delta==0 ) delta = 1; if( spills != -1 ) diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java index e584f9bc..259cbb4f 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -13,16 +13,15 @@ import static org.junit.Assert.*; public class Chapter21Test { @Test - public void testJig() { - CodeGen code = new CodeGen("return 0;"); - code.parse().opto().typeCheck().GCM().localSched(); - assertEquals("return 0;", code._stop.toString()); - assertEquals("0", Eval2.eval(code, 2)); + public void testJig() throws IOException { + String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); + testCPU(src,"x86_64_v2", "SystemV",1,null); + testCPU(src,"riscv" , "SystemV",1,null); + testCPU(src,"arm" , "SystemV",1,null); } static void testCPU( String src, String cpu, String os, int spills, String stop ) { - CodeGen code = new CodeGen(src); - code.parse().opto().typeCheck().instSelect(cpu,os).GCM().localSched().regAlloc().encode(); + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); int delta = spills>>3; if( delta==0 ) delta = 1; if( spills != -1 ) diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Simple.java b/chapter21/src/test/java/com/seaofnodes/simple/Simple.java index 56761e7a..9b1e2827 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Simple.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Simple.java @@ -16,11 +16,12 @@ public class Simple { 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_INSTR_SELECT = 1<<3; - static final int DUMP_AFTER_GCM = 1<<4; - static final int DUMP_AFTER_LOCAL_SCHED = 1<<5; - static final int DUMP_AFTER_REG_ALLOC = 1<<6; - static final int DUMP_AFTER_ENCODE = 1<<7; + static final int DUMP_AFTER_LOOP_TREE = 1<<3; + static final int DUMP_AFTER_INSTR_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; @@ -88,12 +89,13 @@ Options: 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_INSTR_SELECT -> "04-instr_select.dot"; - case DUMP_AFTER_GCM -> "05-gcm.dot"; - case DUMP_AFTER_LOCAL_SCHED -> "06-local_sched.dot"; - case DUMP_AFTER_REG_ALLOC -> "07-reg_allos.dot"; - case DUMP_AFTER_ENCODE -> "08-local_sched.dot"; - case DUMP_FINAL -> "09-final.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(); }; @@ -110,6 +112,7 @@ Options: 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_INSTR_SELECT -> "After Instruction Selection:"; case DUMP_AFTER_GCM -> "After GCM:"; case DUMP_AFTER_LOCAL_SCHED -> "After Local Scheduling:"; @@ -134,6 +137,8 @@ Options: System.out.println(String.format("Optimization Time: %.3f sec", t)); total += t = code._tTypeCheck / 1e3; System.out.println(String.format("Type Checking Time: %.3f sec", t)); + total += t = code._tLoopTree / 1e3; + System.out.println(String.format("Loop Tree Time: %.3f sec", t)); total += t = code._tInsSel / 1e3; System.out.println(String.format("Instruction Selection Time: %.3f sec", t)); total += t = code._tGCM / 1e3; @@ -180,6 +185,7 @@ loop: for (int i = 0; i < args.length; i++) { 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; @@ -250,6 +256,9 @@ loop: for (int i = 0; i < args.length; i++) { code.typeCheck(); dump(code, dump, DUMP_AFTER_TYPE_CHECK); + code.loopTree(); + dump(code, dump, DUMP_AFTER_LOOP_TREE); + if (do_codegen) { code.instSelect(PORTS, cpu, abi); dump(code, dump, DUMP_AFTER_INSTR_SELECT); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestC.java b/chapter21/src/test/java/com/seaofnodes/simple/TestC.java index 2d908699..c6e0b196 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/TestC.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/TestC.java @@ -49,7 +49,7 @@ public abstract class TestC { String bin = efile+xtn; String obj = bin+".o"; // Compile simple, emit ELF - CodeGen code = new CodeGen(src).parse().opto().typeCheck().instSelect( CPU_PORT, simple_conv).GCM().localSched().regAlloc().encode().exportELF(obj); + CodeGen code = new CodeGen(src).driver( CPU_PORT, simple_conv, obj); // Compile the C program var params = new String[] { diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java index 275cdebb..9c64fe9f 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java @@ -18,7 +18,7 @@ public abstract class TestRisc5 { public static EvalRisc5 build( String dir, String file, int arg ) throws IOException { // Compile and export Simple String src = Files.readString(Path.of(dir+"/"+file+".smp")); - CodeGen code = new CodeGen(src).parse().opto().typeCheck().instSelect( "riscv", "SystemV").GCM().localSched().regAlloc().encode(); + CodeGen code = new CodeGen(src).driver(CodeGen.Phase.Encoding,"riscv", "SystemV"); // Image byte[] image = new byte[1<<20]; // A megabyte diff --git a/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java b/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java index 669a1e6a..b90b663d 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/FuzzerUtils.java @@ -101,7 +101,7 @@ class FuzzerUtils { System.setErr(NULL_PRINT_STREAM); System.setOut(NULL_PRINT_STREAM); var code = new CodeGen(script, TypeInteger.BOT, workListSeed); - return code.parse().opto().typeCheck().GCM().localSched(); + return code.driver(CodeGen.Phase.LocalSched); } finally { System.setErr(err); System.setOut(out); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp new file mode 100644 index 00000000..47aeb2e5 --- /dev/null +++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp @@ -0,0 +1,17 @@ +// -*- mode: java; -*- +struct s0 { + bool v0; + u8 v2; + i16 v1; + byte v3; + int v4; + i16 v5; + int v6; +}; + while(new s0.v1) {} + if(new s0.v6) return new s0.v5; + return new s0.v2; +struct s1 { + int v7; +}; + while(new s1.v7) arg=new s0.v3; -- cgit v1.2.3