summaryrefslogtreecommitdiff
path: root/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
blob: 9406f48026a40e489398e2081aad8b0eb270f6af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package com.seaofnodes.simple;

import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import java.util.BitSet;
import org.junit.Test;
import static org.junit.Assert.*;

// Execution regressions are separate from the fixed spill-measurement cohorts.
public class MemoryEncodingTest {
    @Test public void testLoopLoadSearch() {
        String[] sources = {
            """
            u8[] !program=new u8[106]; u8[] !out=new u8[0];
            int sum=0;
            for(int i=0; i<arg; i++) {
                sum+=program#;
                if(i==1) out=new u8[i+1];
                else if(i==3) out=new u8[2];
            }
            return sum+out#;
            """,
            // One possibly aliasing arm must reject the unchanged-memory proof.
            """
            struct S { int x; }; !S !a=new S; !S !b=new S;
            a.x=10; b.x=20; !S !p=a; if(arg&1) p=b;
            int sum=0;
            for(int i=0; i<6; i++) {
                if(i==2) p.x=30;
                else if(i==4) b.x=40;
                sum+=a.x;
            }
            return sum;
            """,
            // Unchanged memory does not imply an unchanged loop-carried pointer.
            """
            struct S { int x; }; !S !a=new S; !S !b=new S;
            a.x=10; b.x=20; !S !p=a; int sum=0;
            for(int i=0; i<6; i++) {
                if(i==2) a.x=30;
                sum+=p.x;
                p=b; if(i&1) p=a;
            }
            return sum;
            """,
            // All arms fold, but their values differ: build a value Phi.
            """
            struct S { int x; }; !S !a=new S; a.x=1; int sum=0;
            for(int i=0; i<6; i++) {
                sum+=a.x;
                if(i&1) a.x=2;
                else if(i==2) a.x=3;
                else a.x=4;
            }
            return sum;
            """
        };
        // Exercise both unresolved Store aliases and nested value-Phi cleanup.
        for( long seed : new long[]{0,9,126} )
            for( int p=0; p<sources.length; p++ ) {
                CodeGen code=new CodeGen(sources[p],seed,true).parse().opto();
                if( p==0 ) assertNull(code._stop.walk(n ->
                    n instanceof LoadNode ld && ld.ptr() instanceof ProjNode ptr &&
                    ptr.in(0) instanceof NewNode nn &&
                    nn.size()._type==com.seaofnodes.simple.type.TypeInteger.constant(110) ? ld : null));
                for( int arg=0; arg<7; arg++ ) {
                    long expected=switch(p) {
                    case 0 -> 106*arg+(arg>=2 ? 2 : 0);
                    case 1 -> (arg&1)==0 ? 140 : 60;
                    case 2 -> 130;
                    default -> 16;
                    };
                    assertEquals(Long.toString(expected),Eval2.eval(code,arg));
                }
            }
    }

    @Test public void testKeepReadsBeforeWrites() {
        var code = new CodeGen("""
            struct S { int x; int y; };
            !S !a = new S; !S !b = new S;
            a.x=arg; b.x=arg+1;
            !S !p=a; !S !q=b;
            if (arg<0) { p=b; q=a; }
            int v;
            if (arg>1) { v=p.x; p.x=41; p.y=5; }
            else       { v=q.x; q.x=42; }
            return v;
            """).parse().opto();
        StopNode stop = code._stop;
        assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
        assertEquals("-1",Eval2.eval(code,-1));
        assertEquals("1",Eval2.eval(code,0));
        assertEquals("3",Eval2.eval(code,3));
    }

    private static int countMemoryNodes(Node n, Class<?> kind, BitSet seen) {
        if (n==null || seen.get(n._nid)) return 0;
        seen.set(n._nid);
        int cnt=kind.isInstance(n) ? 1 : 0;
        for (Node def : n._inputs) cnt+=countMemoryNodes(def,kind,seen);
        return cnt;
    }
}