package com.seaofnodes.simple; import com.seaofnodes.simple.codegen.CodeGen; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter10Test { @Test public void testFuzzer() { CodeGen code = new CodeGen( """ int a = arg/3; int b = arg*5; int x = arg*7; int y = arg/11; int p; int g; int h; if( (arg/13)==0 ) { p = x + y; g = x; h = y; } else { p = a + b; g = a; h = b; } int r = g+h; return p-r; """); code.parse().opto(); assertEquals("return 0;", code.print()); } @Test public void testStruct() { CodeGen code = new CodeGen(""" struct _Bar { int a; int b; }; struct _Foo { int x; }; _Foo? foo = null; _Bar !bar = new _Bar; bar.a = 1; bar.a = 2; return bar.a; """); code.parse().opto(); assertEquals("return 2;", code.print()); } @Test public void testExample() { CodeGen code = new CodeGen(""" struct Vector2D { int x; int y; }; Vector2D !v = new Vector2D; v.x = 1; if (arg) v.y = 2; else v.y = 3; return v; """); code.parse().opto(); assertEquals("Stop[ return Test.Vector2D; return MEM[ 2:.x=0; 3:.y=0;]; ]", code.print()); } @Test public void testBug() { CodeGen code = new CodeGen(""" struct s0 { int v0; }; s0? v1=null; int v3=v1.zAicm; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'zAicm'",e.getMessage()); } } @Test public void testBug2() { CodeGen code = new CodeGen(""" struct s0 { int v0; }; arg=0+new s0.0; """); try { code.parse(); fail(); } catch( Exception e ) { assertEquals("Expected an identifier, found 'null'",e.getMessage()); } } @Test public void testLoop() { CodeGen code = new CodeGen(""" struct Bar { int a; }; Bar !bar = new Bar; while (arg) { bar.a = bar.a + 2; arg = arg + 1; } return bar.a; """); code.parse().opto(); assertEquals("Stop[ return Phi(Loop,0,(Phi_a+2)); return MEM[ 2:.a=0;]; ]", code.print()); } @Test public void testIf() { CodeGen code = new CodeGen(""" struct Bar { int a; }; Bar !bar = new Bar; if (arg) bar = null; bar.a = 1; return bar.a; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Type null is not of declared type *Test.Bar",e.getMessage()); } } @Test public void testIf2() { CodeGen code = new CodeGen(""" struct Bar { int a; }; Bar? !bar = null; if (arg) bar = new Bar; bar.a = 1; return bar.a; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'a'",e.getMessage()); } } @Test public void testIf3() { CodeGen code = new CodeGen(""" struct Bar { int a; }; Bar bar = null; if (arg) bar = null; bar.a = 1; return bar.a; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Type null is not of declared type *Test.Bar", e.getMessage()); } } @Test public void testIfOrNull() { CodeGen code = new CodeGen(""" struct _Bar { int a; }; _Bar? !bar = new _Bar; if (arg) bar = null; if( bar ) bar.a = 1; return bar.a; """); code.parse().opto(); assertEquals("return Phi(Region,1,.a);", code.print()); } @Test public void testIfOrNull2() { CodeGen code = new CodeGen( """ struct _Bar { int a; }; _Bar? !bar = new _Bar; if (arg) bar = null; int rez = 3; if( !bar ) rez=4; else bar.a = 1; return rez; """); code.parse().opto(); assertEquals("return Phi(Region,4,3);", code.print()); } @Test public void testWhileWithNullInside() { CodeGen code = new CodeGen(""" struct s0 {int v0;}; s0? !v0 = new s0; int ret = 0; while(arg) { ret = v0.v0; v0 = null; arg = arg - 1; } return ret; """); try { code.parse().opto().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'v0'", e.getMessage()); } } @Test public void testRedeclareStruct() { CodeGen code = new CodeGen(""" struct s0 { int v0; }; s0? v1=new s0; s0? v1; v1=new s0; """); try { code.parse(); fail(); } catch( Exception e ) { assertEquals("Redefining name 'v1'", e.getMessage()); } } @Test public void testIter() { // Build and use an iterator CodeGen code = new CodeGen( """ struct Iter { int x; int len; }; Iter !i = new Iter; i.len = arg; int sum=0; while( i.x < i.len ) { sum = sum + i.x; i.x = i.x + 1; } return sum; """); code.parse().opto(); assertEquals("Stop[ return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum)); return MEM[ 2:.x=0; 3:.len=0;]; ]", code.print()); } @Test public void test1() { CodeGen code = new CodeGen(""" struct s0 {int v0;}; s0 !ret = new s0; while(arg) { s0 !v0 = new s0; v0.v0 = arg; arg = arg-1; if (arg==5) ret=v0; } return ret; """); code.parse().opto(); assertEquals("Stop[ return Phi(Loop,Test.s0,Phi(Region,Test.s0,Phi_ret)); return MEM[ 2:.v0=0;]; ]", code.print()); } @Test public void test2() { CodeGen code = new CodeGen(""" struct _s0 {int v0;}; _s0 !ret = new _s0; _s0 !v0 = new _s0; while(arg) { v0.v0 = arg; arg = arg-1; if (arg==5) ret=v0; } return ret.v0; """); code.parse().opto(); assertEquals("return .v0;", code.print()); } @Test public void test3() { CodeGen code = new CodeGen(""" struct _s0 {int v0;}; _s0 !ret = new _s0; while(arg < 10) { _s0 !v1 = new _s0; if (arg == 5) ret=v1; arg = arg + 1; } return ret.v0; """); code.parse().opto(); assertEquals("return .v0;", code.print()); } @Test public void testModGlobalInConstructor() { CodeGen code = new CodeGen( """ int cnt = 1; // cnt is incremented exactly once, it is not part of s0 constructor // hence s0.x is always 1, and cnt remains at 2 struct s0 { int x = cnt++; }; s0 a = new s0(); s0 b = new s0(); // a.x==1, b.x==1, cnt==2 return a.x * 100 + b.x * 10 + cnt; """); code.parse().iter().opto(); assertEquals("Stop[ return 112; return MEM[ 2:___ 3:.x=1;]; ]", code.print()); } @Test public void testBug3() { CodeGen code = new CodeGen(""" struct s0 { int f0; }; return new s0; int v0=null.f0; """); try { code.parse(); fail(); } catch( Exception e ) { assertEquals("Syntax error, expected `;` but found `.`",e.getMessage()); } } @Test public void testBug4() { CodeGen code = new CodeGen(""" if(0) { while(0) if(arg) continue; int v0=0; while(1) { int v2=-arg; v0=v2; } } return 0; """); code.parse().opto(); assertEquals("return 0;", code.print()); } @Test public void testBug5() { CodeGen code = new CodeGen(""" struct s0 { int f0; }; if(0) return 0; else return new s0; if(new s0.f0) return 0; """); code.parse().iter().opto().typeCheck(); assertEquals("Stop[ return Test.s0; return MEM[ 2:.f0=0;]; ]", code.print()); } @Test public void testBug6MissedWorklist() { CodeGen code = new CodeGen(""" while(0) {} int v4=0; while(0