001/* 002 * Copyright (c) 2009, 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.gen; 024 025import static com.oracle.graal.lir.LIRValueUtil.*; 026import static jdk.internal.jvmci.code.ValueUtil.*; 027import static jdk.internal.jvmci.meta.Value.*; 028 029import java.util.*; 030 031import jdk.internal.jvmci.meta.*; 032 033import com.oracle.graal.compiler.common.*; 034import com.oracle.graal.compiler.common.cfg.*; 035import com.oracle.graal.lir.*; 036import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; 037 038/** 039 * Converts phi instructions into moves. 040 * 041 * Resolves cycles: 042 * 043 * <pre> 044 * 045 * r1 := r2 becomes temp := r1 046 * r2 := r1 r1 := r2 047 * r2 := temp 048 * </pre> 049 * 050 * and orders moves: 051 * 052 * <pre> 053 * r2 := r3 becomes r1 := r2 054 * r1 := r2 r2 := r3 055 * </pre> 056 */ 057public class PhiResolver { 058 059 /** 060 * Tracks a data flow dependency between a source operand and any number of the destination 061 * operands. 062 */ 063 static class PhiResolverNode { 064 065 /** 066 * A source operand whose value flows into the {@linkplain #destinations destination} 067 * operands. 068 */ 069 final Value operand; 070 071 /** 072 * The operands whose values are defined by the {@linkplain #operand source} operand. 073 */ 074 final ArrayList<PhiResolverNode> destinations; 075 076 /** 077 * Denotes if a move instruction has already been emitted to initialize the value of 078 * {@link #operand}. 079 */ 080 boolean assigned; 081 082 /** 083 * Specifies if this operand been visited for the purpose of emitting a move instruction. 084 */ 085 boolean visited; 086 087 /** 088 * Specifies if this is the initial definition in data flow path for a given value. 089 */ 090 boolean startNode; 091 092 PhiResolverNode(Value operand) { 093 this.operand = operand; 094 destinations = new ArrayList<>(4); 095 } 096 097 @Override 098 public String toString() { 099 StringBuilder buf = new StringBuilder(operand.toString()); 100 if (!destinations.isEmpty()) { 101 buf.append(" ->"); 102 for (PhiResolverNode node : destinations) { 103 buf.append(' ').append(node.operand); 104 } 105 } 106 return buf.toString(); 107 } 108 } 109 110 private final LIRGeneratorTool gen; 111 private final SpillMoveFactory moveFactory; 112 private final LIRInsertionBuffer buffer; 113 private final int insertBefore; 114 115 /** 116 * The operand loop header phi for the operand currently being process in {@link #dispose()}. 117 */ 118 private PhiResolverNode loop; 119 120 private Value temp; 121 122 private final ArrayList<PhiResolverNode> variableOperands = new ArrayList<>(3); 123 private final ArrayList<PhiResolverNode> otherOperands = new ArrayList<>(3); 124 125 /** 126 * Maps operands to nodes. 127 */ 128 private final HashMap<Value, PhiResolverNode> operandToNodeMap = CollectionsFactory.newMap(); 129 130 public static PhiResolver create(LIRGeneratorTool gen) { 131 AbstractBlockBase<?> block = gen.getCurrentBlock(); 132 assert block != null; 133 List<LIRInstruction> instructions = gen.getResult().getLIR().getLIRforBlock(block); 134 135 return new PhiResolver(gen, new LIRInsertionBuffer(), instructions, instructions.size()); 136 } 137 138 public static PhiResolver create(LIRGeneratorTool gen, LIRInsertionBuffer buffer, List<LIRInstruction> instructions, int insertBefore) { 139 return new PhiResolver(gen, buffer, instructions, insertBefore); 140 } 141 142 protected PhiResolver(LIRGeneratorTool gen, LIRInsertionBuffer buffer, List<LIRInstruction> instructions, int insertBefore) { 143 this.gen = gen; 144 moveFactory = gen.getSpillMoveFactory(); 145 temp = ILLEGAL; 146 147 this.buffer = buffer; 148 this.buffer.init(instructions); 149 this.insertBefore = insertBefore; 150 151 } 152 153 public void dispose() { 154 // resolve any cycles in moves from and to variables 155 for (int i = variableOperands.size() - 1; i >= 0; i--) { 156 PhiResolverNode node = variableOperands.get(i); 157 if (!node.visited) { 158 loop = null; 159 move(node, null); 160 node.startNode = true; 161 assert isIllegal(temp) : "moveTempTo() call missing"; 162 } 163 } 164 165 // generate move for move from non variable to arbitrary destination 166 for (int i = otherOperands.size() - 1; i >= 0; i--) { 167 PhiResolverNode node = otherOperands.get(i); 168 for (int j = node.destinations.size() - 1; j >= 0; j--) { 169 emitMove(node.destinations.get(j).operand, node.operand); 170 } 171 } 172 buffer.finish(); 173 } 174 175 public void move(Value dest, Value src) { 176 assert isVariable(dest) : "destination must be virtual"; 177 // tty.print("move "); src.print(); tty.print(" to "); dest.print(); tty.cr(); 178 assert isLegal(src) : "source for phi move is illegal"; 179 assert isLegal(dest) : "destination for phi move is illegal"; 180 PhiResolverNode srcNode = sourceNode(src); 181 PhiResolverNode destNode = destinationNode(dest); 182 srcNode.destinations.add(destNode); 183 } 184 185 private PhiResolverNode createNode(Value operand, boolean source) { 186 PhiResolverNode node; 187 if (isVariable(operand)) { 188 node = operandToNodeMap.get(operand); 189 assert node == null || node.operand.equals(operand); 190 if (node == null) { 191 node = new PhiResolverNode(operand); 192 operandToNodeMap.put(operand, node); 193 } 194 // Make sure that all variables show up in the list when 195 // they are used as the source of a move. 196 if (source) { 197 if (!variableOperands.contains(node)) { 198 variableOperands.add(node); 199 } 200 } 201 } else { 202 assert source; 203 node = new PhiResolverNode(operand); 204 otherOperands.add(node); 205 } 206 return node; 207 } 208 209 private PhiResolverNode destinationNode(Value opr) { 210 return createNode(opr, false); 211 } 212 213 private void emitMove(Value dest, Value src) { 214 assert isLegal(src); 215 assert isLegal(dest); 216 LIRInstruction move = moveFactory.createMove((AllocatableValue) dest, src); 217 buffer.append(insertBefore, move); 218 } 219 220 // Traverse assignment graph in depth first order and generate moves in post order 221 // ie. two assignments: b := c, a := b start with node c: 222 // Call graph: move(c, NULL) -> move(b, c) -> move(a, b) 223 // Generates moves in this order: move b to a and move c to b 224 // ie. cycle a := b, b := a start with node a 225 // Call graph: move(a, NULL) -> move(b, a) -> move(a, b) 226 // Generates moves in this order: move b to temp, move a to b, move temp to a 227 private void move(PhiResolverNode dest, PhiResolverNode src) { 228 if (!dest.visited) { 229 dest.visited = true; 230 for (int i = dest.destinations.size() - 1; i >= 0; i--) { 231 move(dest.destinations.get(i), dest); 232 } 233 } else if (!dest.startNode) { 234 // cycle in graph detected 235 assert loop == null : "only one loop valid!"; 236 loop = dest; 237 moveToTemp(src.operand); 238 return; 239 } // else dest is a start node 240 241 if (!dest.assigned) { 242 if (loop == dest) { 243 moveTempTo(dest.operand); 244 dest.assigned = true; 245 } else if (src != null) { 246 emitMove(dest.operand, src.operand); 247 dest.assigned = true; 248 } 249 } 250 } 251 252 private void moveTempTo(Value dest) { 253 assert isLegal(temp); 254 emitMove(dest, temp); 255 temp = ILLEGAL; 256 } 257 258 private void moveToTemp(Value src) { 259 assert isIllegal(temp); 260 temp = gen.newVariable(src.getLIRKind()); 261 emitMove(temp, src); 262 } 263 264 private PhiResolverNode sourceNode(Value opr) { 265 return createNode(opr, true); 266 } 267}