/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
/* NOTE: this is a mechanically generated file, see class JavaDoc
for details */
package org.jikesrvm.compilers.opt.ir;
import org.jikesrvm.VM;
/**
* An Operator represents the operator of an {@link Instruction}.
* For each operator in the IR, we create exactly one Operator instance
* to represent it. These instances are all stored in static fields
* of {@link Operators}. Since only one instance is created for each
* semantic operator, they can be compared using <code>==</code>.
*
* @see Operators
* @see Instruction
*/
public abstract class Operator {
/*
* The following are used to encode operator traits in OperatorList.dat.
* Had to make a few of them public (yuck) to let us get at them
* from InstructionFormat.java.
*/
/** operator has no interesting traits */
public static final int none = 0x00000000;
/** operator is a simple move operation from one "register" to another */
protected static final int move = 0x00000001;
/** operator is an intraprocedural branch of some form */
protected static final int branch = 0x00000002;
/** operator is some kind of call (interprocedural branch) */
protected static final int call = 0x00000004;
/** modifer for branches/calls */
protected static final int conditional = 0x00000008;
/** modifier for branches/calls, mostly on MIR */
protected static final int indirect = 0x00000010;
/** an explicit load of a value from memory */
protected static final int load = 0x00000020;
/** operator is modeled as a load by memory system, mostly on MIR */
protected static final int memAsLoad = 0x00000040;
/** an explicit store of a value to memory */
protected static final int store = 0x00000080;
/** operator is modeled as a store by memory system, mostly on MIR */
protected static final int memAsStore = 0x00000100;
/** is an exception throw */
protected static final int ethrow = 0x00000200;
/** an immediate PEI (null_check, int_zero_check, but _not_ call); */
protected static final int immedPEI = 0x00000400;
/** operator is some kind of compare (val,val)-> cond */
protected static final int compare = 0x00000800;
/** an explicit memory allocation */
protected static final int alloc = 0x00001000;
/** a return instruction (interprocedural branch) */
protected static final int ret = 0x00002000;
/** operator has a variable number of uses */
public static final int varUses = 0x00004000;
/** operator has a variable number of defs */
public static final int varDefs = 0x00008000;
/**
* operator is a potential thread switch point for some reason
* other than being a call/immedPEI
*/
protected static final int tsp = 0x00010000;
/** operator is an acquire (monitorenter/lock) HIR only */
protected static final int acquire = 0x00020000;
/** operator is a relase (monitorexit/unlock) HIR only */
protected static final int release = 0x00040000;
/** operator either directly or indirectly may casue dynamic linking */
protected static final int dynLink = 0x00080000;
/** operator is a yield point */
protected static final int yieldPoint = 0x00100000;
/** operator pops floating-point stack after performing defs */
protected static final int fpPop = 0x00200000;
/** operator pushs floating-point stack before performing defs */
protected static final int fpPush = 0x00400000;
/** operator is commutative */
protected static final int commutative = 0x00800000;
/**
* The operators opcode.
* This value serves as a unique id suitable for use in switches
*/
final char opcode;
/**
* Encoding of the operator's InstructionFormat.
* This field is only meant to be directly referenced
* from the mechanically generated InstructionFormat
* classes defined in the instructionFormats package.
* {@link Instruction} contains an explanation
* of the role of InstructionFormats in the IR.
*/
public final byte format;
/**
* encoding of operator traits (characteristics)
*/
private final int traits;
/**
* How many operands of the operator are (pure) defs?
*/
private final int numberDefs;
/**
* How many operands of the operator are both defs and uses?
* Only non-zero on IA32, 390.
*/
private final int numberDefUses;
/**
* How many operands of the operator are pure uses?
* Only contains a valid value for non-variableLength operators
*/
private final int numberUses;
/**
* Physical registers that are implicitly defined by the operator.
*/
public final int implicitDefs;
/**
* Physical registers that are implicitly used by the operator.
*/
public final int implicitUses;
protected Operator(char opcode, byte format, int traits,
int numDefs, int numDefUses, int numUses,
int iDefs, int iUses) {
this.opcode = opcode;
this.format = format;
this.traits = traits;
this.numberDefs = numDefs;
this.numberDefUses = numDefUses;
this.numberUses = numUses;
this.implicitDefs = iDefs;
this.implicitUses = iUses;
}
public static Operator lookupOpcode(int opcode) {
if (VM.BuildForIA32) {
return org.jikesrvm.compilers.opt.ir.ia32.ArchOperator.lookupOpcode(opcode);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
return org.jikesrvm.compilers.opt.ir.ppc.ArchOperator.lookupOpcode(opcode);
}
}
public final char getOpcode() {
return opcode;
}
/**
* Returns the string representation of this operator.
*
* @return the name of the operator
*/
@Override
public String toString() {
if (VM.BuildForIA32) {
return org.jikesrvm.compilers.opt.ir.ia32.ArchOperatorNames.toString(this);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
return org.jikesrvm.compilers.opt.ir.ppc.ArchOperatorNames.toString(this);
}
}
/**
* Returns the number of operands that are defs.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return number of operands that are pure defs
*/
public int getNumberOfPureDefs() {
if (VM.VerifyAssertions) VM._assert(!hasVarDefs());
return numberDefs;
}
/**
* Returns the number of operands that are pure defs
* and are not in the variable-length part of the operand list.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return how many non-variable operands are pure defs
*/
public int getNumberOfFixedPureDefs() {
return numberDefs;
}
/**
* Returns the number of operands that are pure uses
* and are not in the variable-length part of the operand list.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return how many non-variable operands are pure uses
*/
public int getNumberOfFixedPureUses() {
return numberUses;
}
/**
* Returns the number of operands that are defs
* and uses.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return number of operands that are combined defs and uses
*/
public int getNumberOfDefUses() {
return numberDefUses;
}
/**
* Returns the number of operands that are pure uses.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return number of operands that are pure uses
*/
public int getNumberOfPureUses() {
return numberUses;
}
/**
* Returns the number of operands that are defs
* (either pure defs or combined def/uses).
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return number of operands that are defs
*/
public int getNumberOfDefs() {
if (VM.VerifyAssertions) VM._assert(!hasVarDefs());
return numberDefs + numberDefUses;
}
/**
* Returns the number of operands that are uses
* (either combined def/uses or pure uses).
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return how many operands are uses
*/
public int getNumberOfUses() {
if (VM.VerifyAssertions) VM._assert(!hasVarUses());
return numberDefUses + numberUses;
}
/**
* Returns the number of operands that are pure uses
* and are not in the variable-length part of the operand list.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return how many non-variable operands are pure uses
*/
public int getNumberOfPureFixedUses() {
return numberUses;
}
/**
* Returns the number of operands that are uses
* (either combined use/defs or pure uses)
* and are not in the variable-length part of the operand list.
* By convention, operands are ordered in instructions
* such that all defs are first, followed by all
* combined defs/uses, followed by all pure uses.
*
* @return number of non-variable operands are uses
*/
public int getNumberOfFixedUses() {
return numberDefUses + numberUses;
}
/**
* Returns the number of physical registers that are
* implicitly defined by this operator.
*
* @return number of implicit defs
*/
public int getNumberOfImplicitDefs() {
return Integer.bitCount(implicitDefs);
}
/**
* Returns the number of physical registers that are
* implicitly used by this operator.
*
* @return number of implicit uses
*/
public int getNumberOfImplicitUses() {
return Integer.bitCount(implicitUses);
}
/**
* Does the operator represent a simple move (the value is unchanged)
* from one "register" location to another "register" location?
*
* @return <code>true</code> if the operator is a simple move
* or <code>false</code> if it is not.
*/
public boolean isMove() {
return (traits & move) != 0;
}
/**
* Is the operator an intraprocedural branch?
*
* @return <code>true</code> if the operator is am
* intraprocedural branch or <code>false</code> if it is not.
*/
public boolean isBranch() {
return (traits & branch) != 0;
}
/**
* Is the operator a conditional intraprocedural branch?
*
* @return <code>true</code> if the operator is a conditoonal
* intraprocedural branch or <code>false</code> if it is not.
*/
public boolean isConditionalBranch() {
return (traits & (branch | conditional)) == (branch | conditional);
}
/**
* Is the operator an unconditional intraprocedural branch?
* We consider various forms of switches to be unconditional
* intraprocedural branches, even though they are multi-way branches
* and we may not no exactly which target will be taken.
* This turns out to be the right thing to do, since some
* arm of the switch will always be taken (unlike conditional branches).
*
* @return <code>true</code> if the operator is an unconditional
* intraprocedural branch or <code>false</code> if it is not.
*/
public boolean isUnconditionalBranch() {
return (traits & (branch | conditional)) == branch;
}
/**
* Is the operator a direct intraprocedural branch?
* In the HIR and LIR we consider switches to be direct branches,
* because their targets are known precisely.
*
* @return <code>true</code> if the operator is a direct
* intraprocedural branch or <code>false</code> if it is not.
*/
public boolean isDirectBranch() {
return (traits & (branch | indirect)) == branch;
}
/**
* Is the operator an indirect intraprocedural branch?
*
* @return <code>true</code> if the operator is an indirect
* interprocedural branch or <code>false</code> if it is not.
*/
public boolean isIndirectBranch() {
return (traits & (branch | indirect)) == (branch | indirect);
}
/**
* Is the operator a call (one kind of interprocedural branch)?
*
* @return <code>true</code> if the operator is a call
* or <code>false</code> if it is not.
*/
public boolean isCall() {
return (traits & call) != 0;
}
/**
* Is the operator a conditional call?
* We only allow conditional calls in the MIR, since they
* tend to only be directly implementable on some architecutres.
*
* @return <code>true</code> if the operator is a
* conditional call or <code>false</code> if it is not.
*/
public boolean isConditionalCall() {
return (traits & (call | conditional)) == (call | conditional);
}
/**
* Is the operator an unconditional call?
* Really only an interesting question in the MIR, since
* it is by definition true for all HIR and LIR calls.
*
* @return <code>true</code> if the operator is an unconditional
* call or <code>false</code> if it is not.
*/
public boolean isUnconditionalCall() {
return (traits & (call | conditional)) == call;
}
/**
* Is the operator a direct call?
* Only interesting on the MIR. In the HIR and LIR we pretend that
* all calls are "direct" even though most of them aren't.
*
* @return <code>true</code> if the operator is a direct call
* or <code>false</code> if it is not.
*/
public boolean isDirectCall() {
return (traits & (call | indirect)) == call;
}
/**
* Is the operator an indirect call?
* Only interesting on the MIR. In the HIR and LIR we pretend that
* all calls are "direct" even though most of them aren't.
*
* @return <code>true</code> if the operator is an indirect call
* or <code>false</code> if it is not.
*/
public boolean isIndirectCall() {
return (traits & (call | indirect)) == (call | indirect);
}
/**
* Is the operator an explicit load of a finite set of values from
* a finite set of memory locations (load, load multiple, _not_ call)?
*
* @return <code>true</code> if the operator is an explicit load
* or <code>false</code> if it is not.
*/
public boolean isExplicitLoad() {
return (traits & load) != 0;
}
/**
* Should the operator be treated as a load from some unknown location(s)
* for the purposes of scheduling and/or modeling the memory subsystem?
*
* @return <code>true</code> if the operator is an implicit load
* or <code>false</code> if it is not.
*/
public boolean isImplicitLoad() {
return (traits & (load | memAsLoad | call)) != 0;
}
/**
* Is the operator an explicit store of a finite set of values to
* a finite set of memory locations (store, store multiple, _not_ call)?
*
* @return <code>true</code> if the operator is an explicit store
* or <code>false</code> if it is not.
*/
public boolean isExplicitStore() {
return (traits & store) != 0;
}
/**
* Should the operator be treated as a store to some unknown location(s)
* for the purposes of scheduling and/or modeling the memory subsystem?
*
* @return <code>true</code> if the operator is an implicit store
* or <code>false</code> if it is not.
*/
public boolean isImplicitStore() {
return (traits & (store | memAsStore | call)) != 0;
}
/**
* Is the operator a throw of a Java exception?
*
* @return <code>true</code> if the operator is a throw
* or <code>false</code> if it is not.
*/
public boolean isThrow() {
return (traits & ethrow) != 0;
}
/**
* Is the operator a PEI (Potentially Excepting Instruction)?
*
* @return <code>true</code> if the operator is a PEI
* or <code>false</code> if it is not.
*/
public boolean isPEI() {
return (traits & (ethrow | immedPEI)) != 0;
}
/**
* Is the operator a potential GC point?
*
* @return <code>true</code> if the operator is a potential
* GC point or <code>false</code> if it is not.
*/
public boolean isGCPoint() {
return isPEI() || ((traits & (alloc | tsp)) != 0);
}
/**
* is the operator a potential thread switch point?
*
* @return <code>true</code> if the operator is a potential
* threadswitch point or <code>false</code> if it is not.
*/
public boolean isTSPoint() {
return isGCPoint();
}
/**
* Is the operator a compare (val,val) => condition?
*
* @return <code>true</code> if the operator is a compare
* or <code>false</code> if it is not.
*/
public boolean isCompare() {
return (traits & compare) != 0;
}
/**
* Is the operator an actual memory allocation instruction
* (NEW, NEWARRAY, etc)?
*
* @return <code>true</code> if the operator is an allocation
* or <code>false</code> if it is not.
*/
public boolean isAllocation() {
return (traits & alloc) != 0;
}
/**
* Is the operator a return (interprocedural branch)?
*
* @return <code>true</code> if the operator is a return
* or <code>false</code> if it is not.
*/
public boolean isReturn() {
return (traits & ret) != 0;
}
/**
* Can the operator have a variable number of uses?
*
* @return <code>true</code> if the operator has a variable number
* of uses or <code>false</code> if it does not.
*/
public boolean hasVarUses() {
return (traits & varUses) != 0;
}
/**
* Can the operator have a variable number of uses?
*
* @return <code>true</code> if the operator has a variable number
* of uses or <code>false</code> if it does not.
*/
public boolean hasVarDefs() {
return (traits & varDefs) != 0;
}
/**
* Can the operator have a variable number of uses or defs?
*
* @return <code>true</code> if the operator has a variable number
* of uses or defs or <code>false</code> if it does not.
*/
public boolean hasVarUsesOrDefs() {
return (traits & (varUses | varDefs)) != 0;
}
/**
* Is the operator an acquire (monitorenter/lock)?
*
* @return <code>true</code> if the operator is an acquire
* or <code>false</code> if it is not.
*/
public boolean isAcquire() {
return (traits & acquire) != 0;
}
/**
* Is the operator a release (monitorexit/unlock)?
*
* @return <code>true</code> if the operator is a release
* or <code>false</code> if it is not.
*/
public boolean isRelease() {
return (traits & release) != 0;
}
/**
* Could the operator either directly or indirectly
* cause dynamic class loading?
*
* @return <code>true</code> if the operator is a dynamic linking point
* or <code>false</code> if it is not.
*/
public boolean isDynamicLinkingPoint() {
return (traits & dynLink) != 0;
}
/**
* Is the operator a yield point?
*
* @return <code>true</code> if the operator is a yield point
* or <code>false</code> if it is not.
*/
public boolean isYieldPoint() {
return (traits & yieldPoint) != 0;
}
/**
* Does the operator pop the floating-point stack?
*
* @return <code>true</code> if the operator pops the floating-point
* stack.
* or <code>false</code> if not.
*/
public boolean isFpPop() {
return (traits & fpPop) != 0;
}
/**
* Does the operator push on the floating-point stack?
*
* @return <code>true</code> if the operator pushes on the floating-point
* stack.
* or <code>false</code> if not.
*/
public boolean isFpPush() {
return (traits & fpPush) != 0;
}
/**
* Is the operator commutative?
*
* @return <code>true</code> if the operator is commutative.
* or <code>false</code> if not.
*/
public boolean isCommutative() {
return (traits & commutative) != 0;
}
/**
* @return whether this is a operator a call to a routine that will save volatile
* registers
*/
public boolean isCallSaveVolatile() {
if (VM.BuildForIA32) {
return this == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.CALL_SAVE_VOLATILE;
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
return this == org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.CALL_SAVE_VOLATILE;
}
}
/** @return is this the IA32 ADVISE_ESP operator? */
public boolean isAdviseESP() {
return VM.BuildForIA32 &&
this == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.ADVISE_ESP;
}
/** @return is this the IA32 FNINIT operator? */
public boolean isFNInit() {
return VM.BuildForIA32 &&
this == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FNINIT;
}
/** @return is this the IA32 FCLEAR operator? */
public boolean isFClear() {
return VM.BuildForIA32 &&
this == org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.IA32_FCLEAR;
}
/**
* @return Instruction template used by the assembler to
* generate binary code. Only valid on MIR operators.
*/
public abstract int instTemplate();
}