001/*
002 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir.constopt;
024
025import java.util.*;
026import java.util.function.*;
027
028import com.oracle.graal.compiler.common.cfg.*;
029
030/**
031 * Represents a dominator (sub-)tree for a constant definition.
032 */
033public class ConstantTree extends PrintableDominatorOptimizationProblem<ConstantTree.Flags, ConstantTree.NodeCost> {
034
035    public enum Flags {
036        SUBTREE,
037        USAGE,
038        MATERIALIZE,
039        CANDIDATE,
040    }
041
042    /**
043     * Costs associated with a block.
044     */
045    public static class NodeCost implements PropertyConsumable {
046        private List<UseEntry> usages;
047        private double bestCost;
048        private int numMat;
049
050        public NodeCost(double bestCost, List<UseEntry> usages, int numMat) {
051            this.bestCost = bestCost;
052            this.usages = usages;
053            this.numMat = numMat;
054        }
055
056        public void forEachProperty(BiConsumer<String, String> action) {
057            action.accept("bestCost", Double.toString(getBestCost()));
058            action.accept("numMat", Integer.toString(getNumMaterializations()));
059            action.accept("numUsages", Integer.toString(usages.size()));
060        }
061
062        public void addUsage(UseEntry usage) {
063            if (usages == null) {
064                usages = new ArrayList<>();
065            }
066            usages.add(usage);
067        }
068
069        public List<UseEntry> getUsages() {
070            if (usages == null) {
071                Collections.emptyList();
072            }
073            return usages;
074        }
075
076        public double getBestCost() {
077            return bestCost;
078        }
079
080        public int getNumMaterializations() {
081            return numMat;
082        }
083
084        public void setBestCost(double cost) {
085            bestCost = cost;
086        }
087
088        @Override
089        public String toString() {
090            return "NodeCost [bestCost=" + bestCost + ", numUsages=" + usages.size() + ", numMat=" + numMat + "]";
091        }
092    }
093
094    private final BlockMap<List<UseEntry>> blockMap;
095
096    public ConstantTree(AbstractControlFlowGraph<?> cfg, DefUseTree tree) {
097        super(Flags.class, cfg);
098        this.blockMap = new BlockMap<>(cfg);
099        tree.forEach(u -> getOrInitList(u.getBlock()).add(u));
100    }
101
102    private List<UseEntry> getOrInitList(AbstractBlockBase<?> block) {
103        List<UseEntry> list = blockMap.get(block);
104        if (list == null) {
105            list = new ArrayList<>();
106            blockMap.put(block, list);
107        }
108        return list;
109    }
110
111    public List<UseEntry> getUsages(AbstractBlockBase<?> block) {
112        List<UseEntry> list = blockMap.get(block);
113        if (list == null) {
114            return Collections.emptyList();
115        }
116        return Collections.unmodifiableList(list);
117    }
118
119    /**
120     * Returns the cost object associated with {@code block}. If there is none, a new cost object is
121     * created.
122     */
123    NodeCost getOrInitCost(AbstractBlockBase<?> block) {
124        NodeCost cost = getCost(block);
125        if (cost == null) {
126            cost = new NodeCost(block.probability(), blockMap.get(block), 1);
127            setCost(block, cost);
128        }
129        return cost;
130    }
131
132    @Override
133    public String getName(Flags type) {
134        switch (type) {
135            case USAGE:
136                return "hasUsage";
137            case SUBTREE:
138                return "inSubtree";
139            case MATERIALIZE:
140                return "materialize";
141            case CANDIDATE:
142                return "candidate";
143        }
144        return super.getName(type);
145    }
146
147    @Override
148    public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
149        if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) {
150            action.accept("hasDefinition", "true");
151        }
152        super.forEachPropertyPair(block, action);
153    }
154
155    public long subTreeSize() {
156        return stream(Flags.SUBTREE).count();
157    }
158
159    public AbstractBlockBase<?> getStartBlock() {
160        return stream(Flags.SUBTREE).findFirst().get();
161    }
162
163    public void markBlocks() {
164        for (AbstractBlockBase<?> block : getBlocks()) {
165            if (get(Flags.USAGE, block)) {
166                setDominatorPath(Flags.SUBTREE, block);
167            }
168        }
169    }
170
171    public boolean isMarked(AbstractBlockBase<?> block) {
172        return get(Flags.SUBTREE, block);
173    }
174
175    public boolean isLeafBlock(AbstractBlockBase<?> block) {
176        for (AbstractBlockBase<?> dom : block.getDominated()) {
177            if (isMarked(dom)) {
178                return false;
179            }
180        }
181        return true;
182    }
183
184    public void setSolution(AbstractBlockBase<?> block) {
185        set(Flags.MATERIALIZE, block);
186    }
187
188    public int size() {
189        return getBlocks().size();
190    }
191
192    public void traverseTreeWhileTrue(AbstractBlockBase<?> block, Predicate<AbstractBlockBase<?>> action) {
193        assert block != null : "block must not be null!";
194        if (action.test(block)) {
195            block.getDominated().stream().filter(this::isMarked).forEach(dominated -> traverseTreeWhileTrue(dominated, action));
196        }
197    }
198
199}