All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jdk.graal.compiler.truffle.phases.inlining.DefaultInliningPolicy Maven / Gradle / Ivy

There is a newer version: 24.2.1
Show newest version
/*
 * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.graal.compiler.truffle.phases.inlining;

import java.util.Comparator;
import java.util.Map;
import java.util.PriorityQueue;

import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.truffle.TruffleCompilerOptions;

final class DefaultInliningPolicy implements InliningPolicy {

    private static final int MAX_DEPTH = 15;
    private static final Comparator CALL_NODE_COMPARATOR = (o1, o2) -> {
        if (o1.isTrivial() && !o2.isTrivial()) {
            return 1;
        }
        if (o2.isTrivial() && !o1.isTrivial()) {
            return -1;
        }
        final int compare = Double.compare(o2.getRootRelativeFrequency(), o1.getRootRelativeFrequency());
        if (compare == 0) {
            return o1.compareTo(o2);
        }
        return compare;
    };
    private final OptionValues options;
    private int expanded;

    DefaultInliningPolicy(OptionValues options) {
        this.options = options;
    }

    private static PriorityQueue getQueue(CallTree tree, CallNode.State state) {
        PriorityQueue queue = new PriorityQueue<>(CALL_NODE_COMPARATOR);
        for (CallNode child : tree.getRoot().getChildren()) {
            if (child.getState() == state) {
                queue.add(child);
            }
        }
        return queue;
    }

    private static void updateQueue(CallNode candidate, PriorityQueue inlineQueue, CallNode.State expanded) {
        for (CallNode child : candidate.getChildren()) {
            if (child.getState() == expanded) {
                inlineQueue.add(child);
            }
        }
    }

    @Override
    public void run(CallTree tree) {
        expand(tree);
        analyse(tree.getRoot());
        inline(tree);
    }

    private void analyse(CallNode node) {
        for (CallNode child : node.getChildren()) {
            analyse(child);
        }
        final Data data = data(node);
        if (node.getState() == CallNode.State.Cutoff && node.getRecursionDepth() == 0) {
            data.callDiff = node.getRootRelativeFrequency();
        }
        if (node.getState() == CallNode.State.Expanded) {
            data.callDiff = -1 * node.getRootRelativeFrequency();
            for (CallNode child : node.getChildren()) {
                switch (child.getState()) {
                    case Indirect:
                    case Removed:
                    case BailedOut:
                        // nothing to do
                        break;
                    case Cutoff:
                    case Inlined:
                    case Expanded:
                        data.callDiff += data(child).callDiff;
                        break;
                }
            }
            if (data.callDiff > 0) {
                data.callDiff = node.getRootRelativeFrequency();
            }
        }
    }

    private static Data data(CallNode node) {
        return (Data) node.getPolicyData();
    }

    @Override
    public Object newCallNodeData(CallNode callNode) {
        return new Data();
    }

    private void inline(CallTree tree) {
        String inlineOnly = TruffleCompilerOptions.InlineOnly.getValue(options);
        final int inliningBudget = TruffleCompilerOptions.InliningInliningBudget.getValue(options);
        final PriorityQueue inlineQueue = getQueue(tree, CallNode.State.Expanded);
        int rootSize = tree.getRoot().getSize();
        CallNode candidate;
        while ((candidate = inlineQueue.poll()) != null) {
            if (!InliningPolicy.acceptForInline(candidate, inlineOnly)) {
                continue;
            }
            if (candidate.isTrivial()) {
                candidate.inline();
                continue;
            }
            int candidateCost = candidate.getSize();
            if (rootSize + candidateCost > inliningBudget) {
                rootSize = tree.getRoot().recalculateSize();
                if (rootSize + candidateCost > inliningBudget) {
                    break;
                }
            }
            if (data(candidate).callDiff <= 0) {
                candidate.inline();
                rootSize += candidateCost;
                updateQueue(candidate, inlineQueue, CallNode.State.Expanded);
            }
        }
    }

    private void expand(CallTree tree) {
        final int expansionBudget = TruffleCompilerOptions.InliningExpansionBudget.getValue(options);
        final int maximumRecursiveInliningValue = TruffleCompilerOptions.InliningRecursionDepth.getValue(options);
        expanded = tree.getRoot().getSize();
        final PriorityQueue expandQueue = getQueue(tree, CallNode.State.Cutoff);
        CallNode candidate;
        while ((candidate = expandQueue.poll()) != null && expanded < expansionBudget) {
            if (candidate.getRecursionDepth() <= maximumRecursiveInliningValue && candidate.getDepth() <= MAX_DEPTH) {
                expand(candidate, expandQueue);
            }
        }
    }

    private void expand(CallNode candidate, PriorityQueue expandQueue) {
        candidate.expand();
        if (candidate.getState() == CallNode.State.Expanded) {
            expanded += candidate.getSize();
            updateQueue(candidate, expandQueue, CallNode.State.Cutoff);
        }
    }

    @Override
    public void afterExpand(CallNode callNode) {
        for (CallNode child : callNode.getChildren()) {
            if (child.isTrivial()) {
                child.expand();
            }
        }
    }

    @Override
    public void putProperties(CallNode callNode, Map properties) {
        Data data = data(callNode);
        properties.put("call diff", data != null ? data.callDiff : 0);
    }

    private static final class Data {
        double callDiff;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy