1 /* 2 * Copyright (c) 2014, 2015, 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 package org.graalvm.compiler.lir.dfa; 24 25 import static jdk.vm.ci.code.ValueUtil.isIllegal; 26 27 import java.util.ArrayList; 28 import java.util.EnumSet; 29 30 import org.graalvm.compiler.core.common.LIRKind; 31 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 32 import org.graalvm.compiler.core.common.cfg.BlockMap; 33 import org.graalvm.compiler.debug.Debug; 34 import org.graalvm.compiler.debug.Indent; 35 import org.graalvm.compiler.lir.InstructionStateProcedure; 36 import org.graalvm.compiler.lir.LIR; 37 import org.graalvm.compiler.lir.LIRFrameState; 38 import org.graalvm.compiler.lir.LIRInstruction; 39 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 40 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 41 import org.graalvm.compiler.lir.ValueConsumer; 42 import org.graalvm.compiler.lir.framemap.FrameMap; 43 import org.graalvm.compiler.lir.util.ValueSet; 44 45 import jdk.vm.ci.code.Register; 46 import jdk.vm.ci.meta.PlatformKind; 47 import jdk.vm.ci.meta.Value; 48 49 public abstract class LocationMarker<S extends ValueSet<S>> { 50 51 private final LIR lir; 52 private final BlockMap<S> liveInMap; 53 private final BlockMap<S> liveOutMap; 54 55 protected final FrameMap frameMap; 56 57 protected LocationMarker(LIR lir, FrameMap frameMap) { 58 this.lir = lir; 59 this.frameMap = frameMap; 60 liveInMap = new BlockMap<>(lir.getControlFlowGraph()); 61 liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); 62 } 63 64 protected abstract S newLiveValueSet(); 65 66 protected abstract boolean shouldProcessValue(Value operand); 67 68 protected abstract void processState(LIRInstruction op, LIRFrameState info, S values); 69 70 void build() { 71 AbstractBlockBase<?>[] blocks = lir.getControlFlowGraph().getBlocks(); 72 UniqueWorkList worklist = new UniqueWorkList(blocks.length); 73 for (int i = blocks.length - 1; i >= 0; i--) { 74 worklist.add(blocks[i]); 75 } 76 for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) { 77 liveInMap.put(block, newLiveValueSet()); 78 } 79 while (!worklist.isEmpty()) { 80 AbstractBlockBase<?> block = worklist.poll(); 81 processBlock(block, worklist); 82 } 83 } 84 85 /** 86 * Merge outSet with in-set of successors. 87 */ 88 private boolean updateOutBlock(AbstractBlockBase<?> block) { 89 S union = newLiveValueSet(); 90 for (AbstractBlockBase<?> succ : block.getSuccessors()) { 91 union.putAll(liveInMap.get(succ)); 92 } 93 S outSet = liveOutMap.get(block); 94 // check if changed 95 if (outSet == null || !union.equals(outSet)) { 96 liveOutMap.put(block, union); 97 return true; 98 } 99 return false; 100 } 101 102 @SuppressWarnings("try") 103 private void processBlock(AbstractBlockBase<?> block, UniqueWorkList worklist) { 104 if (updateOutBlock(block)) { 105 try (Indent indent = Debug.logAndIndent("handle block %s", block)) { 106 currentSet = liveOutMap.get(block).copy(); 107 ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block); 108 for (int i = instructions.size() - 1; i >= 0; i--) { 109 LIRInstruction inst = instructions.get(i); 110 processInstructionBottomUp(inst); 111 } 112 liveInMap.put(block, currentSet); 113 currentSet = null; 114 for (AbstractBlockBase<?> b : block.getPredecessors()) { 115 worklist.add(b); 116 } 117 } 118 } 119 } 120 121 private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG); 122 123 private S currentSet; 124 125 /** 126 * Process all values of an instruction bottom-up, i.e. definitions before usages. Values that 127 * start or end at the current operation are not included. 128 */ 129 @SuppressWarnings("try") 130 private void processInstructionBottomUp(LIRInstruction op) { 131 try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { 132 // kills 133 134 op.visitEachTemp(defConsumer); 135 op.visitEachOutput(defConsumer); 136 if (frameMap != null && op.destroysCallerSavedRegisters()) { 137 for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) { 138 PlatformKind kind = frameMap.getTarget().arch.getLargestStorableKind(reg.getRegisterCategory()); 139 defConsumer.visitValue(reg.asValue(LIRKind.value(kind)), OperandMode.TEMP, REGISTER_FLAG_SET); 140 } 141 } 142 143 // gen - values that are considered alive for this state 144 op.visitEachAlive(useConsumer); 145 op.visitEachState(useConsumer); 146 // mark locations 147 op.forEachState(stateConsumer); 148 // gen 149 op.visitEachInput(useConsumer); 150 } 151 } 152 153 InstructionStateProcedure stateConsumer = new InstructionStateProcedure() { 154 @Override 155 public void doState(LIRInstruction inst, LIRFrameState info) { 156 processState(inst, info, currentSet); 157 } 158 }; 159 160 ValueConsumer useConsumer = new ValueConsumer() { 161 @Override 162 public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 163 if (shouldProcessValue(operand)) { 164 // no need to insert values and derived reference 165 if (Debug.isLogEnabled()) { 166 Debug.log("set operand: %s", operand); 167 } 168 currentSet.put(operand); 169 } 170 } 171 }; 172 173 ValueConsumer defConsumer = new ValueConsumer() { 174 @Override 175 public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { 176 if (shouldProcessValue(operand)) { 177 if (Debug.isLogEnabled()) { 178 Debug.log("clear operand: %s", operand); 179 } 180 currentSet.remove(operand); 181 } else { 182 assert isIllegal(operand) || !operand.getValueKind().equals(LIRKind.Illegal) || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s", 183 operand, mode); 184 } 185 } 186 }; 187 }