Package org.teavm.model.util

Source Code of org.teavm.model.util.RegisterAllocator

/*
*  Copyright 2014 Alexey Andreev.
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.teavm.model.util;

import java.util.*;
import org.teavm.common.*;
import org.teavm.model.*;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.JumpInstruction;

/**
*
* @author Alexey Andreev
*/
public class RegisterAllocator {
    public void allocateRegisters(MethodReader method, Program program) {
        insertPhiArgumentsCopies(program);
        InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
        LivenessAnalyzer liveness = new LivenessAnalyzer();
        liveness.analyze(program);
        List<MutableGraphNode> interferenceGraph = interferenceBuilder.build(
                program, method.parameterCount(), liveness);
        DisjointSet congruenceClasses = buildPhiCongruenceClasses(program);
        joinClassNodes(interferenceGraph, congruenceClasses);
        removeRedundantCopies(program, interferenceGraph, congruenceClasses);
        int[] classArray = congruenceClasses.pack(program.variableCount());
        renameVariables(program, classArray);
        int[] colors = new int[program.variableCount()];
        Arrays.fill(colors, -1);
        for (int i = 0; i <= method.parameterCount(); ++i) {
            colors[i] = i;
        }
        renameInterferenceGraph(interferenceGraph, congruenceClasses, classArray);
        GraphColorer colorer = new GraphColorer();
        colorer.colorize(interferenceGraph, colors);
        for (int i = 0; i < colors.length; ++i) {
            program.variableAt(i).setRegister(colors[i]);
        }
    }

    private static void joinClassNodes(List<MutableGraphNode> graph, DisjointSet classes) {
        int sz = graph.size();
        for (int i = 0; i < sz; ++i) {
            int cls = classes.find(i);
            while (cls >= graph.size()) {
                graph.add(new MutableGraphNode(graph.size()));
            }
            if (cls != i) {
                for (MutableGraphEdge edge : graph.get(i).getEdges().toArray(new MutableGraphEdge[0])) {
                    if (edge.getFirst() == graph.get(i)) {
                        edge.setFirst(graph.get(cls));
                    }
                    if (edge.getSecond() == graph.get(i)) {
                        edge.setSecond(graph.get(cls));
                    }
                }
                graph.set(i, graph.get(cls));
            }
        }
    }

    private void insertPhiArgumentsCopies(Program program) {
        for (int i = 0; i < program.basicBlockCount(); ++i) {
            Map<BasicBlock, BasicBlock> blockMap = new HashMap<>();
            for (Phi phi : program.basicBlockAt(i).getPhis()) {
                for (Incoming incoming : phi.getIncomings()) {
                    if (!isExceptionHandler(incoming)) {
                        insertCopy(incoming, blockMap);
                    }
                }
            }
            for (Phi phi : program.basicBlockAt(i).getPhis()) {
                for (Incoming incoming : phi.getIncomings()) {
                    if (!isExceptionHandler(incoming)) {
                        insertCopy(incoming, blockMap);
                    }
                }
            }
        }
    }

    private void insertCopy(Incoming incoming, Map<BasicBlock, BasicBlock> blockMap) {
        final Phi phi = incoming.getPhi();
        Program program = phi.getBasicBlock().getProgram();
        AssignInstruction copyInstruction = new AssignInstruction();
        Variable firstCopy = program.createVariable();
        copyInstruction.setReceiver(firstCopy);
        copyInstruction.setAssignee(incoming.getValue());
        BasicBlock source = blockMap.get(incoming.getSource());
        if (source == null) {
            source = incoming.getSource();
        } else {
            incoming.setSource(source);
        }
        if (!(incoming.getSource().getLastInstruction() instanceof JumpInstruction)) {
            final BasicBlock copyBlock = program.createBasicBlock();
            JumpInstruction jumpInstruction = new JumpInstruction();
            jumpInstruction.setTarget(phi.getBasicBlock());
            copyBlock.getInstructions().add(jumpInstruction);
            incoming.getSource().getLastInstruction().acceptVisitor(new BasicBlockMapper() {
                @Override protected BasicBlock map(BasicBlock block) {
                    if (block == phi.getBasicBlock()) {
                        return copyBlock;
                    } else {
                        return block;
                    }
                }
            });
            blockMap.put(source, copyBlock);
            incoming.setSource(copyBlock);
            source = copyBlock;
        }
        source.getInstructions().add(source.getInstructions().size() - 1, copyInstruction);
        incoming.setValue(copyInstruction.getReceiver());
    }

    private boolean isExceptionHandler(Incoming incoming) {
        for (TryCatchBlock tryCatch : incoming.getSource().getTryCatchBlocks()) {
            if (tryCatch.getExceptionVariable() == incoming.getValue()) {
                return true;
            }
        }
        return false;
    }

    private void removeRedundantCopies(Program program, List<MutableGraphNode> interferenceGraph,
            DisjointSet congruenceClasses) {
        for (int i = 0; i < program.basicBlockCount(); ++i) {
            BasicBlock block = program.basicBlockAt(i);
            for (int j = 0; j < block.getInstructions().size(); ++j) {
                Instruction insn = block.getInstructions().get(j);
                if (!(insn instanceof AssignInstruction)) {
                    continue;
                }
                AssignInstruction assignment = (AssignInstruction)insn;
                boolean interfere = false;
                int copyClass = congruenceClasses.find(assignment.getReceiver().getIndex());
                int origClass = congruenceClasses.find(assignment.getAssignee().getIndex());
                for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()) {
                    if (edge.getFirst() == edge.getSecond()) {
                        continue;
                    }
                    int neighbour = congruenceClasses.find(edge.getSecond().getTag());
                    if (neighbour == copyClass || neighbour == origClass) {
                        interfere = true;
                        break;
                    }
                }
                if (!interfere) {
                    int newClass = congruenceClasses.union(copyClass, origClass);
                    block.getInstructions().set(j, new EmptyInstruction());
                    if (newClass == interferenceGraph.size()) {
                        MutableGraphNode newNode = new MutableGraphNode(interferenceGraph.size());
                        interferenceGraph.add(newNode);
                    }
                    for (MutableGraphEdge edge : interferenceGraph.get(origClass).getEdges()
                            .toArray(new MutableGraphEdge[0])) {
                        if (edge.getFirst() == interferenceGraph.get(origClass)) {
                            edge.setFirst(interferenceGraph.get(newClass));
                        }
                        if (edge.getSecond() == interferenceGraph.get(origClass)) {
                            edge.setSecond(interferenceGraph.get(newClass));
                        }
                    }
                    for (MutableGraphEdge edge : interferenceGraph.get(copyClass).getEdges()
                            .toArray(new MutableGraphEdge[0])) {
                        if (edge.getFirst() == interferenceGraph.get(copyClass)) {
                            edge.setFirst(interferenceGraph.get(newClass));
                        }
                        if (edge.getSecond() == interferenceGraph.get(copyClass)) {
                            edge.setSecond(interferenceGraph.get(newClass));
                        }
                    }
                    interferenceGraph.set(copyClass, interferenceGraph.get(newClass));
                    interferenceGraph.set(origClass, interferenceGraph.get(newClass));
                }
            }
        }
    }

    private void renameVariables(final Program program, final int[] varMap) {
        InstructionVariableMapper mapper = new InstructionVariableMapper() {
            @Override protected Variable map(Variable var) {
                return program.variableAt(varMap[var.getIndex()]);
            }
        };
        for (int i = 0; i < program.basicBlockCount(); ++i) {
            BasicBlock block = program.basicBlockAt(i);
            for (Instruction insn : block.getInstructions()) {
                insn.acceptVisitor(mapper);
            }
            for (Phi phi : block.getPhis()) {
                phi.setReceiver(program.variableAt(varMap[phi.getReceiver().getIndex()]));
                for (Incoming incoming : phi.getIncomings()) {
                    incoming.setValue(program.variableAt(varMap[incoming.getValue().getIndex()]));
                }
            }
            for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
                tryCatch.setExceptionVariable(program.variableAt(
                        varMap[tryCatch.getExceptionVariable().getIndex()]));
            }
        }
        String[][] originalNames = new String[program.variableCount()][];
        for (int i = 0; i < program.variableCount(); ++i) {
            Variable var = program.variableAt(i);
            originalNames[i] = var.getDebugNames().toArray(new String[0]);
            var.getDebugNames().clear();
        }
        for (int i = 0; i < program.variableCount(); ++i) {
            program.variableAt(varMap[i]).getDebugNames().addAll(Arrays.asList(originalNames[i]));
        }
    }

    private void renameInterferenceGraph(List<MutableGraphNode> graph, DisjointSet classes, final int[] varMap) {
        List<MutableGraphNode> newGraph = new ArrayList<>();
        for (int i = 0; i < graph.size(); ++i) {
            int mapped = varMap[i];
            while (newGraph.size() <= mapped) {
                newGraph.add(null);
            }
            if (newGraph.get(mapped) == null) {
                int cls = classes.find(i);
                newGraph.set(mapped, graph.get(cls));
                graph.get(cls).setTag(mapped);
            }
        }
        graph.clear();
        graph.addAll(newGraph);
    }

    private DisjointSet buildPhiCongruenceClasses(Program program) {
        DisjointSet classes = new DisjointSet();
        for (int i = 0; i < program.variableCount(); ++i) {
            classes.create();
        }
        for (int i = 0; i < program.basicBlockCount(); ++i) {
            BasicBlock block = program.basicBlockAt(i);
            for (Phi phi : block.getPhis()) {
                for (Incoming incoming : phi.getIncomings()) {
                    classes.union(phi.getReceiver().getIndex(), incoming.getValue().getIndex());
                }
            }
        }
        return classes;
    }
}
TOP

Related Classes of org.teavm.model.util.RegisterAllocator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.