summaryrefslogtreecommitdiff
path: root/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java
blob: 96d73f2648d9b84b39266b07e7156c7514886c09 (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
package com.seaofnodes.simple;

import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.ConvertNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.*;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Test;
import static org.junit.Assert.*;

public class ConvertNodeTest {
    @Test public void testMonotoneCompute() {
        CodeGen code = new CodeGen("return 0;");
        ArrayList<Type> inputs = new ArrayList<>(Arrays.asList(
            Type.BOTTOM,Type.CONTROL,Type.NIL,TypeScalar.BOT,TypeMem.BOT));
        TypeInteger.gather(inputs);
        TypeFloat.gather(inputs);
        TypePtr.gather(inputs);
        TypeMemPtr.gather(inputs);
        TypeFunPtr.gather(inputs);
        // Writable arrays require matching element access in both directions.
        // Widening the element's access can make that check pass while keeping
        // a known length; compute must not suddenly gain that length fact.
        for( TypeInteger len : new TypeInteger[]{TypeInteger.U32,TypeInteger.TRUE} )
            for( boolean elementRO : new boolean[]{false,true} )
                for( boolean arrayRO : new boolean[]{false,true} )
                    inputs.add(TypeMemPtr.make(TypeStruct.makeAry("[]test",len,-1,
                        TypeMemPtr.TEST.withAccess(elementRO),-2,false)).withAccess(arrayRO));
        inputs.add(TypeConAryB.make(new byte[]{1,2,3}));
        for( long value : new long[]{Long.MIN_VALUE,-129,-128,-1,0,1,127,128,255,256,Long.MAX_VALUE} )
            inputs.add(TypeInteger.constant(value));
        for( double value : new double[]{-0.0,0.0,1.0,16777217.0,Double.NaN,Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY} )
            inputs.add(TypeFloat.constant(value));
        int size = inputs.size();
        for( int i = 0; i<size; i++ ) inputs.add(inputs.get(i).dual());

        ArrayList<Type> destinations = new ArrayList<>();
        for( Type t : inputs )
            if( !t.isHigh() && (t instanceof TypeInteger || t instanceof TypeFloat || t instanceof TypeNil) )
                destinations.add(t);

        // Vary one isolated input without folding or lowering the conversion.
        Node input = ConstantNode.seed(Type.BOTTOM);
        input.setDef(0,null);
        Type[][] expected = new Type[destinations.size()][inputs.size()];
        for( CodeGen.Phase phase : new CodeGen.Phase[]{CodeGen.Phase.Parse,CodeGen.Phase.Iter,CodeGen.Phase.Opto,CodeGen.Phase.IterPostOpto} ) {
            code.driver(phase);
            for( int d = 0; d<destinations.size(); d++ ) {
                Type dst = destinations.get(d);
                ConvertNode convert = new ConvertNode(dst,input);
                Type[] results = new Type[inputs.size()];
                for( int i = 0; i<inputs.size(); i++ ) {
                    input._type = inputs.get(i);
                    results[i] = convert.compute();
                    if( phase==CodeGen.Phase.Parse ) expected[d][i] = results[i];
                    else assertSame("Phase changed compute for "+inputs.get(i)+" to "+dst,expected[d][i],results[i]);
                }
                // Check both rising Iter and falling SCCP with the same order.
                for( int i = 0; i<inputs.size(); i++ )
                    for( int j = 0; j<inputs.size(); j++ )
                        if( inputs.get(i).isa(inputs.get(j)) && !results[i].isa(results[j]) )
                            fail("Convert to "+dst+": "+inputs.get(i)+" -> "+inputs.get(j)+
                                 " gave "+results[i]+" -> "+results[j]);
            }
        }
    }
}