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 }