1 /*
   2  * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.lir.constopt;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Collections;
  29 import java.util.List;
  30 import java.util.function.BiConsumer;
  31 import java.util.function.Predicate;
  32 
  33 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  34 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
  35 import org.graalvm.compiler.core.common.cfg.BlockMap;
  36 import org.graalvm.compiler.core.common.cfg.PrintableDominatorOptimizationProblem;
  37 import org.graalvm.compiler.core.common.cfg.PropertyConsumable;
  38 
  39 /**
  40  * Represents a dominator (sub-)tree for a constant definition.
  41  */
  42 public class ConstantTree extends PrintableDominatorOptimizationProblem<ConstantTree.Flags, ConstantTree.NodeCost> {
  43 
  44     public enum Flags {
  45         SUBTREE,
  46         USAGE,
  47         MATERIALIZE,
  48         CANDIDATE,
  49     }
  50 
  51     /**
  52      * Costs associated with a block.
  53      */
  54     public static class NodeCost implements PropertyConsumable {
  55         private List<UseEntry> usages;
  56         private double bestCost;
  57         private int numMat;
  58 
  59         public NodeCost(double bestCost, List<UseEntry> usages, int numMat) {
  60             this.bestCost = bestCost;
  61             this.usages = usages;
  62             this.numMat = numMat;
  63         }
  64 
  65         @Override
  66         public void forEachProperty(BiConsumer<String, String> action) {
  67             action.accept("bestCost", Double.toString(getBestCost()));
  68             action.accept("numMat", Integer.toString(getNumMaterializations()));
  69             action.accept("numUsages", Integer.toString(usages.size()));
  70         }
  71 
  72         public void addUsage(UseEntry usage) {
  73             if (usages == null) {
  74                 usages = new ArrayList<>();
  75             }
  76             usages.add(usage);
  77         }
  78 
  79         public List<UseEntry> getUsages() {
  80             if (usages == null) {
  81                 return Collections.emptyList();
  82             }
  83             return usages;
  84         }
  85 
  86         public double getBestCost() {
  87             return bestCost;
  88         }
  89 
  90         public int getNumMaterializations() {
  91             return numMat;
  92         }
  93 
  94         public void setBestCost(double cost) {
  95             bestCost = cost;
  96         }
  97 
  98         @Override
  99         public String toString() {
 100             return "NodeCost [bestCost=" + bestCost + ", numUsages=" + usages.size() + ", numMat=" + numMat + "]";
 101         }
 102     }
 103 
 104     private final BlockMap<List<UseEntry>> blockMap;
 105 
 106     public ConstantTree(AbstractControlFlowGraph<?> cfg, DefUseTree tree) {
 107         super(Flags.class, cfg);
 108         this.blockMap = new BlockMap<>(cfg);
 109         tree.forEach(u -> getOrInitList(u.getBlock()).add(u));
 110     }
 111 
 112     private List<UseEntry> getOrInitList(AbstractBlockBase<?> block) {
 113         List<UseEntry> list = blockMap.get(block);
 114         if (list == null) {
 115             list = new ArrayList<>();
 116             blockMap.put(block, list);
 117         }
 118         return list;
 119     }
 120 
 121     public List<UseEntry> getUsages(AbstractBlockBase<?> block) {
 122         List<UseEntry> list = blockMap.get(block);
 123         if (list == null) {
 124             return Collections.emptyList();
 125         }
 126         return Collections.unmodifiableList(list);
 127     }
 128 
 129     /**
 130      * Returns the cost object associated with {@code block}. If there is none, a new cost object is
 131      * created.
 132      */
 133     NodeCost getOrInitCost(AbstractBlockBase<?> block) {
 134         NodeCost cost = getCost(block);
 135         if (cost == null) {
 136             cost = new NodeCost(block.probability(), blockMap.get(block), 1);
 137             setCost(block, cost);
 138         }
 139         return cost;
 140     }
 141 
 142     @Override
 143     public String getName(Flags type) {
 144         switch (type) {
 145             case USAGE:
 146                 return "hasUsage";
 147             case SUBTREE:
 148                 return "inSubtree";
 149             case MATERIALIZE:
 150                 return "materialize";
 151             case CANDIDATE:
 152                 return "candidate";
 153         }
 154         return super.getName(type);
 155     }
 156 
 157     @Override
 158     public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
 159         if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) {
 160             action.accept("hasDefinition", "true");
 161         }
 162         super.forEachPropertyPair(block, action);
 163     }
 164 
 165     public long subTreeSize() {
 166         return stream(Flags.SUBTREE).count();
 167     }
 168 
 169     public AbstractBlockBase<?> getStartBlock() {
 170         return stream(Flags.SUBTREE).findFirst().get();
 171     }
 172 
 173     public void markBlocks() {
 174         for (AbstractBlockBase<?> block : getBlocks()) {
 175             if (get(Flags.USAGE, block)) {
 176                 setDominatorPath(Flags.SUBTREE, block);
 177             }
 178         }
 179     }
 180 
 181     public boolean isMarked(AbstractBlockBase<?> block) {
 182         return get(Flags.SUBTREE, block);
 183     }
 184 
 185     public boolean isLeafBlock(AbstractBlockBase<?> block) {
 186         AbstractBlockBase<?> dom = block.getFirstDominated();
 187         while (dom != null) {
 188             if (isMarked(dom)) {
 189                 return false;
 190             }
 191             dom = dom.getDominatedSibling();
 192         }
 193         return true;
 194     }
 195 
 196     public void setSolution(AbstractBlockBase<?> block) {
 197         set(Flags.MATERIALIZE, block);
 198     }
 199 
 200     public int size() {
 201         return getBlocks().length;
 202     }
 203 
 204     public void traverseTreeWhileTrue(AbstractBlockBase<?> block, Predicate<AbstractBlockBase<?>> action) {
 205         assert block != null : "block must not be null!";
 206         if (action.test(block)) {
 207             AbstractBlockBase<?> dom = block.getFirstDominated();
 208             while (dom != null) {
 209                 if (this.isMarked(dom)) {
 210                     traverseTreeWhileTrue(dom, action);
 211                 }
 212                 dom = dom.getDominatedSibling();
 213             }
 214         }
 215     }
 216 
 217 }