28 import java.util.ArrayList; |
28 import java.util.ArrayList; |
29 import java.util.EnumSet; |
29 import java.util.EnumSet; |
30 |
30 |
31 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
31 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; |
32 import org.graalvm.compiler.core.common.cfg.BlockMap; |
32 import org.graalvm.compiler.core.common.cfg.BlockMap; |
33 import org.graalvm.compiler.debug.Debug; |
33 import org.graalvm.compiler.debug.DebugContext; |
34 import org.graalvm.compiler.debug.Debug.Scope; |
|
35 import org.graalvm.compiler.debug.GraalError; |
34 import org.graalvm.compiler.debug.GraalError; |
36 import org.graalvm.compiler.debug.Indent; |
35 import org.graalvm.compiler.debug.Indent; |
37 import org.graalvm.compiler.lir.InstructionValueConsumer; |
36 import org.graalvm.compiler.lir.InstructionValueConsumer; |
38 import org.graalvm.compiler.lir.LIRInstruction; |
37 import org.graalvm.compiler.lir.LIRInstruction; |
39 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
38 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; |
82 |
81 |
83 } |
82 } |
84 |
83 |
85 @SuppressWarnings("try") |
84 @SuppressWarnings("try") |
86 void verify(AbstractBlockBase<?> start) { |
85 void verify(AbstractBlockBase<?> start) { |
87 try (Scope s = Debug.scope("RegisterVerifier")) { |
86 DebugContext debug = allocator.getDebug(); |
|
87 try (DebugContext.Scope s = debug.scope("RegisterVerifier")) { |
88 // setup input registers (method arguments) for first block |
88 // setup input registers (method arguments) for first block |
89 Interval[] inputState = new Interval[stateSize()]; |
89 Interval[] inputState = new Interval[stateSize()]; |
90 setStateForBlock(start, inputState); |
90 setStateForBlock(start, inputState); |
91 addToWorkList(start); |
91 addToWorkList(start); |
92 |
92 |
100 } |
100 } |
101 } |
101 } |
102 |
102 |
103 @SuppressWarnings("try") |
103 @SuppressWarnings("try") |
104 private void processBlock(AbstractBlockBase<?> block) { |
104 private void processBlock(AbstractBlockBase<?> block) { |
105 try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) { |
105 DebugContext debug = allocator.getDebug(); |
|
106 try (Indent indent = debug.logAndIndent("processBlock B%d", block.getId())) { |
106 // must copy state because it is modified |
107 // must copy state because it is modified |
107 Interval[] inputState = copy(stateForBlock(block)); |
108 Interval[] inputState = copy(stateForBlock(block)); |
108 |
109 |
109 try (Indent indent2 = Debug.logAndIndent("Input-State of intervals:")) { |
110 try (Indent indent2 = debug.logAndIndent("Input-State of intervals:")) { |
110 printState(inputState); |
111 printState(inputState); |
111 } |
112 } |
112 |
113 |
113 // process all operations of the block |
114 // process all operations of the block |
114 processOperations(block, inputState); |
115 processOperations(block, inputState); |
115 |
116 |
116 try (Indent indent2 = Debug.logAndIndent("Output-State of intervals:")) { |
117 try (Indent indent2 = debug.logAndIndent("Output-State of intervals:")) { |
117 printState(inputState); |
118 printState(inputState); |
118 } |
119 } |
119 |
120 |
120 // iterate all successors |
121 // iterate all successors |
121 for (AbstractBlockBase<?> succ : block.getSuccessors()) { |
122 for (AbstractBlockBase<?> succ : block.getSuccessors()) { |
123 } |
124 } |
124 } |
125 } |
125 } |
126 } |
126 |
127 |
127 protected void printState(Interval[] inputState) { |
128 protected void printState(Interval[] inputState) { |
|
129 DebugContext debug = allocator.getDebug(); |
128 for (int i = 0; i < stateSize(); i++) { |
130 for (int i = 0; i < stateSize(); i++) { |
129 Register reg = allocator.getRegisters().get(i); |
131 Register reg = allocator.getRegisters().get(i); |
130 assert reg.number == i; |
132 assert reg.number == i; |
131 if (inputState[i] != null) { |
133 if (inputState[i] != null) { |
132 Debug.log(" %6s %4d -- %s", reg, inputState[i].operandNumber, inputState[i]); |
134 debug.log(" %6s %4d -- %s", reg, inputState[i].operandNumber, inputState[i]); |
133 } else { |
135 } else { |
134 Debug.log(" %6s __", reg); |
136 debug.log(" %6s __", reg); |
135 } |
137 } |
136 } |
138 } |
137 } |
139 } |
138 |
140 |
139 private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) { |
141 private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) { |
|
142 DebugContext debug = allocator.getDebug(); |
140 Interval[] savedState = stateForBlock(block); |
143 Interval[] savedState = stateForBlock(block); |
141 |
144 |
142 if (savedState != null) { |
145 if (savedState != null) { |
143 // this block was already processed before. |
146 // this block was already processed before. |
144 // check if new inputState is consistent with savedState |
147 // check if new inputState is consistent with savedState |
153 // register was valid. when the register was already invalid, |
156 // register was valid. when the register was already invalid, |
154 // then the old calculation was correct. |
157 // then the old calculation was correct. |
155 savedStateCorrect = false; |
158 savedStateCorrect = false; |
156 savedState[i] = null; |
159 savedState[i] = null; |
157 |
160 |
158 Debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i); |
161 debug.log("processSuccessor B%d: invalidating slot %d", block.getId(), i); |
159 } |
162 } |
160 } |
163 } |
161 } |
164 } |
162 |
165 |
163 if (savedStateCorrect) { |
166 if (savedStateCorrect) { |
164 // already processed block with correct inputState |
167 // already processed block with correct inputState |
165 Debug.log("processSuccessor B%d: previous visit already correct", block.getId()); |
168 debug.log("processSuccessor B%d: previous visit already correct", block.getId()); |
166 } else { |
169 } else { |
167 // must re-visit this block |
170 // must re-visit this block |
168 Debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId()); |
171 debug.log("processSuccessor B%d: must re-visit because input state changed", block.getId()); |
169 addToWorkList(block); |
172 addToWorkList(block); |
170 } |
173 } |
171 |
174 |
172 } else { |
175 } else { |
173 // block was not processed before, so set initial inputState |
176 // block was not processed before, so set initial inputState |
174 Debug.log("processSuccessor B%d: initial visit", block.getId()); |
177 debug.log("processSuccessor B%d: initial visit", block.getId()); |
175 |
178 |
176 setStateForBlock(block, copy(inputState)); |
179 setStateForBlock(block, copy(inputState)); |
177 addToWorkList(block); |
180 addToWorkList(block); |
178 } |
181 } |
179 } |
182 } |
180 |
183 |
181 static Interval[] copy(Interval[] inputState) { |
184 static Interval[] copy(Interval[] inputState) { |
182 return inputState.clone(); |
185 return inputState.clone(); |
183 } |
186 } |
184 |
187 |
185 static void statePut(Interval[] inputState, Value location, Interval interval) { |
188 static void statePut(DebugContext debug, Interval[] inputState, Value location, Interval interval) { |
186 if (location != null && isRegister(location)) { |
189 if (location != null && isRegister(location)) { |
187 Register reg = asRegister(location); |
190 Register reg = asRegister(location); |
188 int regNum = reg.number; |
191 int regNum = reg.number; |
189 if (interval != null) { |
192 if (interval != null) { |
190 Debug.log("%s = %s", reg, interval.operand); |
193 debug.log("%s = %s", reg, interval.operand); |
191 } else if (inputState[regNum] != null) { |
194 } else if (inputState[regNum] != null) { |
192 Debug.log("%s = null", reg); |
195 debug.log("%s = null", reg); |
193 } |
196 } |
194 |
197 |
195 inputState[regNum] = interval; |
198 inputState[regNum] = interval; |
196 } |
199 } |
197 } |
200 } |
207 return true; |
210 return true; |
208 } |
211 } |
209 |
212 |
210 void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) { |
213 void processOperations(AbstractBlockBase<?> block, final Interval[] inputState) { |
211 ArrayList<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block); |
214 ArrayList<LIRInstruction> ops = allocator.getLIR().getLIRforBlock(block); |
|
215 DebugContext debug = allocator.getDebug(); |
212 InstructionValueConsumer useConsumer = new InstructionValueConsumer() { |
216 InstructionValueConsumer useConsumer = new InstructionValueConsumer() { |
213 |
217 |
214 @Override |
218 @Override |
215 public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { |
219 public void visitValue(LIRInstruction op, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) { |
216 // we skip spill moves inserted by the spill position optimization |
220 // we skip spill moves inserted by the spill position optimization |
230 Interval interval = intervalAt(operand); |
234 Interval interval = intervalAt(operand); |
231 if (op.id() != -1) { |
235 if (op.id() != -1) { |
232 interval = interval.getSplitChildAtOpId(op.id(), mode, allocator); |
236 interval = interval.getSplitChildAtOpId(op.id(), mode, allocator); |
233 } |
237 } |
234 |
238 |
235 statePut(inputState, interval.location(), interval.splitParent()); |
239 statePut(debug, inputState, interval.location(), interval.splitParent()); |
236 } |
240 } |
237 }; |
241 }; |
238 |
242 |
239 // visit all instructions of the block |
243 // visit all instructions of the block |
240 for (int i = 0; i < ops.size(); i++) { |
244 for (int i = 0; i < ops.size(); i++) { |
241 final LIRInstruction op = ops.get(i); |
245 final LIRInstruction op = ops.get(i); |
242 |
246 |
243 if (Debug.isLogEnabled()) { |
247 if (debug.isLogEnabled()) { |
244 Debug.log("%s", op.toStringWithIdPrefix()); |
248 debug.log("%s", op.toStringWithIdPrefix()); |
245 } |
249 } |
246 |
250 |
247 // check if input operands are correct |
251 // check if input operands are correct |
248 op.visitEachInput(useConsumer); |
252 op.visitEachInput(useConsumer); |
249 // invalidate all caller save registers at calls |
253 // invalidate all caller save registers at calls |
250 if (op.destroysCallerSavedRegisters()) { |
254 if (op.destroysCallerSavedRegisters()) { |
251 for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) { |
255 for (Register r : allocator.getRegisterAllocationConfig().getRegisterConfig().getCallerSaveRegisters()) { |
252 statePut(inputState, r.asValue(), null); |
256 statePut(debug, inputState, r.asValue(), null); |
253 } |
257 } |
254 } |
258 } |
255 op.visitEachAlive(useConsumer); |
259 op.visitEachAlive(useConsumer); |
256 // set temp operands (some operations use temp operands also as output operands, so |
260 // set temp operands (some operations use temp operands also as output operands, so |
257 // can't set them null) |
261 // can't set them null) |