| /* |
| * 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 Vyacheslav P. Shakin |
| */ |
| |
| #ifndef HYX86INST_H_ |
| #define HYX86INST_H_ |
| |
| #include "open/types.h" |
| #include "Stl.h" |
| #include "MemoryManager.h" |
| #include "Type.h" |
| #include "CodeGenIntfc.h" |
| #include "MemoryAttribute.h" |
| #include "ControlFlowGraph.h" |
| |
| #include "Ia32Encoder.h" |
| #include "Ia32CallingConvention.h" |
| namespace Jitrino |
| { |
| namespace Ia32{ |
| |
| //========================================================================================================= |
| class CodeEmitter; |
| class IRManager; |
| class Opnd; |
| class Inst; |
| class BasicBlock; |
| class I8Lowerer; |
| class ConstantAreaItem; |
| |
| //========================================================================================================= |
| // class Opnd |
| //========================================================================================================= |
| /** |
| class Opnd represents an operand in the LIR. |
| |
| Instructions contain pointers to Opnd instances for their operands. |
| For example the following LIR pseudo-code: |
| I0: mov t1, t0 |
| I1: add t1, t3 |
| |
| instructions I0 and I1 will contain pointers (at index 0) to the same Opnd instance with id==1 |
| |
| Physical locations where an operand can be placed is controlled |
| by an array of 3 constraints: |
| ConstraintKind_Initial, |
| ConstraintKind_Calculated, |
| ConstraintKind_Location, |
| |
| When an operand is created it is assigned ConstraintKind_Initial for the rest of its live |
| At opnd creation time ConstraintKind_Calculated is also set to ConstraintKind_Initial |
| When the operand is assigned to a specific physical location (Imm, Reg, Mem), its Location constraint |
| is set appropriately (representing the assigned location). |
| |
| The Calculated constraint is calculated during special passes |
| taking into account all instruction irregularities |
| The Initial constraint always contains the Calculated constraint and |
| the Calculated constraint contains the Location one. |
| |
| */ |
| |
| class Opnd: public CG_OpndHandle |
| { |
| public: |
| |
| /** enum DefScope defines properties of the set of definitions of an operand */ |
| enum DefScope{ |
| DefScope_Null=0, |
| /** The operand has single definition */ |
| DefScope_Temporary, |
| /** The operand has multiple defs all within one basic block (occurs after conversion into 2-operand form) */ |
| DefScope_SemiTemporary, |
| /** The operand has merging defs */ |
| DefScope_Variable, |
| }; |
| |
| /** enum ConstraintKind is used to indicate a particular constraint of an operand */ |
| enum ConstraintKind{ |
| /** An additional constraint assigned during Opnd creation */ |
| ConstraintKind_Initial=0, |
| /** A constraint calculated in the constraint resolver from instruction properties */ |
| ConstraintKind_Calculated=1, |
| /** A constraint defining assigned physical location of an operand */ |
| ConstraintKind_Location=2, |
| /** The current constraint. If an operand is not assigned with physical storage, |
| getConstraint will return the Calculated constraint, |
| otherwise, it will return the Location constraint |
| */ |
| ConstraintKind_Current |
| }; |
| |
| enum MemOpndAlignment{ |
| MemOpndAlignment_Any = 0, |
| MemOpndAlignment_4 = 4, |
| MemOpndAlignment_8 = 8, |
| MemOpndAlignment_16 = 16 |
| }; |
| |
| //------------------------------------------------------------------------- |
| /** class RuntimeInfo contains information allowing CG to determine operand value from the current runtime information |
| Initially added to support AOT compiler the class is used to annotate operands with runtime info |
| */ |
| class RuntimeInfo |
| { |
| public: |
| enum Kind{ |
| Kind_Null=0, |
| /** The value of the operand is [0]->ObjectType::getAllocationHandle() */ |
| Kind_AllocationHandle, |
| /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ |
| Kind_TypeRuntimeId, |
| /** The value of the operand is [0]->NamedType::getRuntimeIdentifier() */ |
| Kind_MethodRuntimeId, |
| /** The value of the operand is [1], but the information can be used to serialize/deserialize |
| this value: [0] - Type * - the containing class, [1] - string token */ |
| Kind_StringDescription, |
| /** The value of the operand is [0]->ObjectType::getObjectSize() */ |
| Kind_Size, |
| /** The value of the operand is compilationInterface->getRuntimeHelperAddress([0]) */ |
| Kind_HelperAddress, |
| /** The value of the operand is irManager.getInternalHelperInfo((const char*)[0]).pfn */ |
| Kind_InternalHelperAddress, |
| /** The value of the operand is the address where the interned version of the string is stored*/ |
| Kind_StringAddress, |
| /** The value of the operand is [0]->FieldDesc::getAddress() */ |
| Kind_StaticFieldAddress, |
| /** The value of the operand is [0]->FieldDesc::getOffset() */ |
| Kind_FieldOffset, |
| /** The value of the operand is compilationInterface.getVTableOffset(), zero args */ |
| Kind_VTableAddrOffset, |
| /** The value of the operand is [0]->ObjectType::getVTable() */ |
| Kind_VTableConstantAddr, |
| /** The value of the operand is [0]->MethodDesc::getOffset() */ |
| Kind_MethodVtableSlotOffset, |
| /** The value of the operand is [0]->MethodDesc::getIndirectAddress() */ |
| Kind_MethodIndirectAddr, |
| /** The value of the operand is *[0]->MethodDesc::getIndirectAddress() */ |
| Kind_MethodDirectAddr, |
| |
| /** The value of the operand is address of constant pool item ((ConstantPoolItem*)[0])->getAddress() */ |
| Kind_ConstantAreaItem=0x80, |
| |
| /** The value of the operand is a pointer to the EM_ProfileAccessInterface */ |
| Kind_EM_ProfileAccessInterface, |
| /** The value of the operand is Method_Profile_Handle for the value profile of the compiled method */ |
| Kind_Method_Value_Profile_Handle, |
| |
| /** more ... */ |
| }; |
| |
| /** Constructs a RuntimeInfo instance of RuntimeInfo::Type t and initialize it with given values */ |
| RuntimeInfo(RuntimeInfo::Kind k, void * value0, void * value1=0, void * value2=0, void * value3=0, U_32 addOffset=0) |
| :kind(k), additionalOffset(addOffset) |
| { value[0]=value0; value[1]=value1; value[2]=value2; value[3]=value3; } |
| |
| /** Returns the the value at index i */ |
| void * getValue(U_32 i)const{ assert(i<sizeof(value)/sizeof(value[0])); return value[i]; } |
| |
| U_32 getAdditionalOffset()const{ return additionalOffset; } |
| |
| /** Returns the kind of the info */ |
| RuntimeInfo::Kind getKind()const { return kind; } |
| private: |
| RuntimeInfo::Kind kind; |
| void * value[4]; |
| U_32 additionalOffset; |
| }; |
| |
| public: |
| |
| /** Returns the ID of the operand */ |
| U_32 getId()const{ return id; } |
| |
| /** |
| * Returns the ID of the operand assigned at its creation. |
| * The ID of an operand returned by getId maybe changed by IRManager::packOpnds. |
| * The original ID returned by getFirstID is used in logging and IR dumps |
| * for convenience. |
| */ |
| U_32 getFirstId()const{ return firstId; } |
| |
| /** Returns the type of the operand */ |
| Type * getType()const{ return type; } |
| void setType(Type* newType) {type = newType; } |
| |
| /** Returns the constraint of the specified kind sk */ |
| Constraint getConstraint(ConstraintKind ck) const |
| { |
| if (ck==ConstraintKind_Current) |
| return constraints[ConstraintKind_Location].isNull()?constraints[ConstraintKind_Calculated]:constraints[ConstraintKind_Location]; |
| return constraints[ck]; |
| } |
| |
| /** |
| * Returns the constraint of the specified kind sk and adjusts the |
| * results to the specified size. |
| */ |
| Constraint getConstraint(ConstraintKind ck, OpndSize size) const |
| { Constraint c=getConstraint(ck); return size==OpndSize_Any?c:c.getAliasConstraint(size); } |
| |
| /** Returns true if the operand CAN BE assigned to a location defined by constraint |
| */ |
| bool canBePlacedIn(Constraint c)const |
| { return !(getConstraint(ConstraintKind_Calculated, c.getSize())&c).isNull(); } |
| inline bool canBePlacedIn(OpndKind opndKind)const |
| { return ((U_32)opndKind & constraints[ConstraintKind_Calculated].getKind()) != 0; } |
| |
| /** Returns the physical register assigned to the operand */ |
| RegName getRegName()const{ return isPlacedIn(OpndKind_Reg)?regName:RegName_Null; } |
| |
| /** Returns the immediate value assigned to the operand */ |
| int64 getImmValue()const{ return isPlacedIn(OpndKind_Imm)?immValue:0; } |
| |
| /** Returns a sub-operand of a memory operand or NULL */ |
| Opnd * getMemOpndSubOpnd(MemOpndSubOpndKind so)const |
| { assert(memOpndKind != MemOpndKind_Null); return memOpndSubOpnds[so]; } |
| Opnd * const * getMemOpndSubOpnds()const { return memOpndSubOpnds; } |
| |
| /** Returns the memory kind of the operand |
| if it has been assigned to a memory location or Null otherwise */ |
| MemOpndKind getMemOpndKind()const{ return memOpndKind; } |
| |
| void setMemOpndKind(MemOpndKind k){ memOpndKind=k; } |
| |
| /** |
| * Returns alignment for the operand. It makes sense to query |
| * alignment for memory operands that have stack auto layout kind only. |
| * For all other operands MemOpndAlignment_Any will be returned. |
| */ |
| MemOpndAlignment getMemOpndAlignment() { |
| return memOpndAlignment; |
| } |
| |
| /** |
| * Sets desirable memory operand alignment. |
| */ |
| void setMemOpndAlignment(MemOpndAlignment alignment) { |
| // It makes sense to specify alignment for memory operands |
| // which have stack auto layout kind only. |
| memOpndAlignment = alignment; |
| } |
| |
| /** |
| * Returns true if the operand IS assigned to a location defined by constraint. |
| * The constraint can be either explicitly created or implicitly created from RegName values. |
| */ |
| inline bool isPlacedIn(Constraint c)const |
| { Constraint cl=getConstraint(ConstraintKind_Location, c.getSize()); return !cl.isNull() && c.contains(cl); } |
| |
| /** |
| * Returns true if the operand IS assigned to a location defined by opndKind. |
| * This is an "optimized" version of the isPlacedIn method for OpndKind args. |
| */ |
| inline bool isPlacedIn(OpndKind opndKind)const |
| { return ( (U_32)opndKind & constraints[ConstraintKind_Location].getKind() ) != 0; } |
| |
| /** Returns true if the operand IS assigned to any location. */ |
| bool hasAssignedPhysicalLocation()const |
| { return !constraints[ConstraintKind_Location].isNull(); } |
| |
| /** Returns the size of the operand. */ |
| OpndSize getSize()const |
| { OpndSize sz=constraints[ConstraintKind_Initial].getSize(); assert(sz!=OpndSize_Null && sz!=OpndSize_Any); return sz; } |
| |
| /** Returns true if the operand can be allocated on register kind described by constraint c */ |
| bool isAllocationCandidate(Constraint c)const |
| { return canBePlacedIn((OpndKind)c.getKind()) && constraints[ConstraintKind_Location].isNull(); } |
| |
| /** Returns the RuntimeInfo associated with the operand or NULL */ |
| RuntimeInfo * getRuntimeInfo()const |
| { return runtimeInfo; } |
| |
| /** Associates a RuntimeInfo with the operand */ |
| void setRuntimeInfo(RuntimeInfo * ri) |
| { assert(isPlacedIn(OpndKind_Imm)); runtimeInfo=ri; } |
| |
| /** Assigns immediate value to the operand */ |
| void assignImmValue(int64 v); |
| |
| /** Assigns physical register to the operand */ |
| void assignRegName(RegName r); |
| |
| /** Assigns a memory location to the operand */ |
| void assignMemLocation(MemOpndKind k, Opnd * _base, Opnd * _index=0, Opnd * _scale=0, Opnd * _displacement=0); |
| |
| /** Changes sub-operands of a memory opnd (should be already assigned to memory location) */ |
| void setMemOpndSubOpnd(MemOpndSubOpndKind so, Opnd * opnd); |
| |
| /** Returns sub-operand constraint for the sub-operand defined by so |
| according to the Current operand constraints |
| */ |
| Constraint getMemOpndSubOpndConstraint(MemOpndSubOpndKind so) |
| { return Encoder::getMemOpndSubOpndConstraint(Constraint(), so); } |
| |
| /** Returns the definition scope of the operand */ |
| DefScope getDefScope()const{ return defScope; } |
| |
| /** |
| * Returns the number of occurrences of the operand in LIR. |
| * The value may take into account basic block execution count (profile information). |
| * Non-zero result means the operand is used in LIR and zero means it is not. |
| * |
| * The refCount value is calculated during IRManager::calculateOpndStatistics. |
| */ |
| U_32 getRefCount()const{ return refCount; } |
| |
| /** Assigns the Calculated constrain to the operand. */ |
| void setCalculatedConstraint(Constraint c); |
| |
| /** |
| * Return the defining inst for operands with a single definition. |
| * If the operand has multiple definitions the method returns 0. |
| * |
| * The definingInst value is normally calculated during IRManager::calculateOpndStatistics. |
| */ |
| Inst * getDefiningInst()const{ return definingInst; } |
| |
| /** |
| * Assigns the defining inst for operands with a single definition. |
| */ |
| void setDefiningInst(Inst * inst); |
| |
| /** |
| * Returns true if the operand is used in liveness analysis. |
| * For example, immediate values and heap operands do not participate |
| * in liveness analysis. |
| */ |
| bool isSubjectForLivenessAnalysis()const |
| { |
| return (memOpndKind&(MemOpndKind_StackManualLayout|MemOpndKind_ConstantArea|MemOpndKind_Heap|MemOpndKind_LEA))==0 && !isPlacedIn(OpndKind_Imm); |
| } |
| |
| /** Returns the segment register used with the operand (memory). */ |
| RegName getSegReg() const { return segReg; } |
| |
| /** Assigns the segment register to be used with the operand (memory). */ |
| void setSegReg(RegName sr) { segReg = sr; } |
| |
| protected: |
| bool replaceMemOpndSubOpnd(Opnd * opndOld, Opnd * opndNew); |
| bool replaceMemOpndSubOpnds(Opnd * const * opndMap); |
| /** |
| * 'Normalizes' memory sub opnds. That is ensures that an immediate is |
| * placed at the displacement, and a register gets placed ad the base. |
| */ |
| void normalizeMemSubOpnds(void); |
| |
| void addRefCount(U_32& index, U_32 blockExecCount); |
| |
| #ifdef _DEBUG |
| void checkConstraints(); |
| #else |
| void checkConstraints(){} |
| #endif |
| private: |
| |
| //------------------------------------------------------------------------- |
| Opnd(U_32 _id, Type * t, Constraint c) |
| :id(_id), firstId(_id), type(t), |
| defScope(DefScope_Null), definingInst(NULL), refCount(0), |
| segReg(RegName_Null), memOpndKind(MemOpndKind_Null), |
| memOpndAlignment(MemOpndAlignment_Any), |
| immValue(0), runtimeInfo(NULL) { |
| constraints[ConstraintKind_Initial]=constraints[ConstraintKind_Calculated]=c; |
| } |
| |
| //------------------------------------------------------------------------- |
| U_32 id; |
| U_32 firstId; |
| Type * type; |
| Constraint constraints[ConstraintKind_Current]; |
| |
| DefScope defScope; |
| Inst * definingInst; |
| U_32 refCount; |
| RegName segReg; |
| |
| MemOpndKind memOpndKind; |
| // Defines alignment for memory oprands that have stack auto layout kind. |
| MemOpndAlignment memOpndAlignment; |
| |
| union{ |
| RegName regName; |
| struct{ |
| int64 immValue; |
| RuntimeInfo * runtimeInfo; |
| }; |
| Opnd * memOpndSubOpnds[MemOpndSubOpndKind_Count]; |
| }; |
| |
| //------------------------------------------------------------------------- |
| friend class IRManager; |
| friend class Inst; |
| }; |
| |
| typedef Opnd * POpnd; |
| typedef StlVector<Opnd*> OpndVector; |
| |
| //========================================================================================================= |
| // class Inst |
| //========================================================================================================= |
| /** |
| |
| class Inst represents an instruction of the LIR. |
| |
| Each instruction contains an array of all its operands (pointers to Opnd instances). |
| |
| Each instruction contains a pointer to the basic block it is attached to. |
| |
| Each instruction has an ID unique in the method it belongs to. |
| |
| Each instruction can be assigned a sequential index using IRManager::indexInsts() to order instruction |
| in a particular order. |
| |
| Inst provides Opnds collection allowing it to iterate over all the operands the instruction |
| uses or defines explicitly or implicitly. |
| |
| Inst also provides an interface to instruction-level operand constraints defined by ISA. |
| */ |
| |
| class Inst: public CFGInst |
| { |
| |
| public: |
| |
| //--------------------------------------------------------------- |
| /** enum Kind represents dynamic type info of Inst and descendants. |
| This enumeration is hierarchical and is used in getKind and hasKind Inst methods. |
| */ |
| enum Kind |
| { |
| Kind_Inst = 0x7fffffff, |
| Kind_PseudoInst = 0x7ff00000, |
| Kind_MethodEntryPseudoInst = 0x00100000, |
| Kind_MethodEndPseudoInst = 0x00200000, |
| Kind_EmptyPseudoInst = 0x00400000, |
| Kind_CMPXCHG8BPseudoInst = 0x00800000, |
| Kind_CopyPseudoInst = 0x01000000, |
| Kind_I8PseudoInst = 0x02000000, |
| Kind_GCInfoPseudoInst = 0x04000000, |
| Kind_SystemExceptionCheckPseudoInst = 0x08000000, |
| Kind_CatchPseudoInst = 0x10000000, |
| Kind_AliasPseudoInst = 0x20000000, |
| Kind_EntryPointPseudoInst = 0x40000000, |
| Kind_ControlTransferInst = 0x0000fff0, |
| Kind_LocalControlTransferInst = 0x000003F0, |
| Kind_JmpInst = 0x00000200, |
| Kind_BranchInst = 0x000001C0, |
| Kind_SwitchInst = 0x00000030, |
| Kind_InterProceduralControlTransferInst = 0x0000fc00, |
| Kind_CallInst = 0x0000f000, |
| Kind_RetInst = 0x00000c00, |
| }; |
| |
| /** Misc properties of an instruction */ |
| enum Properties{ |
| /** The operation of the instruction is commutative regarding its uses */ |
| Properties_Symmetric=0x1, |
| /** The instruction is conditional (e.g. SETCC) */ |
| Properties_Conditional=0x2, |
| Properties_PureDef=0x4, |
| /** |
| * Memory operands of the instruction are conditional. |
| * This means different operands of the instructions can be assigned to memory |
| * but only one of them at the same time. This is a wide-known constraint of IA32 ISA. |
| */ |
| Properties_MemoryOpndConditional=0x8, |
| }; |
| |
| |
| /** |
| * Enum OpndRole defines the role of an operand in an instruction. |
| * The structure of the enumeration is filter-like allowing to combine its values with '|'. |
| * |
| * It is important to notice that the role mask consists of two parts |
| * covered by OpndRole_FromEncoder and OpndRole_ForIterator. |
| * When used as filter values from each part are virtually combined by "and" |
| * meaning that an operand must satisfy filters from both parts. |
| * |
| * For example OpndRole_Use|OpndRole_Def|OpndRole_Explicit |
| * will filter explicit operand which are both uses and defs while |
| * OpndRole_Use|OpndRole_Explicit will filter only explicit operands which are uses. |
| */ |
| enum OpndRole |
| { |
| OpndRole_Null=0, |
| /** Instruction uses this operand. */ |
| OpndRole_Use=0x1, |
| /** Instruction defines this operand. */ |
| OpndRole_Def=0x2, |
| /** Both uses and defs. */ |
| OpndRole_UseDef=OpndRole_Use|OpndRole_Def, |
| |
| /** Roles retrieved from Encoder. */ |
| OpndRole_FromEncoder=OpndRole_UseDef, |
| |
| /** |
| * Explicit operand, defined by ISA, must be explicitly provided during inst creation. |
| */ |
| OpndRole_Explicit=0x10, |
| |
| /** |
| * Auxilary operand, not defined by ISA, |
| * e.g. return values, arguments of a call instruction, and so on. |
| */ |
| OpndRole_Auxilary=0x20, |
| |
| /** |
| * Implicit operand, defined by ISA, must not be explicitly provided during inst creation. |
| * These operands are assigned with a physical location from the moment of creation, |
| * cannot be replaced in instructions, and fully defined by the semantics of an instruction. |
| * Examples are: EFLAG. |
| * |
| * ESP could also be implicit operands of PUSH/POP |
| * but this is not done in the current implementation. |
| * |
| */ |
| OpndRole_Implicit=0x40, |
| |
| /** |
| * Operands contained directly in the instruction |
| * (as oppsed to sub-operands of memory InstLevel operands). |
| */ |
| OpndRole_InstLevel=OpndRole_Explicit|OpndRole_Auxilary|OpndRole_Implicit, |
| |
| /** Sub-operand of an instruction memory operand (base, index, scale, displacement). */ |
| OpndRole_MemOpndSubOpnd=0x80, |
| /** Sub-operands of the InstLevel operands. */ |
| OpndRole_OpndLevel=OpndRole_MemOpndSubOpnd, |
| |
| /** Operands which can be set or replaced directly in an instruction. */ |
| OpndRole_Changeable=OpndRole_Explicit|OpndRole_Auxilary|OpndRole_MemOpndSubOpnd, |
| |
| OpndRole_ForIterator=OpndRole_InstLevel|OpndRole_OpndLevel, |
| |
| OpndRole_All=0xff, |
| OpndRole_AllDefs=OpndRole_ForIterator|OpndRole_Def, |
| OpndRole_AllUses=OpndRole_ForIterator|OpndRole_Use, |
| }; |
| |
| /** enum Form represents the form of an instruction |
| Inst can be in either Extended ("3-address") form or Native ("2-address") form. |
| */ |
| enum Form |
| { |
| /** Instructions's operands are in the "2-address" native form, e.g. add t0, t1. */ |
| Form_Native, |
| /** Instructions's operands are in the "3-address" extended form, e.g. t2=add t0, t1. */ |
| Form_Extended, |
| }; |
| |
| //--------------------------------------------------------------- |
| public: |
| |
| /** Returns the next inst in a double-linked list. */ |
| Inst* getNextInst() const {return (Inst*)next();} |
| /** Returns the previous inst in a double-linked list. */ |
| Inst* getPrevInst() const {return (Inst*)prev();} |
| |
| /** Returns the kind of the instruction representing its class. */ |
| Kind getKind()const{ return kind; } |
| /** Returns true if the instruction is of kind (class) k or its subclass. */ |
| bool hasKind(Kind k)const{ return (kind&k)==kind; } |
| |
| /** Returns the id of the instruction. */ |
| U_32 getId()const{ return id; } |
| |
| /** Returns the current form of the instruction. */ |
| Form getForm()const{ return (Form)form; } |
| |
| /** |
| * Returns the stack depth at the instruction. |
| * This information is calculated in IRManager::calculateStackDepth(). |
| */ |
| U_32 getStackDepth() const { return stackDepth; } |
| |
| /** Returns the mnemonic of the instruction. */ |
| Mnemonic getMnemonic()const{ return mnemonic; } |
| |
| /** Returns the prefix of the instruction. */ |
| InstPrefix getPrefix()const{ return prefix; } |
| |
| /** Sets the prefix of the instruction. */ |
| void setPrefix(InstPrefix newPrefix){prefix = newPrefix;} |
| |
| /** Returns opcode group description associated with this instruction. */ |
| const Encoder::OpcodeGroup* getOpcodeGroup()const |
| { assert(opcodeGroup); return opcodeGroup; } |
| |
| |
| /** Shortcut: returns the properties of the instruction (bit-mask of Properties). */ |
| U_32 getProperties()const |
| { return properties; } |
| |
| bool getPureDefProperty() const; |
| |
| /** Returns the sequential index of the instruction after ordering via IRManager::indexInsts. */ |
| U_32 getIndex()const{ return index; } |
| |
| /** |
| * Returns the number of InstLevel operands in the instruction. |
| * This is an optimized version of getOpndCount(OpndRole_InstLevel|OpndRole_UseDef). |
| */ |
| U_32 getOpndCount()const{ return opndCount; } |
| |
| /** |
| * Returns the number of operands in the instruction satisfying the given mask. |
| * Please refer to documentation of enum OpndRole for description of usage of opnd roles as filters. |
| */ |
| U_32 getOpndCount(U_32 roles)const |
| { return |
| roles == (OpndRole_InstLevel|OpndRole_UseDef) ? opndCount: |
| roles == (OpndRole_InstLevel|OpndRole_Def) ? defOpndCount: |
| roles == (OpndRole_InstLevel|OpndRole_Use) && (Form)form == Form_Extended ? opndCount - defOpndCount: |
| countOpnds(roles); |
| } |
| |
| /** |
| * Returns the operand at the given index. |
| * The indexing space is sparce and common for all operands including both InstLevel and OpndLevel. |
| * |
| * The indexing space is organized as follows: |
| * - All InstLevel operands |
| * - OpndLevel operands for each InstLevel operand, |
| * organized in 4 slots for each InstLevel operand. |
| * If an InstLevel operand is not a memory operand the |
| * corresponding OpndLevel slots will contain undefined value. |
| * For example, for MOV op0, op1 ([op10(base)+op11(disp)]) the virtual array of operands will appear as |
| * { op0, op1, ?, ?, ?, ?, op10, ?, ?, op11 }. |
| * |
| * All defs in an instruction go before uses in the indexing space. |
| * |
| * Simple loops from 0 to getOpndCount() can be used to access InstLevel operands only. |
| * Inst::Opnds::iterator can also be used as index in this method and should be used to iterate |
| * over all operands including OpndLevel. |
| */ |
| Opnd * getOpnd(U_32 index)const |
| { |
| Opnd * const * opnds = getOpnds(); |
| if (index < opndCount) |
| return opnds[index]; |
| return opnds[(index - opndCount) / 4]->getMemOpndSubOpnd((MemOpndSubOpndKind)((index - opndCount) & 3)); |
| } |
| |
| /** |
| * Returns a mask describing operand roles (|-ed from OpndRole values). |
| * |
| * The indexing space is common for all operands including OpndLevel |
| * (please see comments to Opnd * getOpnd(U_32 index)const). |
| */ |
| U_32 getOpndRoles(U_32 index) const |
| { return index < opndCount ? getOpndRoles()[index] : OpndRole_OpndLevel|OpndRole_Use; } |
| |
| /** Returns a const array of all InstLevel operands. */ |
| Opnd * const * getOpnds()const { return opnds; } |
| |
| /** Returns a const array of InstLevel operand roles. */ |
| const U_32 * getOpndRoles()const |
| { U_32 aoc = allocatedOpndCount; return (const U_32*)(opnds + aoc); } |
| |
| /** Returns a const array of InstLevel operand constraints. */ |
| const Constraint * getConstraints()const |
| { U_32 aoc = allocatedOpndCount; return (const Constraint*)((const U_32*)(opnds + aoc) + aoc); } |
| |
| /** |
| * Returns the constraint imposed by the instruction for the operand at idx. |
| * |
| * The indexing space is common for all operands including OpndLevel |
| * (please see comments to Opnd * getOpnd(U_32 index)const). |
| * |
| * @param idx - operand index to get the constraint for. |
| * |
| * @param memOpndMask - the mask of the operands which are checked if |
| * they are assigned to memory when determining conditional constraints. |
| * memOpndMask is indexed in the standard operand indexing space, the same as idx. |
| * The method takes into account only those memOpndMask bits which correspond to |
| * Explicit operands and not the operand defined by idx. |
| * |
| * @param size - if this parameter is not OpndSize_Null the resulted constraint |
| * is adjusted to the requested size. |
| */ |
| Constraint getConstraint(U_32 idx, U_32 memOpndMask, OpndSize size = OpndSize_Null) const; |
| |
| /** |
| * Returns true if the position at idx starts or extends the operand live range |
| * (simplistically its a use of the operand). |
| */ |
| bool isLiveRangeStart(U_32 idx)const |
| { return (getOpndRoles(idx) & Inst::OpndRole_Use) != 0 && getOpnd(idx)->isSubjectForLivenessAnalysis() && !getPureDefProperty(); } |
| |
| |
| /** |
| * Returns true if the position at idx ends the operand live range |
| * (simplistically its a pure def of the operand). |
| */ |
| bool isLiveRangeEnd(U_32 idx)const |
| { return ((getOpndRoles(idx) & Inst::OpndRole_UseDef) == Inst::OpndRole_Def && (getProperties() & Inst::Properties_Conditional)==0) || ((getOpndRoles(idx) & Inst::OpndRole_Def)!=0 && getPureDefProperty()); } |
| |
| |
| /** |
| * Sets opnd in the instruction at idx. |
| * |
| * The indexing space is common for all operands including OpndLevel |
| * (please see comments to Opnd * getOpnd(U_32 index)const). |
| */ |
| void setOpnd(U_32 idx, Opnd * opnd); |
| |
| |
| /** |
| * Inserts opnd into the instruction at idx. |
| * |
| * Works only for InstLevel operands. The total number of operands cannot |
| * exceed pre-allocated capacity. |
| */ |
| void insertOpnd(U_32 idx, Opnd * opnd, U_32 opndRoles); |
| |
| /** Replaces all occurences of opndOld with roles matching opndRoleMask to opndNew */ |
| bool replaceOpnd(Opnd * opndOld, Opnd * opndNew, U_32 opndRoleMask=OpndRole_All); |
| |
| /** |
| * Replaces all occurences of operands with roles matching opndRoleMask |
| * which has an entry in opndMap to the operand from that entry. |
| * |
| * The opndMap map is organized as an array indexed by from-operand ID which contains to-operands. |
| * The number of entries in the array must be no less than the value returned by IRManager::getOpndCount() |
| */ |
| bool replaceOpnds(Opnd * const * opndMap, U_32 opndRoleMask=OpndRole_All); |
| |
| /** Returns true if the instruction has side effect not described by its operands */ |
| virtual bool hasSideEffect()const |
| { |
| Mnemonic m = getMnemonic(); |
| if(m==Mnemonic_MOVS8 || |
| m==Mnemonic_MOVS16 || |
| m==Mnemonic_MOVS32 || |
| m==Mnemonic_MOVS64 || |
| m==Mnemonic_STOS || |
| m==Mnemonic_STD || |
| m==Mnemonic_CLD || |
| m==Mnemonic_POPFD || |
| m==Mnemonic_PUSHFD || |
| m==Mnemonic_POP || |
| m==Mnemonic_PUSH || |
| m==Mnemonic_FSTP || |
| m==Mnemonic_FST || |
| m==Mnemonic_FIST || |
| m==Mnemonic_FLD || |
| m==Mnemonic_FILD || |
| m==Mnemonic_FLDLN2 || |
| m==Mnemonic_FLDLG2 || |
| m==Mnemonic_FLD1 ) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| /* Checks that inst is valid*/ |
| virtual void verify() const { assert(node!=NULL);} |
| |
| /** Emits (encodes) the instruction into stream */ |
| U_8 * emit(U_8* stream); |
| |
| void initFindInfo(Encoder::FindInfo& fi, Opnd::ConstraintKind opndConstraintKind)const; |
| |
| /** Shortcut to get the next instruction in an Inst list */ |
| Inst * getNext()const{ return (Inst*)_next; } |
| /** Shortcut to get the prev instruction in an Inst list */ |
| Inst * getPrev()const{ return (Inst*)_prev; } |
| |
| /** Swaps inst's operands at idx0 and idx1 */ |
| void swapOperands(U_32 idx0, U_32 idx1); |
| |
| /** |
| * Changes instruction form to native |
| * and makes all necessary changes in instruction operands |
| */ |
| virtual void makeNative(IRManager * irManager); |
| |
| /** |
| * Changes condition for a conditional instruction (SETcc, MOVcc, Jcc) |
| * Conditional instructions have Properies_Conditional. |
| */ |
| void changeInstCondition(ConditionMnemonic cc, IRManager * irManager); |
| |
| /* Reverses condition of a conditional inst and updates its opcode group appropriately. */ |
| virtual void reverse(IRManager * irManager); |
| |
| /* Returns true if the condition of a conditional inst can be reversed. */ |
| virtual bool canReverse()const |
| { return getProperties()&&Properties_Conditional; } |
| |
| /** Sets the offset of native code for this instruction. */ |
| void setCodeOffset(U_32 offset) {codeOffset = offset;} |
| /** Returns the offset of native code for this instruction. */ |
| U_32 getCodeOffset()const { return codeOffset; } |
| /** Returns the size of native code for this instruction. */ |
| U_32 getCodeSize()const { return codeSize; } |
| |
| /** Returns the pointer to the native code for this instruction. */ |
| void * getCodeStartAddr()const; |
| |
| /** Returns the basic block this inst is inserted into or null. */ |
| BasicBlock* getBasicBlock() const |
| { |
| assert(node == NULL || node->isBlockNode()); |
| return (BasicBlock*)node; |
| } |
| |
| /** |
| * Returns the kind of edge according to the kind of the inst. |
| * Called by CFG to detect BB->BB block edges. |
| * ControlTransferInst descendants override this method. |
| */ |
| virtual Edge::Kind getEdgeKind(const Edge* edge) const; |
| |
| class Opnds; |
| protected: |
| //--------------------------------------------------------------- |
| |
| static void* operator new(size_t sz, MemoryManager& mm, U_32 opndCount); |
| |
| static inline void operator delete(void * p, MemoryManager& mm, U_32 opndCount) {} |
| static inline void operator delete(void * p) {} |
| |
| Inst(Mnemonic m, U_32 _id, Form f) |
| :kind(Kind_Inst), id(_id), mnemonic(m), prefix(InstPrefix_Null), |
| form(f), reservedFlags(0), codeSize(0), properties(0), reservedFlags2(0), |
| opcodeGroup(0), index(0), codeOffset(0), |
| /*allocatedOpndCount(0), */defOpndCount(0), opndCount(0), stackDepth(0)/*, opnds(0)*/ |
| |
| // WARN! commented opnds are assigned in overloaded 'new' operator before the constructor |
| // : void* Inst::operator new(size_t sz, MemoryManager& mm, U_32 opndCount) |
| {} |
| virtual ~Inst(){}; |
| |
| static U_32 getOpndChunkSize(U_32 opndCount){ return opndCount * (sizeof(Opnd*) + sizeof(U_32) * 2); } |
| |
| /** sets the size of native code for this instruction */ |
| void setCodeSize(U_32 size) {codeSize = size;} |
| |
| Opnd ** getOpnds() { return opnds; } |
| U_32 * getOpndRoles() |
| { U_32 aoc = allocatedOpndCount; return (U_32*)(opnds + aoc); } |
| Constraint * getConstraints() |
| { U_32 aoc = allocatedOpndCount; return (Constraint*)((const U_32*)(opnds + aoc) + aoc); } |
| static U_32 getExplicitOpndIndexFromOpndRoles(U_32 roles) |
| { return roles>>16; } |
| |
| |
| U_32 countOpnds(U_32 roles)const; |
| |
| void setConstraint(U_32 idx, Constraint c) |
| { assert( (getOpndRoles()[idx] & OpndRole_Explicit) == 0 ); getConstraints()[idx] = c; } |
| |
| void fixOpndsForOpcodeGroup(IRManager * irManager); |
| void assignOpcodeGroup(IRManager * irManager); |
| |
| void setStackDepth(const U_32 sd) { stackDepth = sd; } |
| |
| |
| //--------------------------------------------------------------- |
| Kind kind; |
| U_32 id; |
| Mnemonic mnemonic; |
| InstPrefix prefix; |
| |
| U_32 form:1; |
| U_32 reservedFlags:7; |
| U_32 codeSize:8; |
| U_32 properties:8; |
| U_32 reservedFlags2:8; |
| |
| Encoder::OpcodeGroup * opcodeGroup; |
| |
| U_32 index; |
| U_32 codeOffset; |
| |
| U_32 allocatedOpndCount:16; |
| U_32 defOpndCount:16; |
| U_32 opndCount:16; |
| U_32 stackDepth:16; |
| |
| Opnd ** opnds; |
| |
| //--------------------------------------------------------------- |
| friend class IRManager; |
| friend class Encoder; |
| friend class CallingConventionClient; |
| friend class I8Lowerer; |
| }; |
| |
| |
| //========================================================================================================= |
| // Inst virtual operand collection for iteration |
| //========================================================================================================= |
| |
| class Inst::Opnds |
| { |
| public: |
| typedef U_32 iterator; |
| inline Opnds(const Inst * inst, U_32 r) |
| { |
| rolesToCheck = 0; |
| roles = NULL; |
| |
| opnds = inst->getOpnds(); |
| |
| if (r & Inst::OpndRole_InstLevel) { |
| startIndex = 0; |
| if (r & Inst::OpndRole_Use){ |
| endIndex = instEndIndex = inst->opndCount; |
| if (r & Inst::OpndRole_OpndLevel) |
| endIndex += endIndex<<2; |
| }else if (r & Inst::OpndRole_Def) |
| endIndex = instEndIndex = inst->defOpndCount; |
| else |
| endIndex = instEndIndex = 0; |
| |
| if ((r & Inst::OpndRole_InstLevel) != Inst::OpndRole_InstLevel || |
| (r & Inst::OpndRole_UseDef) == Inst::OpndRole_Use ) |
| { |
| roles = inst->getOpndRoles(); |
| rolesToCheck = r; |
| startIndex = next(startIndex - 1); |
| } |
| }else{ |
| instEndIndex = inst->opndCount; |
| endIndex = instEndIndex + (instEndIndex<<2); |
| startIndex = skipNulls(instEndIndex); |
| } |
| } |
| |
| inline iterator begin()const{ return startIndex; } |
| inline iterator end()const{ return endIndex; } |
| |
| inline iterator next(iterator index)const |
| { |
| ++index; |
| if (index < instEndIndex){ |
| if (roles == NULL) |
| return index; |
| U_32 r = rolesToCheck; |
| do { |
| U_32 ri = roles[index] & r; |
| if ( (ri & Inst::OpndRole_ForIterator) && (ri & Inst::OpndRole_FromEncoder) ) return index; |
| }while (++index < instEndIndex); |
| } |
| return skipNulls(index); |
| } |
| |
| U_32 skipNulls(iterator index)const |
| { |
| while (index < endIndex){ |
| U_32 diffIndex = index - instEndIndex; |
| Opnd * instOpnd = opnds[diffIndex / 4]; |
| U_32 subIndex = diffIndex & 3; |
| if (subIndex == 0 && instOpnd->getMemOpndKind()==MemOpndKind_Null) |
| index += 4; |
| else if (instOpnd->getMemOpndSubOpnd((MemOpndSubOpndKind)(subIndex))==NULL) index++; |
| else break; |
| } |
| return index; |
| } |
| |
| U_32 fill( Opnd ** opnds )const; |
| |
| Opnd * getOpnd(iterator index)const |
| { |
| if (index < instEndIndex) |
| return opnds[index]; |
| else { |
| return opnds[(index - instEndIndex) / 4]->getMemOpndSubOpnd((MemOpndSubOpndKind)((index - instEndIndex) & 3)); |
| } |
| } |
| |
| U_32 startIndex, endIndex, instEndIndex; |
| Opnd * const * opnds; const U_32 * roles; |
| U_32 rolesToCheck; |
| |
| }; |
| |
| |
| //========================================================================================================= |
| // class CMPXCHG8BPseudoInst |
| //========================================================================================================= |
| /** |
| Class CMPXCHG8BPseudoInst represents ... |
| */ |
| class CMPXCHG8BPseudoInst: public Inst |
| { |
| protected: |
| CMPXCHG8BPseudoInst(int id) |
| : Inst(Mnemonic_NULL, id, Inst::Form_Extended) |
| {kind=Kind_CMPXCHG8BPseudoInst;} |
| |
| friend class IRManager; |
| }; |
| |
| //========================================================================================================= |
| // class AliasPseudoInst |
| //========================================================================================================= |
| /** |
| Class AliasPseudoInst represents ... |
| */ |
| class AliasPseudoInst: public Inst |
| { |
| protected: |
| AliasPseudoInst(int id) |
| : Inst(Mnemonic_NULL, id, Inst::Form_Extended), offset(EmptyUint32) |
| {kind=Kind_AliasPseudoInst;} |
| |
| U_32 offset; |
| |
| friend class IRManager; |
| }; |
| |
| //========================================================================================================= |
| // class CatchPseudoInst |
| //========================================================================================================= |
| /** |
| Class CatchPseudoInst represents ... |
| */ |
| class CatchPseudoInst: public Inst |
| { |
| protected: |
| CatchPseudoInst(int id) |
| : Inst(Mnemonic_NULL, id, Inst::Form_Extended) |
| {kind=Kind_CatchPseudoInst;} |
| |
| virtual bool hasSideEffect()const{ return true; } |
| virtual bool isHeaderCriticalInst() const {return true;} |
| friend class IRManager; |
| }; |
| |
| //========================================================================================================= |
| // class GCInfoPseudoInst |
| //========================================================================================================= |
| /** |
| Class GCInfoPseudoInst adds uses of managed pointers bases to CFG |
| All opnds of this inst are bases that must be live in a place in CFG this inst is located. |
| staticMPtrs offsets contains resolved static offsets of managed pointers |
| */ |
| |
| class GCInfoPseudoInst: public Inst { |
| friend class IRManager; |
| |
| protected: |
| GCInfoPseudoInst(IRManager * irm, int id); |
| virtual bool hasSideEffect()const{ return true; } |
| |
| public: |
| StlVector<I_32> offsets; |
| const char* desc; |
| }; |
| |
| //========================================================================================================= |
| // class SystemExceptionCheckInst |
| //========================================================================================================= |
| |
| class SystemExceptionCheckPseudoInst: public Inst |
| { |
| public: |
| CompilationInterface::SystemExceptionId getExceptionId()const{ return exceptionId; } |
| bool checksThisOfInlinedMethod() const { return checksThis; } |
| protected: |
| SystemExceptionCheckPseudoInst(CompilationInterface::SystemExceptionId eid, int id, bool chkThis) |
| : Inst(Mnemonic_CALL, id, Inst::Form_Extended), exceptionId(eid), checksThis(chkThis) |
| {kind=Kind_SystemExceptionCheckPseudoInst;} |
| |
| CompilationInterface::SystemExceptionId exceptionId; |
| |
| virtual bool hasSideEffect()const{ return false; } |
| bool checksThis; |
| friend class IRManager; |
| }; |
| |
| |
| //========================================================================================================= |
| // class ControlTransferInst |
| //========================================================================================================= |
| /** class ControlTransferInst is a base class for all intructions which trasfers control: |
| branches, calls, rets |
| */ |
| class ControlTransferInst: public Inst |
| { |
| |
| public: |
| /** Sub-type: returns true if the instruction is a direct ConstrolTransferInst instance |
| (direct branch or direct call), which means that its operand is immediate */ |
| virtual bool isDirect()const |
| { return getOpndCount()>0 && getOpnd(getTargetOpndIndex())->isPlacedIn(OpndKind_Imm); } |
| |
| U_32 getTargetOpndIndex()const{ return getOpndCount(OpndRole_InstLevel|OpndRole_Def); } |
| |
| virtual bool hasSideEffect()const { return true; } |
| protected: |
| ControlTransferInst(Mnemonic mnemonic, int id) |
| : Inst(mnemonic, id, Form_Native){kind=Kind_ControlTransferInst;} |
| |
| friend class IRManager; |
| }; |
| |
| //========================================================================================================= |
| // class BranchInst |
| //========================================================================================================= |
| /** class BranchInst is used for all branching (conditional control transfers) instructions |
| */ |
| class BranchInst: public ControlTransferInst |
| { |
| friend class IRManager; |
| public: |
| |
| /** Returns the basic block this branch transfers control to*/ |
| Node* getTrueTarget() const {return trueTarget;} |
| void setTrueTarget(Node* node) {trueTarget = node;} |
| Node* getFalseTarget() const {return falseTarget;} |
| void setFalseTarget(Node* node) { falseTarget = node;} |
| |
| /* Reverses direct branch condition and updates target&fallthrough edges |
| WARN: does not affect layout. |
| */ |
| void reverse(IRManager * irManager); |
| |
| /* Returns true if the direct branch can be reverted, i.e. it is direct and is conditional */ |
| bool canReverse()const; |
| |
| virtual void verify() const; |
| |
| protected: |
| BranchInst(Mnemonic mnemonic, int id) |
| : ControlTransferInst(mnemonic, id) , |
| trueTarget(NULL), falseTarget(NULL) |
| { |
| kind=Kind_BranchInst; |
| } |
| // called by CFG to detect BB->BB block edges |
| virtual Edge::Kind getEdgeKind(const Edge* edge) const; |
| |
| // called from CFG when edge target is replaced |
| virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); |
| |
| // called from CFG when 2 blocks are merging and one of the branches is redundant. |
| virtual void removeRedundantBranch(); |
| |
| Node* trueTarget; |
| Node* falseTarget; |
| }; |
| |
| //========================================================================================================= |
| // class JumpInst |
| //========================================================================================================= |
| /** class JumpInst is used for unconditional jumps |
| */ |
| class JumpInst: public ControlTransferInst { |
| friend class IRManager; |
| protected: |
| JumpInst(int id) : ControlTransferInst(Mnemonic_JMP, id) { kind = Kind_JmpInst;} |
| virtual void verify() const; |
| }; |
| |
| //========================================================================================================= |
| // class SwitchInst |
| //========================================================================================================= |
| /** class SwitchInst is used for unconditional indirect jumps that use table mapping for targets |
| */ |
| class SwitchInst : public ControlTransferInst |
| { |
| friend class IRManager; |
| public: |
| |
| /** Returns the basic block for index i */ |
| U_32 getNumTargets() const; |
| Node* getTarget(U_32 i)const; |
| /** Sets the basic block for index i */ |
| void setTarget(U_32 i, Node* bb); |
| |
| Opnd * getTableAddress() const; |
| ConstantAreaItem * getConstantAreaItem() const; |
| |
| virtual void verify() const; |
| protected: |
| SwitchInst(Mnemonic mnemonic, int id, Opnd * addr = 0) : |
| ControlTransferInst(mnemonic, id), tableAddr(addr) |
| { |
| kind=Kind_SwitchInst; |
| tableAddrRI = addr->getRuntimeInfo(); |
| assert(tableAddrRI->getKind()==Opnd::RuntimeInfo::Kind_ConstantAreaItem); |
| } |
| |
| |
| // called by CFG to detect BB->BB block edges |
| virtual Edge::Kind getEdgeKind(const Edge* edge) const; |
| // called from CFG when edge target is replaced |
| virtual void updateControlTransferInst(Node* oldTarget, Node* newTarget); |
| // called from CFG when 2 blocks are merging and one of the branches is redundant. |
| virtual void removeRedundantBranch(); |
| |
| void replaceTarget(Node* bbFrom, Node* bbTo); |
| |
| private: |
| Opnd * tableAddr; |
| //keep original opnd runtime info. |
| //if orig opnd is spilled by spillgen and it's replacement has no runtime info |
| Opnd::RuntimeInfo* tableAddrRI; |
| |
| }; |
| |
| //========================================================================================================= |
| // class CallingConventionClient |
| //========================================================================================================= |
| class CallingConventionClient |
| { |
| public: |
| struct StackOpndInfo |
| { |
| U_32 opndIndex; |
| U_32 offset; |
| bool operator<(const StackOpndInfo& r)const{ return offset < r.offset; } |
| }; |
| |
| CallingConventionClient(MemoryManager& mm, const CallingConvention * cc) |
| :callingConvention(cc), defInfos(mm), useInfos(mm), defStackOpndInfos(mm), useStackOpndInfos(mm), defArgStackDepth(0), useArgStackDepth(0){} |
| |
| const StlVector<CallingConvention::OpndInfo> & getInfos(Inst::OpndRole role)const |
| { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } |
| const StlVector<StackOpndInfo> & getStackOpndInfos(Inst::OpndRole role)const |
| { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } |
| |
| void pushInfo(Inst::OpndRole role, Type::Tag typeTag) |
| { |
| CallingConvention::OpndInfo info; |
| info.typeTag=(U_32)typeTag; info.slotCount=0; |
| StlVector<CallingConvention::OpndInfo> & infos = getInfos(role); |
| infos.push_back(info); |
| } |
| |
| void finalizeInfos(Inst::OpndRole role, CallingConvention::ArgKind argKind); |
| void layoutAuxilaryOpnds(Inst::OpndRole role, OpndKind kindForStackArgs); |
| |
| const CallingConvention * getCallingConvention()const |
| { assert(callingConvention!=NULL); return callingConvention; } |
| |
| U_32 getArgStackDepth(Inst::OpndRole role)const |
| { return ((role & Inst::OpndRole_UseDef) == Inst::OpndRole_Def) ? defArgStackDepth : useArgStackDepth; } |
| |
| U_32 getArgStackDepthAlignment(Inst::OpndRole role) const |
| { return ((role & Inst::OpndRole_UseDef) == Inst::OpndRole_Def) ? useArgStackDepthAlignment : useArgStackDepthAlignment; } |
| |
| void setOwnerInst(Inst * oi){ ownerInst = oi; } |
| protected: |
| StlVector<CallingConvention::OpndInfo> & getInfos(Inst::OpndRole role) |
| { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defInfos:useInfos; } |
| StlVector<StackOpndInfo> & getStackOpndInfos(Inst::OpndRole role) |
| { return (role & Inst::OpndRole_UseDef)==Inst::OpndRole_Def?defStackOpndInfos:useStackOpndInfos; } |
| |
| const CallingConvention * callingConvention; |
| |
| Inst * ownerInst; |
| |
| StlVector<CallingConvention::OpndInfo> defInfos; |
| StlVector<CallingConvention::OpndInfo> useInfos; |
| StlVector<StackOpndInfo> defStackOpndInfos; |
| StlVector<StackOpndInfo> useStackOpndInfos; |
| |
| U_32 defArgStackDepth, useArgStackDepth; |
| U_32 defArgStackDepthAlignment, useArgStackDepthAlignment; |
| |
| }; |
| |
| //========================================================================================================= |
| // class EntryPointPseudoInst |
| //========================================================================================================= |
| /** |
| Class EntryPointPseudoInst represents an entry point for an instruction |
| and is used as definition point for all incoming arguments |
| */ |
| class EntryPointPseudoInst: public Inst |
| { |
| public: |
| virtual bool isHeaderCriticalInst() const {return true;} |
| |
| Opnd * getDefArg(U_32 i)const; |
| |
| U_32 getArgStackDepth()const |
| { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Def); } |
| |
| CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } |
| const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } |
| |
| virtual bool hasSideEffect()const { return true; } |
| |
| #ifdef HYX86_64 |
| Opnd * thisOpnd; |
| #endif |
| //-------------------------------------------------------------------- |
| protected: |
| CallingConventionClient callingConventionClient; |
| |
| EntryPointPseudoInst(IRManager * irm, int id, const CallingConvention * cc); |
| friend class IRManager; |
| }; |
| |
| |
| //========================================================================================================= |
| // class CallInst |
| //========================================================================================================= |
| /** class CallInst is used for all calls instructions: CALL |
| */ |
| class CallInst: public ControlTransferInst |
| { |
| public: |
| |
| U_32 getArgStackDepth()const |
| { return callingConventionClient.getArgStackDepth(Inst::OpndRole_Use); } |
| |
| U_32 getArgStackDepthAlignment() const |
| { return callingConventionClient.getArgStackDepthAlignment(Inst::OpndRole_Use); } |
| |
| CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } |
| const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } |
| |
| Constraint getCalleeSaveRegs(OpndKind regKind=OpndKind_GPReg)const |
| { |
| return callingConventionClient.getCallingConvention()->getCalleeSavedRegs(regKind); |
| } |
| |
| Opnd::RuntimeInfo* getRuntimeInfo() const {return runtimeInfo;} |
| |
| protected: |
| CallingConventionClient callingConventionClient; |
| CallInst(IRManager * irm, int id, const CallingConvention * cc, Opnd::RuntimeInfo* targetInfo); |
| |
| //-------------------------------------------------------------------- |
| friend class IRManager; |
| private: |
| Opnd::RuntimeInfo* runtimeInfo; |
| }; |
| |
| //========================================================================================================= |
| // class RetInst |
| //========================================================================================================= |
| /** class RetInst is used for ret instructions: RET, RET N |
| */ |
| class RetInst: public ControlTransferInst |
| { |
| public: |
| RetInst(IRManager * irm, int id); |
| friend class IRManager; |
| |
| CallingConventionClient& getCallingConventionClient(){ return callingConventionClient; } |
| const CallingConventionClient& getCallingConventionClient()const { return callingConventionClient; } |
| |
| protected: |
| CallingConventionClient callingConventionClient; |
| |
| }; |
| |
| //================================================================================== |
| // class EmptyPseudoInst |
| //================================================================================== |
| /** class EmptyPseudoInst is used to fill blocks which should not be considered as an empty |
| */ |
| class EmptyPseudoInst: public Inst { |
| public: |
| void makeNative(IRManager * irManager) {} |
| protected: |
| EmptyPseudoInst(int id): Inst(Mnemonic_NULL, id, Inst::Form_Extended) { |
| kind = Kind_EmptyPseudoInst; |
| } |
| virtual bool hasSideEffect()const{ return true; } |
| |
| friend class IRManager; |
| }; |
| |
| //================================================================================== |
| // class MethodMarkerPseudoInst |
| //================================================================================== |
| /** class MethodMarkerPseudoInst is used to track inlined method boundaries |
| */ |
| class MethodMarkerPseudoInst: public Inst { |
| public: |
| MethodDesc* getMethodDesc(){ return methDesc; } |
| void makeNative(IRManager * irManager) {} |
| protected: |
| MethodMarkerPseudoInst(MethodDesc* mDesc, int id, Kind k): Inst(Mnemonic_NULL, id, Inst::Form_Extended) { |
| kind = k; |
| methDesc = mDesc; |
| } |
| virtual bool hasSideEffect()const{ return true; } |
| |
| friend class IRManager; |
| |
| private: |
| MethodDesc* methDesc; |
| |
| }; |
| |
| //========================================================================================================= |
| // class ConstantAreaItem |
| //========================================================================================================= |
| /** class ConstantAreaItem |
| |
| */ |
| class ConstantAreaItem |
| { |
| public: |
| enum Kind{ |
| Kind_ConstantAreaItem=0xffffffff, |
| Kind_ValueConstantAreaItem=0xff, |
| Kind_FPSingleConstantAreaItem=0x1, |
| Kind_FPDoubleConstantAreaItem=0x2, |
| Kind_InternalStringConstantAreaItem=0x4, |
| Kind_BinaryConstantAreaItem=0x80, |
| Kind_SwitchTableConstantAreaItem=0x100, |
| }; |
| |
| ConstantAreaItem(Kind k, U_32 s, const void * v) |
| :kind(k), size(s), value(v), address(NULL){} |
| |
| Kind getKind()const{ return kind; } |
| bool hasKind(Kind k)const{ return (kind&k)==kind; } |
| |
| U_32 getSize()const{ return size; } |
| void const * getValue()const{ return value; } |
| |
| void * getAddress()const { return address; } |
| void setAddress(void * addr) { address=addr; } |
| protected: |
| const Kind kind; |
| const U_32 size; |
| void const * value; |
| void * address; |
| }; |
| |
| }}; // namespace Ia32 |
| |
| #endif |