// Profiler.h: interface for the CProfiler class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_PROFILER_H__CBCD933F_CDD7_4FB0_96B7_BDF982C2CF09__INCLUDED_) #define AFX_PROFILER_H__CBCD933F_CDD7_4FB0_96B7_BDF982C2CF09__INCLUDED_ #include "ArmDisassembler.h" // Added by ClassView #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "TarmacGlobals.h" // disable warning about labels being too long in the debugger viewer, this // doesn't affect the generated code #pragma warning (disable : 4786) #include #include "LinkedList.h" #include "TestMemory.h" // // options for status of recompilation from recompilation of an // individual instruction // // ??? unused at the moment typedef enum { recSTOP = 0, // don't recompile and more instructions recCONTINUE, // keep recompiling recROLLBACK // don't recompile this instruction and stop } recOpt; // // ARM condition codes // typedef enum { ccEQ = 0, ccNE, ccCS, ccCC, ccMI, ccPL, ccVS, ccVC, ccHI, ccLS, ccGE, ccLT, ccGT, ccLE, ccAL, ccNV } conditionCodes; // // armlet opcodes // // note, markers are employed at start and end of each class of opcode // for debugging purposes typedef enum { // implied, no operands, emit() irFirstImplied=0, irCLEARTRANS, irSETTRANS, irSETPC, irLastImplied, // one variable and one value operand, emit1() irFirstOneVar, irMOVC, irGETPC, irINTCHECK, irLastOneVar, // two variable operands, emit2() irFirstTwoVar, irMOV, irMVN, irTST, irTEQ, irCMP, irCMN, irRRX, irLastTwoVar, // three variable operands, emit3() irFirstThreeVar, irAND, irEOR, irSUB, irADD, irADC, irSBC, irORR, irLSL, irLSR, irASR, irROR, irMUL, irLDB, irSTB, irLDW, irSTW, irLastThreeVar, // one value operand, emitV() irFirstValue, irGOTOEQ, irGOTONE, irGOTOCS, irGOTOCC, irGOTOMI, irGOTOPL, irGOTOVS, irGOTOVC, irGOTOHI, irGOTOLS, irGOTOGE, irGOTOLT, irGOTOGT, irGOTOLE, irGOTO, irGOTONV, // equivalent to nop, here for completeness, never emitted irLEAVE, irLastValue } armletOpcodes; // // reason for leaving chunk (arguments for leave opcode) // typedef enum { leaveBranchBackward, // branch before start of chunk leaveBranchForward, // branch ahead of currently recompiling instruction leaveDynamicPC, // PC has been adjusted (dynamically known only) leaveDataAbortException, // data abort exception has occurred leaveSwi, // swi instruction executed leaveAddressException, // address exception has occurred leaveBlockDTUser, // block data transfer needed to temporarily switch to user mode leaveCoProDTPreIndex, // coprocessor data transfer pre indexed executed leaveCoProDTPostIndex, // coprocessor data transfer post indexed executed leaveCoProRTorDO, // coprocessor register transfer or data operation executed leavePSRChanged, // PSR has been adjusted (e.g. by TEQP in priviledged mode) leaveIntCheck // intcheck opcode found an interrupt had occurred } leaveReasons; // // armlet variables // typedef enum { vR0 = 0, vR1, vR2, vR3, vR4, vR5, vR6, vR7, vR8, vR9, vR10, vR11, vR12, vR13, vR14, vPC, vNFLAG, vZFLAG, vCFLAG, vVFLAG, vIFLAG, vFFLAG, vMODE, vUNUSED, // exists to fill blanks in MOV,MVN instructions which have 2 operands but access rd (unlike cmp etc.) vT0, vT1, vT2, vT3, vT4, vT5, vT6, vT7, vT8, vT9, vT10, vT11, vT12, vT13, vT14, vT15, vT16, vT17, vT18, vT19, vT20, vT21, vT22, vT23, vT24, vT25, vT26, vT27, vT28, vT29 } armletVariables; const int maxTemp = vT29; // combinations of flags that may be set by each instruction const int fNONE = 0; const int fALL = 15; const int fN = 8; const int fZ = 4; const int fC = 2; const int fV = 1; // // data structure for single Armlet intermediate representation instruction // struct Armlet { uint8 inflags; // bitmap of NZCV flags required uint8 outflags; // bitmap of NZCV flags adjusted uint8 opcode; // armlet opcode uint8 rd; union { struct { uint8 rx,ry,rz,ra; }; // 4 x 8bit operands for armlet uint32 value; // 1 x 32bit operand for armlet }; BOOL leader; // is this armlet the leader of a basic block? - filled in by generator uint32 armAddress; // address of ARM instruction this armlet is part of BOOL continued; // does this armlet continue a previous ARM instruction }; #include "ArmletDisassembler.h" #include "Optimiser.h" #include "CodeCache.h" class COptimiser; // // information about a block of conditionally executed instructions // struct ConditionalBlockInfo { uint32 startArmlet; // number of 1st armlet in block i.e. the GOTOcc uint32 endArmlet; // number of last armlet in block // such that endArmlet+1 is the destination of the block's initial GOTO uint8 conditionCode; // condition code of the block }; // // debug options // const BOOL useTestMemory = TRUE; // // Profiler class // class CProfiler { public: void setCodeCache(CCodeCache* aCodeCache); BOOL translateSingleDataSwap(uint32 address, uint32 instruction); BOOL translateMultiply(uint32 address, uint32 instruction); uint32 readWord(uint32 address); BOOL translateARMtoArmlets(uint32 address, uint32 instruction); void recompile(uint32 address); CProfiler(); virtual ~CProfiler(); private: void checkPBit(uint32 address, uint32 instruction, uint8 op1, uint8 op2, uint8 outFlags); uint8 getCondFlags(uint8 conditionCode); uint8 useNextTemp(); void emit(uint8 opcode, uint8 inflags, uint8 outflags); void emitV(uint8 opcode, uint32 value, uint8 inflags, uint8 outflags); void emit1(uint8 opcode, uint8 rd, uint32 value, uint8 inflags, uint8 outflags); void emit2(uint8 opcode, uint8 rx, uint8 ry, uint8 inflags, uint8 outflags); void emit3(uint8 opcode, uint8 rd, uint8 rx, uint8 ry, uint8 inflags, uint8 outflags); BOOL translateMultiplyOrDataProcessing(uint32 address, uint32 instruction); BOOL translateSingleDataSwapOrDataProcessing(uint32 address, uint32 instruction); BOOL translateDataProcessing(uint32 address, uint32 instruction); BOOL translateSingleDTImmOffsetPostIndex(uint32 address, uint32 instruction); BOOL translateSingleDTImmOffsetPreIndex(uint32 address, uint32 instruction); BOOL translateSingleDTRegOffsetPostIndex(uint32 address, uint32 instruction); BOOL translateSingleDTRegOffsetPreIndex(uint32 address, uint32 instruction); BOOL translateBlockDataTransfer(uint32 address, uint32 instruction); BOOL translateBranch(uint32 address, uint32 instruction); BOOL translateBranchWithLink(uint32 address, uint32 instruction); BOOL translateCoProDTPreIndex(uint32 address, uint32 instruction); BOOL translateCoProDTPostIndex(uint32 address, uint32 instruction); BOOL translateCoProRegTransferOrDataOperation(uint32 address, uint32 instruction); BOOL translateSoftwareInterrupt(uint32 address, uint32 instruction); private: void emitInterruptCheck(uint32 address, BOOL updatePC); void translateBranchInternal(uint32 destination, uint8 gotoOpcode); uint8 invertConditionCode(uint8 conditionCode); Armlet* getEmit(uint8 opcode, uint32 value, uint8 rd, uint8 inflags, uint8 outflags); void resetAvailableTemps(); BOOL checkRdForPC(uint8 rd, BOOL sFlag, uint32 address); uint32 basicBlockCount; // number of instructions since last adjustment to PC uint8 nextFreeTemp; // temp variable to use next time one is needed BOOL isExtendedInstruction(uint32 instruction); BOOL gotoGenerated; // set if last instruction used a goto in it's body, e.g. a B back inside chunk CLinkedList* conditionalBlockList; // linked list of all ConditionalBlockInfo's for the current chunk ConditionalBlockInfo* currentConditionalBlockInfo; // pointer to info about the current conditional block CLinkedList* armletList; // linked list of all armlets, valid during recompilation only Armlet* lastArmlet; // pointer to last armlet emitted int armletCounter; // number of the last armlet added to chunk (first armlet is 0) uint32 startAddress; // ARM address to start of current chunk std::map addressToArmletNumber; // mapping from ARM instruction to armlet number BOOL inConditionalBlock; // TRUE if current instruction is part of a conditional block BOOL gotoBackpatchNeeded; // TRUE if there is a goto that needs backpatching Armlet* lastGoto; // the last goto that needs backpatching uint8 previousARMConditionCode; // the previous ARM instruction's condition code BOOL flagsAdjusted; // set if previous ARM instruction adjusted NZCV // and therefore can't extend conditional execution uint32* immediateCarry; // look up tables for immediate decoding uint32* immediateValue; COptimiser* optimiser; // optimiser // debugging CTestMemory* testMemory; // test memory buffer CStdioFile armReportFile; }; #endif // !defined(AFX_PROFILER_H__CBCD933F_CDD7_4FB0_96B7_BDF982C2CF09__INCLUDED_)