blob: feff6948835129e47eb4395e92f964d6ea2e3db2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Pavel A. Ozhdikhin
*
*/
#ifndef _OPCODE_H_
#define _OPCODE_H_
#include "Type.h"
namespace Jitrino {
//
// Runtime exceptions that can be thrown by instructions.
//
enum OpcodeExceptions {
OverflowException, // for signed/unsigned arithmetic instruction
DivideByZeroException, // for divide and remainder instructions
NullPointerException, // any field, element or method access
OutOfMemoryException, // object allocation
StackOverflowException, // for local memory allocation (localloc)
CastException, // for dynamic type casting (Op_TauCast)
BoundsException, // array index out of bounds
ArrayStoreTypeException, // stored object type incompatible with array element type
NegativeArraySizeException, // (Java only)
};
//
// ** An instruction's opcode, modifiers, and type are encoded in a single 32-bit
// word as an Operation value; see definition of Operation below.
//
//
// The OverflowModifier is used for the Op_Add, Op_Mul, Op_Sub, and Op_Conv opcodes.
// This modifier indicates whether the instruction will throw an arithmetic overflow
// exception.
// bits 0-1
//
enum OverflowModifier {
Overflow_None = 0x1 << 0, // (signed arith)
Overflow_Signed = 0x2 << 0, // .ovf
Overflow_Unsigned = 0x3 << 0, // .ovf.un
Overflow_Mask = 0x3 << 0,
OverflowModifier_IsShiftedBy = 0,
OverflowModifier_BitsToEncode = 2,
OverflowModifier_BitsConsumed = 2
};
inline bool isOverflowModifierSigned(enum OverflowModifier mod)
{
assert((Overflow_None <= mod) && (mod <= Overflow_Unsigned));
return (mod != Overflow_Unsigned);
}
//
// The SignedModifier is used for the Op_TauDiv, Op_TauRem, Op_MulHi, and Op_Shr opcodes.
// bit 2-3
//
enum SignedModifier {
SignedOp = 0x1 << 2,
UnsignedOp = 0x2 << 2, // .un
Signed_Mask = 0x3 << 2,
SignedModifier_IsShiftedBy = 2, // = OverflowModifier_IsShiftedBy + OverflowModifier_BitsConsumed
SignedModifier_BitsToEncode = 1,
SignedModifier_BitsConsumed = 2
};
inline bool isSignedModifierSigned(enum SignedModifier mod)
{
assert((SignedOp <= mod) && (mod <= UnsignedOp));
return (mod != UnsignedOp);
}
//
// The ComparisonModifier is used by the OP_Cmp and Op_Branch opcodes.
// For less than and less than or equal comparisons, commute the operands and use
// the Cmp_GT, and Cmp_GTE modifiers.
// bits 4-7
//
// Suffix _Un means:
// - if integers, main function, but treat operands as unsigned integers
// - if floating point, main function or unordered
//
enum ComparisonModifier {
Cmp_EQ = 0x1 << 4,
Cmp_NE_Un = 0x2 << 4, // .un: unsigned or unordered comparison (true if either parameter is NaN)
Cmp_GT = 0x3 << 4,
Cmp_GT_Un = 0x4 << 4, // .un: unsigned or unordered comparison (true if either parameter is NaN)
Cmp_GTE = 0x5 << 4,
Cmp_GTE_Un = 0x6 << 4, // .un: unsigned or unordered comparison (true if either parameter is NaN)
// unary boolean comparisons
Cmp_Zero = 0x7 << 4, // also cmp_null
Cmp_NonZero = 0x8 << 4, // also cmp_nonull
Cmp_Mask = 0xf << 4,
ComparisonModifier_IsShiftedBy = 4, // = SignedModifier_IsShiftedBy + SignedModifier_BitsConsumed
ComparisonModifier_BitsToEncode = 3,
ComparisonModifier_BitsConsumed = 4
};
inline bool isComparisonModifierSigned(enum ComparisonModifier mod)
{
switch (mod) {
case Cmp_EQ: case Cmp_GT: case Cmp_GTE: return true;
case Cmp_NE_Un: case Cmp_GT_Un: case Cmp_GTE_Un: return false;
default:
break;
}
assert(((int)SignedOp <= (int)mod) && ((int)mod <= (int)UnsignedOp));
return ((int)mod != (int)UnsignedOp);
}
// There is a difference in semantics of variable shift instructions between CLI and Java.
// Java says that the shift amount is quantity & mask, where mask is 0x1f for 32 bit shifts,
// and 0x3f for 64 bit shifts. CLI says that this is implementation dependent. The following
// bits capture that notion:
enum ShiftMaskModifier {
ShiftMask_None = 0x1 << 8,
ShiftMask_Masked = 0x2 << 8,
ShiftMask_Mask = 0x3 << 8,
ShiftMaskModifier_IsShiftedBy = 8,//= ComparisonModifier_IsShiftedBy + ShiftMaskModifier_BitsConsumed
ShiftMaskModifier_BitsToEncode = 1,
ShiftMaskModifier_BitsConsumed = 2
};
// Java can specify strict mode for floating-point operations
//
enum StrictModifier {
Strict_No = 0x01 << 10,
Strict_Yes = 0x02 << 10,
Strict_Mask = 0x03 << 10,
StrictModifier_IsShiftedBy = 10, // = ShiftMaskModifier_IsShiftedBy + ..._BitsConsumed
StrictModifier_BitsToEncode = 1,
StrictModifier_BitsConsumed = 2
};
//
// Modifier for Op_DefArg
// NonNullThisArgFlag indicates that the argument is the this
// parameter and is non-null. Used for the Java this parameter (which
// can never be null) and for CLI when the method is specialized for
// the vtable.
//
// SpecializedToExactType indicates that the parameter's type is exactly
// the type of the instruction. This is used when a method is specialized
// for the vtable type.
//
// Note, that these are flags, so both or neither may be set.
//
// update:
// also a modifier for Op_TauCheckNull with different semantics:
// DefArgNoModifier <-- a common 'chknull' operation that can be eliminated
// by the 'hardware NPE' optimization
// NonNullThisArg <-- means that 'chknull' checks for 'this' operand
// (of an inlined method) and cannot be eliminated
// by the 'hardware NPE' optimization
// SpecializedToExactType <-- unused
//
enum DefArgModifier {
DefArgNoModifier = 0x1 << 12,
NonNullThisArg = 0x2 << 12,
SpecializedToExactType = 0x3 << 12,
DefArgBothModifiers = 0x4 << 12,
DefArg_Mask = 0x7 << 12,
DefArgModifier_IsShiftedBy = 12, // = StrictModifier_IsShiftedBy + ..._BitsConsumed
DefArgModifier_BitsToEncode = 2,
DefArgModifier_BitsConsumed = 3
};
enum StoreModifier {
Store_NoWriteBarrier = 0x1 << 15,
Store_WriteBarrier = 0x2 << 15,
Store_Mask = 0x3 << 15,
StoreModifier_IsShiftedBy = 15, // = DefArgModifier_IsShiftedBy + ..._BitsConsumed
StoreModifier_BitsToEncode = 1,
StoreModifier_BitsConsumed = 2
};
enum ExceptionModifier {
Exception_Sometimes = 0x1 << 17, // the default
Exception_Always = 0x2 << 17,
Exception_Never = 0x3 << 17,
Exception_Mask = 0x3 << 17,
ExceptionModifier_IsShiftedBy = 17, // = StoreModifier_IsShiftedBy + ..._BitsConsumed
ExceptionModifier_BitsToEncode = 2,
ExceptionModifier_BitsConsumed = 2
};
enum SrcNonNullModifier {
SrcNonNull_No = 0x1 << 19, // the default
SrcNonNull_Yes = 0x2 << 19,
SrcNonNull_Mask = 0x3 << 19,
SrcNonNullModifier_IsShiftedBy = 19, // = ExceptionModifier_IsShiftedBy + ..._BitsConsumed
SrcNonNullModifier_BitsToEncode = 1,
SrcNonNullModifier_BitsConsumed = 2
};
enum AutoCompressModifier {
AutoCompress_Yes = 0x1 << 21, // the default
AutoCompress_No = 0x2 << 21,
AutoCompress_Mask = 0x3 << 21,
AutoCompressModifier_IsShiftedBy = 21, // = SrcNonNullModifier_IsShiftedBy + ..._BitsConsumed
AutoCompressModifier_BitsToEncode = 1,
AutoCompressModifier_BitsConsumed = 2
};
// If we are marking an instruction (load) as speculative, then the
// back-end should produce either an speculative instruction (IPF's ld.s)
// or enclose it in a 'catchall' region where exceptions are ignored.
//
enum SpeculativeModifier {
Speculative_Yes = 0x1 << 23,
Speculative_No = 0x2 << 23,
Speculative_Mask = 0x3 << 23,
SpeculativeModifier_IsShiftedBy = 23, // = AutoCompressModifier_IsShiftedBy + ..._BitsConsumed
SpeculativeModifier_BitsToEncode = 1,
SpeculativeModifier_BitsConsumed = 2
};
enum ThrowModifier {
Throw_NoModifier = 0x1 << 25,
Throw_CreateStackTrace = 0x2 << 25,
Throw_Mask = 0x3 << 25,
ThrowModifier_IsShiftedBy = 25, // = SpeculativeModifier_IsShiftedBy + ..._BitsConsumed
ThrowModifier_BitsToEncode = 1,
ThrowModifier_BitsConsumed = 2
};
enum NewModifier1 {
NewModifier1_Value1 = 0x1 << 27,
NewModifier1_Value2 = 0x2 << 27,
NewModifier1_Mask = 0x3 << 27,
NewModifier1_IsShiftedBy = 27, // = ThrowModifier_IsShiftedBy + ..._BitsConsumed
NewModifier1_BitsToEncode = 1,
NewModifier1_BitsConsumed = 2
};
enum NewModifier2 {
NewModifier2_Value1 = 0x1 << 29,
NewModifier2_Value2 = 0x2 << 29,
NewModifier2_Value3 = 0x3 << 29,
NewModifier2_Mask = 0x3 << 29,
NewModifier2_IsShiftedBy = 29, // = NewModifier1_IsShiftedBy + ..._BitsConsumed
NewModifier2_BitsToEncode = 2,
NewModifier2_BitsConsumed = 2
};
enum JitHelperCallId {
Prefetch,
Memset0,
InitializeArray,
FillArrayWithConst,
SaveThisState, //todo: replace with GetTLS + offset sequence
ReadThisState, //todo: replace with GetTLS + offset sequence
LockedCompareAndExchange,
AddValueProfileValue,
ArrayCopyDirect,
ArrayCopyReverse,
StringCompareTo,
StringRegionMatches,
StringIndexOf,
ClassIsArray,
ClassGetAllocationHandle,
ClassGetTypeSize,
ClassGetArrayElemSize,
ClassIsInterface,
ClassIsFinal,
ClassGetArrayClass,
ClassIsFinalizable,
ClassGetFastCheckDepth
};
enum Opcode {
// Arithmetic
Op_Add, Op_Mul, Op_Sub, // OverflowModifier, ExceptionModifier
Op_TauDiv, Op_TauRem, // SignedModifier, (opnds must already be checked for 0/overflow)
Op_Neg,
Op_MulHi, // SignedModifier (but only signed needed now)
Op_Min, Op_Max, Op_Abs, // no modifiers
// Bitwise
Op_And, Op_Or, Op_Xor,
Op_Not,
// Selection
Op_Select, // (src1 ? src2 : src3)
// Conversion
Op_Conv, // OverflowModifier, ExceptionModifier
Op_ConvZE, // OverflowModifier, ExceptionModifier
Op_ConvUnmanaged, // OverflowModifier, ExceptionModifier
// Shift
Op_Shladd, // no mods, 2nd operand must be LdConstant
Op_Shl, // ShiftMaskModifier
Op_Shr, // ShiftMaskModifier, SignedModifier
// Comparison
Op_Cmp, // ComparisonModifier
Op_Cmp3, // 3-way compare, e.g.: ((s0>s1)?1:((s1>s0)?-1:0))
// for floats, exactly 1 of the two comparisons is unordered; the modifier in
// the instruction applies to the first test
// Control flow
Op_Branch, // ComparisonModifier
Op_Jump, // (different from the CLI jmp opcode)
Op_Switch,
Op_DirectCall,
Op_TauVirtualCall,
Op_IndirectCall,
Op_IndirectMemoryCall,
Op_JitHelperCall, // call to a jit helper routine
Op_VMHelperCall, // call to a vm (runtime) helper routine
Op_Return,
// Exception processing
Op_Catch,
Op_Throw,
Op_PseudoThrow, // pseudo instruction to break infinte loops
Op_ThrowSystemException, // takes a CompilationInterface::SystemExceptionId parameter
Op_ThrowLinkingException, // generate a call to Helper_Throw_LinkingException
Op_JSR,
Op_Ret,
Op_SaveRet,
// Move instruction
Op_Copy,
Op_DefArg, // DefArgModifier
// Load instructions
Op_LdConstant,
Op_LdRef, // String or reference
Op_LdVar,
Op_LdVarAddr,
Op_TauLdInd,
Op_TauLdField,
Op_LdStatic,
Op_TauLdElem,
Op_LdFieldAddr, // lower to ldoffset+addoffset
Op_LdStaticAddr,
Op_LdElemAddr,
Op_TauLdVTableAddr,
Op_TauLdIntfcVTableAddr,
Op_TauLdVirtFunAddr,
Op_TauLdVirtFunAddrSlot,
Op_LdFunAddr,
Op_LdFunAddrSlot,
// Move these to the loads
Op_GetVTableAddr, // obtains the address of the vtable for a particular object type
Op_GetClassObj,
// array manipulation
Op_TauArrayLen,
Op_LdArrayBaseAddr, // load the base (zero'th element) address of array
Op_AddScaledIndex, // Add a scaled index to an array element address
// Store instructions
Op_StVar,
Op_TauStInd, // StoreModifier
Op_TauStField, // StoreModifier
Op_TauStElem, // StoreModifier
Op_TauStStatic,
Op_TauStRef, // high-level version that will make a call to the VM
// Runtime exception check instructions
// all of these take ExceptionModifier
Op_TauCheckBounds, // takes index and array length arguments, ovf mod==none indicates 0<=idx*eltsize<2^31
Op_TauCheckLowerBound, // throws unless src0 <= src1
Op_TauCheckUpperBound, // throws unless src0 < src1
Op_TauCheckNull, // throws NullPointerException if source is null
Op_TauCheckZero, // for divide by zero exceptions (div and rem)
Op_TauCheckDivOpnds, // for signed divide overflow in CLI (div/rem of MAXNEGINT, -1): generates an ArithmeticException
Op_TauCheckElemType, // Array element type check for aastore
Op_TauCheckFinite, // throws ArithmeticException if value is NaN or +- inifinity
// Allocation
Op_NewObj, // OutOfMemoryException
Op_NewArray, // OutOfMemoryException, NegativeArraySizeException
Op_NewMultiArray, // OutOfMemoryException, NegativeArraySizeException
// Synchronization
Op_TauMonitorEnter, // (opnd must be non-null)
// this could take an ExceptionModifier
Op_TauMonitorExit, // (opnd must be non-null), IllegalMonitorStateException
Op_TypeMonitorEnter,
Op_TypeMonitorExit,
// Lowered parts of MonitorEnter/Exit
Op_LdLockAddr, // yields ref:int16
Op_IncRecCount, // allows BalancedMonitorEnter to be used with regular MonitorExit
Op_TauBalancedMonitorEnter, // (opnd must be non-null), post-dominated by BalancedMonitorExit
Op_BalancedMonitorExit, // (cannot yield exception), dominated by BalancedMonitorEnter
Op_TauOptimisticBalancedMonitorEnter, // (opnd must be non-null), post-dominated by BalancedMonitorExit
Op_OptimisticBalancedMonitorExit, // (may yield exception), dominated by BalancedMonitorEnter
Op_MonitorEnterFence, // (opnd must be non-null)
Op_MonitorExitFence, // (opnd must be non-null)
// type checking
// cast takes an ExceptionModifier
Op_TauStaticCast, // Compile-time assertion. Asserts that cast is legal.
Op_TauCast, // CastException (succeeds if argument is null, returns casted object)
Op_TauAsType, // returns casted object if argument is an instance of, null otherwise
Op_TauInstanceOf, // returns true if argument is a non-null instance of type T
// type initialization
Op_InitType, // initialize type before static method invocation
// or field access.
// Labels & markers
Op_Label, // special label instructions for branch labels, finally, catch
Op_MethodEntry, // method entry label
Op_MethodEnd, // end of a method
// Special SSA nodes
Op_Phi, // merge point
Op_TauPi, // leverage split based on condition
// Profile instrumentation instructions
Op_IncCounter, // Increment a profile counter by 1
Op_Prefetch,
// Compressed Pointer instructions
Op_UncompressRef, // uncmpref = (cmpref<<s) + heapbase
Op_CompressRef, // cmpref = uncmpref - heapbase
Op_LdFieldOffset, // just offset
Op_LdFieldOffsetPlusHeapbase, // offset + heapbase
Op_LdArrayBaseOffset, // offset of array base
Op_LdArrayBaseOffsetPlusHeapbase, // offset of array base
Op_LdArrayLenOffset, // offset of array length field
Op_LdArrayLenOffsetPlusHeapbase, // offset of array length field
Op_AddOffset, // add uncompref+offset
Op_AddOffsetPlusHeapbase, // add compref+offsetPlusHeapbase (uncompressing)
// ADDED FOR TAU:
Op_TauPoint,
Op_TauEdge,
Op_TauAnd,
Op_TauUnsafe,
Op_TauSafe,
Op_TauCheckCast,
Op_TauHasType,
Op_TauHasExactType,
Op_TauIsNonNull,
// prefixes: unaligned, volatile, tail,
Op_IdentHC,
NumOpcodes,
};
class Modifier {
U_32 value;
public:
struct Kind {
enum Enum {
// these values must be disjoint bits:
None = 0,
Overflow = 1,
Signed = 2,
Comparison = 4,
ShiftMask = 8,
Strict = 16,
DefArg = 32,
SrcNonNull = 64,
Store = 128,
Exception = 256,
AutoCompress = 512,
Speculative = 1024,
Throw = 2048,
NewModifier1 = 4096,
NewModifier2 = 8192,
// these are combinations for convenient use in Opcode.cpp:
Signed_and_Strict = (2 | 16),
Overflow_and_Exception = (1 | 256),
Overflow_and_Exception_and_Strict = (1 | 256 | 16),
ShiftMask_and_Signed = (8 | 2),
SrcNonNull_and_Exception = (64 | 256),
Store_AutoCompress = (Store | AutoCompress),
AutoCompress_Speculative = (AutoCompress | Speculative),
Exception_and_DefArg = (Exception | DefArg)
};
};
Modifier() : value(0) { };
Modifier(U_32 mask, U_32 value0) : value(value0) {
assert((mask & value) == value);
assert(value0 != 0);
};
Modifier(enum OverflowModifier mod) : value((U_32)mod) {
assert((Overflow_None <= value) && (value <= Overflow_Unsigned));
}
Modifier(enum SignedModifier mod) : value((U_32)mod) {
assert((SignedOp <= value) && (value <= UnsignedOp));
}
Modifier(enum ComparisonModifier mod) : value((U_32)mod) {
assert((Cmp_EQ <= value) && (value <= Cmp_NonZero));
}
Modifier(enum ShiftMaskModifier mod) : value((U_32)mod) {
assert((ShiftMask_None <= value) && (value <= ShiftMask_Masked));
}
Modifier(enum StrictModifier mod) : value((U_32)mod) {
assert((Strict_No <= value) && (value <= Strict_Yes));
}
Modifier(enum DefArgModifier mod) : value((U_32)mod) {
assert((DefArgNoModifier <= value) && (value <= DefArgBothModifiers));
}
Modifier(enum StoreModifier mod) : value((U_32)mod) {
assert((Store_NoWriteBarrier <= value) && (value <= Store_WriteBarrier));
}
Modifier(enum ExceptionModifier mod) : value((U_32)mod) {
assert((Exception_Sometimes <= value) && (value <= Exception_Never));
}
Modifier(enum SrcNonNullModifier mod) : value((U_32)mod) {
assert((SrcNonNull_No <= value) && (value <= SrcNonNull_Yes));
}
Modifier(enum AutoCompressModifier mod) : value((U_32)mod) {
assert((AutoCompress_Yes <= value) && (value <= AutoCompress_No));
}
Modifier(enum SpeculativeModifier mod) : value((U_32)mod) {
assert((Speculative_Yes <= value) && (value <= Speculative_No));
}
Modifier(enum ThrowModifier mod) : value((U_32)mod) {
assert((Throw_NoModifier <= value) && (value <= Throw_CreateStackTrace));
}
Modifier(enum NewModifier1 mod) : value((U_32)mod) {
assert((NewModifier1_Value1 <= value) && (value <= NewModifier1_Value2));
}
Modifier(enum NewModifier2 mod) : value((U_32)mod) {
assert((NewModifier2_Value1 <= value) && (value <= NewModifier2_Value3));
}
Modifier operator|(const Modifier &other) const {
assert((value & other.value) == 0);
U_32 newvalue = value | other.value;
return Modifier(newvalue, newvalue);
};
enum OverflowModifier getOverflowModifier() const {
assert(hasOverflowModifier());
return (enum OverflowModifier)(value & Overflow_Mask);
};
bool hasOverflowModifier() const { return ((value & Overflow_Mask) != 0); };
void setOverflowModifier(enum OverflowModifier newmod) {
assert(hasOverflowModifier());
assert((newmod & Overflow_Mask) == newmod);
U_32 newval = value & (~Overflow_Mask);
value = newval | newmod;
}
bool hasSignedModifier() const { return ((value & Signed_Mask) != 0); };
enum SignedModifier getSignedModifier() const {
assert(hasSignedModifier());
return (enum SignedModifier)(value & Signed_Mask);
};
void setSignedModifier(enum SignedModifier newmod) {
assert(hasSignedModifier());
assert((newmod & Signed_Mask) == newmod);
U_32 newval = value & (~Signed_Mask);
value = newval | newmod;
}
bool hasComparisonModifier() const { return ((value & Cmp_Mask) != 0); };
enum ComparisonModifier getComparisonModifier() const {
assert(hasComparisonModifier());
return (enum ComparisonModifier)(value & Cmp_Mask);
};
void setComparisonModifier(enum ComparisonModifier newmod) {
assert(hasComparisonModifier());
assert((newmod & Cmp_Mask) == newmod);
U_32 newval = value & (~Cmp_Mask);
value = newval | newmod;
}
bool hasShiftMaskModifier() const { return ((value & ShiftMask_Mask) != 0); };
enum ShiftMaskModifier getShiftMaskModifier() const {
assert(hasShiftMaskModifier());
return (enum ShiftMaskModifier)(value & ShiftMask_Mask);
};
void setShiftMaskModifier(enum ShiftMaskModifier newmod) {
assert(hasShiftMaskModifier());
assert((newmod & ShiftMask_Mask) == newmod);
U_32 newval = value & (~ShiftMask_Mask);
value = newval | newmod;
}
bool hasStrictModifier() const { return ((value & Strict_Mask) != 0); };
enum StrictModifier getStrictModifier() const {
assert(hasStrictModifier());
return (enum StrictModifier)(value & Strict_Mask);
};
void setStrictModifier(enum StrictModifier newmod) {
assert(hasStrictModifier());
assert((newmod & Strict_Mask) == newmod);
U_32 newval = value & (~Strict_Mask);
value = newval | newmod;
}
bool hasDefArgModifier() const { return ((value & DefArg_Mask) != 0); };
enum DefArgModifier getDefArgModifier() const {
assert(hasDefArgModifier());
return (enum DefArgModifier)(value & DefArg_Mask);
};
void setDefArgModifier(enum DefArgModifier newmod) {
assert(hasDefArgModifier());
assert((newmod & DefArg_Mask) == newmod);
U_32 newval = value & (~DefArg_Mask);
value = newval | newmod;
}
bool hasSrcNonNullModifier() const { return ((value & SrcNonNull_Mask) != 0); };
enum SrcNonNullModifier getSrcNonNullModifier() const {
assert(hasSrcNonNullModifier());
return (enum SrcNonNullModifier)(value & SrcNonNull_Mask);
};
void setSrcNonNullModifier(enum SrcNonNullModifier newmod) {
assert(hasSrcNonNullModifier());
assert((newmod & SrcNonNull_Mask) == newmod);
U_32 newval = value & (~SrcNonNull_Mask);
value = newval | newmod;
}
bool hasStoreModifier() const { return ((value & Store_Mask) != 0); };
enum StoreModifier getStoreModifier() const {
assert(hasStoreModifier());
return (enum StoreModifier)(value & Store_Mask);
};
void setStoreModifier(enum StoreModifier newmod) {
assert(hasStoreModifier());
assert((newmod & Store_Mask) == newmod);
U_32 newval = value & (~Store_Mask);
value = newval | newmod;
}
bool hasExceptionModifier() const { return ((value & Exception_Mask) != 0); };
enum ExceptionModifier getExceptionModifier() const {
assert(hasExceptionModifier());
return (enum ExceptionModifier)(value & Exception_Mask);
};
void setExceptionModifier(enum ExceptionModifier newmod) {
assert(hasExceptionModifier());
assert((newmod & Exception_Mask) == newmod);
U_32 newval = value & (~Exception_Mask);
value = newval | newmod;
}
bool hasAutoCompressModifier() const { return ((value & AutoCompress_Mask) != 0); };
enum AutoCompressModifier getAutoCompressModifier() const {
assert(hasAutoCompressModifier());
return (enum AutoCompressModifier)(value & AutoCompress_Mask);
};
void setAutoCompressModifier(enum AutoCompressModifier newmod) {
assert(hasAutoCompressModifier());
assert((newmod & AutoCompress_Mask) == newmod);
U_32 newval = value & (~AutoCompress_Mask);
value = newval | newmod;
}
bool hasSpeculativeModifier() const { return ((value & Speculative_Mask) != 0); };
enum SpeculativeModifier getSpeculativeModifier() const {
return (enum SpeculativeModifier)(value & Speculative_Mask);
};
void setSpeculativeModifier(enum SpeculativeModifier newmod) {
assert(hasSpeculativeModifier());
U_32 newval = value & (~Speculative_Mask);
value = newval | newmod;
}
bool hasThrowModifier() const { return ((value & Throw_Mask) != 0); };
enum ThrowModifier getThrowModifier() const {
assert(hasThrowModifier());
return (enum ThrowModifier)(value & Throw_Mask);
};
void setThrowModifier(enum ThrowModifier newmod) {
assert(hasThrowModifier());
assert((newmod & Throw_Mask) == newmod);
U_32 newval = value & (~Throw_Mask);
value = newval | newmod;
}
bool hasNewModifier1() const { return ((value & NewModifier1_Mask) != 0); };
enum NewModifier1 getNewModifier1() const {
assert(hasNewModifier1());
return (enum NewModifier1)(value & NewModifier1_Mask);
};
void setNewModifier1(enum NewModifier1 newmod) {
assert(hasNewModifier1());
assert((newmod & NewModifier1_Mask) == newmod);
U_32 newval = value & (~NewModifier1_Mask);
value = newval | newmod;
}
bool hasNewModifier2() const { return ((value & NewModifier2_Mask) != 0); };
enum NewModifier2 getNewModifier2() const {
assert(hasNewModifier2());
return (enum NewModifier2)(value & NewModifier2_Mask);
};
void setNewModifier2(enum NewModifier2 newmod) {
assert(hasNewModifier2());
assert((newmod & NewModifier2_Mask) == newmod);
U_32 newval = value & (~NewModifier2_Mask);
value = newval | newmod;
}
bool isSigned() const {
if (hasSignedModifier()) return (getSignedModifier()==SignedOp);
if (hasOverflowModifier()) {
enum OverflowModifier omod = getOverflowModifier();
return ((omod == Overflow_None) || (omod == Overflow_Signed));
};
return false;
}
bool isUnSigned() const {
return !isSigned();
}
bool isSignedModifierSigned() const {
assert(hasSignedModifier());
return (getSignedModifier()==SignedOp);
}
protected:
friend class Operation;
unsigned short encode(Opcode opcode, U_32 bits) const;
Modifier(Opcode opcode, U_32 encoding);
private:
void addEncoding(U_32 &encoded, U_32 &bitsused, U_32 mask,
U_32 minval, U_32 maxval, U_32 isshiftedby,
U_32 bitstoencode) const;
void addDecoding(U_32 &encoding, U_32 &bitsused, U_32 mask,
U_32 minval, U_32 maxval, U_32 isshiftedby,
U_32 bitstoencode);
};
#define OPERATION_OPCODE_BITS 8
#define OPERATION_MODIFIER_BITS 12
#define OPERATION_TYPE_BITS 6
class Operation {
private:
unsigned short opcode : OPERATION_OPCODE_BITS;
unsigned short modifiers : OPERATION_MODIFIER_BITS;
unsigned short typetag : OPERATION_TYPE_BITS;
public:
Opcode getOpcode() const { return (enum Opcode)opcode; };
Modifier getModifier() const { return Modifier(getOpcode(), modifiers); };
Type::Tag getType() const { return (Type::Tag) typetag; };
void setType(Type::Tag newType) { typetag = newType; };
void setModifier(Modifier newmod) {
modifiers = newmod.encode(getOpcode(), OPERATION_MODIFIER_BITS);
}
bool hasComparisonModifier() const {
return getModifier().hasComparisonModifier();
}
enum ComparisonModifier getComparisonModifier() const {
return getModifier().getComparisonModifier();
};
void setComparisonModifier(enum ComparisonModifier newMod) {
Modifier mod = getModifier();
mod.setComparisonModifier(newMod);
setModifier(mod);
};
bool hasSignedModifier() const {
return getModifier().hasSignedModifier();
}
enum SignedModifier getSignedModifier() const {
return getModifier().getSignedModifier();
};
void setSignedModifier(enum SignedModifier newMod) {
Modifier mod = getModifier();
mod.setSignedModifier(newMod);
setModifier(mod);
};
bool hasOverflowModifier() const {
return getModifier().hasOverflowModifier();
}
enum OverflowModifier getOverflowModifier() const {
return getModifier().getOverflowModifier();
};
void setOverflowModifier(enum OverflowModifier newMod) {
Modifier mod = getModifier();
mod.setOverflowModifier(newMod);
setModifier(mod);
};
bool hasShiftMaskModifier() const {
return getModifier().hasShiftMaskModifier();
}
enum ShiftMaskModifier getShiftMaskModifier() const {
return getModifier().getShiftMaskModifier();
};
void setShiftMaskModifier(enum ShiftMaskModifier newMod) {
Modifier mod = getModifier();
mod.setShiftMaskModifier(newMod);
setModifier(mod);
};
bool hasStrictModifier() const {
return getModifier().hasStrictModifier();
}
enum StrictModifier getStrictModifier() const {
return getModifier().getStrictModifier();
};
void setStrictModifier(enum StrictModifier newMod) {
Modifier mod = getModifier();
mod.setStrictModifier(newMod);
setModifier(mod);
};
bool hasDefArgModifier() const {
return getModifier().hasDefArgModifier();
}
enum DefArgModifier getDefArgModifier() const {
return getModifier().getDefArgModifier();
};
void setDefArgModifier(enum DefArgModifier newMod) {
Modifier mod = getModifier();
mod.setDefArgModifier(newMod);
setModifier(mod);
};
bool hasSrcNonNullModifier() const {
return getModifier().hasSrcNonNullModifier();
}
enum SrcNonNullModifier getSrcNonNullModifier() const {
return getModifier().getSrcNonNullModifier();
};
void setSrcNonNullModifier(enum SrcNonNullModifier newMod) {
Modifier mod = getModifier();
mod.setSrcNonNullModifier(newMod);
setModifier(mod);
};
bool hasStoreModifier() const {
return getModifier().hasStoreModifier();
}
enum StoreModifier getStoreModifier() const {
return getModifier().getStoreModifier();
};
void setStoreModifier(enum StoreModifier newMod) {
Modifier mod = getModifier();
mod.setStoreModifier(newMod);
setModifier(mod);
};
bool hasExceptionModifier() const {
return getModifier().hasExceptionModifier();
}
enum ExceptionModifier getExceptionModifier() const {
return getModifier().getExceptionModifier();
};
void setExceptionModifier(enum ExceptionModifier newMod) {
Modifier mod = getModifier();
mod.setExceptionModifier(newMod);
setModifier(mod);
};
bool hasAutoCompressModifier() const {
return getModifier().hasAutoCompressModifier();
}
enum AutoCompressModifier getAutoCompressModifier() const {
return getModifier().getAutoCompressModifier();
};
void setAutoCompressModifier(enum AutoCompressModifier newMod) {
Modifier mod = getModifier();
mod.setAutoCompressModifier(newMod);
setModifier(mod);
};
bool hasThrowModifier() const {
return getModifier().hasThrowModifier();
}
enum ThrowModifier getThrowModifier() const {
return getModifier().getThrowModifier();
};
void setThrowModifier(enum ThrowModifier newMod) {
Modifier mod = getModifier();
mod.setThrowModifier(newMod);
setModifier(mod);
};
bool hasNewModifier1() const {
return getModifier().hasNewModifier1();
}
enum NewModifier1 getNewModifier1() const {
return getModifier().getNewModifier1();
};
void setNewModifier1(enum NewModifier1 newMod) {
Modifier mod = getModifier();
mod.setNewModifier1(newMod);
setModifier(mod);
};
bool hasSpeculativeModifier() const {
return getModifier().hasSpeculativeModifier();
}
enum SpeculativeModifier getSpeculativeModifier() const {
return getModifier().getSpeculativeModifier();
};
void setSpeculativeModifier(enum SpeculativeModifier newMod) {
Modifier mod = getModifier();
mod.setSpeculativeModifier(newMod);
setModifier(mod);
};
bool hasNewModifier2() const {
return getModifier().hasNewModifier2();
}
enum NewModifier2 getNewModifier2() const {
return getModifier().getNewModifier2();
};
void setNewModifier2(enum NewModifier2 newMod) {
Modifier mod = getModifier();
mod.setNewModifier2(newMod);
setModifier(mod);
};
U_32 encodeForHashing() const {
if (Type::isReference((Type::Tag)typetag)) {
return ((opcode << (OPERATION_MODIFIER_BITS+OPERATION_TYPE_BITS))
| (modifiers << OPERATION_TYPE_BITS)
| (U_32)Type::SystemObject);
} else {
return ((opcode << (OPERATION_MODIFIER_BITS+OPERATION_TYPE_BITS))
| (modifiers << OPERATION_TYPE_BITS)
| typetag);
}
}
public:
Operation() : opcode(0), modifiers(0), typetag(0)
{
}
Operation(enum Opcode opcode0) :
opcode((unsigned short) opcode0),
modifiers(0),
typetag(0)
{
assert(((unsigned) Type::NumTypeTags) < (1<<OPERATION_TYPE_BITS));
assert(((unsigned) opcode0) < (1<<OPERATION_OPCODE_BITS));
};
Operation(enum Opcode opcode0, Type::Tag typetag0) :
opcode((unsigned short)opcode0),
modifiers(0),
typetag((unsigned short)typetag0)
{
assert(((unsigned) opcode0) < (1<<OPERATION_OPCODE_BITS));
assert(((unsigned) typetag0) < (1<<OPERATION_TYPE_BITS));
};
// detect automatic argument conversions
Operation(enum Opcode opcode0, Type::Tag typetag0,
Modifier modifier) :
opcode((unsigned short)opcode0),
modifiers(modifier.encode(opcode0, OPERATION_MODIFIER_BITS)),
typetag((unsigned short)typetag0)
{
assert(((unsigned) opcode0) < (1<<OPERATION_OPCODE_BITS));
assert(((unsigned) typetag0) < (1<<OPERATION_TYPE_BITS));
};
bool hasModifier(Modifier::Kind::Enum modifierKind) const;
int getModifier(Modifier::Kind::Enum modifierKind) const;
bool isSigned() const {
return getModifier().isSigned();
}
bool isUnSigned() const {
return getModifier().isUnSigned();
}
bool isSignedModifierSigned() const {
return getModifier().isSignedModifierSigned();
}
const char* getModifierString() const;
const char* getOpcodeFormatString() const;
const char* getOpcodeString() const;
bool canThrow() const;
bool isCheck() const;
bool isMovable() const;
bool isCSEable() const;
bool isStoreOrSync() const;
bool mustEndBlock() const;
bool isLoad() const;
bool isNonEssential() const;
bool isConstant() const;
bool operator==(const Operation &other) const {
return ((opcode == other.opcode) && (modifiers == other.modifiers)
&& (typetag == other.typetag));
}
private:
friend class Modifier;
};
} //namespace Jitrino
#endif // _OPCODE_H_