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}