Mercurial > hg > truffle
comparison graal/GraalCompiler/src/com/sun/c1x/lir/LIRInstruction.java @ 2509:16b9a8b5ad39
Renamings Runtime=>GraalRuntime and Compiler=>GraalCompiler
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 27 Apr 2011 11:50:44 +0200 |
parents | graal/Compiler/src/com/sun/c1x/lir/LIRInstruction.java@9ec15d6914ca |
children | 7ed72769d51a |
comparison
equal
deleted
inserted
replaced
2508:fea94949e0a2 | 2509:16b9a8b5ad39 |
---|---|
1 /* | |
2 * Copyright (c) 2009, 2011, 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 com.sun.c1x.lir; | |
24 | |
25 import static com.sun.c1x.C1XCompilation.*; | |
26 | |
27 import java.util.*; | |
28 | |
29 import com.sun.c1x.*; | |
30 import com.sun.c1x.ir.*; | |
31 import com.sun.c1x.lir.LIROperand.LIRAddressOperand; | |
32 import com.sun.c1x.lir.LIROperand.LIRVariableOperand; | |
33 import com.sun.cri.ci.*; | |
34 | |
35 /** | |
36 * The {@code LIRInstruction} class definition. | |
37 * | |
38 * @author Marcelo Cintra | |
39 * @author Thomas Wuerthinger | |
40 */ | |
41 public abstract class LIRInstruction { | |
42 | |
43 private static final LIROperand ILLEGAL_SLOT = new LIROperand(CiValue.IllegalValue); | |
44 | |
45 private static final CiValue[] NO_OPERANDS = {}; | |
46 | |
47 public static final OperandMode[] OPERAND_MODES = OperandMode.values(); | |
48 | |
49 /** | |
50 * Constants denoting how a LIR instruction uses an operand. Any combination of these modes | |
51 * can be applied to an operand as long as every operand has at least one mode applied to it. | |
52 */ | |
53 public enum OperandMode { | |
54 /** | |
55 * An operand that is defined by a LIR instruction and is live after the code emitted for a LIR instruction. | |
56 */ | |
57 Output, | |
58 | |
59 /** | |
60 * An operand that is used by a LIR instruction and is live before the code emitted for a LIR instruction. | |
61 * Unless such an operand is also an output or temp operand, it must not be modified by a LIR instruction. | |
62 */ | |
63 Input, | |
64 | |
65 /** | |
66 * An operand that is both modified and used by a LIR instruction. | |
67 */ | |
68 Temp | |
69 } | |
70 | |
71 /** | |
72 * The opcode of this instruction. | |
73 */ | |
74 public final LIROpcode code; | |
75 | |
76 /** | |
77 * The result operand for this instruction. | |
78 */ | |
79 private final LIROperand result; | |
80 | |
81 /** | |
82 * The input and temporary operands of this instruction. | |
83 */ | |
84 protected final LIROperand[] operands; | |
85 | |
86 /** | |
87 * Used to emit debug information. | |
88 */ | |
89 public final LIRDebugInfo info; | |
90 | |
91 /** | |
92 * Value id for register allocation. | |
93 */ | |
94 public int id; | |
95 | |
96 /** | |
97 * Determines if all caller-saved registers are destroyed by this instruction. | |
98 */ | |
99 public final boolean hasCall; | |
100 | |
101 /** | |
102 * The number of variable or register output operands for this instruction. | |
103 * These operands are at indexes {@code [0 .. allocatorOutputCount-1]} in {@link #allocatorOperands}. | |
104 * | |
105 * @see OperandMode#Output | |
106 */ | |
107 private byte allocatorOutputCount; | |
108 | |
109 /** | |
110 * The number of variable or register input operands for this instruction. | |
111 * These operands are at indexes {@code [allocatorOutputCount .. (allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. | |
112 * | |
113 * @see OperandMode#Input | |
114 */ | |
115 private byte allocatorInputCount; | |
116 | |
117 /** | |
118 * The number of variable or register temp operands for this instruction. | |
119 * These operands are at indexes {@code [allocatorInputCount+allocatorOutputCount .. (allocatorTempCount+allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. | |
120 * | |
121 * @see OperandMode#Temp | |
122 */ | |
123 private byte allocatorTempCount; | |
124 | |
125 /** | |
126 * The number of variable or register input or temp operands for this instruction. | |
127 */ | |
128 private byte allocatorTempInputCount; | |
129 | |
130 /** | |
131 * The set of operands that must be known to the register allocator either to bind a register | |
132 * or stack slot to a {@linkplain CiVariable variable} or to inform the allocator about operands | |
133 * that are already fixed to a specific register. | |
134 * This set excludes all constant operands as well as operands that are bound to | |
135 * a stack slot in the {@linkplain CiStackSlot#inCallerFrame() caller's frame}. | |
136 * This array is partitioned as follows. | |
137 * <pre> | |
138 * | |
139 * <-- allocatorOutputCount --> <-- allocatorInputCount --> <-- allocatorTempCount --> | |
140 * +----------------------------+---------------------------+--------------------------+ | |
141 * | output operands | input operands | temp operands | | |
142 * +----------------------------+---------------------------+--------------------------+ | |
143 * | |
144 * </pre> | |
145 */ | |
146 final List<CiValue> allocatorOperands; | |
147 | |
148 /** | |
149 * Constructs a new LIR instruction that has no input or temp operands. | |
150 * | |
151 * @param opcode the opcode of the new instruction | |
152 * @param result the operand that holds the operation result of this instruction. This will be | |
153 * {@link CiValue#IllegalValue} for instructions that do not produce a result. | |
154 * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. | |
155 * @param hasCall specifies if all caller-saved registers are destroyed by this instruction | |
156 */ | |
157 public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall) { | |
158 this(opcode, result, info, hasCall, 0, 0, NO_OPERANDS); | |
159 } | |
160 | |
161 /** | |
162 * Constructs a new LIR instruction. The {@code operands} array is partitioned as follows: | |
163 * <pre> | |
164 * | |
165 * <------- tempInput -------> <--------- temp ---------> | |
166 * +--------------------------+---------------------------+--------------------------+ | |
167 * | input operands | input+temp operands | temp operands | | |
168 * +--------------------------+---------------------------+--------------------------+ | |
169 * | |
170 * </pre> | |
171 * | |
172 * @param opcode the opcode of the new instruction | |
173 * @param result the operand that holds the operation result of this instruction. This will be | |
174 * {@link CiValue#IllegalValue} for instructions that do not produce a result. | |
175 * @param info the {@link LIRDebugInfo} that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. | |
176 * @param hasCall specifies if all caller-saved registers are destroyed by this instruction | |
177 * @param tempInput the number of operands that are both {@linkplain OperandMode#Input input} and {@link OperandMode#Temp temp} operands for this instruction | |
178 * @param temp the number of operands that are {@link OperandMode#Temp temp} operands for this instruction | |
179 * @param operands the input and temp operands for the instruction | |
180 */ | |
181 public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall, int tempInput, int temp, CiValue... operands) { | |
182 this.code = opcode; | |
183 this.info = info; | |
184 this.hasCall = hasCall; | |
185 | |
186 assert opcode != LIROpcode.Move || result != CiValue.IllegalValue; | |
187 allocatorOperands = new ArrayList<CiValue>(operands.length + 3); | |
188 this.result = initOutput(result); | |
189 | |
190 C1XMetrics.LIRInstructions++; | |
191 | |
192 if (opcode == LIROpcode.Move) { | |
193 C1XMetrics.LIRMoveInstructions++; | |
194 } | |
195 id = -1; | |
196 this.operands = new LIROperand[operands.length]; | |
197 initInputsAndTemps(tempInput, temp, operands); | |
198 | |
199 assert verifyOperands(); | |
200 } | |
201 | |
202 private LIROperand initOutput(CiValue output) { | |
203 assert output != null; | |
204 if (output != CiValue.IllegalValue) { | |
205 if (output.isAddress()) { | |
206 return addAddress((CiAddress) output); | |
207 } | |
208 if (output.isStackSlot()) { | |
209 return new LIROperand(output); | |
210 } | |
211 | |
212 assert allocatorOperands.size() == allocatorOutputCount; | |
213 allocatorOperands.add(output); | |
214 allocatorOutputCount++; | |
215 return new LIRVariableOperand(allocatorOperands.size() - 1); | |
216 } else { | |
217 return ILLEGAL_SLOT; | |
218 } | |
219 } | |
220 | |
221 /** | |
222 * Adds a {@linkplain CiValue#isLegal() legal} value that is part of an address to | |
223 * the list of {@linkplain #allocatorOperands register allocator operands}. If | |
224 * the value is {@linkplain CiVariable variable}, then its index into the list | |
225 * of register allocator operands is returned. Otherwise, {@code -1} is returned. | |
226 */ | |
227 private int addAddressPart(CiValue part) { | |
228 if (part.isRegister()) { | |
229 allocatorInputCount++; | |
230 allocatorOperands.add(part); | |
231 return -1; | |
232 } | |
233 if (part.isVariable()) { | |
234 allocatorInputCount++; | |
235 allocatorOperands.add(part); | |
236 return allocatorOperands.size() - 1; | |
237 } | |
238 assert part.isIllegal(); | |
239 return -1; | |
240 } | |
241 | |
242 private LIROperand addAddress(CiAddress address) { | |
243 assert address.base.isVariableOrRegister(); | |
244 | |
245 int base = addAddressPart(address.base); | |
246 int index = addAddressPart(address.index); | |
247 | |
248 if (base != -1 || index != -1) { | |
249 return new LIRAddressOperand(base, index, address); | |
250 } | |
251 | |
252 assert address.base.isRegister() && (address.index.isIllegal() || address.index.isRegister()); | |
253 return new LIROperand(address); | |
254 } | |
255 | |
256 private LIROperand addOperand(CiValue operand, boolean isInput, boolean isTemp) { | |
257 assert operand != null; | |
258 if (operand != CiValue.IllegalValue) { | |
259 assert !(operand.isAddress()); | |
260 if (operand.isStackSlot()) { | |
261 // no variables to add | |
262 return new LIROperand(operand); | |
263 } else if (operand.isConstant()) { | |
264 // no variables to add | |
265 return new LIROperand(operand); | |
266 } else { | |
267 assert allocatorOperands.size() == allocatorOutputCount + allocatorInputCount + allocatorTempInputCount + allocatorTempCount; | |
268 allocatorOperands.add(operand); | |
269 | |
270 if (isInput && isTemp) { | |
271 allocatorTempInputCount++; | |
272 } else if (isInput) { | |
273 allocatorInputCount++; | |
274 } else { | |
275 assert isTemp; | |
276 allocatorTempCount++; | |
277 } | |
278 | |
279 return new LIRVariableOperand(allocatorOperands.size() - 1); | |
280 } | |
281 } else { | |
282 return ILLEGAL_SLOT; | |
283 } | |
284 } | |
285 | |
286 /** | |
287 * Gets an input or temp operand of this instruction. | |
288 * | |
289 * @param index the index of the operand requested | |
290 * @return the {@code index}'th operand | |
291 */ | |
292 public final CiValue operand(int index) { | |
293 if (index >= operands.length) { | |
294 return CiValue.IllegalValue; | |
295 } | |
296 | |
297 return operands[index].value(this); | |
298 } | |
299 | |
300 private void initInputsAndTemps(int tempInputCount, int tempCount, CiValue[] operands) { | |
301 | |
302 // Addresses in instruction | |
303 for (int i = 0; i < operands.length; i++) { | |
304 CiValue op = operands[i]; | |
305 if (op.isAddress()) { | |
306 this.operands[i] = addAddress((CiAddress) op); | |
307 } | |
308 } | |
309 | |
310 int z = 0; | |
311 // Input-only operands | |
312 for (int i = 0; i < operands.length - tempInputCount - tempCount; i++) { | |
313 if (this.operands[z] == null) { | |
314 this.operands[z] = addOperand(operands[z], true, false); | |
315 } | |
316 z++; | |
317 } | |
318 | |
319 // Operands that are both inputs and temps | |
320 for (int i = 0; i < tempInputCount; i++) { | |
321 if (this.operands[z] == null) { | |
322 this.operands[z] = addOperand(operands[z], true, true); | |
323 } | |
324 z++; | |
325 } | |
326 | |
327 // Temp-only operands | |
328 for (int i = 0; i < tempCount; i++) { | |
329 if (this.operands[z] == null) { | |
330 this.operands[z] = addOperand(operands[z], false, true); | |
331 } | |
332 z++; | |
333 } | |
334 } | |
335 | |
336 private boolean verifyOperands() { | |
337 for (LIROperand operandSlot : operands) { | |
338 assert operandSlot != null; | |
339 } | |
340 | |
341 for (CiValue operand : this.allocatorOperands) { | |
342 assert operand != null; | |
343 assert operand.isVariableOrRegister() : "LIR operands can only be variables and registers initially, not " + operand.getClass().getSimpleName(); | |
344 } | |
345 return true; | |
346 } | |
347 | |
348 /** | |
349 * Gets the result operand for this instruction. | |
350 * | |
351 * @return return the result operand | |
352 */ | |
353 public final CiValue result() { | |
354 return result.value(this); | |
355 } | |
356 | |
357 /** | |
358 * Gets the instruction name. | |
359 * | |
360 * @return the name of the enum constant that represents the instruction opcode, exactly as declared in the enum | |
361 * LIROpcode declaration. | |
362 */ | |
363 public String name() { | |
364 return code.name(); | |
365 } | |
366 | |
367 /** | |
368 * Abstract method to be used to emit target code for this instruction. | |
369 * | |
370 * @param masm the target assembler. | |
371 */ | |
372 public abstract void emitCode(LIRAssembler masm); | |
373 | |
374 /** | |
375 * Utility for specializing how a {@linkplain CiValue LIR operand} is formatted to a string. | |
376 * The {@linkplain OperandFormatter#DEFAULT default formatter} returns the value of | |
377 * {@link CiValue#toString()}. | |
378 */ | |
379 public static class OperandFormatter { | |
380 public static final OperandFormatter DEFAULT = new OperandFormatter(); | |
381 | |
382 /** | |
383 * Formats a given operand as a string. | |
384 * | |
385 * @param operand the operand to format | |
386 * @return {@code operand} as a string | |
387 */ | |
388 public String format(CiValue operand) { | |
389 return operand.toString(); | |
390 } | |
391 } | |
392 | |
393 /** | |
394 * Gets the operation performed by this instruction in terms of its operands as a string. | |
395 */ | |
396 public String operationString(OperandFormatter operandFmt) { | |
397 StringBuilder buf = new StringBuilder(); | |
398 if (result != ILLEGAL_SLOT) { | |
399 buf.append(operandFmt.format(result.value(this))).append(" = "); | |
400 } | |
401 if (operands.length > 1) { | |
402 buf.append("("); | |
403 } | |
404 boolean first = true; | |
405 for (LIROperand operandSlot : operands) { | |
406 String operand = operandFmt.format(operandSlot.value(this)); | |
407 if (!operand.isEmpty()) { | |
408 if (!first) { | |
409 buf.append(", "); | |
410 } else { | |
411 first = false; | |
412 } | |
413 buf.append(operand); | |
414 } | |
415 } | |
416 if (operands.length > 1) { | |
417 buf.append(")"); | |
418 } | |
419 return buf.toString(); | |
420 } | |
421 | |
422 public boolean verify() { | |
423 return true; | |
424 } | |
425 | |
426 /** | |
427 * Determines if a given opcode is in a given range of valid opcodes. | |
428 * | |
429 * @param opcode the opcode to be tested. | |
430 * @param start the lower bound range limit of valid opcodes | |
431 * @param end the upper bound range limit of valid opcodes | |
432 */ | |
433 protected static boolean isInRange(LIROpcode opcode, LIROpcode start, LIROpcode end) { | |
434 return start.ordinal() < opcode.ordinal() && opcode.ordinal() < end.ordinal(); | |
435 } | |
436 | |
437 public boolean hasOperands() { | |
438 if (info != null || hasCall) { | |
439 return true; | |
440 } | |
441 return allocatorOperands.size() > 0; | |
442 } | |
443 | |
444 public final int operandCount(OperandMode mode) { | |
445 if (mode == OperandMode.Output) { | |
446 return allocatorOutputCount; | |
447 } else if (mode == OperandMode.Input) { | |
448 return allocatorInputCount + allocatorTempInputCount; | |
449 } else { | |
450 assert mode == OperandMode.Temp; | |
451 return allocatorTempInputCount + allocatorTempCount; | |
452 } | |
453 } | |
454 | |
455 public final CiValue operandAt(OperandMode mode, int index) { | |
456 if (mode == OperandMode.Output) { | |
457 assert index < allocatorOutputCount; | |
458 return allocatorOperands.get(index); | |
459 } else if (mode == OperandMode.Input) { | |
460 assert index < allocatorInputCount + allocatorTempInputCount; | |
461 return allocatorOperands.get(index + allocatorOutputCount); | |
462 } else { | |
463 assert mode == OperandMode.Temp; | |
464 assert index < allocatorTempInputCount + allocatorTempCount; | |
465 return allocatorOperands.get(index + allocatorOutputCount + allocatorInputCount); | |
466 } | |
467 } | |
468 | |
469 public final void setOperandAt(OperandMode mode, int index, CiValue location) { | |
470 assert index < operandCount(mode); | |
471 assert location.kind != CiKind.Illegal; | |
472 assert operandAt(mode, index).isVariable(); | |
473 if (mode == OperandMode.Output) { | |
474 assert index < allocatorOutputCount; | |
475 allocatorOperands.set(index, location); | |
476 } else if (mode == OperandMode.Input) { | |
477 assert index < allocatorInputCount + allocatorTempInputCount; | |
478 allocatorOperands.set(index + allocatorOutputCount, location); | |
479 } else { | |
480 assert mode == OperandMode.Temp; | |
481 assert index < allocatorTempInputCount + allocatorTempCount; | |
482 allocatorOperands.set(index + allocatorOutputCount + allocatorInputCount, location); | |
483 } | |
484 } | |
485 | |
486 public final List<ExceptionHandler> exceptionEdges() { | |
487 if (info != null && info.exceptionHandlers != null) { | |
488 return info.exceptionHandlers; | |
489 } | |
490 | |
491 return Collections.emptyList(); | |
492 } | |
493 | |
494 @Override | |
495 public String toString() { | |
496 return toString(OperandFormatter.DEFAULT); | |
497 } | |
498 | |
499 public final String toStringWithIdPrefix() { | |
500 if (id != -1) { | |
501 return String.format("%4d %s", id, toString()); | |
502 } | |
503 return " " + toString(); | |
504 } | |
505 | |
506 protected static String refMapToString(CiDebugInfo debugInfo, OperandFormatter operandFmt) { | |
507 StringBuilder buf = new StringBuilder(); | |
508 if (debugInfo.hasStackRefMap()) { | |
509 CiBitMap bm = debugInfo.frameRefMap; | |
510 for (int slot = bm.nextSetBit(0); slot >= 0; slot = bm.nextSetBit(slot + 1)) { | |
511 if (buf.length() != 0) { | |
512 buf.append(", "); | |
513 } | |
514 buf.append(operandFmt.format(CiStackSlot.get(CiKind.Object, slot))); | |
515 } | |
516 } | |
517 if (debugInfo.hasRegisterRefMap()) { | |
518 CiBitMap bm = debugInfo.registerRefMap; | |
519 for (int reg = bm.nextSetBit(0); reg >= 0; reg = bm.nextSetBit(reg + 1)) { | |
520 if (buf.length() != 0) { | |
521 buf.append(", "); | |
522 } | |
523 CiRegisterValue register = compilation().target.arch.registers[reg].asValue(CiKind.Object); | |
524 buf.append(operandFmt.format(register)); | |
525 } | |
526 } | |
527 return buf.toString(); | |
528 } | |
529 | |
530 protected void appendDebugInfo(StringBuilder buf, OperandFormatter operandFmt, LIRDebugInfo info) { | |
531 if (info != null) { | |
532 buf.append(" [bci:").append(info.state.bci); | |
533 if (info.hasDebugInfo()) { | |
534 CiDebugInfo debugInfo = info.debugInfo(); | |
535 String refmap = refMapToString(debugInfo, operandFmt); | |
536 if (refmap.length() != 0) { | |
537 buf.append(", refmap(").append(refmap.trim()).append(')'); | |
538 } | |
539 } | |
540 buf.append(']'); | |
541 } | |
542 } | |
543 | |
544 public String toString(OperandFormatter operandFmt) { | |
545 StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString(operandFmt)); | |
546 appendDebugInfo(buf, operandFmt, info); | |
547 return buf.toString(); | |
548 } | |
549 } |