001/* 002 * Copyright (c) 2015, 2015, 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.ssi; 024 025import static com.oracle.graal.lir.LIRValueUtil.*; 026import static jdk.internal.jvmci.code.ValueUtil.*; 027 028import java.util.*; 029 030import jdk.internal.jvmci.meta.*; 031 032import com.oracle.graal.compiler.common.cfg.*; 033import com.oracle.graal.debug.*; 034import com.oracle.graal.lir.*; 035import com.oracle.graal.lir.LIRInstruction.OperandMode; 036import com.oracle.graal.lir.StandardOp.BlockEndOp; 037import com.oracle.graal.lir.StandardOp.LabelOp; 038import com.oracle.graal.lir.gen.*; 039import com.oracle.graal.lir.util.*; 040 041public final class SSIBlockValueMapImpl implements BlockValueMap { 042 043 private static final class BlockData { 044 045 /** Mapping from value to index into {@link #incoming}. */ 046 private final ValueMap<Value, Integer> valueIndexMap; 047 private final ArrayList<Value> incoming; 048 private final ArrayList<Value> outgoing; 049 050 private BlockData(int initialVariableCapacity, int initialStackSlotCapacity) { 051 valueIndexMap = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity); 052 incoming = new ArrayList<>(); 053 outgoing = new ArrayList<>(); 054 } 055 056 public Integer getIndex(Value operand) { 057 return valueIndexMap.get(operand); 058 } 059 060 public Value getIncoming(int index) { 061 return incoming.get(index); 062 } 063 064 public void setIncoming(int index, Value value) { 065 incoming.set(index, value); 066 } 067 068 public int addIncoming(Value operand) { 069 assert isVariable(operand) || isVirtualStackSlot(operand) : "Not a variable or vstack: " + operand; 070 int index = incoming.size(); 071 incoming.add(Value.ILLEGAL); 072 valueIndexMap.put(operand, index); 073 return index; 074 } 075 076 public boolean contains(Value operand) { 077 return getIndex(operand) != null; 078 } 079 080 public int addOutgoing(Value operand) { 081 int index = outgoing.size(); 082 outgoing.add(operand); 083 return index; 084 } 085 086 } 087 088 /** Mapping from value to definition block. */ 089 private final ValueMap<Value, AbstractBlockBase<?>> valueToDefBlock; 090 private final BlockMap<BlockData> blockData; 091 private final int initialVariableCapacity; 092 private final int initialStackSlotCapacity; 093 094 public SSIBlockValueMapImpl(AbstractControlFlowGraph<?> cfg, int initialVariableCapacity, int initialStackSlotCapacity) { 095 this.initialVariableCapacity = initialVariableCapacity; 096 this.initialStackSlotCapacity = initialStackSlotCapacity; 097 valueToDefBlock = new VariableVirtualStackValueMap<>(initialVariableCapacity, initialStackSlotCapacity); 098 blockData = new BlockMap<>(cfg); 099 } 100 101 @Override 102 public void accessOperand(Value operand, AbstractBlockBase<?> block) { 103 assert block != null : "block is null"; 104 if (operand instanceof CompositeValue) { 105 ((CompositeValue) operand).forEachComponent(null, OperandMode.USE, (op, value, mode, flag) -> { 106 accessOperand(value, block); 107 return value; 108 }); 109 } else if (processValue(operand)) { 110 AbstractBlockBase<?> defBlock = getDefinitionBlock(operand); 111 assert defBlock != null : "Value is not defined: " + operand; 112 assert AbstractControlFlowGraph.dominates(defBlock, block) : "Block " + defBlock + " does not dominate " + block; 113 accessRecursive(operand, defBlock, block); 114 } 115 } 116 117 @Override 118 public void defineOperand(Value operand, AbstractBlockBase<?> block) { 119 assert block != null : "block is null"; 120 if (processValue(operand)) { 121 AbstractBlockBase<?> defBlock = getDefinitionBlock(operand); 122 if (defBlock == null) { 123 setDefinitionBlock(operand, block); 124 } else { 125 /* 126 * Redefinition: this can happen for nodes that do not produce a new value but proxy 127 * another one (PiNode, reinterpret). 128 */ 129 assert AbstractControlFlowGraph.dominates(defBlock, block) : String.format("Definition of %s in %s does not dominate the redefinition %s", operand, defBlock, block); 130 } 131 } 132 } 133 134 private static boolean processValue(Value operand) { 135 return isVariable(operand) || isVirtualStackSlot(operand); 136 } 137 138 // setter getter for internal data structures 139 140 private AbstractBlockBase<?> getDefinitionBlock(Value operand) { 141 return valueToDefBlock.get(operand); 142 } 143 144 private void setDefinitionBlock(Value operand, AbstractBlockBase<?> block) { 145 valueToDefBlock.put(operand, block); 146 } 147 148 private BlockData getOrInit(AbstractBlockBase<?> block) { 149 BlockData data = blockData.get(block); 150 if (data == null) { 151 data = new BlockData(initialVariableCapacity, initialStackSlotCapacity); 152 blockData.put(block, data); 153 } 154 return data; 155 } 156 157 // implementation 158 159 private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block) { 160 Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>(); 161 worklist.add(block); 162 163 while (!worklist.isEmpty()) { 164 accessRecursive(operand, defBlock, worklist.pollLast(), worklist); 165 } 166 } 167 168 private void accessRecursive(Value operand, AbstractBlockBase<?> defBlock, AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) { 169 try (Indent indent = Debug.logAndIndent("get operand %s in block %s", operand, block)) { 170 if (block.equals(defBlock)) { 171 Debug.log("found definition!"); 172 return; 173 } 174 BlockData data = getOrInit(block); 175 Integer index = data.getIndex(operand); 176 if (index != null) { 177 // value is live at block begin but might not be initialized 178 Value in = data.getIncoming(index); 179 if (Value.ILLEGAL.equals(in)) { 180 data.setIncoming(index, operand); 181 Debug.log("uninitialized incoming value -> initialize!"); 182 } else { 183 Debug.log("incoming value already initialized!"); 184 } 185 return; 186 } 187 188 // the value is not yet live a current block 189 int idx = addLiveValueToBlock(operand, block); 190 data.setIncoming(idx, operand); 191 192 for (AbstractBlockBase<?> pred : block.getPredecessors()) { 193 worklist.addLast(pred); 194 } 195 } 196 } 197 198 private int addLiveValueToBlock(Value operand, AbstractBlockBase<?> block) { 199 try (Indent indent = Debug.logAndIndent("add incoming value!")) { 200 int index = -1; 201 for (AbstractBlockBase<?> pred : block.getPredecessors()) { 202 try (Indent indent1 = Debug.logAndIndent("Add outgoing operand to %s", pred)) { 203 BlockData predData = getOrInit(pred); 204 int predIndex = predData.addOutgoing(operand); 205 206 if (index == -1) { 207 index = predIndex; 208 } else { 209 assert predIndex == index; 210 } 211 212 for (AbstractBlockBase<?> succ : pred.getSuccessors()) { 213 Debug.log("Add incoming operand to %s", succ); 214 BlockData succData = getOrInit(succ); 215 if (!succData.contains(operand)) { 216 int succIndex = succData.addIncoming(operand); 217 assert succIndex == predIndex; 218 } 219 } 220 } 221 } 222 Debug.log("new index: %d", index); 223 return index; 224 } 225 } 226 227 // finish 228 229 public void finish(LIRGeneratorTool gen) { 230 Debug.dump(gen.getResult().getLIR(), "Before SSI operands"); 231 AbstractControlFlowGraph<?> cfg = gen.getResult().getLIR().getControlFlowGraph(); 232 for (AbstractBlockBase<?> block : cfg.getBlocks()) { 233 // set label 234 BlockData data = blockData.get(block); 235 if (data != null) { 236 if (data.incoming != null && data.incoming.size() > 0) { 237 LabelOp label = getLabel(gen, block); 238 label.addIncomingValues(data.incoming.toArray(new Value[data.incoming.size()])); 239 } 240 // set block end 241 if (data.outgoing != null && data.outgoing.size() > 0) { 242 BlockEndOp blockEndOp = getBlockEnd(gen, block); 243 blockEndOp.addOutgoingValues(data.outgoing.toArray(new Value[data.outgoing.size()])); 244 } 245 } 246 } 247 } 248 249 private static List<LIRInstruction> getLIRforBlock(LIRGeneratorTool gen, AbstractBlockBase<?> block) { 250 return gen.getResult().getLIR().getLIRforBlock(block); 251 } 252 253 private static LabelOp getLabel(LIRGeneratorTool gen, AbstractBlockBase<?> block) { 254 return (LabelOp) getLIRforBlock(gen, block).get(0); 255 } 256 257 private static BlockEndOp getBlockEnd(LIRGeneratorTool gen, AbstractBlockBase<?> block) { 258 List<LIRInstruction> instructions = getLIRforBlock(gen, block); 259 return (BlockEndOp) instructions.get(instructions.size() - 1); 260 } 261}