summaryrefslogtreecommitdiff
path: root/chapter19/src/main/java/com/seaofnodes/simple/InstSelect.java
blob: 967a553cfedc2010bc52ad37dcc6266f48b72c07 (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
package com.seaofnodes.simple;

import com.seaofnodes.simple.node.*;
import java.util.BitSet;
import java.util.IdentityHashMap;
import com.seaofnodes.simple.node.cpus.x86_64_v2.MemOpX86;

// Replace ideal nodes with machine nodes, then rebuild the copied graph's uses.
class InstSelect {
    private final CodeGen _code;
    InstSelect(CodeGen code) { _code=code; }

    @SuppressWarnings("unchecked")
    void run(String cpu, String callingConv, String base) {
        _code._callingConv = switch(callingConv) {
        case "SystemV" -> CodeGen.CallingConv.SystemV;
        case "Win64"   -> CodeGen.CallingConv.Win64;
        default -> throw Utils.TODO(); // Unknown calling convention
        };

        // Look for CPU in fixed named place:
        //   com.seaofnodes.simple.node.cpus."cpu"."cpu.class"
        String clzFile = "com.seaofnodes.simple.node.cpus."+cpu+"."+cpu;
        try { _code._mach = ((Class<Machine>) Class.forName( clzFile )).getDeclaredConstructor().newInstance(); }
        catch( Exception e ) { throw new RuntimeException(e); }

        // Convert to machine ops
        _code._uid = 1;               // All new machine nodes reset numbering
        var map = new IdentityHashMap<Node,Node>();
        _instSelect( _code._stop, map );
        _code._stop  = ( StopNode)map.get(_code._stop );
        _code._start = (StartNode)map.get(_code._start);
        _instOuts(_code._stop,_code.visit());
        _code._visit.clear();
    }

    private Node _instSelect( Node n, IdentityHashMap<Node,Node> map ) {
        if( n==null ) return null;
        Node x = map.get(n);
        if( x !=null ) return x; // Been there, done that

        // If n is a MachConcrete, then its part of a multi-node expansion.
        // It does not need instruction selection (already selected!)
        // but it does need its inputs walked.
        if( n instanceof MachConcreteNode || n instanceof MemOpX86) {
            for( int i=0; i < n.nIns(); i++ )
                n._inputs.set(i, _instSelect(n.in(i),map) );
            return n;
        }

        // Produce a machine node from n; map it to flag as done so stops cycles.
        map.put(n, x=_code._mach.instSelect(n) );
        // Walk machine op and replace inputs with mapped inputs
        for( int i=0; i < x.nIns(); i++ )
            x._inputs.set(i, _instSelect(x.in(i),map) );
        if( x instanceof MachNode mach )
            mach.postSelect();  // Post selection action

        // Updates forward edges only.
        n._outputs.clear();
        return x;
    }

    private void _instOuts( Node n, BitSet visit ) {
        if( visit.get(n._nid) ) return;
        visit.set(n._nid);
        for( Node in : n._inputs )
            if( in!=null ) {
                in._outputs.push(n);
                _instOuts(in,visit);
            }
    }

}