summaryrefslogtreecommitdiffstats
path: root/vm/compiler/codegen/x86/AnalysisO1.cpp
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2014-08-05 12:46:17 -0700
committerBrian Carlstrom <bdc@google.com>2014-08-05 12:51:13 -0700
commit870b4f2d70d67d6dbb7d0881d101c61bed8caad2 (patch)
tree7487dad3970556a040f88a49852a3dc9ed19bebd /vm/compiler/codegen/x86/AnalysisO1.cpp
parent76e15e367ae1189b6f641ba8d16ca92bd179dac0 (diff)
downloadandroid_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.gz
android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.bz2
android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.zip
Dalvik is dead, long live Dalvik!
croot cd dalvik repo start dalvik-is-dead-long-live-dalvik . repo sync -c . git rm -r README.txt git rm -r dexopt git rm -r tools/deadcode.py git rm -r tools/dex-preopt git rm -r tools/dexcheck git rm -r tools/gdbjithelper git rm -r unit-tests git rm -r vm git checkout HEAD vm/Common.h (needed by libdex) git checkout HEAD vm/DalvikVersion.h (needed by libdex) git checkout HEAD vm/Profile.h (needed by dmtracedump) git add Android.mk (after removing vm, dexopt, and unit-tests references) git commit -a -m 'Dalvik is dead, long live Dalvik!' Bug: 14298175 Change-Id: I9dd13053677629d13496d4238af4374452cda415
Diffstat (limited to 'vm/compiler/codegen/x86/AnalysisO1.cpp')
-rw-r--r--vm/compiler/codegen/x86/AnalysisO1.cpp5323
1 files changed, 0 insertions, 5323 deletions
diff --git a/vm/compiler/codegen/x86/AnalysisO1.cpp b/vm/compiler/codegen/x86/AnalysisO1.cpp
deleted file mode 100644
index a9fd5ce8a..000000000
--- a/vm/compiler/codegen/x86/AnalysisO1.cpp
+++ /dev/null
@@ -1,5323 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed 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.
- */
-
-
-/*! \file AnalysisO1.cpp
- \brief This file implements register allocator, constant folding
-*/
-#include "libdex/DexOpcodes.h"
-#include "libdex/DexFile.h"
-#include "Lower.h"
-#include "interp/InterpState.h"
-#include "interp/InterpDefs.h"
-#include "libdex/Leb128.h"
-
-/* compilation flags to turn on debug printout */
-//#define DEBUG_COMPILE_TABLE
-//#define DEBUG_ALLOC_CONSTRAINT
-//#define DEBUG_REGALLOC
-//#define DEBUG_REG_USED
-//#define DEBUG_REFCOUNT
-//#define DEBUG_REACHING_DEF2
-//#define DEBUG_REACHING_DEF
-//#define DEBUG_LIVE_RANGE
-//#define DEBUG_MOVE_OPT
-//#define DEBUG_SPILL
-//#define DEBUG_ENDOFBB
-//#define DEBUG_CONST
-/*
- #define DEBUG_XFER_POINTS
- #define DEBUG_DSE
- #define DEBUG_CFG
- #define DEBUG_GLOBALTYPE
- #define DEBUG_STATE
- #define DEBUG_COMPILE_TABLE
- #define DEBUG_VIRTUAL_INFO
- #define DEBUG_MOVE_OPT
- #define DEBUG_MERGE_ENTRY
- #define DEBUG_INVALIDATE
-*/
-#include "AnalysisO1.h"
-
-void dumpCompileTable();
-
-/* There are 3 kinds of variables that are handled in this file:
- 1> virtual register (isVirtualReg())
- 2> temporary (!isVirtualReg() && regNum < PhysicalReg_GLUE_DVMDEX)
- 3> glue variables: regNum >= PhysicalReg_GLUE_DVMDEX
-*/
-/** check whether a variable is a virtual register
- */
-bool isVirtualReg(int type) {
- if((type & LowOpndRegType_virtual) != 0) return true;
- return false;
-}
-bool isTemporary(int type, int regNum) {
- if(!isVirtualReg(type) && regNum < PhysicalReg_GLUE_DVMDEX) return true;
- return false;
-}
-
-/** convert type defined in lowering module to type defined in register allocator
- in lowering module <type, isPhysical>
- in register allocator: LowOpndRegType_hard LowOpndRegType_virtual LowOpndRegType_scratch
-*/
-int convertType(int type, int reg, bool isPhysical) {
- int newType = type;
- if(isPhysical) newType |= LowOpndRegType_hard;
- if(isVirtualReg(type)) newType |= LowOpndRegType_virtual;
- else {
- /* reg number for a VR can exceed PhysicalReg_SCRATCH_1 */
- if(reg >= PhysicalReg_SCRATCH_1 && reg < PhysicalReg_GLUE_DVMDEX)
- newType |= LowOpndRegType_scratch;
- }
- return newType;
-}
-
-/** return the size of a variable
- */
-OpndSize getRegSize(int type) {
- if((type & MASK_FOR_TYPE) == LowOpndRegType_xmm) return OpndSize_64;
- if((type & MASK_FOR_TYPE) == LowOpndRegType_fs) return OpndSize_64;
- /* for type _gp, _fs_s, _ss */
- return OpndSize_32;
-}
-
-/*
- Overlapping cases between two variables A and B
- layout for A,B isAPartiallyOverlapB isBPartiallyOverlapA
- 1> |__| |____| OVERLAP_ALIGN OVERLAP_B_COVER_A
- |__| |____|
- 2> |____| OVERLAP_B_IS_LOW_OF_A OVERLAP_B_COVER_LOW_OF_A
- |__|
- 3> |____| OVERLAP_B_IS_HIGH_OF_A OVERLAP_B_COVER_HIGH_OF_A
- |__|
- 4> |____| OVERLAP_LOW_OF_A_IS_HIGH_OF_B OVERLAP_B_COVER_LOW_OF_A
- |____|
- 5> |____| OVERLAP_HIGH_OF_A_IS_LOW_OF_B OVERLAP_B_COVER_HIGH_OF_A
- |____|
- 6> |__| OVERLAP_A_IS_LOW_OF_B OVERLAP_B_COVER_A
- |____|
- 7> |__| OVERLAP_A_IS_HIGH_OF_B OVERLAP_B_COVER_A
- |____|
-*/
-/** determine the overlapping between variable B and A
-*/
-OverlapCase getBPartiallyOverlapA(int regB, LowOpndRegType tB, int regA, LowOpndRegType tA) {
- if(getRegSize(tA) == getRegSize(tB) && regA == regB) return OVERLAP_B_COVER_A;
- if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regA == regB) return OVERLAP_B_COVER_LOW_OF_A;
- if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regB == regA + 1) return OVERLAP_B_COVER_HIGH_OF_A;
- if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && (regA == regB || regA == regB+1)) return OVERLAP_B_COVER_A;
- if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regA == regB+1) return OVERLAP_B_COVER_LOW_OF_A;
- if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regB == regA+1) return OVERLAP_B_COVER_HIGH_OF_A;
- return OVERLAP_NO;
-}
-
-/** determine overlapping between variable A and B
-*/
-OverlapCase getAPartiallyOverlapB(int regA, LowOpndRegType tA, int regB, LowOpndRegType tB) {
- if(getRegSize(tA) == getRegSize(tB) && regA == regB) return OVERLAP_ALIGN;
- if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regA == regB)
- return OVERLAP_B_IS_LOW_OF_A;
- if(getRegSize(tA) == OpndSize_64 && getRegSize(tB) == OpndSize_32 && regB == regA+1)
- return OVERLAP_B_IS_HIGH_OF_A;
- if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regA == regB+1)
- return OVERLAP_LOW_OF_A_IS_HIGH_OF_B;
- if(getRegSize(tB) == OpndSize_64 && getRegSize(tA) == OpndSize_64 && regB == regA+1)
- return OVERLAP_HIGH_OF_A_IS_LOW_OF_B;
- if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && regA == regB)
- return OVERLAP_A_IS_LOW_OF_B;
- if(getRegSize(tA) == OpndSize_32 && getRegSize(tB) == OpndSize_64 && regA == regB+1)
- return OVERLAP_A_IS_HIGH_OF_B;
- return OVERLAP_NO;
-}
-
-/** determine whether variable A fully covers B
- */
-bool isAFullyCoverB(int regA, LowOpndRegType tA, int regB, LowOpndRegType tB) {
- if(getRegSize(tB) == OpndSize_32) return true;
- if(getRegSize(tA) == getRegSize(tB) && regA == regB) return true;
- return false;
-}
-
-/*
- RegAccessType accessType
- 1> DefOrUse.accessType
- can only be D(VR), L(low part of VR), H(high part of VR), N(none)
- for def, it means which part of the VR is live
- for use, it means which part of the VR comes from the def
- 2> VirtualRegInfo.accessType
- for currentInfo, it can only be a combination of U & D
- for entries in infoBasicBlock, it can be a combination of U & D|L|H
-*/
-
-/*
- Key data structures used:
- 1> BasicBlock_O1
- VirtualRegInfo infoBasicBlock[]
- DefUsePair* defUseTable
- XferPoint xferPoints[]
- 2> MemoryVRInfo memVRTable[]
- LiveRange* ranges
- 3> compileTableEntry compileTable[]
- 4> VirtualRegInfo
- DefOrUse reachingDefs[3]
- 5> DefUsePair, LiveRange
-*/
-
-//! one entry for each variable used
-
-//! a variable can be virtual register, or a temporary (can be hard-coded)
-compileTableEntry compileTable[COMPILE_TABLE_SIZE];
-int num_compile_entries;
-//! tables to save the states of register allocation
-regAllocStateEntry1 stateTable1_1[COMPILE_TABLE_SIZE];
-regAllocStateEntry1 stateTable1_2[COMPILE_TABLE_SIZE];
-regAllocStateEntry1 stateTable1_3[COMPILE_TABLE_SIZE];
-regAllocStateEntry1 stateTable1_4[COMPILE_TABLE_SIZE];
-regAllocStateEntry2 stateTable2_1[COMPILE_TABLE_SIZE];
-regAllocStateEntry2 stateTable2_2[COMPILE_TABLE_SIZE];
-regAllocStateEntry2 stateTable2_3[COMPILE_TABLE_SIZE];
-regAllocStateEntry2 stateTable2_4[COMPILE_TABLE_SIZE];
-
-//! array of VirtualRegInfo to store VRs accessed by a single bytecode
-VirtualRegInfo infoByteCode[MAX_REG_PER_BYTECODE];
-int num_regs_per_bytecode;
-//! array of TempRegInfo to store temporaries accessed by a single bytecode
-TempRegInfo infoByteCodeTemp[MAX_TEMP_REG_PER_BYTECODE];
-int num_temp_regs_per_bytecode;
-//! array of MemoryVRInfo to store whether a VR is in memory
-#define NUM_MEM_VR_ENTRY 140
-MemoryVRInfo memVRTable[NUM_MEM_VR_ENTRY];
-int num_memory_vr;
-
-CompilationUnit* currentUnit = NULL;
-
-//! the current basic block
-BasicBlock_O1* currentBB = NULL;
-//! array of RegisterInfo for all the physical registers
-RegisterInfo allRegs[PhysicalReg_GLUE+1]; //initialized in codeGen
-
-VirtualRegInfo currentInfo;
-VirtualRegInfo tmpInfo;
-
-//! this array says whether a spill location is used (0 means not used, 1 means used)
-int spillIndexUsed[MAX_SPILL_JIT_IA];
-int indexForGlue = -1;
-
-int num_bbs_for_method;
-//! array of basic blocks in a method in program order
-BasicBlock_O1* method_bbs_sorted[MAX_NUM_BBS_PER_METHOD];
-//! the entry basic block
-BasicBlock_O1* bb_entry;
-int pc_start = -1;
-int pc_end = -1;
-
-//!array of PCs for exception handlers
-int exceptionHandlers[10];
-int num_exception_handlers;
-
-bool canSpillReg[PhysicalReg_Null]; //physical registers that should not be spilled
-int inGetVR_num = -1;
-int inGetVR_type;
-
-///////////////////////////////////////////////////////////////////////////////
-// FORWARD FUNCTION DECLARATION
-void addExceptionHandler(s4 tmp);
-
-int createCFG(Method* method);
-int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb);
-void dumpVirtualInfoOfBasicBlock(BasicBlock_O1* bb);
-void setTypeOfVR();
-void insertGlueReg();
-void dumpVirtualInfoOfMethod();
-int codeGenBasicBlock(const Method* method, BasicBlock_O1* bb);
-
-//used in collectInfoOfBasicBlock: getVirtualRegInfo
-int mergeEntry2(BasicBlock_O1* bb);
-int sortAllocConstraint(RegAllocConstraint* allocConstraints,
- RegAllocConstraint* allocConstraintsSorted, bool fromHighToLow);
-
-//used in codeGenBasicBlock
-void insertFromVirtualInfo(BasicBlock_O1* bb, int k); //update compileTable
-void insertFromTempInfo(int k); //update compileTable
-int updateXferPoints();
-void updateLiveTable();
-void printDefUseTable();
-bool isFirstOfHandler(BasicBlock_O1* bb);
-
-//used in mergeEntry2
-//following functions will not update global data structure
-RegAccessType mergeAccess2(RegAccessType A, RegAccessType B, OverlapCase isBPartiallyOverlapA);
-RegAccessType updateAccess1(RegAccessType A, OverlapCase isAPartiallyOverlapB); //will not update global data structure
-RegAccessType updateAccess2(RegAccessType C1, RegAccessType C2);
-RegAccessType updateAccess3(RegAccessType C, RegAccessType B);
-
-void updateDefUseTable();
-void updateReachingDefA(int indexToA, OverlapCase isBPartiallyOverlapA);
-void updateReachingDefB1(int indexToA);
-void updateReachingDefB2();
-void updateReachingDefB3();
-
-RegAccessType insertAUse(DefUsePair* ptr, int offsetPC, int regNum, LowOpndRegType physicalType);
-DefUsePair* insertADef(int offsetPC, int regNum, LowOpndRegType pType, RegAccessType rType);
-RegAccessType insertDefUsePair(int reachingDefIndex);
-
-//used in updateXferPoints
-int fakeUsageAtEndOfBB(BasicBlock_O1* bb);
-void insertLoadXfer(int offset, int regNum, LowOpndRegType pType);
-int searchMemTable(int regNum);
-void mergeLiveRange(int tableIndex, int rangeStart, int rangeEnd);
-//used in updateLiveTable
-RegAccessType setAccessTypeOfUse(OverlapCase isDefPartiallyOverlapUse, RegAccessType reachingDefLive);
-DefUsePair* searchDefUseTable(int offsetPC, int regNum, LowOpndRegType pType);
-void insertAccess(int tableIndex, LiveRange* startP, int rangeStart);
-
-//register allocation
-int spillLogicalReg(int spill_index, bool updateTable);
-
-/** check whether the current bytecode is IF or GOTO or SWITCH
- */
-bool isCurrentByteCodeJump() {
- u2 inst_op = INST_INST(inst);
- if(inst_op == OP_IF_EQ || inst_op == OP_IF_NE || inst_op == OP_IF_LT ||
- inst_op == OP_IF_GE || inst_op == OP_IF_GT || inst_op == OP_IF_LE) return true;
- if(inst_op == OP_IF_EQZ || inst_op == OP_IF_NEZ || inst_op == OP_IF_LTZ ||
- inst_op == OP_IF_GEZ || inst_op == OP_IF_GTZ || inst_op == OP_IF_LEZ) return true;
- if(inst_op == OP_GOTO || inst_op == OP_GOTO_16 || inst_op == OP_GOTO_32) return true;
- if(inst_op == OP_PACKED_SWITCH || inst_op == OP_SPARSE_SWITCH) return true;
- return false;
-}
-
-/* this function is called before code generation of basic blocks
- initialize data structure allRegs, which stores information for each physical register,
- whether it is used, when it was last freed, whether it is callee-saved */
-void initializeAllRegs() {
- int k;
- for(k = PhysicalReg_EAX; k <= PhysicalReg_EBP; k++) {
- allRegs[k].physicalReg = (PhysicalReg) k;
- if(k == PhysicalReg_EDI || k == PhysicalReg_ESP || k == PhysicalReg_EBP)
- allRegs[k].isUsed = true;
- else {
- allRegs[k].isUsed = false;
- allRegs[k].freeTimeStamp = -1;
- }
- if(k == PhysicalReg_EBX || k == PhysicalReg_EBP || k == PhysicalReg_ESI || k == PhysicalReg_EDI)
- allRegs[k].isCalleeSaved = true;
- else
- allRegs[k].isCalleeSaved = false;
- }
- for(k = PhysicalReg_XMM0; k <= PhysicalReg_XMM7; k++) {
- allRegs[k].physicalReg = (PhysicalReg) k;
- allRegs[k].isUsed = false;
- allRegs[k].freeTimeStamp = -1;
- allRegs[k].isCalleeSaved = false;
- }
-}
-
-/** sync up allRegs (isUsed & freeTimeStamp) with compileTable
- global data: RegisterInfo allRegs[PhysicalReg_Null]
- update allRegs[EAX to XMM7] except EDI,ESP,EBP
- update RegisterInfo.isUsed & RegisterInfo.freeTimeStamp
- if the physical register was used and is not used now
-*/
-void syncAllRegs() {
- int k, k2;
- for(k = PhysicalReg_EAX; k <= PhysicalReg_XMM7; k++) {
- if(k == PhysicalReg_EDI || k == PhysicalReg_ESP || k == PhysicalReg_EBP)
- continue;
- //check whether the physical register is used by any logical register
- bool stillUsed = false;
- for(k2 = 0; k2 < num_compile_entries; k2++) {
- if(compileTable[k2].physicalReg == k) {
- stillUsed = true;
- break;
- }
- }
- if(stillUsed && !allRegs[k].isUsed) {
- allRegs[k].isUsed = true;
- }
- if(!stillUsed && allRegs[k].isUsed) {
- allRegs[k].isUsed = false;
- allRegs[k].freeTimeStamp = lowOpTimeStamp;
- }
- }
- return;
-}
-
-//!sync up spillIndexUsed with compileTable
-
-//!
-void updateSpillIndexUsed() {
- int k;
- for(k = 0; k <= MAX_SPILL_JIT_IA-1; k++) spillIndexUsed[k] = 0;
- for(k = 0; k < num_compile_entries; k++) {
- if(isVirtualReg(compileTable[k].physicalType)) continue;
- if(compileTable[k].spill_loc_index >= 0) {
- if(compileTable[k].spill_loc_index > 4*(MAX_SPILL_JIT_IA-1))
- ALOGE("spill_loc_index is wrong for entry %d: %d",
- k, compileTable[k].spill_loc_index);
- spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 1;
- }
- }
-}
-
-/* free memory used in all basic blocks */
-void freeCFG() {
- int k;
- for(k = 0; k < num_bbs_for_method; k++) {
- /* free defUseTable for method_bbs_sorted[k] */
- DefUsePair* ptr = method_bbs_sorted[k]->defUseTable;
- while(ptr != NULL) {
- DefUsePair* tmp = ptr->next;
- /* free ptr->uses */
- DefOrUseLink* ptrUse = ptr->uses;
- while(ptrUse != NULL) {
- DefOrUseLink* tmp2 = ptrUse->next;
- free(ptrUse);
- ptrUse = tmp2;
- }
- free(ptr);
- ptr = tmp;
- }
- free(method_bbs_sorted[k]);
- }
-}
-
-/* update compileTable.physicalReg, compileTable.spill_loc_index & allRegs.isUsed
- for glue-related variables, they do not exist
- not in a physical register (physicalReg is Null)
- not in a spilled memory location (spill_loc_index is -1)
-*/
-void initializeRegStateOfBB(BasicBlock_O1* bb) {
- //for GLUE variables, do not exist
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- /* trace-based JIT: there is no VR with GG type */
- if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType == GLOBALTYPE_GG) {
- if(bb->bb_index > 0) { //non-entry block
- if(isFirstOfHandler(bb)) {
- /* at the beginning of an exception handler, GG VR is in the interpreted stack */
- compileTable[k].physicalReg = PhysicalReg_Null;
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("at the first basic block of an exception handler, GG VR %d type %d is in memory",
- compileTable[k].regNum, compileTable[k].physicalType);
-#endif
- } else {
- if(compileTable[k].physicalReg == PhysicalReg_Null) {
- /* GG VR is in a specific physical register */
- compileTable[k].physicalReg = compileTable[k].physicalReg_prev;
- }
- int tReg = compileTable[k].physicalReg;
- allRegs[tReg].isUsed = true;
-#ifdef DEBUG_REG_USED
- ALOGI("REGALLOC: physical reg %d is used by a GG VR %d %d at beginning of BB", tReg, compileTable[k].regNum, compileTable[k].physicalType);
-#endif
- }
- } //non-entry block
- } //if GG VR
- if(compileTable[k].regNum != PhysicalReg_GLUE &&
- compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX) {
- /* glue related registers */
- compileTable[k].physicalReg = PhysicalReg_Null;
- compileTable[k].spill_loc_index = -1;
- }
- }
-}
-
-/* update memVRTable[].nullCheckDone */
-void initializeNullCheck(int indexToMemVR) {
- bool found = false;
-#ifdef GLOBAL_NULLCHECK_OPT
- /* search nullCheck_inB of the current Basic Block */
- for(k = 0; k < nullCheck_inSize[currentBB->bb_index2]; k++) {
- if(nullCheck_inB[currentBB->bb_index2][k] == memVRTable[indexToMemVR].regNum) {
- found = true;
- break;
- }
- }
-#endif
- memVRTable[indexToMemVR].nullCheckDone = found;
-}
-
-/* initialize memVRTable */
-void initializeMemVRTable() {
- num_memory_vr = 0;
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(!isVirtualReg(compileTable[k].physicalType)) continue;
- /* VRs in compileTable */
- bool setToInMemory = (compileTable[k].physicalReg == PhysicalReg_Null);
- int regNum = compileTable[k].regNum;
- OpndSize sizeVR = getRegSize(compileTable[k].physicalType);
- /* search memVRTable for the VR in compileTable */
- int kk;
- int indexL = -1;
- int indexH = -1;
- for(kk = 0; kk < num_memory_vr; kk++) {
- if(memVRTable[kk].regNum == regNum) {
- indexL = kk;
- continue;
- }
- if(memVRTable[kk].regNum == regNum+1 && sizeVR == OpndSize_64) {
- indexH = kk;
- continue;
- }
- }
- if(indexL < 0) {
- /* the low half of VR is not in memVRTable
- add an entry for the low half in memVRTable */
- if(num_memory_vr >= NUM_MEM_VR_ENTRY) {
- ALOGE("exceeds size of memVRTable");
- dvmAbort();
- }
- memVRTable[num_memory_vr].regNum = regNum;
- memVRTable[num_memory_vr].inMemory = setToInMemory;
- initializeNullCheck(num_memory_vr); //set nullCheckDone
- memVRTable[num_memory_vr].boundCheck.checkDone = false;
- memVRTable[num_memory_vr].num_ranges = 0;
- memVRTable[num_memory_vr].ranges = NULL;
- memVRTable[num_memory_vr].delayFreeFlags = VRDELAY_NONE;
- num_memory_vr++;
- }
- if(sizeVR == OpndSize_64 && indexH < 0) {
- /* the high half of VR is not in memVRTable
- add an entry for the high half in memVRTable */
- if(num_memory_vr >= NUM_MEM_VR_ENTRY) {
- ALOGE("exceeds size of memVRTable");
- dvmAbort();
- }
- memVRTable[num_memory_vr].regNum = regNum+1;
- memVRTable[num_memory_vr].inMemory = setToInMemory;
- initializeNullCheck(num_memory_vr);
- memVRTable[num_memory_vr].boundCheck.checkDone = false;
- memVRTable[num_memory_vr].num_ranges = 0;
- memVRTable[num_memory_vr].ranges = NULL;
- memVRTable[num_memory_vr].delayFreeFlags = VRDELAY_NONE;
- num_memory_vr++;
- }
- }
-}
-
-/* create a O1 basic block from basic block constructed in JIT MIR */
-BasicBlock_O1* createBasicBlockO1(BasicBlock* bb) {
- BasicBlock_O1* bb1 = createBasicBlock(0, -1);
- bb1->jitBasicBlock = bb;
- return bb1;
-}
-
-/* a basic block in JIT MIR can contain bytecodes that are not in program order
- for example, a "goto" bytecode will be followed by the goto target */
-void preprocessingBB(BasicBlock* bb) {
- currentBB = createBasicBlockO1(bb);
- /* initialize currentBB->allocConstraints */
- int ii;
- for(ii = 0; ii < 8; ii++) {
- currentBB->allocConstraints[ii].physicalReg = (PhysicalReg)ii;
- currentBB->allocConstraints[ii].count = 0;
- }
- collectInfoOfBasicBlock(currentMethod, currentBB);
-#ifdef DEBUG_COMPILE_TABLE
- dumpVirtualInfoOfBasicBlock(currentBB);
-#endif
- currentBB = NULL;
-}
-
-void preprocessingTrace() {
- int k, k2, k3, jj;
- /* this is a simplified verson of setTypeOfVR()
- all VRs are assumed to be GL, no VR will be GG
- */
- for(k = 0; k < num_bbs_for_method; k++)
- for(jj = 0; jj < method_bbs_sorted[k]->num_regs; jj++)
- method_bbs_sorted[k]->infoBasicBlock[jj].gType = GLOBALTYPE_GL;
-
- /* insert a glue-related register GLUE_DVMDEX to compileTable */
- insertGlueReg();
-
- int compile_entries_old = num_compile_entries;
- for(k2 = 0; k2 < num_bbs_for_method; k2++) {
- currentBB = method_bbs_sorted[k2];
- /* update compileTable with virtual register from currentBB */
- for(k3 = 0; k3 < currentBB->num_regs; k3++) {
- insertFromVirtualInfo(currentBB, k3);
- }
-
- /* for each GL|GG type VR, insert fake usage at end of basic block to keep it live */
- int offsetPC_back = offsetPC;
- offsetPC = PC_FOR_END_OF_BB;
- for(k = 0; k < num_compile_entries; k++) {
- currentInfo.regNum = compileTable[k].regNum;
- currentInfo.physicalType = (LowOpndRegType)compileTable[k].physicalType;
- if(isVirtualReg(compileTable[k].physicalType) &&
- compileTable[k].gType == GLOBALTYPE_GL) {
- /* update defUseTable by assuming a fake usage at END of a basic block for variable @ currentInfo */
- fakeUsageAtEndOfBB(currentBB);
- }
- if(isVirtualReg(compileTable[k].physicalType) &&
- compileTable[k].gType == GLOBALTYPE_GG) {
- fakeUsageAtEndOfBB(currentBB);
- }
- }
- offsetPC = offsetPC_back;
- num_compile_entries = compile_entries_old;
- }
- /* initialize data structure allRegs */
- initializeAllRegs();
-#ifdef DEBUG_COMPILE_TABLE
- dumpCompileTable();
-#endif
- currentBB = NULL;
-}
-
-void printJitTraceInfoAtRunTime(const Method* method, int offset) {
- ALOGI("execute trace for %s%s at offset %x", method->clazz->descriptor, method->name, offset);
-}
-
-void startOfTraceO1(const Method* method, LowOpBlockLabel* labelList, int exceptionBlockId, CompilationUnit *cUnit) {
- num_exception_handlers = 0;
- num_compile_entries = 0;
- currentBB = NULL;
- pc_start = -1;
- bb_entry = NULL;
- num_bbs_for_method = 0;
- currentUnit = cUnit;
- lowOpTimeStamp = 0;
-
-// dumpDebuggingInfo is gone in CompilationUnit struct
-#if 0
- /* add code to dump debugging information */
- if(cUnit->dumpDebuggingInfo) {
- move_imm_to_mem(OpndSize_32, cUnit->startOffset, -4, PhysicalReg_ESP, true); //2nd argument: offset
- move_imm_to_mem(OpndSize_32, (int)currentMethod, -8, PhysicalReg_ESP, true); //1st argument: method
- load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
-
- typedef void (*vmHelper)(const Method*, int);
- vmHelper funcPtr = printJitTraceInfoAtRunTime;
- move_imm_to_reg(OpndSize_32, (int)funcPtr, PhysicalReg_ECX, true);
- call_reg(PhysicalReg_ECX, true);
-
- load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
- }
-#endif
-}
-
-
-/* Code generation for a basic block defined for JIT
- We have two data structures for a basic block:
- BasicBlock defined in vm/compiler by JIT
- BasicBlock_O1 defined in o1 */
-int codeGenBasicBlockJit(const Method* method, BasicBlock* bb) {
- /* search method_bbs_sorted to find the O1 basic block corresponding to bb */
- int k;
- for(k = 0; k < num_bbs_for_method; k++) {
- if(method_bbs_sorted[k]->jitBasicBlock == bb) {
- lowOpTimeStamp = 0; //reset time stamp at start of a basic block
- currentBB = method_bbs_sorted[k];
- int cg_ret = codeGenBasicBlock(method, currentBB);
- currentBB = NULL;
- return cg_ret;
- }
- }
- ALOGE("can't find the corresponding O1 basic block for id %d type %d",
- bb->id, bb->blockType);
- return -1;
-}
-void endOfBasicBlock(BasicBlock* bb) {
- isScratchPhysical = true;
- currentBB = NULL;
-}
-void endOfTraceO1() {
- freeCFG();
-}
-
-/** entry point to collect information about virtual registers used in a basic block
- Initialize data structure BasicBlock_O1
- The usage information of virtual registers is stoerd in bb->infoBasicBlock
-
- Global variables accessed: offsetPC, rPC
-*/
-int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb) {
- bb->num_regs = 0;
- bb->num_defs = 0;
- bb->defUseTable = NULL;
- bb->defUseTail = NULL;
- u2* rPC_start = (u2*)method->insns;
- int kk;
- bb->endsWithReturn = false;
- bb->hasAccessToGlue = false;
-
- MIR* mir;
- int seqNum = 0;
- /* traverse the MIR in basic block
- sequence number is used to make sure next bytecode will have a larger sequence number */
- for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
- offsetPC = seqNum;
- mir->seqNum = seqNum++;
- rPC = rPC_start + mir->offset;
-#ifdef WITH_JIT_INLINING
- if(mir->dalvikInsn.opcode >= kMirOpFirst &&
- mir->dalvikInsn.opcode != kMirOpCheckInlinePrediction) continue;
- if(ir->dalvikInsn.opcode == kMirOpCheckInlinePrediction) { //TODO
- }
-#else
- if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) continue;
-#endif
- inst = FETCH(0);
- u2 inst_op = INST_INST(inst);
- /* update bb->hasAccessToGlue */
- if((inst_op >= OP_MOVE_RESULT && inst_op <= OP_RETURN_OBJECT) ||
- (inst_op >= OP_MONITOR_ENTER && inst_op <= OP_INSTANCE_OF) ||
- (inst_op == OP_FILLED_NEW_ARRAY) ||
- (inst_op == OP_FILLED_NEW_ARRAY_RANGE) ||
- (inst_op == OP_THROW) ||
- (inst_op >= OP_INVOKE_VIRTUAL && inst_op <= OP_INVOKE_INTERFACE_RANGE) ||
- (inst_op >= OP_THROW_VERIFICATION_ERROR &&
- inst_op <= OP_EXECUTE_INLINE_RANGE) ||
- (inst_op >= OP_INVOKE_VIRTUAL_QUICK && inst_op <= OP_INVOKE_SUPER_QUICK_RANGE))
- bb->hasAccessToGlue = true;
- /* update bb->endsWithReturn */
- if(inst_op == OP_RETURN_VOID || inst_op == OP_RETURN || inst_op == OP_RETURN_VOID_BARRIER ||
- inst_op == OP_RETURN_OBJECT || inst_op == OP_RETURN_WIDE)
- bb->endsWithReturn = true;
-
- /* get virtual register usage in current bytecode */
- getVirtualRegInfo(infoByteCode);
- int num_regs = num_regs_per_bytecode;
- for(kk = 0; kk < num_regs; kk++) {
- currentInfo = infoByteCode[kk];
-#ifdef DEBUG_MERGE_ENTRY
- ALOGI("call mergeEntry2 at offsetPC %x kk %d VR %d %d", offsetPC, kk,
- currentInfo.regNum, currentInfo.physicalType);
-#endif
- mergeEntry2(bb); //update defUseTable of the basic block
- }
-
- //dumpVirtualInfoOfBasicBlock(bb);
- }//for each bytecode
-
- bb->pc_end = seqNum;
-
- //sort allocConstraints of each basic block
- for(kk = 0; kk < bb->num_regs; kk++) {
-#ifdef DEBUG_ALLOC_CONSTRAINT
- ALOGI("sort virtual reg %d type %d -------", bb->infoBasicBlock[kk].regNum,
- bb->infoBasicBlock[kk].physicalType);
-#endif
- sortAllocConstraint(bb->infoBasicBlock[kk].allocConstraints,
- bb->infoBasicBlock[kk].allocConstraintsSorted, true);
- }
-#ifdef DEBUG_ALLOC_CONSTRAINT
- ALOGI("sort constraints for BB %d --------", bb->bb_index);
-#endif
- sortAllocConstraint(bb->allocConstraints, bb->allocConstraintsSorted, false);
- return 0;
-}
-
-/** entry point to generate native code for a O1 basic block
- There are 3 kinds of virtual registers in a O1 basic block:
- 1> L VR: local within the basic block
- 2> GG VR: is live in other basic blocks,
- its content is in a pre-defined GPR at the beginning of a basic block
- 3> GL VR: is live in other basic blocks,
- its content is in the interpreted stack at the beginning of a basic block
- compileTable is updated with infoBasicBlock at the start of the basic block;
- Before lowering each bytecode, compileTable is updated with infoByteCodeTemp;
- At end of the basic block, right before the jump instruction, handles constant VRs and GG VRs
-*/
-int codeGenBasicBlock(const Method* method, BasicBlock_O1* bb) {
- /* we assume at the beginning of each basic block,
- all GL VRs reside in memory and all GG VRs reside in predefined physical registers,
- so at the end of a basic block, recover a spilled GG VR, store a GL VR to memory */
- /* update compileTable with entries in bb->infoBasicBlock */
- int k;
- for(k = 0; k < bb->num_regs; k++) {
- insertFromVirtualInfo(bb, k);
- }
- updateXferPoints(); //call fakeUsageAtEndOfBB
-#ifdef DEBUG_REACHING_DEF
- printDefUseTable();
-#endif
-#ifdef DSE_OPT
- removeDeadDefs();
- printDefUseTable();
-#endif
- //clear const section of compileTable
- for(k = 0; k < num_compile_entries; k++) compileTable[k].isConst = false;
- num_const_vr = 0;
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("At start of basic block %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
- dumpCompileTable();
-#endif
- initializeRegStateOfBB(bb);
- initializeMemVRTable();
- updateLiveTable();
- freeReg(true); //before code gen of a basic block, also called at end of a basic block?
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("At start of basic block %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
-#endif
-
- u2* rPC_start = (u2*)method->insns;
- bool lastByteCodeIsJump = false;
- MIR* mir;
- for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
- offsetPC = mir->seqNum;
- rPC = rPC_start + mir->offset;
-#ifdef WITH_JIT_INLINING
- if(mir->dalvikInsn.opcode >= kMirOpFirst &&
- mir->dalvikInsn.opcode != kMirOpCheckInlinePrediction) {
-#else
- if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) {
-#endif
- handleExtendedMIR(currentUnit, mir);
- continue;
- }
-
- inst = FETCH(0);
- //before handling a bytecode, import info of temporary registers to compileTable including refCount
- num_temp_regs_per_bytecode = getTempRegInfo(infoByteCodeTemp);
- for(k = 0; k < num_temp_regs_per_bytecode; k++) {
- if(infoByteCodeTemp[k].versionNum > 0) continue;
- insertFromTempInfo(k);
- }
- startNativeCode(-1, -1);
- for(k = 0; k <= MAX_SPILL_JIT_IA-1; k++) spillIndexUsed[k] = 0;
- //update spillIndexUsed if a glue variable was spilled
- for(k = 0; k < num_compile_entries; k++) {
- if(compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX) {
- if(compileTable[k].spill_loc_index >= 0)
- spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 1;
- }
- }
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("compile table size after importing temporary info %d", num_compile_entries);
- ALOGI("before one bytecode %d (num of VRs %d) -------", bb->bb_index, bb->num_regs);
-#endif
- //set isConst to true for CONST & MOVE MOVE_OBJ?
- //clear isConst to true for MOVE, MOVE_OBJ, MOVE_RESULT, MOVE_EXCEPTION ...
- bool isConst = getConstInfo(bb); //will reset isConst if a VR is updated by the bytecode
- bool isDeadStmt = false;
-#ifdef DSE_OPT
- for(k = 0; k < num_dead_pc; k++) {
- if(deadPCs[k] == offsetPC) {
- isDeadStmt = true;
- break;
- }
- }
-#endif
- getVirtualRegInfo(infoByteCode);
- //call something similar to mergeEntry2, but only update refCount
- //clear refCount
- for(k = 0; k < num_regs_per_bytecode; k++) {
- int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
- infoByteCode[k].regNum);
- if(indexT >= 0)
- compileTable[indexT].refCount = 0;
- }
- for(k = 0; k < num_regs_per_bytecode; k++) {
- int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
- infoByteCode[k].regNum);
- if(indexT >= 0)
- compileTable[indexT].refCount += infoByteCode[k].refCount;
- } //for k
-#ifdef DSE_OPT
- if(isDeadStmt) { //search compileTable
- getVirtualRegInfo(infoByteCode);
-#ifdef DEBUG_DSE
- ALOGI("DSE: stmt at offsetPC %d is dead", offsetPC);
-#endif
- for(k = 0; k < num_regs_per_bytecode; k++) {
- int indexT = searchCompileTable(LowOpndRegType_virtual | infoByteCode[k].physicalType,
- infoByteCode[k].regNum);
- if(indexT >= 0)
- compileTable[indexT].refCount -= infoByteCode[k].refCount;
- }
- }
-#endif
- lastByteCodeIsJump = false;
- if(!isConst && !isDeadStmt) //isDeadStmt is false when DSE_OPT is not enabled
- {
-#ifdef DEBUG_COMPILE_TABLE
- dumpCompileTable();
-#endif
- globalShortMap = NULL;
- if(isCurrentByteCodeJump()) lastByteCodeIsJump = true;
- //lowerByteCode will call globalVREndOfBB if it is jump
- int retCode = lowerByteCodeJit(method, rPC, mir);
- if(gDvmJit.codeCacheByteUsed + (stream - streamStart) +
- CODE_CACHE_PADDING > gDvmJit.codeCacheSize) {
- ALOGE("JIT code cache full");
- gDvmJit.codeCacheFull = true;
- return -1;
- }
-
- if (retCode == 1) {
- // We always fall back to the interpreter for OP_INVOKE_OBJECT_INIT_RANGE,
- // but any other failure is unexpected and should be logged.
- if (mir->dalvikInsn.opcode != OP_INVOKE_OBJECT_INIT_RANGE) {
- ALOGE("JIT couldn't compile %s%s dex_pc=%d opcode=%d",
- method->clazz->descriptor,
- method->name,
- offsetPC,
- mir->dalvikInsn.opcode);
- }
- return -1;
- }
- updateConstInfo(bb);
- freeShortMap();
- if(retCode < 0) {
- ALOGE("error in lowering the bytecode");
- return retCode;
- }
- freeReg(true); //may dump GL VR to memory (this is necessary)
- //after each bytecode, make sure non-VRs have refCount of zero
- for(k = 0; k < num_compile_entries; k++) {
- if(isTemporary(compileTable[k].physicalType, compileTable[k].regNum)) {
-#ifdef PRINT_WARNING
- if(compileTable[k].refCount > 0) {
- ALOGW("refCount for a temporary reg %d %d is %d after a bytecode", compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
- }
-#endif
- compileTable[k].refCount = 0;
- }
- }
- } else { //isConst || isDeadStmt
- //if this bytecode is the target of a jump, the mapFromBCtoNCG should be updated
- offsetNCG = stream - streamMethodStart;
- mapFromBCtoNCG[offsetPC] = offsetNCG;
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("this bytecode generates a constant and has no side effect");
-#endif
- freeReg(true); //may dump GL VR to memory (this is necessary)
- }
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("after one bytecode BB %d (num of VRs %d)", bb->bb_index, bb->num_regs);
-#endif
- }//for each bytecode
-#ifdef DEBUG_COMPILE_TABLE
- dumpCompileTable();
-#endif
- if(!lastByteCodeIsJump) constVREndOfBB();
- //at end of a basic block, get spilled GG VR & dump GL VR
- if(!lastByteCodeIsJump) globalVREndOfBB(method);
- //remove entries for temporary registers, L VR and GL VR
- int jj;
- for(k = 0; k < num_compile_entries; ) {
- bool removeEntry = false;
- if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType != GLOBALTYPE_GG) {
- removeEntry = true;
- }
- if(isTemporary(compileTable[k].physicalType, compileTable[k].regNum))
- removeEntry = true;
- if(removeEntry) {
-#ifdef PRINT_WARNING
- if(compileTable[k].refCount > 0)
- ALOGW("refCount for REG %d %d is %d at end of a basic block", compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
-#endif
- compileTable[k].refCount = 0;
- for(jj = k+1; jj < num_compile_entries; jj++) {
- compileTable[jj-1] = compileTable[jj];
- }
- num_compile_entries--;
- } else {
- k++;
- }
- }
- freeReg(true);
- //free LIVE TABLE
- for(k = 0; k < num_memory_vr; k++) {
- LiveRange* ptr2 = memVRTable[k].ranges;
- while(ptr2 != NULL) {
- LiveRange* tmpP = ptr2->next;
- free(ptr2->accessPC);
- free(ptr2);
- ptr2 = tmpP;
- }
- }
-#ifdef DEBUG_COMPILE_TABLE
- ALOGI("At end of basic block -------");
- dumpCompileTable();
-#endif
- return 0;
-}
-
-/** update infoBasicBlock & defUseTable
- input: currentInfo
- side effect: update currentInfo.reachingDefs
-
- update entries in infoBasicBlock by calling updateReachingDefA
- if there is no entry in infoBasicBlock for B, an entry will be created and inserted to infoBasicBlock
-
- defUseTable is updated to account for the access at currentInfo
- if accessType of B is U or UD, we call updateReachingDefB to update currentInfo.reachingDefs
- in order to correctly insert the usage to defUseTable
-*/
-int mergeEntry2(BasicBlock_O1* bb) {
- LowOpndRegType typeB = currentInfo.physicalType;
- int regB = currentInfo.regNum;
- int jj, k;
- int jjend = bb->num_regs;
- bool isMerged = false;
- bool hasAlias = false;
- OverlapCase isBPartiallyOverlapA, isAPartiallyOverlapB;
- RegAccessType tmpType = REGACCESS_N;
- currentInfo.num_reaching_defs = 0;
-
- /* traverse variable A in infoBasicBlock */
- for(jj = 0; jj < jjend; jj++) {
- int regA = bb->infoBasicBlock[jj].regNum;
- LowOpndRegType typeA = bb->infoBasicBlock[jj].physicalType;
- isBPartiallyOverlapA = getBPartiallyOverlapA(regB, typeB, regA, typeA);
- isAPartiallyOverlapB = getAPartiallyOverlapB(regA, typeA, regB, typeB);
- if(regA == regB && typeA == typeB) {
- /* variable A and B are aligned */
- bb->infoBasicBlock[jj].accessType = mergeAccess2(bb->infoBasicBlock[jj].accessType, currentInfo.accessType,
- OVERLAP_B_COVER_A);
- bb->infoBasicBlock[jj].refCount += currentInfo.refCount;
- /* copy reaching defs of variable B from variable A */
- currentInfo.num_reaching_defs = bb->infoBasicBlock[jj].num_reaching_defs;
- for(k = 0; k < currentInfo.num_reaching_defs; k++)
- currentInfo.reachingDefs[k] = bb->infoBasicBlock[jj].reachingDefs[k];
- updateDefUseTable(); //use currentInfo to update defUseTable
- updateReachingDefA(jj, OVERLAP_B_COVER_A); //update reachingDefs of A
- isMerged = true;
- hasAlias = true;
- if(typeB == LowOpndRegType_gp) {
- //merge allocConstraints
- for(k = 0; k < 8; k++) {
- bb->infoBasicBlock[jj].allocConstraints[k].count += currentInfo.allocConstraints[k].count;
- }
- }
- }
- else if(isBPartiallyOverlapA != OVERLAP_NO) {
- tmpType = updateAccess2(tmpType, updateAccess1(bb->infoBasicBlock[jj].accessType, isAPartiallyOverlapB));
- bb->infoBasicBlock[jj].accessType = mergeAccess2(bb->infoBasicBlock[jj].accessType, currentInfo.accessType,
- isBPartiallyOverlapA);
-#ifdef DEBUG_MERGE_ENTRY
- ALOGI("update accessType in case 2: VR %d %d accessType %d", regA, typeA, bb->infoBasicBlock[jj].accessType);
-#endif
- hasAlias = true;
- if(currentInfo.accessType == REGACCESS_U || currentInfo.accessType == REGACCESS_UD) {
- /* update currentInfo.reachingDefs */
- updateReachingDefB1(jj);
- updateReachingDefB2();
- }
- updateReachingDefA(jj, isBPartiallyOverlapA);
- }
- else {
- //even if B does not overlap with A, B can affect the reaching defs of A
- //for example, B is a def of "v0", A is "v1"
- // B can kill some reaching defs of A or affect the accessType of a reaching def
- updateReachingDefA(jj, OVERLAP_NO); //update reachingDefs of A
- }
- }//for each variable A in infoBasicBlock
- if(!isMerged) {
- /* create a new entry in infoBasicBlock */
- bb->infoBasicBlock[bb->num_regs].refCount = currentInfo.refCount;
- bb->infoBasicBlock[bb->num_regs].physicalType = typeB;
- if(hasAlias)
- bb->infoBasicBlock[bb->num_regs].accessType = updateAccess3(tmpType, currentInfo.accessType);
- else
- bb->infoBasicBlock[bb->num_regs].accessType = currentInfo.accessType;
-#ifdef DEBUG_MERGE_ENTRY
- ALOGI("update accessType in case 3: VR %d %d accessType %d", regB, typeB, bb->infoBasicBlock[bb->num_regs].accessType);
-#endif
- bb->infoBasicBlock[bb->num_regs].regNum = regB;
- for(k = 0; k < 8; k++)
- bb->infoBasicBlock[bb->num_regs].allocConstraints[k] = currentInfo.allocConstraints[k];
-#ifdef DEBUG_MERGE_ENTRY
- ALOGI("isMerged is false, call updateDefUseTable");
-#endif
- updateDefUseTable(); //use currentInfo to update defUseTable
- updateReachingDefB3(); //update currentInfo.reachingDefs if currentInfo defines variable B
-
- //copy from currentInfo.reachingDefs to bb->infoBasicBlock[bb->num_regs]
- bb->infoBasicBlock[bb->num_regs].num_reaching_defs = currentInfo.num_reaching_defs;
- for(k = 0; k < currentInfo.num_reaching_defs; k++)
- bb->infoBasicBlock[bb->num_regs].reachingDefs[k] = currentInfo.reachingDefs[k];
-#ifdef DEBUG_MERGE_ENTRY
- ALOGI("try to update reaching defs for VR %d %d", regB, typeB);
- for(k = 0; k < bb->infoBasicBlock[bb->num_regs].num_reaching_defs; k++)
- ALOGI("reaching def %d @ %d for VR %d %d access %d", k, currentInfo.reachingDefs[k].offsetPC,
- currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType,
- currentInfo.reachingDefs[k].accessType);
-#endif
- bb->num_regs++;
- if(bb->num_regs >= MAX_REG_PER_BASICBLOCK) {
- ALOGE("too many VRs in a basic block");
- dvmAbort();
- }
- return -1;
- }
- return 0;
-}
-
-//!update reaching defs for infoBasicBlock[indexToA]
-
-//!use currentInfo.reachingDefs to update reaching defs for variable A
-void updateReachingDefA(int indexToA, OverlapCase isBPartiallyOverlapA) {
- if(indexToA < 0) return;
- int k, k2;
- OverlapCase isBPartiallyOverlapDef;
- if(currentInfo.accessType == REGACCESS_U) {
- return; //no update to reachingDefs of the VR
- }
- /* access in currentInfo is DU, D, or UD */
- if(isBPartiallyOverlapA == OVERLAP_B_COVER_A) {
- /* from this point on, the reachingDefs for variable A is a single def to currentInfo at offsetPC */
- currentBB->infoBasicBlock[indexToA].num_reaching_defs = 1;
- currentBB->infoBasicBlock[indexToA].reachingDefs[0].offsetPC = offsetPC;
- currentBB->infoBasicBlock[indexToA].reachingDefs[0].regNum = currentInfo.regNum;
- currentBB->infoBasicBlock[indexToA].reachingDefs[0].physicalType = currentInfo.physicalType;
- currentBB->infoBasicBlock[indexToA].reachingDefs[0].accessType = REGACCESS_D;
-#ifdef DEBUG_REACHING_DEF
- ALOGI("single reaching def @ %d for VR %d %d", offsetPC, currentInfo.regNum, currentInfo.physicalType);
-#endif
- return;
- }
- /* update reachingDefs for variable A to get rid of dead defs */
- /* Bug fix: it is possible that more than one reaching defs need to be removed
- after one reaching def is removed, num_reaching_defs--, but k should not change
- */
- for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; ) {
- /* remove one reaching def in one interation of the loop */
- //check overlapping between def & B
- isBPartiallyOverlapDef = getBPartiallyOverlapA(currentInfo.regNum, currentInfo.physicalType,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType);
-#ifdef DEBUG_REACHING_DEF
- ALOGI("DEBUG B %d %d def %d %d %d", currentInfo.regNum, currentInfo.physicalType,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType);
-#endif
- /* cases where one def nees to be removed:
- if B fully covers def, def is removed
- if B overlaps high half of def & def's accessType is H, def is removed
- if B overlaps low half of def & def's accessType is L, def is removed
- */
- if((isBPartiallyOverlapDef == OVERLAP_B_COVER_HIGH_OF_A &&
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType == REGACCESS_H) ||
- (isBPartiallyOverlapDef == OVERLAP_B_COVER_LOW_OF_A &&
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType == REGACCESS_L) ||
- isBPartiallyOverlapDef == OVERLAP_B_COVER_A
- ) { //remove def
- //shift from k+1 to end
- for(k2 = k+1; k2 < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k2++)
- currentBB->infoBasicBlock[indexToA].reachingDefs[k2-1] = currentBB->infoBasicBlock[indexToA].reachingDefs[k2];
- currentBB->infoBasicBlock[indexToA].num_reaching_defs--;
- }
- /*
- if B overlaps high half of def & def's accessType is not H --> update accessType of def
- */
- else if(isBPartiallyOverlapDef == OVERLAP_B_COVER_HIGH_OF_A &&
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType != REGACCESS_H) {
- //low half is still valid
- if(getRegSize(currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType) == OpndSize_32)
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_D;
- else
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_L;
-#ifdef DEBUG_REACHING_DEF
- ALOGI("DEBUG: set accessType of def to L");
-#endif
- k++;
- }
- /*
- if B overlaps low half of def & def's accessType is not L --> update accessType of def
- */
- else if(isBPartiallyOverlapDef == OVERLAP_B_COVER_LOW_OF_A &&
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType != REGACCESS_L) {
- //high half of def is still valid
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_H;
-#ifdef DEBUG_REACHING_DEF
- ALOGI("DEBUG: set accessType of def to H");
-#endif
- k++;
- }
- else {
- k++;
- }
- }//for k
- if(isBPartiallyOverlapA != OVERLAP_NO) {
- //insert the def to variable @ currentInfo
- k = currentBB->infoBasicBlock[indexToA].num_reaching_defs;
- if(k >= 3) {
- ALOGE("more than 3 reaching defs");
- }
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].offsetPC = offsetPC;
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum = currentInfo.regNum;
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType = currentInfo.physicalType;
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType = REGACCESS_D;
- currentBB->infoBasicBlock[indexToA].num_reaching_defs++;
- }
-#ifdef DEBUG_REACHING_DEF2
- ALOGI("IN updateReachingDefA for VR %d %d", currentBB->infoBasicBlock[indexToA].regNum,
- currentBB->infoBasicBlock[indexToA].physicalType);
- for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k++)
- ALOGI("reaching def %d @ %d for VR %d %d access %d", k,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].offsetPC,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType);
-#endif
-}
-
-/** Given a variable B @currentInfo,
- updates its reaching defs by checking reaching defs of variable A @currentBB->infoBasicBlock[indexToA]
- The result is stored in tmpInfo.reachingDefs
-*/
-void updateReachingDefB1(int indexToA) {
- if(indexToA < 0) return;
- int k;
- tmpInfo.num_reaching_defs = 0;
- for(k = 0; k < currentBB->infoBasicBlock[indexToA].num_reaching_defs; k++) {
- /* go through reachingDefs of variable A @currentBB->infoBasicBlock[indexToA]
- for each def, check whether it overlaps with variable B @currentInfo
- if the def overlaps with variable B, insert it to tmpInfo.reachingDefs
- */
- OverlapCase isDefPartiallyOverlapB = getAPartiallyOverlapB(
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].regNum,
- currentBB->infoBasicBlock[indexToA].reachingDefs[k].physicalType,
- currentInfo.regNum, currentInfo.physicalType
- );
- bool insert1 = false; //whether to insert the def to tmpInfo.reachingDefs
- if(isDefPartiallyOverlapB == OVERLAP_ALIGN ||
- isDefPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B ||
- isDefPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B) {
- /* B aligns with def */
- /* def is low half of B, def is high half of B
- in these two cases, def is 32 bits */
- insert1 = true;
- }
- RegAccessType deftype = currentBB->infoBasicBlock[indexToA].reachingDefs[k].accessType;
- if(isDefPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A ||
- isDefPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B) {
- /* B is the low half of def */
- /* the low half of def is the high half of B */
- if(deftype != REGACCESS_H) insert1 = true;
- }
- if(isDefPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A ||
- isDefPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B) {
- /* B is the high half of def */
- /* the high half of def is the low half of B */
- if(deftype != REGACCESS_L) insert1 = true;
- }
- if(insert1) {
- if(tmpInfo.num_reaching_defs >= 3) {
- ALOGE("more than 3 reaching defs for tmpInfo");
- }
- tmpInfo.reachingDefs[tmpInfo.num_reaching_defs] = currentBB->infoBasicBlock[indexToA].reachingDefs[k];
- tmpInfo.num_reaching_defs++;
-#ifdef DEBUG_REACHING_DEF2
- ALOGI("insert from entry %d %d: index %d", currentBB->infoBasicBlock[indexToA].regNum,
- currentBB->infoBasicBlock[indexToA].physicalType, k);
-#endif
- }
- }
-}
-
-/** update currentInfo.reachingDefs by merging currentInfo.reachingDefs with tmpInfo.reachingDefs
-*/
-void updateReachingDefB2() {
- int k, k2;
- for(k2 = 0; k2 < tmpInfo.num_reaching_defs; k2++ ) {
- bool merged = false;
- for(k = 0; k < currentInfo.num_reaching_defs; k++) {
- /* check whether it is the same def, if yes, do nothing */
- if(currentInfo.reachingDefs[k].regNum == tmpInfo.reachingDefs[k2].regNum &&
- currentInfo.reachingDefs[k].physicalType == tmpInfo.reachingDefs[k2].physicalType) {
- merged = true;
- if(currentInfo.reachingDefs[k].offsetPC != tmpInfo.reachingDefs[k2].offsetPC) {
- ALOGE("defs on the same VR %d %d with different offsetPC %d vs %d",
- currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType,
- currentInfo.reachingDefs[k].offsetPC, tmpInfo.reachingDefs[k2].offsetPC);
- }
- if(currentInfo.reachingDefs[k].accessType != tmpInfo.reachingDefs[k2].accessType)
- ALOGE("defs on the same VR %d %d with different accessType",
- currentInfo.reachingDefs[k].regNum, currentInfo.reachingDefs[k].physicalType);
- break;
- }
- }
- if(!merged) {
- if(currentInfo.num_reaching_defs >= 3) {
- ALOGE("more than 3 reaching defs for currentInfo");
- }
- currentInfo.reachingDefs[currentInfo.num_reaching_defs] = tmpInfo.reachingDefs[k2];
- currentInfo.num_reaching_defs++;
- }
- }
-}
-
-//!update currentInfo.reachingDefs with currentInfo if variable is defined in currentInfo
-
-//!
-void updateReachingDefB3() {
- if(currentInfo.accessType == REGACCESS_U) {
- return; //no need to update currentInfo.reachingDefs
- }
- currentInfo.num_reaching_defs = 1;
- currentInfo.reachingDefs[0].regNum = currentInfo.regNum;
- currentInfo.reachingDefs[0].physicalType = currentInfo.physicalType;
- currentInfo.reachingDefs[0].offsetPC = offsetPC;
- currentInfo.reachingDefs[0].accessType = REGACCESS_D;
-}
-
-/** update defUseTable by checking currentInfo
-*/
-void updateDefUseTable() {
- /* no access */
- if(currentInfo.accessType == REGACCESS_N) return;
- /* define then use, or define only */
- if(currentInfo.accessType == REGACCESS_DU || currentInfo.accessType == REGACCESS_D) {
- /* insert a definition at offsetPC to variable @ currentInfo */
- DefUsePair* ptr = insertADef(offsetPC, currentInfo.regNum, currentInfo.physicalType, REGACCESS_D);
- if(currentInfo.accessType != REGACCESS_D) {
- /* if access is define then use, insert a use at offsetPC */
- insertAUse(ptr, offsetPC, currentInfo.regNum, currentInfo.physicalType);
- }
- return;
- }
- /* use only or use then define
- check the reaching defs for the usage */
- int k;
- bool isLCovered = false, isHCovered = false, isDCovered = false;
- for(k = 0; k < currentInfo.num_reaching_defs; k++) {
- /* insert a def currentInfo.reachingDefs[k] and a use of variable at offsetPC */
- RegAccessType useType = insertDefUsePair(k);
- if(useType == REGACCESS_D) isDCovered = true;
- if(useType == REGACCESS_L) isLCovered = true;
- if(useType == REGACCESS_H) isHCovered = true;
- }
- OpndSize useSize = getRegSize(currentInfo.physicalType);
- if((!isDCovered) && (!isLCovered)) {
- /* the low half of variable is not defined in the basic block
- so insert a def to the low half at START of the basic block */
- insertDefUsePair(-1);
- }
- if(useSize == OpndSize_64 && (!isDCovered) && (!isHCovered)) {
- /* the high half of variable is not defined in the basic block
- so insert a def to the high half at START of the basic block */
- insertDefUsePair(-2);
- }
- if(currentInfo.accessType == REGACCESS_UD) {
- /* insert a def at offsetPC to variable @ currentInfo */
- insertADef(offsetPC, currentInfo.regNum, currentInfo.physicalType, REGACCESS_D);
- return;
- }
-}
-
-//! insert a use at offsetPC of given variable at end of DefUsePair
-
-//!
-RegAccessType insertAUse(DefUsePair* ptr, int offsetPC, int regNum, LowOpndRegType physicalType) {
- DefOrUseLink* tLink = (DefOrUseLink*)malloc(sizeof(DefOrUseLink));
- if(tLink == NULL) {
- ALOGE("Memory allocation failed");
- return REGACCESS_UNKNOWN;
- }
- tLink->offsetPC = offsetPC;
- tLink->regNum = regNum;
- tLink->physicalType = physicalType;
- tLink->next = NULL;
- if(ptr->useTail != NULL)
- ptr->useTail->next = tLink;
- ptr->useTail = tLink;
- if(ptr->uses == NULL)
- ptr->uses = tLink;
- ptr->num_uses++;
-
- //check whether the def is partially overlapping with the variable
- OverlapCase isDefPartiallyOverlapB = getBPartiallyOverlapA(ptr->def.regNum,
- ptr->def.physicalType,
- regNum, physicalType);
- RegAccessType useType = setAccessTypeOfUse(isDefPartiallyOverlapB, ptr->def.accessType);
- tLink->accessType = useType;
- return useType;
-}
-
-//! insert a def to currentBB->defUseTable
-
-//! update currentBB->defUseTail if necessary
-DefUsePair* insertADef(int offsetPC, int regNum, LowOpndRegType pType, RegAccessType rType) {
- DefUsePair* ptr = (DefUsePair*)malloc(sizeof(DefUsePair));
- if(ptr == NULL) {
- ALOGE("Memory allocation failed");
- return NULL;
- }
- ptr->next = NULL;
- ptr->def.offsetPC = offsetPC;
- ptr->def.regNum = regNum;
- ptr->def.physicalType = pType;
- ptr->def.accessType = rType;
- ptr->num_uses = 0;
- ptr->useTail = NULL;
- ptr->uses = NULL;
- if(currentBB->defUseTail != NULL) {
- currentBB->defUseTail->next = ptr;
- }
- currentBB->defUseTail = ptr;
- if(currentBB->defUseTable == NULL)
- currentBB->defUseTable = ptr;
- currentBB->num_defs++;
-#ifdef DEBUG_REACHING_DEF
- ALOGI("insert a def at %d to defUseTable for VR %d %d", offsetPC,
- regNum, pType);
-#endif
- return ptr;
-}
-
-/** insert a def to defUseTable, then insert a use of variable @ currentInfo
- if reachingDefIndex >= 0, the def is currentInfo.reachingDefs[index]
- if reachingDefIndex is -1, the low half is defined at START of the basic block
- if reachingDefIndex is -2, the high half is defined at START of the basic block
-*/
-RegAccessType insertDefUsePair(int reachingDefIndex) {
- int k = reachingDefIndex;
- DefUsePair* tableIndex = NULL;
- DefOrUse theDef;
- theDef.regNum = 0;
- if(k < 0) {
- /* def at start of the basic blcok */
- theDef.offsetPC = PC_FOR_START_OF_BB;
- theDef.accessType = REGACCESS_D;
- if(k == -1) //low half of variable
- theDef.regNum = currentInfo.regNum;
- if(k == -2) //high half of variable
- theDef.regNum = currentInfo.regNum+1;
- theDef.physicalType = LowOpndRegType_gp;
- }
- else {
- theDef = currentInfo.reachingDefs[k];
- }
- tableIndex = searchDefUseTable(theDef.offsetPC, theDef.regNum, theDef.physicalType);
- if(tableIndex == NULL) //insert an entry
- tableIndex = insertADef(theDef.offsetPC, theDef.regNum, theDef.physicalType, theDef.accessType);
- else
- tableIndex->def.accessType = theDef.accessType;
- RegAccessType useType = insertAUse(tableIndex, offsetPC, currentInfo.regNum, currentInfo.physicalType);
- return useType;
-}
-
-//! insert a XFER_MEM_TO_XMM to currentBB->xferPoints
-
-//!
-void insertLoadXfer(int offset, int regNum, LowOpndRegType pType) {
- //check whether it is already in currentBB->xferPoints
- int k;
- for(k = 0; k < currentBB->num_xfer_points; k++) {
- if(currentBB->xferPoints[k].xtype == XFER_MEM_TO_XMM &&
- currentBB->xferPoints[k].offsetPC == offset &&
- currentBB->xferPoints[k].regNum == regNum &&
- currentBB->xferPoints[k].physicalType == pType)
- return;
- }
- currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_MEM_TO_XMM;
- currentBB->xferPoints[currentBB->num_xfer_points].regNum = regNum;
- currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = offset;
- currentBB->xferPoints[currentBB->num_xfer_points].physicalType = pType;
-#ifdef DEBUG_XFER_POINTS
- ALOGI("insert to xferPoints %d: XFER_MEM_TO_XMM of VR %d %d at %d", currentBB->num_xfer_points, regNum, pType, offset);
-#endif
- currentBB->num_xfer_points++;
- if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
- ALOGE("too many xfer points");
- dvmAbort();
- }
-}
-
-/** update defUseTable by assuming a fake usage at END of a basic block for variable @ currentInfo
- create a fake usage at end of a basic block for variable B (currentInfo.physicalType, currentInfo.regNum)
- get reaching def info for variable B and store the info in currentInfo.reachingDefs
- for each virtual register (variable A) accessed in the basic block
- update reaching defs of B by checking reaching defs of variable A
- update defUseTable
-*/
-int fakeUsageAtEndOfBB(BasicBlock_O1* bb) {
- currentInfo.accessType = REGACCESS_U;
- LowOpndRegType typeB = currentInfo.physicalType;
- int regB = currentInfo.regNum;
- int jj, k;
- currentInfo.num_reaching_defs = 0;
- for(jj = 0; jj < bb->num_regs; jj++) {
- int regA = bb->infoBasicBlock[jj].regNum;
- LowOpndRegType typeA = bb->infoBasicBlock[jj].physicalType;
- OverlapCase isBPartiallyOverlapA = getBPartiallyOverlapA(regB, typeB, regA, typeA);
- if(regA == regB && typeA == typeB) {
- /* copy reachingDefs from variable A */
- currentInfo.num_reaching_defs = bb->infoBasicBlock[jj].num_reaching_defs;
- for(k = 0; k < currentInfo.num_reaching_defs; k++)
- currentInfo.reachingDefs[k] = bb->infoBasicBlock[jj].reachingDefs[k];
- break;
- }
- else if(isBPartiallyOverlapA != OVERLAP_NO) {
- /* B overlaps with A */
- /* update reaching defs of variable B by checking reaching defs of bb->infoBasicBlock[jj] */
- updateReachingDefB1(jj);
- updateReachingDefB2(); //merge currentInfo with tmpInfo
- }
- }
- /* update defUseTable by checking currentInfo */
- updateDefUseTable();
- return 0;
-}
-
-/** update xferPoints of currentBB
- Traverse currentBB->defUseTable
-*/
-int updateXferPoints() {
- int k = 0;
- currentBB->num_xfer_points = 0;
- DefUsePair* ptr = currentBB->defUseTable;
- DefOrUseLink* ptrUse = NULL;
- /* traverse the def use chain of the basic block */
- while(ptr != NULL) {
- LowOpndRegType defType = ptr->def.physicalType;
- //if definition is for a variable of 32 bits
- if(getRegSize(defType) == OpndSize_32) {
- /* check usages of the definition, whether it reaches a GPR, a XMM, a FS, or a SS */
- bool hasGpUsage = false;
- bool hasGpUsage2 = false; //not a fake usage
- bool hasXmmUsage = false;
- bool hasFSUsage = false;
- bool hasSSUsage = false;
- ptrUse = ptr->uses;
- while(ptrUse != NULL) {
- if(ptrUse->physicalType == LowOpndRegType_gp) {
- hasGpUsage = true;
- if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
- hasGpUsage2 = true;
- }
- if(ptrUse->physicalType == LowOpndRegType_ss) hasSSUsage = true;
- if(ptrUse->physicalType == LowOpndRegType_fs ||
- ptrUse->physicalType == LowOpndRegType_fs_s)
- hasFSUsage = true;
- if(ptrUse->physicalType == LowOpndRegType_xmm) {
- hasXmmUsage = true;
- }
- if(ptrUse->physicalType == LowOpndRegType_xmm ||
- ptrUse->physicalType == LowOpndRegType_ss) {
- /* if a 32-bit definition reaches a xmm usage or a SS usage,
- insert a XFER_MEM_TO_XMM */
- insertLoadXfer(ptrUse->offsetPC,
- ptrUse->regNum, LowOpndRegType_xmm);
- }
- ptrUse = ptrUse->next;
- }
- if(((hasXmmUsage || hasFSUsage || hasSSUsage) && defType == LowOpndRegType_gp) ||
- (hasGpUsage && defType == LowOpndRegType_fs) ||
- (defType == LowOpndRegType_ss && (hasGpUsage || hasXmmUsage || hasFSUsage))) {
- /* insert a transfer if def is on a GPR, usage is on a XMM, FS or SS
- if def is on a FS, usage is on a GPR
- if def is on a SS, usage is on a GPR, XMM or FS
- transfer type is XFER_DEF_TO_GP_MEM if a real GPR usage exisits
- transfer type is XFER_DEF_TO_GP otherwise*/
- currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = ptr->def.offsetPC;
- currentBB->xferPoints[currentBB->num_xfer_points].regNum = ptr->def.regNum;
- currentBB->xferPoints[currentBB->num_xfer_points].physicalType = ptr->def.physicalType;
- if(hasGpUsage2) { //create an entry XFER_DEF_TO_GP_MEM
- currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_TO_GP_MEM;
- }
- else { //create an entry XFER_DEF_TO_MEM
- currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_TO_MEM;
- }
- currentBB->xferPoints[currentBB->num_xfer_points].tableIndex = k;
-#ifdef DEBUG_XFER_POINTS
- ALOGI("insert XFER %d at def %d: V%d %d", currentBB->num_xfer_points, ptr->def.offsetPC, ptr->def.regNum, defType);
-#endif
- currentBB->num_xfer_points++;
- if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
- ALOGE("too many xfer points");
- dvmAbort();
- }
- }
- }
- else { /* def is on 64 bits */
- bool hasGpUsageOfL = false; //exist a GPR usage of the low half
- bool hasGpUsageOfH = false; //exist a GPR usage of the high half
- bool hasGpUsageOfL2 = false;
- bool hasGpUsageOfH2 = false;
- bool hasMisaligned = false;
- bool hasAligned = false;
- bool hasFSUsage = false;
- bool hasSSUsage = false;
- ptrUse = ptr->uses;
- while(ptrUse != NULL) {
- if(ptrUse->physicalType == LowOpndRegType_gp &&
- ptrUse->regNum == ptr->def.regNum) {
- hasGpUsageOfL = true;
- if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
- hasGpUsageOfL2 = true;
- }
- if(ptrUse->physicalType == LowOpndRegType_gp &&
- ptrUse->regNum == ptr->def.regNum + 1) {
- hasGpUsageOfH = true;
- if(ptrUse->offsetPC != PC_FOR_END_OF_BB)
- hasGpUsageOfH2 = true;
- }
- if(ptrUse->physicalType == LowOpndRegType_xmm &&
- ptrUse->regNum == ptr->def.regNum) {
- hasAligned = true;
- /* if def is on FS and use is on XMM, insert a XFER_MEM_TO_XMM */
- if(defType == LowOpndRegType_fs)
- insertLoadXfer(ptrUse->offsetPC,
- ptrUse->regNum, LowOpndRegType_xmm);
- }
- if(ptrUse->physicalType == LowOpndRegType_fs ||
- ptrUse->physicalType == LowOpndRegType_fs_s)
- hasFSUsage = true;
- if(ptrUse->physicalType == LowOpndRegType_xmm &&
- ptrUse->regNum != ptr->def.regNum) {
- hasMisaligned = true;
- /* if use is on XMM and use and def are misaligned, insert a XFER_MEM_TO_XMM */
- insertLoadXfer(ptrUse->offsetPC,
- ptrUse->regNum, LowOpndRegType_xmm);
- }
- if(ptrUse->physicalType == LowOpndRegType_ss) {
- hasSSUsage = true;
- /* if use is on SS, insert a XFER_MEM_TO_XMM */
- insertLoadXfer(ptrUse->offsetPC,
- ptrUse->regNum, LowOpndRegType_ss);
- }
- ptrUse = ptrUse->next;
- }
- if(defType == LowOpndRegType_fs && !hasGpUsageOfL && !hasGpUsageOfH) {
- ptr = ptr->next;
- continue;
- }
- if(defType == LowOpndRegType_xmm && !hasFSUsage &&
- !hasGpUsageOfL && !hasGpUsageOfH && !hasMisaligned && !hasSSUsage) {
- ptr = ptr->next;
- continue;
- }
- /* insert a XFER_DEF_IS_XMM */
- currentBB->xferPoints[currentBB->num_xfer_points].regNum = ptr->def.regNum;
- currentBB->xferPoints[currentBB->num_xfer_points].offsetPC = ptr->def.offsetPC;
- currentBB->xferPoints[currentBB->num_xfer_points].physicalType = ptr->def.physicalType;
- currentBB->xferPoints[currentBB->num_xfer_points].xtype = XFER_DEF_IS_XMM;
- currentBB->xferPoints[currentBB->num_xfer_points].vr_gpl = -1;
- currentBB->xferPoints[currentBB->num_xfer_points].vr_gph = -1;
- if(hasGpUsageOfL2) currentBB->xferPoints[currentBB->num_xfer_points].vr_gpl = ptr->def.regNum;
- if(hasGpUsageOfH2) currentBB->xferPoints[currentBB->num_xfer_points].vr_gph = ptr->def.regNum+1;
- currentBB->xferPoints[currentBB->num_xfer_points].dumpToMem = true;
- currentBB->xferPoints[currentBB->num_xfer_points].dumpToXmm = false; //not used in updateVirtualReg
- if(hasAligned) currentBB->xferPoints[currentBB->num_xfer_points].dumpToXmm = true;
- currentBB->xferPoints[currentBB->num_xfer_points].tableIndex = k;
-#ifdef DEBUG_XFER_POINTS
- ALOGI("insert XFER %d at def %d: V%d %d", currentBB->num_xfer_points, ptr->def.offsetPC, ptr->def.regNum, defType);
-#endif
- currentBB->num_xfer_points++;
- if(currentBB->num_xfer_points >= MAX_XFER_PER_BB) {
- ALOGE("too many xfer points");
- dvmAbort();
- }
- }
- ptr = ptr->next;
- } //while ptr
-#ifdef DEBUG_XFER_POINTS
- ALOGI("XFER points for current basic block ------");
- for(k = 0; k < currentBB->num_xfer_points; k++) {
- ALOGI(" at offset %x, VR %d %d: type %d, vr_gpl %d, vr_gph %d, dumpToMem %d, dumpToXmm %d",
- currentBB->xferPoints[k].offsetPC, currentBB->xferPoints[k].regNum,
- currentBB->xferPoints[k].physicalType, currentBB->xferPoints[k].xtype,
- currentBB->xferPoints[k].vr_gpl, currentBB->xferPoints[k].vr_gph,
- currentBB->xferPoints[k].dumpToMem, currentBB->xferPoints[k].dumpToXmm);
- }
-#endif
- return -1;
-}
-
-//! update memVRTable[].ranges by browsing the defUseTable
-
-//! each virtual register has a list of live ranges, and each live range has a list of PCs that access the VR
-void updateLiveTable() {
- DefUsePair* ptr = currentBB->defUseTable;
- while(ptr != NULL) {
- bool updateUse = false;
- if(ptr->num_uses == 0) {
- ptr->num_uses = 1;
- ptr->uses = (DefOrUseLink*)malloc(sizeof(DefOrUseLink));
- if(ptr->uses == NULL) {
- ALOGE("Memory allocation failed");
- return;
- }
- ptr->uses->accessType = REGACCESS_D;
- ptr->uses->regNum = ptr->def.regNum;
- ptr->uses->offsetPC = ptr->def.offsetPC;
- ptr->uses->physicalType = ptr->def.physicalType;
- ptr->uses->next = NULL;
- ptr->useTail = ptr->uses;
- updateUse = true;
- }
- DefOrUseLink* ptrUse = ptr->uses;
- while(ptrUse != NULL) {
- RegAccessType useType = ptrUse->accessType;
- if(useType == REGACCESS_L || useType == REGACCESS_D) {
- int indexL = searchMemTable(ptrUse->regNum);
- if(indexL >= 0)
- mergeLiveRange(indexL, ptr->def.offsetPC,
- ptrUse->offsetPC); //tableIndex, start PC, end PC
- }
- if(getRegSize(ptrUse->physicalType) == OpndSize_64 &&
- (useType == REGACCESS_H || useType == REGACCESS_D)) {
- int indexH = searchMemTable(ptrUse->regNum+1);
- if(indexH >= 0)
- mergeLiveRange(indexH, ptr->def.offsetPC,
- ptrUse->offsetPC);
- }
- ptrUse = ptrUse->next;
- }//while ptrUse
- if(updateUse) {
- ptr->num_uses = 0;
- free(ptr->uses);
- ptr->uses = NULL;
- ptr->useTail = NULL;
- }
- ptr = ptr->next;
- }//while ptr
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVE TABLE");
- for(int k = 0; k < num_memory_vr; k++) {
- ALOGI("VR %d live ", memVRTable[k].regNum);
- LiveRange* ptr = memVRTable[k].ranges;
- while(ptr != NULL) {
- ALOGI("[%x %x] (", ptr->start, ptr->end);
- for(int k3 = 0; k3 < ptr->num_access; k3++)
- ALOGI("%x ", ptr->accessPC[k3]);
- ALOGI(") ");
- ptr = ptr->next;
- }
- ALOGI("");
- }
-#endif
-}
-
-//!add a live range [rangeStart, rangeEnd] to ranges of memVRTable, merge to existing live ranges if necessary
-
-//!ranges are in increasing order of startPC
-void mergeLiveRange(int tableIndex, int rangeStart, int rangeEnd) {
- if(rangeStart == PC_FOR_START_OF_BB) rangeStart = currentBB->pc_start;
- if(rangeEnd == PC_FOR_END_OF_BB) rangeEnd = currentBB->pc_end;
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE call mergeLiveRange on tableIndex %d with [%x %x]", tableIndex, rangeStart, rangeEnd);
-#endif
- int startIndex = -1, endIndex = -1;
- bool startBeforeRange = false, endBeforeRange = false; //before the index or in the range
- bool startDone = false, endDone = false;
- LiveRange* ptr = memVRTable[tableIndex].ranges;
- LiveRange* ptrStart = NULL;
- LiveRange* ptrStart_prev = NULL;
- LiveRange* ptrEnd = NULL;
- LiveRange* ptrEnd_prev = NULL;
- int k = 0;
- while(ptr != NULL) {
- if(!startDone) {
- if(ptr->start <= rangeStart &&
- ptr->end >= rangeStart) {
- startIndex = k;
- ptrStart = ptr;
- startBeforeRange = false;
- startDone = true;
- }
- else if(ptr->start > rangeStart) {
- startIndex = k;
- ptrStart = ptr;
- startBeforeRange = true;
- startDone = true;
- }
- }
- if(!startDone) ptrStart_prev = ptr;
- if(!endDone) {
- if(ptr->start <= rangeEnd &&
- ptr->end >= rangeEnd) {
- endIndex = k;
- ptrEnd = ptr;
- endBeforeRange = false;
- endDone = true;
- }
- else if(ptr->start > rangeEnd) {
- endIndex = k;
- ptrEnd = ptr;
- endBeforeRange = true;
- endDone = true;
- }
- }
- if(!endDone) ptrEnd_prev = ptr;
- ptr = ptr->next;
- k++;
- } //while
- if(!startDone) { //both can be NULL
- startIndex = memVRTable[tableIndex].num_ranges;
- ptrStart = NULL; //ptrStart_prev should be the last live range
- startBeforeRange = true;
- }
- //if endDone, ptrEnd is not NULL, ptrEnd_prev can be NULL
- if(!endDone) { //both can be NULL
- endIndex = memVRTable[tableIndex].num_ranges;
- ptrEnd = NULL;
- endBeforeRange = true;
- }
- if(startIndex == endIndex && startBeforeRange && endBeforeRange) { //insert at startIndex
- //3 cases depending on BeforeRange when startIndex == endIndex
- //insert only if both true
- //merge otherwise
- /////////// insert before ptrStart
- LiveRange* currRange = (LiveRange *)malloc(sizeof(LiveRange));
- if(ptrStart_prev == NULL) {
- currRange->next = memVRTable[tableIndex].ranges;
- memVRTable[tableIndex].ranges = currRange;
- } else {
- currRange->next = ptrStart_prev->next;
- ptrStart_prev->next = currRange;
- }
- currRange->start = rangeStart;
- currRange->end = rangeEnd;
- currRange->accessPC = (int *)malloc(sizeof(int) * NUM_ACCESS_IN_LIVERANGE);
- currRange->num_alloc = NUM_ACCESS_IN_LIVERANGE;
- if(rangeStart != rangeEnd) {
- currRange->num_access = 2;
- currRange->accessPC[0] = rangeStart;
- currRange->accessPC[1] = rangeEnd;
- } else {
- currRange->num_access = 1;
- currRange->accessPC[0] = rangeStart;
- }
- memVRTable[tableIndex].num_ranges++;
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE insert one live range [%x %x] to tableIndex %d", rangeStart, rangeEnd, tableIndex);
-#endif
- return;
- }
- if(!endBeforeRange) { //here ptrEnd is not NULL
- endIndex++; //next
- ptrEnd_prev = ptrEnd; //ptrEnd_prev is not NULL
- ptrEnd = ptrEnd->next; //ptrEnd can be NULL
- }
- if(endIndex < startIndex+1) ALOGE("mergeLiveRange endIndex %d startIndex %d", endIndex, startIndex);
- ///////// use ptrStart & ptrEnd_prev
- if(ptrStart == NULL || ptrEnd_prev == NULL) {
- ALOGE("mergeLiveRange ptr is NULL");
- return;
- }
- //endIndex > startIndex (merge the ranges between startIndex and endIndex-1)
- //update ptrStart
- if(ptrStart->start > rangeStart)
- ptrStart->start = rangeStart; //min of old start & rangeStart
- ptrStart->end = ptrEnd_prev->end; //max of old end & rangeEnd
- if(rangeEnd > ptrStart->end)
- ptrStart->end = rangeEnd;
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE merge entries for tableIndex %d from %d to %d", tableIndex, startIndex+1, endIndex-1);
-#endif
- if(ptrStart->num_access <= 0) ALOGE("mergeLiveRange number of access");
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE tableIndex %d startIndex %d num_access %d (", tableIndex, startIndex, ptrStart->num_access);
- for(k = 0; k < ptrStart->num_access; k++)
- ALOGI("%x ", ptrStart->accessPC[k]);
- ALOGI(")");
-#endif
- ///// go through pointers from ptrStart->next to ptrEnd
- //from startIndex+1 to endIndex-1
- ptr = ptrStart->next;
- while(ptr != NULL && ptr != ptrEnd) {
- int k2;
- for(k2 = 0; k2 < ptr->num_access; k2++) { //merge to startIndex
- insertAccess(tableIndex, ptrStart, ptr->accessPC[k2]);
- }//k2
- ptr = ptr->next;
- }
- insertAccess(tableIndex, ptrStart, rangeStart);
- insertAccess(tableIndex, ptrStart, rangeEnd);
- //remove startIndex+1 to endIndex-1
- if(startIndex+1 < endIndex) {
- ptr = ptrStart->next;
- while(ptr != NULL && ptr != ptrEnd) {
- LiveRange* tmpP = ptr->next;
- free(ptr->accessPC);
- free(ptr);
- ptr = tmpP;
- }
- ptrStart->next = ptrEnd;
- }
- memVRTable[tableIndex].num_ranges -= (endIndex - startIndex - 1);
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("num_ranges for VR %d: %d", memVRTable[tableIndex].regNum, memVRTable[tableIndex].num_ranges);
-#endif
-}
-//! insert an access to a given live range, in order
-
-//!
-void insertAccess(int tableIndex, LiveRange* startP, int rangeStart) {
- int k3, k4;
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE insertAccess %d %x", tableIndex, rangeStart);
-#endif
- int insertIndex = -1;
- for(k3 = 0; k3 < startP->num_access; k3++) {
- if(startP->accessPC[k3] == rangeStart) {
- return;
- }
- if(startP->accessPC[k3] > rangeStart) {
- insertIndex = k3;
- break;
- }
- }
-
- //insert here
- k3 = insertIndex;
- if(insertIndex == -1) {
- k3 = startP->num_access;
- }
- if(startP->num_access == startP->num_alloc) {
- int currentAlloc = startP->num_alloc;
- startP->num_alloc += NUM_ACCESS_IN_LIVERANGE;
- int* tmpPtr = (int *)malloc(sizeof(int) * startP->num_alloc);
- for(k4 = 0; k4 < currentAlloc; k4++)
- tmpPtr[k4] = startP->accessPC[k4];
- free(startP->accessPC);
- startP->accessPC = tmpPtr;
- }
- //insert accessPC
- for(k4 = startP->num_access-1; k4 >= k3; k4--)
- startP->accessPC[k4+1] = startP->accessPC[k4];
- startP->accessPC[k3] = rangeStart;
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("LIVERANGE insert %x to tableIndex %d", rangeStart, tableIndex);
-#endif
- startP->num_access++;
- return;
-}
-
-/////////////////////////////////////////////////////////////////////
-bool isInMemory(int regNum, OpndSize size);
-void setVRToMemory(int regNum, OpndSize size);
-bool isVRLive(int vA);
-int getSpillIndex(bool isGLUE, OpndSize size);
-void clearVRToMemory(int regNum, OpndSize size);
-void clearVRNullCheck(int regNum, OpndSize size);
-
-inline int getSpillLocDisp(int offset) {
-#ifdef SPILL_IN_THREAD
- return offset+offsetof(Thread, spillRegion);;
-#else
- return offset+offEBP_spill;
-#endif
-}
-#if 0
-/* used if we keep self pointer in a physical register */
-inline int getSpillLocReg(int offset) {
- return PhysicalReg_Glue;
-}
-#endif
-#ifdef SPILL_IN_THREAD
-inline void loadFromSpillRegion_with_self(OpndSize size, int reg_self, bool selfPhysical, int reg, int offset) {
- /* only 1 instruction is generated by move_mem_to_reg_noalloc */
- move_mem_to_reg_noalloc(size,
- getSpillLocDisp(offset), reg_self, selfPhysical,
- MemoryAccess_SPILL, offset,
- reg, true);
-}
-inline void loadFromSpillRegion(OpndSize size, int reg, int offset) {
- get_self_pointer(C_SCRATCH_1, isScratchPhysical);
- int reg_self = registerAlloc(LowOpndRegType_scratch, C_SCRATCH_1, isScratchPhysical, false);
- /* only 1 instruction is generated by move_mem_to_reg_noalloc */
- move_mem_to_reg_noalloc(size,
- getSpillLocDisp(offset), reg_self, true,
- MemoryAccess_SPILL, offset,
- reg, true);
-}
-inline void saveToSpillRegion_with_self(OpndSize size, int selfReg, bool selfPhysical, int reg, int offset) {
- move_reg_to_mem_noalloc(size,
- reg, true,
- getSpillLocDisp(offset), selfReg, selfPhysical,
- MemoryAccess_SPILL, offset);
-}
-inline void saveToSpillRegion(OpndSize size, int reg, int offset) {
- get_self_pointer(C_SCRATCH_1, isScratchPhysical);
- int reg_self = registerAlloc(LowOpndRegType_scratch, C_SCRATCH_1, isScratchPhysical, false);
- move_reg_to_mem_noalloc(size,
- reg, true,
- getSpillLocDisp(offset), reg_self, true,
- MemoryAccess_SPILL, offset);
-}
-#else
-inline void loadFromSpillRegion(OpndSize size, int reg, int offset) {
- /* only 1 instruction is generated by move_mem_to_reg_noalloc */
- move_mem_to_reg_noalloc(size,
- getSpillLocDisp(offset), PhysicalReg_EBP, true,
- MemoryAccess_SPILL, offset,
- reg, true);
-}
-inline void saveToSpillRegion(OpndSize size, int reg, int offset) {
- move_reg_to_mem_noalloc(size,
- reg, true,
- getSpillLocDisp(offset), PhysicalReg_EBP, true,
- MemoryAccess_SPILL, offset);
-}
-#endif
-
-//! dump an immediate to memory, set inMemory to true
-
-//!
-void dumpImmToMem(int vrNum, OpndSize size, int value) {
- if(isInMemory(vrNum, size)) {
-#ifdef DEBUG_SPILL
- ALOGI("Skip dumpImmToMem vA %d size %d", vrNum, size);
-#endif
- return;
- }
- set_VR_to_imm_noalloc(vrNum, size, value);
- setVRToMemory(vrNum, size);
-}
-//! dump content of a VR to memory, set inMemory to true
-
-//!
-void dumpToMem(int vrNum, LowOpndRegType type, int regAll) { //ss,gp,xmm
- if(isInMemory(vrNum, getRegSize(type))) {
-#ifdef DEBUG_SPILL
- ALOGI("Skip dumpToMem vA %d type %d", vrNum, type);
-#endif
- return;
- }
- if(type == LowOpndRegType_gp || type == LowOpndRegType_xmm)
- set_virtual_reg_noalloc(vrNum, getRegSize(type), regAll, true);
- if(type == LowOpndRegType_ss)
- move_ss_reg_to_mem_noalloc(regAll, true,
- 4*vrNum, PhysicalReg_FP, true,
- MemoryAccess_VR, vrNum);
- setVRToMemory(vrNum, getRegSize(type));
-}
-//! dump part of a 64-bit VR to memory and update inMemory
-
-//! isLow tells whether low half or high half is dumped
-void dumpPartToMem(int reg /*xmm physical reg*/, int vA, bool isLow) {
- if(isLow) {
- if(isInMemory(vA, OpndSize_32)) {
-#ifdef DEBUG_SPILL
- ALOGI("Skip dumpPartToMem isLow %d vA %d", isLow, vA);
-#endif
- return;
- }
- }
- else {
- if(isInMemory(vA+1, OpndSize_32)) {
-#ifdef DEBUG_SPILL
- ALOGI("Skip dumpPartToMem isLow %d vA %d", isLow, vA);
-#endif
- return;
- }
- }
- if(isLow) {
- if(!isVRLive(vA)) return;
- }
- else {
- if(!isVRLive(vA+1)) return;
- }
- //move part to vA or vA+1
- if(isLow) {
- move_ss_reg_to_mem_noalloc(reg, true,
- 4*vA, PhysicalReg_FP, true, MemoryAccess_VR, vA);
- } else {
- int k = getSpillIndex(false, OpndSize_64);
- //H, L in 4*k+4 & 4*k
-#ifdef SPILL_IN_THREAD
- get_self_pointer(PhysicalReg_SCRATCH_1, isScratchPhysical);
- saveToSpillRegion_with_self(OpndSize_64, PhysicalReg_SCRATCH_1, isScratchPhysical, reg, 4*k);
- //update low 32 bits of xmm reg from 4*k+4
- move_ss_mem_to_reg(NULL,
- getSpillLocDisp(4*k+4), PhysicalReg_SCRATCH_1, isScratchPhysical,
- reg, true);
-#else
- saveToSpillRegion(OpndSize_64, reg, 4*k);
- //update low 32 bits of xmm reg from 4*k+4
- move_ss_mem_to_reg_noalloc(
- getSpillLocDisp(4*k+4), PhysicalReg_EBP, true,
- MemoryAccess_SPILL, 4*k+4,
- reg, true);
-#endif
- //move low 32 bits of xmm reg to vA+1
- move_ss_reg_to_mem_noalloc(reg, true, 4*(vA+1), PhysicalReg_FP, true, MemoryAccess_VR, vA+1);
- }
- if(isLow)
- setVRToMemory(vA, OpndSize_32);
- else
- setVRToMemory(vA+1, OpndSize_32);
-}
-void clearVRBoundCheck(int regNum, OpndSize size);
-//! the content of a VR is no longer in memory or in physical register if the latest content of a VR is constant
-
-//! clear nullCheckDone; if another VR is overlapped with the given VR, the content of that VR is no longer in physical register
-void invalidateVRDueToConst(int reg, OpndSize size) {
- clearVRToMemory(reg, size); //memory content is out-dated
- clearVRNullCheck(reg, size);
- clearVRBoundCheck(reg, size);
- //check reg,gp reg,ss reg,xmm reg-1,xmm
- //if size is 64: check reg+1,gp|ss reg+1,xmm
- int index;
- //if VR is xmm, check whether we need to dump part of VR to memory
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_xmm);
-#endif
- if(size == OpndSize_32)
- dumpPartToMem(compileTable[index].physicalReg, reg, false); //dump high of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg-1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg-1, LowOpndRegType_xmm);
-#endif
- dumpPartToMem(compileTable[index].physicalReg, reg-1, true); //dump low of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_gp);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_ss);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- if(size == OpndSize_64) {
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_xmm);
-#endif
- dumpPartToMem(compileTable[index].physicalReg, reg+1, false); //dump high of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_gp);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_ss);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
-}
-//! check which physical registers hold out-dated content if there is a def
-
-//! if another VR is overlapped with the given VR, the content of that VR is no longer in physical register
-//! should we update inMemory?
-void invalidateVR(int reg, LowOpndRegType pType) {
- //def at fs: content of xmm & gp & ss are out-dated (reg-1,xmm reg,xmm reg+1,xmm) (reg,gp|ss reg+1,gp|ss)
- //def at xmm: content of misaligned xmm & gp are out-dated (reg-1,xmm reg+1,xmm) (reg,gp|ss reg+1,gp|ss)
- //def at fs_s: content of xmm & gp are out-dated (reg-1,xmm reg,xmm) (reg,gp|ss)
- //def at gp: content of xmm is out-dated (reg-1,xmm reg,xmm) (reg,ss)
- //def at ss: content of xmm & gp are out-dated (reg-1,xmm reg,xmm) (reg,gp)
- int index;
- if(pType != LowOpndRegType_xmm) { //check xmm @reg
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_xmm);
-#endif
- if(getRegSize(pType) == OpndSize_32)
- dumpPartToMem(compileTable[index].physicalReg, reg, false); //dump high of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
- //check misaligned xmm @ reg-1
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg-1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg-1, LowOpndRegType_xmm);
-#endif
- dumpPartToMem(compileTable[index].physicalReg, reg-1, true); //dump low of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- //check misaligned xmm @ reg+1
- if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
- //check reg+1,xmm
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_xmm, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_xmm);
-#endif
- dumpPartToMem(compileTable[index].physicalReg, reg+1, false); //dump high of xmm to memory
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
- if(pType != LowOpndRegType_gp) {
- //check reg,gp
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_gp);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
- if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
- //check reg+1,gp
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_gp);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
- if(pType != LowOpndRegType_ss) {
- //check reg,ss
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg, LowOpndRegType_ss);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
- if(pType == LowOpndRegType_xmm || pType == LowOpndRegType_fs) {
- //check reg+1,ss
- index = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_ss, reg+1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_INVALIDATE
- ALOGI("INVALIDATE virtual reg %d type %d", reg+1, LowOpndRegType_ss);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- }
- }
-}
-//! bookkeeping when a VR is updated
-
-//! invalidate contents of some physical registers, clear nullCheckDone, and update inMemory;
-//! check whether there exist tranfer points for this bytecode, if yes, perform the transfer
-int updateVirtualReg(int reg, LowOpndRegType pType) {
- int k;
- OpndSize size = getRegSize(pType);
- //WAS only invalidate xmm VRs for the following cases:
- //if def reaches a use of vA,xmm and (the def is not xmm or is misaligned xmm)
- // invalidate "vA,xmm"
- invalidateVR(reg, pType);
- clearVRNullCheck(reg, size);
- clearVRBoundCheck(reg, size);
- if(pType == LowOpndRegType_fs || pType == LowOpndRegType_fs_s)
- setVRToMemory(reg, size);
- else {
- clearVRToMemory(reg, size);
- }
- for(k = 0; k < currentBB->num_xfer_points; k++) {
- if(currentBB->xferPoints[k].offsetPC == offsetPC &&
- currentBB->xferPoints[k].regNum == reg &&
- currentBB->xferPoints[k].physicalType == pType &&
- currentBB->xferPoints[k].xtype != XFER_MEM_TO_XMM) {
- //perform the corresponding action for the def
- PhysicalReg regAll;
- if(currentBB->xferPoints[k].xtype == XFER_DEF_IS_XMM) {
- //def at fs: content of xmm is out-dated
- //def at xmm: content of misaligned xmm is out-dated
- //invalidateXmmVR(currentBB->xferPoints[k].tableIndex);
-#ifdef DEBUG_XFER_POINTS
- if(currentBB->xferPoints[k].dumpToXmm) ALOGI("XFER set_virtual_reg to xmm: xmm VR %d", reg);
-#endif
- if(pType == LowOpndRegType_xmm) {
-#ifdef DEBUG_XFER_POINTS
- ALOGI("XFER set_virtual_reg to memory: xmm VR %d", reg);
-#endif
- PhysicalReg regAll = (PhysicalReg)checkVirtualReg(reg, LowOpndRegType_xmm, 0 /* do not update*/);
- dumpToMem(reg, LowOpndRegType_xmm, regAll);
- }
- if(currentBB->xferPoints[k].vr_gpl >= 0) { //
- }
- if(currentBB->xferPoints[k].vr_gph >= 0) {
- }
- }
- if((pType == LowOpndRegType_gp || pType == LowOpndRegType_ss) &&
- (currentBB->xferPoints[k].xtype == XFER_DEF_TO_MEM ||
- currentBB->xferPoints[k].xtype == XFER_DEF_TO_GP_MEM)) {
- //the defined gp VR already in register
- //invalidateXmmVR(currentBB->xferPoints[k].tableIndex);
- regAll = (PhysicalReg)checkVirtualReg(reg, pType, 0 /* do not update*/);
- dumpToMem(reg, pType, regAll);
-#ifdef DEBUG_XFER_POINTS
- ALOGI("XFER set_virtual_reg to memory: gp VR %d", reg);
-#endif
- }
- if((pType == LowOpndRegType_fs_s || pType == LowOpndRegType_ss) &&
- currentBB->xferPoints[k].xtype == XFER_DEF_TO_GP_MEM) {
- }
- }
- }
- return -1;
-}
-////////////////////////////////////////////////////////////////
-//REGISTER ALLOCATION
-int spillForHardReg(int regNum, int type);
-void decreaseRefCount(int index);
-int getFreeReg(int type, int reg, int indexToCompileTable);
-PhysicalReg spillForLogicalReg(int type, int reg, int indexToCompileTable);
-int unspillLogicalReg(int spill_index, int physicalReg);
-int searchVirtualInfoOfBB(LowOpndRegType type, int regNum, BasicBlock_O1* bb);
-bool isTemp8Bit(int type, int reg);
-bool matchType(int typeA, int typeB);
-int getNextAccess(int compileIndex);
-void dumpCompileTable();
-
-//! allocate a register for a variable
-
-//!if no physical register is free, call spillForLogicalReg to free up a physical register;
-//!if the variable is a temporary and it was spilled, call unspillLogicalReg to load from spill location to the allocated physical register;
-//!if updateRefCount is true, reduce reference count of the variable by 1
-int registerAlloc(int type, int reg, bool isPhysical, bool updateRefCount) {
-#ifdef DEBUG_REGALLOC
- ALOGI("%p: try to allocate register %d type %d isPhysical %d", currentBB, reg, type, isPhysical);
-#endif
- if(currentBB == NULL) {
- if(type & LowOpndRegType_virtual) return PhysicalReg_Null;
- if(isPhysical) return reg; //for helper functions
- return PhysicalReg_Null;
- }
- //ignore EDI, ESP, EBP (glue)
- if(isPhysical && (reg == PhysicalReg_EDI || reg == PhysicalReg_ESP ||
- reg == PhysicalReg_EBP || reg == PhysicalReg_Null))
- return reg;
-
- int newType = convertType(type, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int tIndex = searchCompileTable(newType, reg);
- if(tIndex < 0) {
- ALOGE("reg %d type %d not found in registerAlloc", reg, newType);
- return PhysicalReg_Null;
- }
-
- //physical register
- if(isPhysical) {
- if(allRegs[reg].isUsed) { //if used by a non hard-coded register
- spillForHardReg(reg, newType);
- }
- allRegs[reg].isUsed = true;
-#ifdef DEBUG_REG_USED
- ALOGI("REGALLOC: allocate a reg %d", reg);
-#endif
- compileTable[tIndex].physicalReg = reg;
- if(updateRefCount)
- decreaseRefCount(tIndex);
-#ifdef DEBUG_REGALLOC
- ALOGI("REGALLOC: allocate register %d for logical register %d %d",
- compileTable[tIndex].physicalReg, reg, newType);
-#endif
- return reg;
- }
- //already allocated
- if(compileTable[tIndex].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_REGALLOC
- ALOGI("already allocated to physical register %d", compileTable[tIndex].physicalReg);
-#endif
- if(updateRefCount)
- decreaseRefCount(tIndex);
- return compileTable[tIndex].physicalReg;
- }
-
- //at this point, the logical register is not hard-coded and is mapped to Reg_Null
- //first check whether there is a free reg
- //if not, call spillForLogicalReg
- int index = getFreeReg(newType, reg, tIndex);
- if(index >= 0 && index < PhysicalReg_Null) {
- //update compileTable & allRegs
- compileTable[tIndex].physicalReg = allRegs[index].physicalReg;
- allRegs[index].isUsed = true;
-#ifdef DEBUG_REG_USED
- ALOGI("REGALLOC: register %d is free", allRegs[index].physicalReg);
-#endif
- } else {
- PhysicalReg allocR = spillForLogicalReg(newType, reg, tIndex);
- compileTable[tIndex].physicalReg = allocR;
- }
- if(compileTable[tIndex].spill_loc_index >= 0) {
- unspillLogicalReg(tIndex, compileTable[tIndex].physicalReg);
- }
- if(updateRefCount)
- decreaseRefCount(tIndex);
-#ifdef DEBUG_REGALLOC
- ALOGI("REGALLOC: allocate register %d for logical register %d %d",
- compileTable[tIndex].physicalReg, reg, newType);
-#endif
- return compileTable[tIndex].physicalReg;
-}
-//!a variable will use a physical register allocated for another variable
-
-//!This is used when MOVE_OPT is on, it tries to alias a virtual register with a temporary to remove a move
-int registerAllocMove(int reg, int type, bool isPhysical, int srcReg) {
- if(srcReg == PhysicalReg_EDI || srcReg == PhysicalReg_ESP || srcReg == PhysicalReg_EBP)
- ALOGE("can't move from srcReg EDI or ESP or EBP");
-#ifdef DEBUG_REGALLOC
- ALOGI("in registerAllocMove: reg %d type %d srcReg %d", reg, type, srcReg);
-#endif
- int newType = convertType(type, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int index = searchCompileTable(newType, reg);
- if(index < 0) {
- ALOGE("reg %d type %d not found in registerAllocMove", reg, newType);
- return -1;
- }
-
- decreaseRefCount(index);
- compileTable[index].physicalReg = srcReg;
-#ifdef DEBUG_REGALLOC
- ALOGI("REGALLOC: registerAllocMove %d for logical register %d %d",
- compileTable[index].physicalReg, reg, newType);
-#endif
- return srcReg;
-}
-
-//! check whether a physical register is available to be used by a variable
-
-//! data structures accessed:
-//! 1> currentBB->infoBasicBlock[index].allocConstraintsSorted
-//! sorted from high count to low count
-//! 2> currentBB->allocConstraintsSorted
-//! sorted from low count to high count
-//! 3> allRegs: whether a physical register is available, indexed by PhysicalReg
-//! NOTE: if a temporary variable is 8-bit, only %eax, %ebx, %ecx, %edx can be used
-int getFreeReg(int type, int reg, int indexToCompileTable) {
- syncAllRegs();
- /* handles requests for xmm or ss registers */
- int k;
- if(((type & MASK_FOR_TYPE) == LowOpndRegType_xmm) ||
- ((type & MASK_FOR_TYPE) == LowOpndRegType_ss)) {
- for(k = PhysicalReg_XMM0; k <= PhysicalReg_XMM7; k++) {
- if(!allRegs[k].isUsed) return k;
- }
- return -1;
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("USED registers: ");
- for(k = 0; k < 8; k++)
- ALOGI("%d used: %d time freed: %d callee-saveld: %d", k, allRegs[k].isUsed,
- allRegs[k].freeTimeStamp, allRegs[k].isCalleeSaved);
- ALOGI("");
-#endif
-
- /* a VR is requesting a physical register */
- if(isVirtualReg(type)) { //find a callee-saved register
- /* if VR is type GG, check the pre-allocated physical register first */
- bool isGGVR = compileTable[indexToCompileTable].gType == GLOBALTYPE_GG;
- if(isGGVR) {
- int regCandidateT = compileTable[indexToCompileTable].physicalReg_prev;
- if(!allRegs[regCandidateT].isUsed) return regCandidateT;
- }
-
- int index = searchVirtualInfoOfBB((LowOpndRegType)(type&MASK_FOR_TYPE), reg, currentBB);
- if(index < 0) {
- ALOGE("VR %d %d not found in infoBasicBlock of currentBB %d (num of VRs %d)",
- reg, type, currentBB->bb_index, currentBB->num_regs);
- dvmAbort();
- }
-
- /* check allocConstraints for this VR,
- return an available physical register with the highest constraint > 0 */
- for(k = 0; k < 8; k++) {
- if(currentBB->infoBasicBlock[index].allocConstraintsSorted[k].count == 0) break;
- int regCandidateT = currentBB->infoBasicBlock[index].allocConstraintsSorted[k].physicalReg;
- assert(regCandidateT < PhysicalReg_Null);
- if(!allRegs[regCandidateT].isUsed) return regCandidateT;
- }
-
- /* WAS: return an available physical register with the lowest constraint
- NOW: consider a new factor (freeTime) when there is a tie
- if 2 available physical registers have the same number of constraints
- choose the one with smaller free time stamp */
- int currentCount = -1;
- int index1 = -1;
- int smallestTime = -1;
- for(k = 0; k < 8; k++) {
- int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
- assert(regCandidateT < PhysicalReg_Null);
- if(index1 >= 0 && currentBB->allocConstraintsSorted[k].count > currentCount)
- break; //candidate has higher count than index1
- if(!allRegs[regCandidateT].isUsed) {
- if(index1 < 0) {
- index1 = k;
- currentCount = currentBB->allocConstraintsSorted[k].count;
- smallestTime = allRegs[regCandidateT].freeTimeStamp;
- } else if(allRegs[regCandidateT].freeTimeStamp < smallestTime) {
- index1 = k;
- smallestTime = allRegs[regCandidateT].freeTimeStamp;
- }
- }
- }
- if(index1 >= 0) return currentBB->allocConstraintsSorted[index1].physicalReg;
- return -1;
- }
- /* handle request from a temporary variable or a glue variable */
- else {
- bool is8Bit = isTemp8Bit(type, reg);
-
- /* if the temporary variable is linked to a VR and
- the VR is not yet allocated to any physical register */
- int vr_num = compileTable[indexToCompileTable].linkageToVR;
- if(vr_num >= 0) {
- int index3 = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_virtual, vr_num);
- if(index3 < 0) {
- ALOGE("2 in tracing linkage to VR %d", vr_num);
- dvmAbort();
- }
-
- if(compileTable[index3].physicalReg == PhysicalReg_Null) {
- int index2 = searchVirtualInfoOfBB(LowOpndRegType_gp, vr_num, currentBB);
- if(index2 < 0) {
- ALOGE("1 in tracing linkage to VR %d", vr_num);
- dvmAbort();
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("in getFreeReg for temporary reg %d, trace the linkage to VR %d",
- reg, vr_num);
-#endif
-
- /* check allocConstraints on the VR
- return an available physical register with the highest constraint > 0
- */
- for(k = 0; k < 8; k++) {
- if(currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].count == 0) break;
- int regCandidateT = currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].physicalReg;
-#ifdef DEBUG_REGALLOC
- ALOGI("check register %d with count %d", regCandidateT,
- currentBB->infoBasicBlock[index2].allocConstraintsSorted[k].count);
-#endif
- /* if the requesting variable is 8 bit */
- if(is8Bit && regCandidateT > PhysicalReg_EDX) continue;
- assert(regCandidateT < PhysicalReg_Null);
- if(!allRegs[regCandidateT].isUsed) return regCandidateT;
- }
- }
- }
- /* check allocConstraints of the basic block
- if 2 available physical registers have the same constraint count,
- return the non callee-saved physical reg */
- /* enhancement: record the time when a register is freed (freeTimeStamp)
- the purpose is to reduce false dependency
- priority: constraint count, non callee-saved, time freed
- let x be the lowest constraint count
- set A be available callee-saved physical registers with count == x
- set B be available non callee-saved physical registers with count == x
- if set B is not null, return the one with smallest free time
- otherwise, return the one in A with smallest free time
- To ignore whether it is callee-saved, add all candidates to set A
- */
- int setAIndex[8];
- int num_A = 0;
- int setBIndex[8];
- int num_B = 0;
- int index1 = -1; //points to an available physical reg with lowest count
- int currentCount = -1;
- for(k = 0; k < 8; k++) {
- int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
- if(is8Bit && regCandidateT > PhysicalReg_EDX) continue;
-
- if(index1 >= 0 && currentBB->allocConstraintsSorted[k].count > currentCount)
- break; //candidate has higher count than index1
- assert(regCandidateT < PhysicalReg_Null);
- if(!allRegs[regCandidateT].isUsed) {
- /*To ignore whether it is callee-saved, add all candidates to set A */
- if(false) {//!allRegs[regCandidateT].isCalleeSaved) { //add to set B
- setBIndex[num_B++] = k;
- } else { //add to set A
- setAIndex[num_A++] = k;
- }
- if(index1 < 0) {
- /* index1 points to a physical reg with lowest count */
- index1 = k;
- currentCount = currentBB->allocConstraintsSorted[k].count;
- }
- }
- }
-
- int kk;
- int smallestTime = -1;
- index1 = -1;
- for(kk = 0; kk < num_B; kk++) {
- k = setBIndex[kk];
- int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
- assert(regCandidateT < PhysicalReg_Null);
- if(kk == 0 || allRegs[regCandidateT].freeTimeStamp < smallestTime) {
- index1 = k;
- smallestTime = allRegs[regCandidateT].freeTimeStamp;
- }
- }
- if(index1 >= 0)
- return currentBB->allocConstraintsSorted[index1].physicalReg;
- index1 = -1;
- for(kk = 0; kk < num_A; kk++) {
- k = setAIndex[kk];
- int regCandidateT = currentBB->allocConstraintsSorted[k].physicalReg;
- if(kk == 0 || allRegs[regCandidateT].freeTimeStamp < smallestTime) {
- index1 = k;
- smallestTime = allRegs[regCandidateT].freeTimeStamp;
- }
- }
- if(index1 >= 0) return currentBB->allocConstraintsSorted[index1].physicalReg;
- return -1;
- }
- return -1;
-}
-
-//! find a candidate physical register for a variable and spill all variables that are mapped to the candidate
-
-//!
-PhysicalReg spillForLogicalReg(int type, int reg, int indexToCompileTable) {
- //choose a used register to spill
- //when a GG virtual register is spilled, write it to interpretd stack, set physicalReg to Null
- // at end of the basic block, load spilled GG VR to physical reg
- //when other types of VR is spilled, write it to interpreted stack, set physicalReg to Null
- //when a temporary (non-virtual) register is spilled, write it to stack, set physicalReg to Null
- //can we spill a hard-coded temporary register? YES
- int k, k2;
- PhysicalReg allocR;
-
- //do not try to free a physical reg that is used by more than one logical registers
- //fix on sep 28, 2009
- //do not try to spill a hard-coded logical register
- //do not try to free a physical reg that is outside of the range for 8-bit logical reg
- /* for each physical register,
- collect number of non-hardcode entries that are mapped to the physical register */
- int numOfUses[PhysicalReg_Null];
- for(k = PhysicalReg_EAX; k < PhysicalReg_Null; k++)
- numOfUses[k] = 0;
- for(k = 0; k < num_compile_entries; k++) {
- if((compileTable[k].physicalReg != PhysicalReg_Null) &&
- matchType(type, compileTable[k].physicalType) &&
- (compileTable[k].physicalType & LowOpndRegType_hard) == 0) {
- numOfUses[compileTable[k].physicalReg]++;
- }
- }
-
- /* candidates: all non-hardcode entries that are mapped to
- a physical register that is used by only one entry*/
- bool is8Bit = isTemp8Bit(type, reg);
- int candidates[COMPILE_TABLE_SIZE];
- int num_cand = 0;
- for(k = 0; k < num_compile_entries; k++) {
- if(matchType(type, compileTable[k].physicalType) &&
- compileTable[k].physicalReg != PhysicalReg_Null) {
- if(is8Bit && compileTable[k].physicalReg > PhysicalReg_EDX) continue; //not a candidate
- if(!canSpillReg[compileTable[k].physicalReg]) continue; //not a candidate
- if((compileTable[k].physicalType & LowOpndRegType_hard) == 0 &&
- numOfUses[compileTable[k].physicalReg] <= 1) {
- candidates[num_cand++] = k;
- }
- }
- }
-
- /* go through all candidates:
- first check GLUE-related entries */
- int spill_index = -1;
- for(k2 = 0; k2 < num_cand; k2++) {
- k = candidates[k2];
- if((compileTable[k].physicalReg != PhysicalReg_Null) &&
- matchType(type, compileTable[k].physicalType) &&
- (compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
- compileTable[k].regNum != PhysicalReg_GLUE)) {
- allocR = (PhysicalReg)spillLogicalReg(k, true);
-#ifdef DEBUG_REGALLOC
- ALOGI("SPILL register used by num %d type %d it is a GLUE register with refCount %d",
- compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].refCount);
-#endif
- return allocR;
- }
- }
-
- /* out of the candates, find a VR that has the furthest next use */
- int furthestUse = offsetPC;
- for(k2 = 0; k2 < num_cand; k2++) {
- k = candidates[k2];
- if((compileTable[k].physicalReg != PhysicalReg_Null) &&
- matchType(type, compileTable[k].physicalType) &&
- isVirtualReg(compileTable[k].physicalType)) {
- int nextUse = getNextAccess(k);
- if(spill_index < 0 || nextUse > furthestUse) {
- spill_index = k;
- furthestUse = nextUse;
- }
- }
- }
-
- /* spill the VR with the furthest next use */
- if(spill_index >= 0) {
- allocR = (PhysicalReg)spillLogicalReg(spill_index, true);
- return allocR; //the register is still being used
- }
-
- /* spill an entry with the smallest refCount */
- int baseLeftOver = 0;
- int index = -1;
- for(k2 = 0; k2 < num_cand; k2++) {
- k = candidates[k2];
- if(k != indexForGlue &&
- (compileTable[k].physicalReg != PhysicalReg_Null) &&
- (compileTable[k].physicalType & LowOpndRegType_hard) == 0 && //not hard-coded
- matchType(type, compileTable[k].physicalType)) {
- if((index < 0) || (compileTable[k].refCount < baseLeftOver)) {
- baseLeftOver = compileTable[k].refCount;
- index = k;
- }
- }
- }
- if(index < 0) {
- dumpCompileTable();
- ALOGE("no register to spill for logical %d %d", reg, type);
- dvmAbort();
- }
- allocR = (PhysicalReg)spillLogicalReg(index, true);
-#ifdef DEBUG_REGALLOC
- ALOGI("SPILL register used by num %d type %d it is a temporary register with refCount %d",
- compileTable[index].regNum, compileTable[index].physicalType, compileTable[index].refCount);
-#endif
- return allocR;
-}
-//!spill a variable to memory, the variable is specified by an index to compileTable
-
-//!If the variable is a temporary, get a spill location that is not in use and spill the content to the spill location;
-//!If updateTable is true, set physicalReg to Null;
-//!Return the physical register that was allocated to the variable
-int spillLogicalReg(int spill_index, bool updateTable) {
- if((compileTable[spill_index].physicalType & LowOpndRegType_hard) != 0) {
- ALOGE("can't spill a hard-coded register");
- dvmAbort();
- }
- int physicalReg = compileTable[spill_index].physicalReg;
- if(!canSpillReg[physicalReg]) {
-#ifdef PRINT_WARNING
- ALOGW("can't spill register %d", physicalReg);
-#endif
- //dvmAbort(); //this happens in get_virtual_reg where VR is allocated to the same reg as the hardcoded temporary
- }
- if(isVirtualReg(compileTable[spill_index].physicalType)) {
- //spill back to memory
- dumpToMem(compileTable[spill_index].regNum,
- (LowOpndRegType)(compileTable[spill_index].physicalType&MASK_FOR_TYPE),
- compileTable[spill_index].physicalReg);
- }
- else {
- //update spill_loc_index
- int k = getSpillIndex(spill_index == indexForGlue,
- getRegSize(compileTable[spill_index].physicalType));
- compileTable[spill_index].spill_loc_index = 4*k;
- if(k >= 0)
- spillIndexUsed[k] = 1;
- saveToSpillRegion(getRegSize(compileTable[spill_index].physicalType),
- compileTable[spill_index].physicalReg, 4*k);
- }
- //compileTable[spill_index].physicalReg_prev = compileTable[spill_index].physicalReg;
-#ifdef DEBUG_REGALLOC
- ALOGI("REGALLOC: SPILL logical reg %d %d with refCount %d allocated to %d",
- compileTable[spill_index].regNum,
- compileTable[spill_index].physicalType, compileTable[spill_index].refCount,
- compileTable[spill_index].physicalReg);
-#endif
- if(!updateTable) return PhysicalReg_Null;
-
- int allocR = compileTable[spill_index].physicalReg;
- compileTable[spill_index].physicalReg = PhysicalReg_Null;
- return allocR;
-}
-//! load a varible from memory to physical register, the variable is specified with an index to compileTable
-
-//!If the variable is a temporary, load from spill location and set the flag for the spill location to not used
-int unspillLogicalReg(int spill_index, int physicalReg) {
- //can't un-spill to %eax in afterCall!!!
- //what if GG VR is allocated to %eax!!!
- if(isVirtualReg(compileTable[spill_index].physicalType)) {
- get_virtual_reg_noalloc(compileTable[spill_index].regNum,
- getRegSize(compileTable[spill_index].physicalType),
- physicalReg, true);
- }
- else {
- loadFromSpillRegion(getRegSize(compileTable[spill_index].physicalType),
- physicalReg, compileTable[spill_index].spill_loc_index);
- spillIndexUsed[compileTable[spill_index].spill_loc_index >> 2] = 0;
- compileTable[spill_index].spill_loc_index = -1;
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("REGALLOC: UNSPILL logical reg %d %d with refCount %d", compileTable[spill_index].regNum,
- compileTable[spill_index].physicalType, compileTable[spill_index].refCount);
-#endif
- return PhysicalReg_Null;
-}
-
-//!spill a virtual register to memory
-
-//!if the current value of a VR is constant, write immediate to memory;
-//!if the current value of a VR is in a physical register, call spillLogicalReg to dump content of the physical register to memory;
-//!ifupdateTable is true, set the physical register for VR to Null and decrease reference count of the virtual register
-int spillVirtualReg(int vrNum, LowOpndRegType type, bool updateTable) {
- int index = searchCompileTable(type | LowOpndRegType_virtual, vrNum);
- if(index < 0) {
- ALOGE("can't find VR %d %d in spillVirtualReg", vrNum, type);
- return -1;
- }
- //check whether it is const
- int value[2];
- int isConst = isVirtualRegConstant(vrNum, type, value, false); //do not update refCount
- if(isConst == 1 || isConst == 3) {
- dumpImmToMem(vrNum, OpndSize_32, value[0]);
- }
- if(getRegSize(type) == OpndSize_64 && (isConst == 2 || isConst == 3)) {
- dumpImmToMem(vrNum+1, OpndSize_32, value[1]);
- }
- if(isConst != 3 && compileTable[index].physicalReg != PhysicalReg_Null)
- spillLogicalReg(index, updateTable);
- if(updateTable) decreaseRefCount(index);
- return -1;
-}
-
-//! spill variables that are mapped to physical register (regNum)
-
-//!
-int spillForHardReg(int regNum, int type) {
- //find an entry that uses the physical register
- int spill_index = -1;
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(k != indexForGlue &&
- compileTable[k].physicalReg == regNum &&
- matchType(type, compileTable[k].physicalType)) {
- spill_index = k;
- if(compileTable[k].regNum == regNum && compileTable[k].physicalType == type)
- continue;
- if(inGetVR_num >= 0 && compileTable[k].regNum == inGetVR_num && compileTable[k].physicalType == (type | LowOpndRegType_virtual))
- continue;
-#ifdef DEBUG_REGALLOC
- ALOGI("SPILL logical reg %d %d to free hard-coded reg %d %d",
- compileTable[spill_index].regNum, compileTable[spill_index].physicalType,
- regNum, type);
- if(compileTable[spill_index].physicalType & LowOpndRegType_hard) dumpCompileTable();
-#endif
- assert(spill_index < COMPILE_TABLE_SIZE);
- spillLogicalReg(spill_index, true);
- }
- }
- return regNum;
-}
-////////////////////////////////////////////////////////////////
-//! update allocConstraints of the current basic block
-
-//! allocConstraints specify how many times a hardcoded register is used in this basic block
-void updateCurrentBBWithConstraints(PhysicalReg reg) {
- if(reg > PhysicalReg_EBP) {
- ALOGE("register %d out of range in updateCurrentBBWithConstraints", reg);
- }
- currentBB->allocConstraints[reg].count++;
-}
-//! sort allocConstraints and save the result in allocConstraintsSorted
-
-//! allocConstraints specify how many times a virtual register is linked to a hardcode register
-//! it is updated in getVirtualRegInfo and merged by mergeEntry2
-int sortAllocConstraint(RegAllocConstraint* allocConstraints,
- RegAllocConstraint* allocConstraintsSorted, bool fromHighToLow) {
- int ii, jj;
- int num_sorted = 0;
- for(jj = 0; jj < 8; jj++) {
- //figure out where to insert allocConstraints[jj]
- int count = allocConstraints[jj].count;
- int regT = allocConstraints[jj].physicalReg;
- assert(regT < PhysicalReg_Null);
- int insertIndex = -1;
- for(ii = 0; ii < num_sorted; ii++) {
- int regT2 = allocConstraintsSorted[ii].physicalReg;
- assert(regT2 < PhysicalReg_Null);
- if(allRegs[regT].isCalleeSaved &&
- count == allocConstraintsSorted[ii].count) {
- insertIndex = ii;
- break;
- }
- if((!allRegs[regT].isCalleeSaved) &&
- count == allocConstraintsSorted[ii].count &&
- (!allRegs[regT2].isCalleeSaved)) { //skip until found one that is not callee-saved
- insertIndex = ii;
- break;
- }
- if((fromHighToLow && count > allocConstraintsSorted[ii].count) ||
- ((!fromHighToLow) && count < allocConstraintsSorted[ii].count)) {
- insertIndex = ii;
- break;
- }
- }
- if(insertIndex < 0) {
- allocConstraintsSorted[num_sorted].physicalReg = (PhysicalReg)regT;
- allocConstraintsSorted[num_sorted].count = count;
- num_sorted++;
- } else {
- for(ii = num_sorted-1; ii >= insertIndex; ii--) {
- allocConstraintsSorted[ii+1] = allocConstraintsSorted[ii];
- }
- allocConstraintsSorted[insertIndex] = allocConstraints[jj];
- num_sorted++;
- }
- } //for jj
-#ifdef DEBUG_ALLOC_CONSTRAINT
- for(jj = 0; jj < 8; jj++) {
- if(allocConstraintsSorted[jj].count > 0)
- ALOGI("%d: register %d has count %d", jj, allocConstraintsSorted[jj].physicalReg, allocConstraintsSorted[jj].count);
- }
-#endif
- return 0;
-}
-//! find the entry for a given virtual register in compileTable
-
-//!
-int findVirtualRegInTable(u2 vA, LowOpndRegType type, bool printError) {
- int k = searchCompileTable(type | LowOpndRegType_virtual, vA);
- if(k < 0 && printError) {
- ALOGE("findVirtualRegInTable virtual register %d type %d", vA, type);
- dvmAbort();
- }
- return k;
-}
-
-//! check whether a virtual register is constant
-
-//! the value of the constant is stored in valuePtr; if updateRefCount is true & the VR is constant, reference count for the VR will be reduced by 1
-int isVirtualRegConstant(int regNum, LowOpndRegType type, int* valuePtr, bool updateRefCount) {
-
- OpndSize size = getRegSize(type);
- int k;
- int indexL = -1;
- int indexH = -1;
- for(k = 0; k < num_const_vr; k++) {
-#ifdef DEBUG_CONST
- ALOGI("constVRTable VR %d isConst %d value %x", constVRTable[k].regNum, constVRTable[k].isConst, constVRTable[k].value);
-#endif
- if(constVRTable[k].regNum == regNum) {
- indexL = k;
- continue;
- }
- if(constVRTable[k].regNum == regNum + 1 && size == OpndSize_64) {
- indexH = k;
- continue;
- }
- }
- bool isConstL = false;
- bool isConstH = false;
- if(indexL >= 0) {
- isConstL = constVRTable[indexL].isConst;
- }
- if(size == OpndSize_64 && indexH >= 0) {
- isConstH = constVRTable[indexH].isConst;
- }
-
- if((isConstL || isConstH)) {
- if(size == OpndSize_64 && isConstH)
- valuePtr[1] = constVRTable[indexH].value;
- if(isConstL)
- *valuePtr = constVRTable[indexL].value;
- }
- if((isConstL && size == OpndSize_32) || (isConstL && isConstH)) {
- if(updateRefCount) {
- int indexOrig = searchCompileTable(type | LowOpndRegType_virtual, regNum);
- if(indexOrig < 0) ALOGE("can't find VR in isVirtualRegConstant num %d type %d", regNum, type);
- decreaseRefCount(indexOrig);
- }
-#ifdef DEBUG_CONST
- ALOGI("VR %d %d is const case", regNum, type);
-#endif
- return 3;
- }
- if(size == OpndSize_32) return 0;
- if(isConstL) return 1;
- if(isConstH) return 2;
- return 0;
-}
-
-//!update RegAccessType of virtual register vB given RegAccessType of vA
-
-//!RegAccessType can be D, L, H
-//!D means full definition, L means only lower-half is defined, H means only higher half is defined
-//!we say a VR has no exposed usage in a basic block if the accessType is D or DU
-//!we say a VR has exposed usage in a basic block if the accessType is not D nor DU
-//!we say a VR has exposed usage in other basic blocks (hasOtherExposedUsage) if
-//! there exists another basic block where VR has exposed usage in that basic block
-//!A can be U, D, L, H, UD, UL, UH, DU, LU, HU (merged result)
-//!B can be U, D, UD, DU (an entry for the current bytecode)
-//!input isAPartiallyOverlapB can be any value between -1 to 6
-//!if A is xmm: gp B lower half of A, (isAPartiallyOverlapB is 1)
-//! gp B higher half of A, (isAPartiallyOverlapB is 2)
-//! lower half of A covers the higher half of xmm B (isAPartiallyOverlapB is 4)
-//! higher half of A covers the lower half of xmm B (isAPartiallyOverlapB is 3)
-//!if A is gp: A covers the lower half of xmm B, (isAPartiallyOverlapB is 5)
-//! A covers the higher half of xmm B (isAPartiallyOverlapB is 6)
-RegAccessType updateAccess1(RegAccessType A, OverlapCase isAPartiallyOverlapB) {
- if(A == REGACCESS_D || A == REGACCESS_DU || A == REGACCESS_UD) {
- if(isAPartiallyOverlapB == OVERLAP_ALIGN) return REGACCESS_D;
- if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A || isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A)
- return REGACCESS_D;
- if(isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
- return REGACCESS_L;
- return REGACCESS_H;
- }
- if(A == REGACCESS_L || A == REGACCESS_LU || A == REGACCESS_UL) {
- if(isAPartiallyOverlapB == OVERLAP_ALIGN || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
- return REGACCESS_L;
- if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A) return REGACCESS_D;
- if(isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A || isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B)
- return REGACCESS_N;
- if(isAPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B)
- return REGACCESS_H;
- }
- if(A == REGACCESS_H || A == REGACCESS_HU || A == REGACCESS_UH) {
- if(isAPartiallyOverlapB == OVERLAP_ALIGN || isAPartiallyOverlapB == OVERLAP_A_IS_HIGH_OF_B)
- return REGACCESS_H;
- if(isAPartiallyOverlapB == OVERLAP_B_IS_LOW_OF_A || isAPartiallyOverlapB == OVERLAP_HIGH_OF_A_IS_LOW_OF_B)
- return REGACCESS_N;
- if(isAPartiallyOverlapB == OVERLAP_B_IS_HIGH_OF_A) return REGACCESS_D;
- if(isAPartiallyOverlapB == OVERLAP_LOW_OF_A_IS_HIGH_OF_B || isAPartiallyOverlapB == OVERLAP_A_IS_LOW_OF_B)
- return REGACCESS_L;
- }
- return REGACCESS_N;
-}
-//! merge RegAccessType C1 with RegAccessType C2
-
-//!C can be N,L,H,D
-RegAccessType updateAccess2(RegAccessType C1, RegAccessType C2) {
- if(C1 == REGACCESS_D || C2 == REGACCESS_D) return REGACCESS_D;
- if(C1 == REGACCESS_N) return C2;
- if(C2 == REGACCESS_N) return C1;
- if(C1 == REGACCESS_L && C2 == REGACCESS_H) return REGACCESS_D;
- if(C1 == REGACCESS_H && C2 == REGACCESS_L) return REGACCESS_D;
- return C1;
-}
-//! merge RegAccessType C with RegAccessType B
-
-//!C can be N,L,H,D
-//!B can be U, D, UD, DU
-RegAccessType updateAccess3(RegAccessType C, RegAccessType B) {
- if(B == REGACCESS_D || B == REGACCESS_DU) return B; //no exposed usage
- if(B == REGACCESS_U || B == REGACCESS_UD) {
- if(C == REGACCESS_N) return B;
- if(C == REGACCESS_L) return REGACCESS_LU;
- if(C == REGACCESS_H) return REGACCESS_HU;
- if(C == REGACCESS_D) return REGACCESS_DU;
- }
- return B;
-}
-//! merge RegAccessType A with RegAccessType B
-
-//!argument isBPartiallyOverlapA can be any value between -1 and 2
-//!0 means fully overlapping, 1 means B is the lower half, 2 means B is the higher half
-RegAccessType mergeAccess2(RegAccessType A, RegAccessType B, OverlapCase isBPartiallyOverlapA) {
- if(A == REGACCESS_UD || A == REGACCESS_UL || A == REGACCESS_UH ||
- A == REGACCESS_DU || A == REGACCESS_LU || A == REGACCESS_HU) return A;
- if(A == REGACCESS_D) {
- if(B == REGACCESS_D) return REGACCESS_D;
- if(B == REGACCESS_U) return REGACCESS_DU;
- if(B == REGACCESS_UD) return REGACCESS_DU;
- if(B == REGACCESS_DU) return B;
- }
- if(A == REGACCESS_U) {
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
- if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
- if(B == REGACCESS_U) return A;
- if(B == REGACCESS_UD && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
- if(B == REGACCESS_UD && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
- if(B == REGACCESS_UD && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_UL;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_UH;
- if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_UD;
- }
- if(A == REGACCESS_L) {
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_L;
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_D;
- if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_D;
- if(B == REGACCESS_U) return REGACCESS_LU;
- if(B == REGACCESS_UD) return REGACCESS_LU;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_LU;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_DU;
- if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_DU;
- }
- if(A == REGACCESS_H) {
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_D;
- if(B == REGACCESS_D && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_H;
- if(B == REGACCESS_D && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_D;
- if(B == REGACCESS_U) return REGACCESS_HU;
- if(B == REGACCESS_UD) return REGACCESS_HU;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_LOW_OF_A) return REGACCESS_DU;
- if(B == REGACCESS_DU && isBPartiallyOverlapA == OVERLAP_B_COVER_HIGH_OF_A) return REGACCESS_HU;
- if(B == REGACCESS_DU && (isBPartiallyOverlapA == OVERLAP_B_COVER_A)) return REGACCESS_DU;
- }
- return REGACCESS_N;
-}
-
-//!determines which part of a use is from a given definition
-
-//!reachingDefLive tells us which part of the def is live at this point
-//!isDefPartiallyOverlapUse can be any value between -1 and 2
-RegAccessType setAccessTypeOfUse(OverlapCase isDefPartiallyOverlapUse, RegAccessType reachingDefLive) {
- if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_A)
- return reachingDefLive;
- if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_LOW_OF_A) { //def covers the low half of use
- return REGACCESS_L;
- }
- if(isDefPartiallyOverlapUse == OVERLAP_B_COVER_HIGH_OF_A) {
- return REGACCESS_H;
- }
- return REGACCESS_N;
-}
-
-//! search currentBB->defUseTable to find a def for regNum at offsetPC
-
-//!
-DefUsePair* searchDefUseTable(int offsetPC, int regNum, LowOpndRegType pType) {
- DefUsePair* ptr = currentBB->defUseTable;
- while(ptr != NULL) {
- if(ptr->def.offsetPC == offsetPC &&
- ptr->def.regNum == regNum &&
- ptr->def.physicalType == pType) {
- return ptr;
- }
- ptr = ptr->next;
- }
- return NULL;
-}
-void printDefUseTable() {
- ALOGI("PRINT defUseTable --------");
- DefUsePair* ptr = currentBB->defUseTable;
- while(ptr != NULL) {
- ALOGI(" def @ %x of VR %d %d has %d uses", ptr->def.offsetPC,
- ptr->def.regNum, ptr->def.physicalType,
- ptr->num_uses);
- DefOrUseLink* ptr2 = ptr->uses;
- while(ptr2 != NULL) {
- ALOGI(" use @ %x of VR %d %d accessType %d", ptr2->offsetPC,
- ptr2->regNum,
- ptr2->physicalType,
- ptr2->accessType);
- ptr2 = ptr2->next;
- }
- ptr = ptr->next;
- }
-}
-//! when a VR is used, check whether a transfer from memory to XMM is necessary
-
-//!
-int updateVRAtUse(int reg, LowOpndRegType pType, int regAll) {
- int k;
- for(k = 0; k < currentBB->num_xfer_points; k++) {
- if(currentBB->xferPoints[k].offsetPC == offsetPC &&
- currentBB->xferPoints[k].xtype == XFER_MEM_TO_XMM &&
- currentBB->xferPoints[k].regNum == reg &&
- currentBB->xferPoints[k].physicalType == pType) {
-#ifdef DEBUG_XFER_POINTS
- ALOGI("XFER from memory to xmm %d", reg);
-#endif
- move_mem_to_reg_noalloc(OpndSize_64,
- 4*currentBB->xferPoints[k].regNum, PhysicalReg_FP, true,
- MemoryAccess_VR, currentBB->xferPoints[k].regNum,
- regAll, true);
- }
- }
- return 0;
-}
-///////////////////////////////////////////////////////////////////////////////
-// DEAD/USELESS STATEMENT ELMINATION
-// bytecodes can be removed if a bytecode has no side effect and the defs are not used
-// this optimization is guarded with DSE_OPT
-// currently, this optimization is not on, since it does not provide observable performance improvement
-// and it increases compilation time
-
-/* we remove a maximal of 40 bytecodes within a single basic block */
-#define MAX_NUM_DEAD_PC_IN_BB 40
-int deadPCs[MAX_NUM_DEAD_PC_IN_BB];
-int num_dead_pc = 0;
-//! collect all PCs that can be removed
-
-//! traverse each byte code in the current basic block and check whether it can be removed, if yes, update deadPCs
-void getDeadStmts() {
- BasicBlock_O1* bb = currentBB;
- int k;
- num_dead_pc = 0;
- //traverse each bytecode in the basic block
- //update offsetPC, rPC & inst
- u2* rPC_start = (u2*)currentMethod->insns;
- MIR* mir;
- for(mir = bb->jitBasicBlock->firstMIRInsn; mir; mir = mir->next) {
- offsetPC = mir->seqNum;
- rPC = rPC_start + mir->offset;
- if(mir->dalvikInsn.opcode >= kNumPackedOpcodes) continue;
-#ifdef DEBUG_DSE
- ALOGI("DSE: offsetPC %x", offsetPC);
-#endif
- inst = FETCH(0);
- bool isDeadStmt = true;
- getVirtualRegInfo(infoByteCode);
- u2 inst_op = INST_INST(inst);
- //skip bytecodes with side effect
- if(inst_op != OP_CONST_STRING && inst_op != OP_CONST_STRING_JUMBO &&
- inst_op != OP_MOVE && inst_op != OP_MOVE_OBJECT &&
- inst_op != OP_MOVE_FROM16 && inst_op != OP_MOVE_OBJECT_FROM16 &&
- inst_op != OP_MOVE_16 && inst_op != OP_CONST_CLASS &&
- inst_op != OP_MOVE_OBJECT_16 && inst_op != OP_MOVE_WIDE &&
- inst_op != OP_MOVE_WIDE_FROM16 && inst_op != OP_MOVE_WIDE_16 &&
- inst_op != OP_MOVE_RESULT && inst_op != OP_MOVE_RESULT_OBJECT) {
- continue;
- }
- //some statements do not define any VR!!!
- int num_defs = 0;
- for(k = 0; k < num_regs_per_bytecode; k++) {
- if(infoByteCode[k].accessType == REGACCESS_D ||
- infoByteCode[k].accessType == REGACCESS_UD ||
- infoByteCode[k].accessType == REGACCESS_DU) { //search defUseTable
- num_defs++;
- DefUsePair* indexT = searchDefUseTable(offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
- if(indexT == NULL) {
- ALOGE("def at %x of VR %d %d not in table",
- offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
- return;
- }
- if(indexT->num_uses > 0) {
- isDeadStmt = false;
- break;
- } else {
-#ifdef DEBUG_DSE
- ALOGI("DSE: num_uses is %d for def at %d for VR %d %d", indexT->num_uses,
- offsetPC, infoByteCode[k].regNum, infoByteCode[k].physicalType);
-#endif
- }
- }
- } //for k
- if(num_defs == 0) isDeadStmt = false;
- if(isDeadStmt && num_dead_pc < MAX_NUM_DEAD_PC_IN_BB) {
-#ifdef DEBUG_DSE
- ALOGI("DSE: stmt at %x is dead", offsetPC);
-#endif
- deadPCs[num_dead_pc++] = offsetPC;
- }
- } //for offsetPC
-#ifdef DEBUG_DSE
- ALOGI("Dead Stmts: ");
- for(k = 0; k < num_dead_pc; k++) ALOGI("%x ", deadPCs[k]);
- ALOGI("");
-#endif
-}
-//! entry point to remove dead statements
-
-//! recursively call getDeadStmts and remove uses in defUseTable that are from a dead PC
-//! until there is no change to number of dead PCs
-void removeDeadDefs() {
- int k;
- int deadPCs_2[MAX_NUM_DEAD_PC_IN_BB];
- int num_dead_pc_2 = 0;
- getDeadStmts();
- if(num_dead_pc == 0) return;
- DefUsePair* ptr = NULL;
- DefOrUseLink* ptrUse = NULL;
- DefOrUseLink* ptrUse_prev = NULL;
- while(true) {
- //check all the uses in defUseTable and remove any use that is from a dead PC
- ptr = currentBB->defUseTable;
- while(ptr != NULL) {
- int k3;
- ptrUse = ptr->uses;
- ptrUse_prev = NULL;
- while(ptrUse != NULL) {
- bool isIn = false;
- for(k3 = 0; k3 < num_dead_pc; k3++) {
- if(ptrUse->offsetPC == deadPCs[k3]) {
- isIn = true;
- break;
- }
- }//k3
- if(!isIn) {
- ptrUse_prev = ptrUse;
- ptrUse = ptrUse->next; //next use
- }
- else {
- //go to next use and remove ptrUse
-#ifdef DEBUG_DSE
- ALOGI("DSE: remove usage at offsetPC %d reached by def at %d", ptrUse->offsetPC,
- ptr->def.offsetPC);
-#endif
- DefOrUseLink* nextP = ptrUse->next;
- if(ptrUse == ptr->useTail) ptr->useTail = ptrUse_prev;
- free(ptrUse);
- if(ptrUse_prev == NULL) {
- ptr->uses = nextP;
- } else {
- ptrUse_prev->next = nextP;
- }
- ptrUse = nextP; //do not update ptrUse_prev
- ptr->num_uses--;
- }
- }//while ptrUse
- ptr = ptr->next;
- }//while ptr
- //save deadPCs in deadPCs_2
- num_dead_pc_2 = num_dead_pc;
- for(k = 0; k < num_dead_pc_2; k++)
- deadPCs_2[k] = deadPCs[k];
- //update deadPCs
- getDeadStmts();
- //if no change to number of dead PCs, break out of the while loop
- if(num_dead_pc_2 == num_dead_pc) break;
- }//while
-#ifdef DEBUG_DSE
- ALOGI("DSE: DEAD STMTS: ");
- for(k = 0; k < num_dead_pc; k++) {
- ALOGI("%d ", deadPCs[k]);
- }
- ALOGI("");
-#endif
-}
-/////////////////////////////////////////////////////////////
-//!search memVRTable for a given virtual register
-
-//!
-int searchMemTable(int regNum) {
- int k;
- for(k = 0; k < num_memory_vr; k++) {
- if(memVRTable[k].regNum == regNum) {
- return k;
- }
- }
- ALOGW("in searchMemTable can't find VR %d num_memory_vr %d", regNum, num_memory_vr);
- return -1;
-}
-/////////////////////////////////////////////////////////////////////////
-// A VR is already in memory && NULL CHECK
-//!check whether the latest content of a VR is in memory
-
-//!
-bool isInMemory(int regNum, OpndSize size) {
- int indexL = searchMemTable(regNum);
- int indexH = -1;
- if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
- if(indexL < 0) return false;
- if(size == OpndSize_64 && indexH < 0) return false;
- if(!memVRTable[indexL].inMemory) return false;
- if(size == OpndSize_64 && (!memVRTable[indexH].inMemory)) return false;
- return true;
-}
-//!set field inMemory of memVRTable to true
-
-//!
-void setVRToMemory(int regNum, OpndSize size) {
- int indexL = searchMemTable(regNum);
- int indexH = -1;
- if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
- if(indexL < 0) {
- ALOGE("VR %d not in memVRTable", regNum);
- return;
- }
- memVRTable[indexL].inMemory = true;
- if(size == OpndSize_64) {
- if(indexH < 0) {
- ALOGE("VR %d not in memVRTable", regNum+1);
- return;
- }
- memVRTable[indexH].inMemory = true;
- }
-}
-//! check whether null check for a VR is performed previously
-
-//!
-bool isVRNullCheck(int regNum, OpndSize size) {
- if(size != OpndSize_32) {
- ALOGE("isVRNullCheck size should be 32");
- dvmAbort();
- }
- int indexL = searchMemTable(regNum);
- if(indexL < 0) {
- ALOGE("VR %d not in memVRTable", regNum);
- return false;
- }
- return memVRTable[indexL].nullCheckDone;
-}
-bool isVRBoundCheck(int vr_array, int vr_index) {
- int indexL = searchMemTable(vr_array);
- if(indexL < 0) {
- ALOGE("isVRBoundCheck: VR %d not in memVRTable", vr_array);
- return false;
- }
- if(memVRTable[indexL].boundCheck.indexVR == vr_index)
- return memVRTable[indexL].boundCheck.checkDone;
- return false;
-}
-//! set nullCheckDone in memVRTable to true
-
-//!
-void setVRNullCheck(int regNum, OpndSize size) {
- if(size != OpndSize_32) {
- ALOGE("setVRNullCheck size should be 32");
- dvmAbort();
- }
- int indexL = searchMemTable(regNum);
- if(indexL < 0) {
- ALOGE("VR %d not in memVRTable", regNum);
- return;
- }
- memVRTable[indexL].nullCheckDone = true;
-}
-void setVRBoundCheck(int vr_array, int vr_index) {
- int indexL = searchMemTable(vr_array);
- if(indexL < 0) {
- ALOGE("setVRBoundCheck: VR %d not in memVRTable", vr_array);
- return;
- }
- memVRTable[indexL].boundCheck.indexVR = vr_index;
- memVRTable[indexL].boundCheck.checkDone = true;
-}
-void clearVRBoundCheck(int regNum, OpndSize size) {
- int k;
- for(k = 0; k < num_memory_vr; k++) {
- if(memVRTable[k].regNum == regNum ||
- (size == OpndSize_64 && memVRTable[k].regNum == regNum+1)) {
- memVRTable[k].boundCheck.checkDone = false;
- }
- if(memVRTable[k].boundCheck.indexVR == regNum ||
- (size == OpndSize_64 && memVRTable[k].boundCheck.indexVR == regNum+1)) {
- memVRTable[k].boundCheck.checkDone = false;
- }
- }
-}
-//! set inMemory of memVRTable to false
-
-//!
-void clearVRToMemory(int regNum, OpndSize size) {
- int indexL = searchMemTable(regNum);
- int indexH = -1;
- if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
- if(indexL >= 0) {
- memVRTable[indexL].inMemory = false;
- }
- if(size == OpndSize_64 && indexH >= 0) {
- memVRTable[indexH].inMemory = false;
- }
-}
-//! set nullCheckDone of memVRTable to false
-
-//!
-void clearVRNullCheck(int regNum, OpndSize size) {
- int indexL = searchMemTable(regNum);
- int indexH = -1;
- if(size == OpndSize_64) indexH = searchMemTable(regNum+1);
- if(indexL >= 0) {
- memVRTable[indexL].nullCheckDone = false;
- }
- if(size == OpndSize_64 && indexH >= 0) {
- memVRTable[indexH].nullCheckDone = false;
- }
-}
-
-//! Extend Virtual Register life
-
-//! Requests that the life of a specific virtual register be extended. This ensures
-//! that its mapping to a physical register won't be canceled while the extension
-//! request is valid. NOTE: This does not support 64-bit values (when two adjacent
-//! VRs are used)
-//! @see cancelVRFreeDelayRequest
-//! @see getVRFreeDelayRequested
-//! @see VRFreeDelayFlags
-//! @param regNum is the VR number
-//! @param reason explains why freeing must be delayed. A single or combination
-//! of VRFreeDelayFlags should be used.
-//! @return negative value if request failed
-int requestVRFreeDelay(int regNum, u4 reason) {
- //TODO Add 64-bit operand support when needed
- int indexL = searchMemTable(regNum);
- if(indexL >= 0) {
- memVRTable[indexL].delayFreeFlags |= reason;
- } else {
- ALOGE("requestVRFreeDelay: VR %d not in memVRTable", regNum);
- }
- return indexL;
-}
-
-//! Cancel request for virtual register life extension
-
-//! Cancels any outstanding requests to extended liveness of VR. Additionally,
-//! this ensures that if the VR is no longer life after this point, it will
-//! no longer be associated with a physical register which can then be reused.
-//! NOTE: This does not support 64-bit values (when two adjacent VRs are used)
-//! @see requestVRFreeDelay
-//! @see getVRFreeDelayRequested
-//! @see VRFreeDelayFlags
-//! @param regNum is the VR number
-//! @param reason explains what freeing delay request should be canceled. A single
-//! or combination of VRFreeDelayFlags should be used.
-void cancelVRFreeDelayRequest(int regNum, u4 reason) {
- //TODO Add 64-bit operand support when needed
- bool needCallToFreeReg = false;
- int indexL = searchMemTable(regNum);
- if(indexL >= 0) {
- if((memVRTable[indexL].delayFreeFlags & reason) != VRDELAY_NONE) { // don't cancel delay if it wasn't requested
- memVRTable[indexL].delayFreeFlags ^= reason; // only cancel this particular reason, not all others
- if(memVRTable[indexL].delayFreeFlags == VRDELAY_NONE)
- needCallToFreeReg = true; // freeReg might want to free this VR now if there is no longer a valid delay
- }
- }
- if(needCallToFreeReg)
- freeReg(true);
-}
-
-//! Gets status of virtual register free delay request
-
-//! Finds out if there was a delay request for freeing this VR.
-//! NOTE: This does not support 64-bit values (when two adjacent VRs are used)
-//! @see requestVRFreeDelay
-//! @see cancelVRFreeDelayRequest
-//! @param regNum is the VR number
-//! @return true if VR has an active delay request
-bool getVRFreeDelayRequested(int regNum) {
- //TODO Add 64-bit operand support when needed
- int indexL = searchMemTable(regNum);
- if(indexL >= 0) {
- if(memVRTable[indexL].delayFreeFlags != VRDELAY_NONE)
- return true;
- return false;
- }
- return false;
-}
-
-//! find the basic block that a bytecode is in
-
-//!
-BasicBlock_O1* findForOffset(int offset) {
- int k;
- for(k = 0; k < num_bbs_for_method; k++) {
- if(method_bbs_sorted[k]->pc_start <= offset && method_bbs_sorted[k]->pc_end > offset)
- return method_bbs_sorted[k];
- }
- return NULL;
-}
-void dump_CFG(Method* method);
-
-int current_bc_size = -1;
-
-//! check whether a virtual register is used in a basic block
-
-//!
-bool isUsedInBB(int regNum, int type, BasicBlock_O1* bb) {
- int k;
- for(k = 0; k < bb->num_regs; k++) {
- if(bb->infoBasicBlock[k].physicalType == (type&MASK_FOR_TYPE) && bb->infoBasicBlock[k].regNum == regNum)
- return true;
- }
- return false;
-}
-//! return the index to infoBasicBlock for a given virtual register
-
-//! return -1 if not found
-int searchVirtualInfoOfBB(LowOpndRegType type, int regNum, BasicBlock_O1* bb) {
- int k;
- for(k = 0; k < bb->num_regs; k++) {
- if(bb->infoBasicBlock[k].physicalType == type && bb->infoBasicBlock[k].regNum == regNum)
- return k;
- }
- return -1;
-}
-//! return the index to compileTable for a given virtual register
-
-//! return -1 if not found
-int searchCompileTable(int type, int regNum) { //returns the index
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(compileTable[k].physicalType == type && compileTable[k].regNum == regNum)
- return k;
- }
- return -1;
-}
-//!check whether a physical register for a variable with typeA will work for another variable with typeB
-
-//!Type LowOpndRegType_ss is compatible with type LowOpndRegType_xmm
-bool matchType(int typeA, int typeB) {
- if((typeA & MASK_FOR_TYPE) == (typeB & MASK_FOR_TYPE)) return true;
- if((typeA & MASK_FOR_TYPE) == LowOpndRegType_ss &&
- (typeB & MASK_FOR_TYPE) == LowOpndRegType_xmm) return true;
- if((typeA & MASK_FOR_TYPE) == LowOpndRegType_xmm &&
- (typeB & MASK_FOR_TYPE) == LowOpndRegType_ss) return true;
- return false;
-}
-//!check whether a virtual register is used in the current bytecode
-
-//!
-bool isUsedInByteCode(int regNum, int type) {
- getVirtualRegInfo(infoByteCode);
- int k;
- for(k = 0; k < num_regs_per_bytecode; k++) {
- if(infoByteCode[k].physicalType == (type&MASK_FOR_TYPE) && infoByteCode[k].regNum == regNum)
- return true;
- }
- return false;
-}
-//! obsolete
-bool defineFirst(int atype) {
- if(atype == REGACCESS_D || atype == REGACCESS_L || atype == REGACCESS_H || atype == REGACCESS_DU)
- return true;
- return false;
-}
-//!check whether a virtual register is updated in a basic block
-
-//!
-bool notUpdated(RegAccessType atype) {
- if(atype == REGACCESS_U) return true;
- return false;
-}
-//!check whether a virtual register has exposed usage within a given basic block
-
-//!
-bool hasExposedUsage2(BasicBlock_O1* bb, int index) {
- RegAccessType atype = bb->infoBasicBlock[index].accessType;
- if(atype == REGACCESS_D || atype == REGACCESS_L || atype == REGACCESS_H || atype == REGACCESS_DU)
- return false;
- return true;
-}
-//! return the spill location that is not used
-
-//!
-int getSpillIndex(bool isGLUE, OpndSize size) {
- if(isGLUE) return 0;
- int k;
- for(k = 1; k <= MAX_SPILL_JIT_IA-1; k++) {
- if(size == OpndSize_64) {
- if(k < MAX_SPILL_JIT_IA-1 && spillIndexUsed[k] == 0 && spillIndexUsed[k+1] == 0)
- return k;
- }
- else if(spillIndexUsed[k] == 0) {
- return k;
- }
- }
- ALOGE("can't find spill position in spillLogicalReg");
- return -1;
-}
-//!this is called before generating a native code, it sets entries in array canSpillReg to true
-
-//!startNativeCode must be paired with endNativeCode
-void startNativeCode(int vr_num, int vr_type) {
- int k;
- for(k = 0; k < PhysicalReg_Null; k++) {
- canSpillReg[k] = true;
- }
- inGetVR_num = vr_num;
- inGetVR_type = vr_type;
-}
-//! called right after generating a native code
-
-//!It sets entries in array canSpillReg to true and reset inGetVR_num to -1
-void endNativeCode() {
- int k;
- for(k = 0; k < PhysicalReg_Null; k++) {
- canSpillReg[k] = true;
- }
- inGetVR_num = -1;
-}
-//! set canSpillReg[physicalReg] to false
-
-//!
-void donotSpillReg(int physicalReg) {
- canSpillReg[physicalReg] = false;
-}
-//! set canSpillReg[physicalReg] to true
-
-//!
-void doSpillReg(int physicalReg) {
- canSpillReg[physicalReg] = true;
-}
-//! touch hardcoded register %ecx and reduce its reference count
-
-//!
-int touchEcx() {
- //registerAlloc will spill logical reg that is mapped to ecx
- //registerAlloc will reduce refCount
- registerAlloc(LowOpndRegType_gp, PhysicalReg_ECX, true, true);
- return 0;
-}
-//! touch hardcoded register %eax and reduce its reference count
-
-//!
-int touchEax() {
- registerAlloc(LowOpndRegType_gp, PhysicalReg_EAX, true, true);
- return 0;
-}
-int touchEsi() {
- registerAlloc(LowOpndRegType_gp, PhysicalReg_ESI, true, true);
- return 0;
-}
-int touchXmm1() {
- registerAlloc(LowOpndRegType_xmm, XMM_1, true, true);
- return 0;
-}
-int touchEbx() {
- registerAlloc(LowOpndRegType_gp, PhysicalReg_EBX, true, true);
- return 0;
-}
-
-//! touch hardcoded register %edx and reduce its reference count
-
-//!
-int touchEdx() {
- registerAlloc(LowOpndRegType_gp, PhysicalReg_EDX, true, true);
- return 0;
-}
-
-#ifdef HACK_FOR_DEBUG
-//for debugging purpose, instructions are added at a certain place
-bool hacked = false;
-void hackBug() {
- if(!hacked && iget_obj_inst == 13) {
-#if 0
- move_reg_to_reg_noalloc(OpndSize_32, PhysicalReg_EBX, true, PhysicalReg_ECX, true);
- //move from ebx to ecx & update compileTable for v3
- int tIndex = searchCompileTable(LowOpndRegType_virtual | LowOpndRegType_gp, 3);
- if(tIndex < 0) ALOGE("hack can't find VR3");
- compileTable[tIndex].physicalReg = PhysicalReg_ECX;
-#else
- move_reg_to_mem_noalloc(OpndSize_32, PhysicalReg_EBX, true, 12, PhysicalReg_FP, true);
-#endif
- }
-}
-void hackBug2() {
- if(!hacked && iget_obj_inst == 13) {
- dump_imm_mem_noalloc(Mnemonic_MOV, OpndSize_32, 0, 12, PhysicalReg_FP, true);
- hacked = true;
- }
-}
-#endif
-
-//! this function is called before calling a helper function or a vm function
-int beforeCall(const char* target) { //spill all live registers
- if(currentBB == NULL) return -1;
-
- /* special case for ncgGetEIP: this function only updates %edx */
- if(!strcmp(target, "ncgGetEIP")) {
- touchEdx();
- return -1;
- }
-
- /* these functions use %eax for the return value */
- if((!strcmp(target, "dvmInstanceofNonTrivial")) ||
- (!strcmp(target, "dvmUnlockObject")) ||
- (!strcmp(target, "dvmAllocObject")) ||
- (!strcmp(target, "dvmAllocArrayByClass")) ||
- (!strcmp(target, "dvmAllocPrimitiveArray")) ||
- (!strcmp(target, "dvmInterpHandleFillArrayData")) ||
- (!strcmp(target, "dvmFindInterfaceMethodInCache")) ||
- (!strcmp(target, "dvmNcgHandlePackedSwitch")) ||
- (!strcmp(target, "dvmNcgHandleSparseSwitch")) ||
- (!strcmp(target, "dvmCanPutArrayElement")) ||
- (!strcmp(target, "moddi3")) || (!strcmp(target, "divdi3")) ||
- (!strcmp(target, "execute_inline"))
- || (!strcmp(target, "dvmJitToPatchPredictedChain"))
- || (!strcmp(target, "dvmJitHandlePackedSwitch"))
- || (!strcmp(target, "dvmJitHandleSparseSwitch"))
- ) {
- touchEax();
- }
-
- //these two functions also use %edx for the return value
- if((!strcmp(target, "moddi3")) || (!strcmp(target, "divdi3"))) {
- touchEdx();
- }
- if((!strcmp(target, ".new_instance_helper"))) {
- touchEsi(); touchEax();
- }
-#if defined(ENABLE_TRACING)
- if((!strcmp(target, "common_periodicChecks4"))) {
- touchEdx();
- }
-#endif
- if((!strcmp(target, ".const_string_helper"))) {
- touchEcx(); touchEax();
- }
- if((!strcmp(target, ".check_cast_helper"))) {
- touchEbx(); touchEsi();
- }
- if((!strcmp(target, ".instance_of_helper"))) {
- touchEbx(); touchEsi(); touchEcx();
- }
- if((!strcmp(target, ".monitor_enter_helper"))) {
- touchEbx();
- }
- if((!strcmp(target, ".monitor_exit_helper"))) {
- touchEbx();
- }
- if((!strcmp(target, ".aget_wide_helper"))) {
- touchEbx(); touchEcx(); touchXmm1();
- }
- if((!strcmp(target, ".aget_helper")) || (!strcmp(target, ".aget_char_helper")) ||
- (!strcmp(target, ".aget_short_helper")) || (!strcmp(target, ".aget_bool_helper")) ||
- (!strcmp(target, ".aget_byte_helper"))) {
- touchEbx(); touchEcx(); touchEdx();
- }
- if((!strcmp(target, ".aput_helper")) || (!strcmp(target, ".aput_char_helper")) ||
- (!strcmp(target, ".aput_short_helper")) || (!strcmp(target, ".aput_bool_helper")) ||
- (!strcmp(target, ".aput_byte_helper")) || (!strcmp(target, ".aput_wide_helper"))) {
- touchEbx(); touchEcx(); touchEdx();
- }
- if((!strcmp(target, ".sput_helper")) || (!strcmp(target, ".sput_wide_helper"))) {
- touchEdx(); touchEax();
- }
- if((!strcmp(target, ".sget_helper"))) {
- touchEdx(); touchEcx();
- }
- if((!strcmp(target, ".sget_wide_helper"))) {
- touchEdx(); touchXmm1();
- }
- if((!strcmp(target, ".aput_obj_helper"))) {
- touchEdx(); touchEcx(); touchEax();
- }
- if((!strcmp(target, ".iput_helper")) || (!strcmp(target, ".iput_wide_helper"))) {
- touchEbx(); touchEcx(); touchEsi();
- }
- if((!strcmp(target, ".iget_helper"))) {
- touchEbx(); touchEcx(); touchEdx();
- }
- if((!strcmp(target, ".iget_wide_helper"))) {
- touchEbx(); touchEcx(); touchXmm1();
- }
- if((!strcmp(target, ".new_array_helper"))) {
- touchEbx(); touchEdx(); touchEax();
- }
- if((!strcmp(target, ".invoke_virtual_helper"))) {
- touchEbx(); touchEcx();
- }
- if((!strcmp(target, ".invoke_direct_helper"))) {
- touchEsi(); touchEcx();
- }
- if((!strcmp(target, ".invoke_super_helper"))) {
- touchEbx(); touchEcx();
- }
- if((!strcmp(target, ".invoke_interface_helper"))) {
- touchEbx(); touchEcx();
- }
- if((!strcmp(target, ".invokeMethodNoRange_5_helper")) ||
- (!strcmp(target, ".invokeMethodNoRange_4_helper"))) {
- touchEbx(); touchEsi(); touchEax(); touchEdx();
- }
- if((!strcmp(target, ".invokeMethodNoRange_3_helper"))) {
- touchEbx(); touchEsi(); touchEax();
- }
- if((!strcmp(target, ".invokeMethodNoRange_2_helper"))) {
- touchEbx(); touchEsi();
- }
- if((!strcmp(target, ".invokeMethodNoRange_1_helper"))) {
- touchEbx();
- }
- if((!strcmp(target, ".invokeMethodRange_helper"))) {
- touchEdx(); touchEsi();
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("enter beforeCall");
-#endif
- if(!strncmp(target, ".invokeArgsDone", 15)) resetGlue(PhysicalReg_GLUE_DVMDEX);
-
- freeReg(true); //to avoid spilling dead logical registers
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- /* before throwing an exception, if GLUE is spilled, load to %ebp
- this should happen at last */
- if(k == indexForGlue) continue;
- if(compileTable[k].physicalReg != PhysicalReg_Null &&
- (compileTable[k].physicalType & LowOpndRegType_hard) == 0) {
- /* handles non hardcoded variables that are in physical registers */
- if(!strcmp(target, "exception")) {
- /* before throwing an exception
- update contents of all VRs in Java stack */
- if(!isVirtualReg(compileTable[k].physicalType)) continue;
- /* to have correct GC, we should update contents for L VRs as well */
- //if(compileTable[k].gType == GLOBALTYPE_L) continue;
- }
- if((!strcmp(target, ".const_string_resolve")) ||
- (!strcmp(target, ".static_field_resolve")) ||
- (!strcmp(target, ".inst_field_resolve")) ||
- (!strcmp(target, ".class_resolve")) ||
- (!strcmp(target, ".direct_method_resolve")) ||
- (!strcmp(target, ".virtual_method_resolve")) ||
- (!strcmp(target, ".static_method_resolve"))) {
- /* physical register %ebx will keep its content
- but to have correct GC, we should dump content of a VR
- that is mapped to %ebx */
- if(compileTable[k].physicalReg == PhysicalReg_EBX &&
- (!isVirtualReg(compileTable[k].physicalType)))
- continue;
- }
- if((!strncmp(target, "dvm", 3)) || (!strcmp(target, "moddi3")) ||
- (!strcmp(target, "divdi3")) ||
- (!strcmp(target, "fmod")) || (!strcmp(target, "fmodf"))) {
- /* callee-saved registers (%ebx, %esi, %ebp, %edi) will keep the content
- but to have correct GC, we should dump content of a VR
- that is mapped to a callee-saved register */
- if((compileTable[k].physicalReg == PhysicalReg_EBX ||
- compileTable[k].physicalReg == PhysicalReg_ESI) &&
- (!isVirtualReg(compileTable[k].physicalType)))
- continue;
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("SPILL logical register %d %d in beforeCall",
- compileTable[k].regNum, compileTable[k].physicalType);
-#endif
- spillLogicalReg(k, true);
- }
- }
- if(indexForGlue >= 0 && !strcmp(target, "exception") &&
- compileTable[indexForGlue].physicalReg == PhysicalReg_Null) {
- unspillLogicalReg(indexForGlue, PhysicalReg_EBP); //load %ebp
- }
-#ifdef DEBUG_REGALLOC
- ALOGI("exit beforeCall");
-#endif
- return 0;
-}
-int getFreeReg(int type, int reg, int indexToCompileTable);
-//! after calling a helper function or a VM function
-
-//!
-int afterCall(const char* target) { //un-spill
- if(currentBB == NULL) return -1;
- if(!strcmp(target, "ncgGetEIP")) return -1;
-
- return 0;
-}
-//! check whether a temporary is 8-bit
-
-//!
-bool isTemp8Bit(int type, int reg) {
- if(currentBB == NULL) return false;
- if(!isTemporary(type, reg)) return false;
- int k;
- for(k = 0; k < num_temp_regs_per_bytecode; k++) {
- if(infoByteCodeTemp[k].physicalType == type &&
- infoByteCodeTemp[k].regNum == reg) {
- return infoByteCodeTemp[k].is8Bit;
- }
- }
- ALOGE("isTemp8Bit %d %d", type, reg);
- return false;
-}
-
-/* functions to access live ranges of a VR
- Live range info is stored in memVRTable[].ranges, which is a linked list
-*/
-//! check whether a VR is live at the current bytecode
-
-//!
-bool isVRLive(int vA) {
- int index = searchMemTable(vA);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", vA);
- return false;
- }
- LiveRange* ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC >= ptr->start && offsetPC <= ptr->end) return true;
- ptr = ptr->next;
- }
- return false;
-}
-
-//! check whether the current bytecode is the last access to a VR within a live range
-
-//!for 64-bit VR, return true only when true for both low half and high half
-bool isLastByteCodeOfLiveRange(int compileIndex) {
- int k = compileIndex;
- OpndSize tSize = getRegSize(compileTable[k].physicalType);
- int index;
- LiveRange* ptr = NULL;
- if(tSize == OpndSize_32) {
- /* check live ranges for the VR */
- index = searchMemTable(compileTable[k].regNum);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return false;
- }
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC == ptr->end) return true;
- ptr = ptr->next;
- }
- return false;
- }
- /* size of the VR is 64 */
- /* check live ranges of the low half */
- index = searchMemTable(compileTable[k].regNum);
- bool tmpB = false;
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return false;
- }
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC == ptr->end) {
- tmpB = true;
- break;
- }
- ptr = ptr->next;
- }
- if(!tmpB) return false;
- /* check live ranges of the high half */
- index = searchMemTable(compileTable[k].regNum+1);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
- return false;
- }
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC == ptr->end) {
- return true;
- }
- ptr = ptr->next;
- }
- return false;
-}
-
-//! check whether the current bytecode is in a live range that extends to end of a basic block
-
-//!for 64 bit, return true if true for both low half and high half
-bool reachEndOfBB(int compileIndex) {
- int k = compileIndex;
- OpndSize tSize = getRegSize(compileTable[k].physicalType);
- int index;
- bool retCode = false;
- /* check live ranges of the low half */
- index = searchMemTable(compileTable[k].regNum);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return false;
- }
- LiveRange* ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC >= ptr->start &&
- offsetPC <= ptr->end) {
- if(ptr->end == currentBB->pc_end) {
- retCode = true;
- }
- break;
- }
- ptr = ptr->next;
- }
- if(!retCode) return false;
- if(tSize == OpndSize_32) return true;
- /* check live ranges of the high half */
- index = searchMemTable(compileTable[k].regNum+1);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
- return false;
- }
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC >= ptr->start &&
- offsetPC <= ptr->end) {
- if(ptr->end == currentBB->pc_end) return true;
- return false;
- }
- ptr = ptr->next;
- }
-#ifdef PRINT_WARNING
- ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum+1);
-#endif
- return false;
-}
-
-//!check whether the current bytecode is the next to last access to a VR within a live range
-
-//!for 64 bit, return true if true for both low half and high half
-bool isNextToLastAccess(int compileIndex) {
- int k = compileIndex;
- OpndSize tSize = getRegSize(compileTable[k].physicalType);
- int index;
- /* check live ranges for the low half */
- bool retCode = false;
- index = searchMemTable(compileTable[k].regNum);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return false;
- }
- LiveRange* ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- int num_access = ptr->num_access;
-
- if(num_access < 2) {
- ptr = ptr->next;
- continue;
- }
-
- if(offsetPC == ptr->accessPC[num_access-2]) {
- retCode = true;
- break;
- }
- ptr = ptr->next;
- }
- if(!retCode) return false;
- if(tSize == OpndSize_32) return true;
- /* check live ranges for the high half */
- index = searchMemTable(compileTable[k].regNum+1);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
- return false;
- }
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- int num_access = ptr->num_access;
-
- if(num_access < 2) {
- ptr = ptr->next;
- continue;
- }
-
- if(offsetPC == ptr->accessPC[num_access-2]) return true;
- ptr = ptr->next;
- }
- return false;
-}
-
-/** return the start of the next live range
- if there does not exist a next live range, return pc_end of the basic block
- for 64 bits, return the larger one for low half and high half
- Assume live ranges are sorted in order
-*/
-int getNextLiveRange(int compileIndex) {
- int k = compileIndex;
- OpndSize tSize = getRegSize(compileTable[k].physicalType);
- /* check live ranges of the low half */
- int index;
- index = searchMemTable(compileTable[k].regNum);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return offsetPC;
- }
- bool found = false;
- int nextUse = offsetPC;
- LiveRange* ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(ptr->start > offsetPC) {
- nextUse = ptr->start;
- found = true;
- break;
- }
- ptr = ptr->next;
- }
- if(!found) return currentBB->pc_end;
- if(tSize == OpndSize_32) return nextUse;
-
- /* check live ranges of the high half */
- found = false;
- index = searchMemTable(compileTable[k].regNum+1);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
- return offsetPC;
- }
- int nextUse2 = offsetPC;
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(ptr->start > offsetPC) {
- nextUse2 = ptr->start;
- found = true;
- break;
- }
- ptr = ptr->next;
- }
- if(!found) return currentBB->pc_end;
- /* return the larger one */
- return (nextUse2 > nextUse ? nextUse2 : nextUse);
-}
-
-/** return the next access to a variable
- If variable is 64-bit, get the next access to the lower half and the high half
- return the eariler one
-*/
-int getNextAccess(int compileIndex) {
- int k = compileIndex;
- OpndSize tSize = getRegSize(compileTable[k].physicalType);
- int index, k3;
- /* check live ranges of the low half */
- index = searchMemTable(compileTable[k].regNum);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum);
- return offsetPC;
- }
- bool found = false;
- int nextUse = offsetPC;
- LiveRange* ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC >= ptr->start &&
- offsetPC <= ptr->end) {
- /* offsetPC belongs to this live range */
- for(k3 = 0; k3 < ptr->num_access; k3++) {
- if(ptr->accessPC[k3] > offsetPC) {
- nextUse = ptr->accessPC[k3];
- break;
- }
- }
- found = true;
- break;
- }
- ptr = ptr->next;
- }
-#ifdef PRINT_WARNING
- if(!found)
- ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum);
-#endif
- if(tSize == OpndSize_32) return nextUse;
-
- /* check live ranges of the high half */
- found = false;
- index = searchMemTable(compileTable[k].regNum+1);
- if(index < 0) {
- ALOGE("couldn't find VR %d in memTable", compileTable[k].regNum+1);
- return offsetPC;
- }
- int nextUse2 = offsetPC;
- ptr = memVRTable[index].ranges;
- while(ptr != NULL) {
- if(offsetPC >= ptr->start &&
- offsetPC <= ptr->end) {
- for(k3 = 0; k3 < ptr->num_access; k3++) {
- if(ptr->accessPC[k3] > offsetPC) {
- nextUse2 = ptr->accessPC[k3];
- break;
- }
- }
- found = true;
- break;
- }
- ptr = ptr->next;
- }
-#ifdef PRINT_WARNING
- if(!found) ALOGW("offsetPC %d not in live range of VR %d", offsetPC, compileTable[k].regNum+1);
-#endif
- /* return the earlier one */
- if(nextUse2 < nextUse) return nextUse2;
- return nextUse;
-}
-
-/** free variables that are no longer in use
- free a temporary with reference count of zero
- will dump content of a GL VR to memory if necessary
-*/
-int freeReg(bool spillGL) {
- if(currentBB == NULL) return 0;
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(compileTable[k].refCount == 0 && compileTable[k].physicalReg != PhysicalReg_Null) {
- /* check entries with reference count of zero and is mapped to a physical register */
- bool typeA = !isVirtualReg(compileTable[k].physicalType);
- bool freeCrit = true, delayFreeing = false;
- bool typeC = false, typeB = false, reachEnd = false;
- if(isVirtualReg(compileTable[k].physicalType)) {
- /* VRs in the compile table */
-
- /* Check if delay for freeing was requested for this VR */
- delayFreeing = getVRFreeDelayRequested(compileTable[k].regNum);
-
- freeCrit = isLastByteCodeOfLiveRange(k); /* last bytecode of a live range */
- reachEnd = reachEndOfBB(k); /* in a live range that extends to end of a basic block */
-#ifdef DEBUG_LIVE_RANGE
- ALOGI("IN freeReg: VR %d offsetPC %x freecrit %d reachEnd %d nextToLast %d", compileTable[k].regNum, offsetPC, freeCrit, reachEnd, isNextToLastAccess(k));
-#endif
- /* Bug: spilling of VRs after edi(rFP) is updated in RETURN bytecode
- will cause variables for callee to be spilled to the caller stack frame and
- to overwrite varaibles for caller
- */
- /* last bytecode of a live range reaching end of BB if not counting the fake usage at end */
- bool boolB = reachEnd && isNextToLastAccess(k);
- /* Bug: when a GG VR is checked at end of a basic block,
- freeCrit will be true and physicalReg will be set to Null
- Fix: change free condition from freeCrit to (freeCrit && offsetPC != currentBB->pc_end)
- */
- /* conditions to free a GG VR:
- last bytecode of a live range reaching end of BB if not counting the fake usage at end && endsWithReturn
- or
- last bytecode of a live range && offsetPC != currentBB->pc_end
- -> last bytecode of a live range not reaching end
- */
- typeC = ((freeCrit && offsetPC != currentBB->pc_end) ||
- (currentBB->endsWithReturn && boolB)) &&
- compileTable[k].gType == GLOBALTYPE_GG &&
- !delayFreeing;
- /* conditions to free a L|GL VR:
- last bytecode of a live range
- or
- last bytecode of a live range reaching end of BB if not counting the fake usage at end
- */
- typeB = (freeCrit || boolB) &&
- (compileTable[k].gType != GLOBALTYPE_GG) &&
- !delayFreeing;
- }
- if(typeA || typeB || typeC) {
-#ifdef DEBUG_REGALLOC
- if(typeA)
- ALOGI("FREE TEMP %d with type %d allocated to %d",
- compileTable[k].regNum, compileTable[k].physicalType,
- compileTable[k].physicalReg);
- else if(typeB)
- ALOGI("FREE VR L|GL %d with type %d allocated to %d",
- compileTable[k].regNum, compileTable[k].physicalType,
- compileTable[k].physicalReg);
- else if(typeC)
- ALOGI("FREE VR GG %d with type %d allocated to %d",
- compileTable[k].regNum, compileTable[k].physicalType,
- compileTable[k].physicalReg);
-#endif
- bool dumpGL = false;
- if(compileTable[k].gType == GLOBALTYPE_GL && !reachEnd) {
- /* if the live range does not reach end of basic block
- and there exists a try block from offsetPC to the next live range
- dump VR to interpreted stack */
- int tmpPC = getNextLiveRange(k);
- if(existATryBlock(currentMethod, offsetPC, tmpPC)) dumpGL = true;
- }
- /* if the live range reach end of basic block, dump VR to interpreted stack */
- if(compileTable[k].gType == GLOBALTYPE_GL && reachEnd) dumpGL = true;
- if(dumpGL) {
- if(spillGL) {
-#ifdef DEBUG_REGALLOC
- ALOGI("SPILL VR GL %d %d", compileTable[k].regNum, compileTable[k].physicalType);
-#endif
- spillLogicalReg(k, true); //will dump VR to memory & update physicalReg
- }
- }
- else
- compileTable[k].physicalReg = PhysicalReg_Null;
- }
- if(typeA) {
- if(compileTable[k].spill_loc_index >= 0) {
- /* update spill info for temporaries */
- spillIndexUsed[compileTable[k].spill_loc_index >> 2] = 0;
- compileTable[k].spill_loc_index = -1;
- ALOGE("free a temporary register with TRSTATE_SPILLED");
- }
- }
- }
- }
- syncAllRegs(); //sync up allRegs (isUsed & freeTimeStamp) with compileTable
- return 0;
-}
-
-//! reduce the reference count by 1
-
-//! input: index to compileTable
-void decreaseRefCount(int index) {
-#ifdef DEBUG_REFCOUNT
- ALOGI("REFCOUNT: %d in decreaseRefCount %d %d", compileTable[index].refCount,
- compileTable[index].regNum, compileTable[index].physicalType);
-#endif
- compileTable[index].refCount--;
- if(compileTable[index].refCount < 0) {
- ALOGE("refCount is negative for REG %d %d", compileTable[index].regNum, compileTable[index].physicalType);
- dvmAbort();
- }
-}
-//! reduce the reference count of a VR by 1
-
-//! input: reg & type
-int updateRefCount(int reg, LowOpndRegType type) {
- if(currentBB == NULL) return 0;
- int index = searchCompileTable(LowOpndRegType_virtual | type, reg);
- if(index < 0) {
- ALOGE("virtual reg %d type %d not found in updateRefCount", reg, type);
- return -1;
- }
- decreaseRefCount(index);
- return 0;
-}
-//! reduce the reference count of a variable by 1
-
-//! The variable is named with lowering module's naming mechanism
-int updateRefCount2(int reg, int type, bool isPhysical) {
- if(currentBB == NULL) return 0;
- int newType = convertType(type, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int index = searchCompileTable(newType, reg);
- if(index < 0) {
- ALOGE("reg %d type %d not found in updateRefCount", reg, newType);
- return -1;
- }
- decreaseRefCount(index);
- return 0;
-}
-//! check whether a glue variable is in physical register or spilled
-
-//!
-bool isGlueHandled(int glue_reg) {
- if(currentBB == NULL) return false;
- int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
- if(index < 0) {
- ALOGE("glue reg %d not found in isGlueHandled", glue_reg);
- return -1;
- }
- if(compileTable[index].spill_loc_index >= 0 ||
- compileTable[index].physicalReg != PhysicalReg_Null) {
-#ifdef DEBUG_GLUE
- ALOGI("GLUE isGlueHandled for %d returns true", glue_reg);
-#endif
- return true;
- }
-#ifdef DEBUG_GLUE
- ALOGI("GLUE isGlueHandled for %d returns false", glue_reg);
-#endif
- return false;
-}
-//! reset the state of a glue variable to not existant (not in physical register nor spilled)
-
-//!
-void resetGlue(int glue_reg) {
- if(currentBB == NULL) return;
- int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
- if(index < 0) {
- ALOGE("glue reg %d not found in resetGlue", glue_reg);
- return;
- }
-#ifdef DEBUG_GLUE
- ALOGI("GLUE reset for %d", glue_reg);
-#endif
- compileTable[index].physicalReg = PhysicalReg_Null;
- if(compileTable[index].spill_loc_index >= 0)
- spillIndexUsed[compileTable[index].spill_loc_index >> 2] = 0;
- compileTable[index].spill_loc_index = -1;
-}
-//! set a glue variable in a physical register allocated for a variable
-
-//! Variable is using lowering module's naming convention
-void updateGlue(int reg, bool isPhysical, int glue_reg) {
- if(currentBB == NULL) return;
- int index = searchCompileTable(LowOpndRegType_gp, glue_reg);
- if(index < 0) {
- ALOGE("glue reg %d not found in updateGlue", glue_reg);
- return;
- }
- /* find the compileTable entry for variable <reg, isPhysical> */
- int newType = convertType(LowOpndRegType_gp, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int index2 = searchCompileTable(newType, reg);
- if(index2 < 0 || compileTable[index2].physicalReg == PhysicalReg_Null) {
- ALOGE("updateGlue reg %d type %d", reg, newType);
- return;
- }
-#ifdef DEBUG_GLUE
- ALOGI("physical register for GLUE %d set to %d", glue_reg, compileTable[index2].physicalReg);
-#endif
- compileTable[index].physicalReg = compileTable[index2].physicalReg;
- compileTable[index].spill_loc_index = -1;
-}
-
-//! check whether a virtual register is in a physical register
-
-//! If updateRefCount is 0, do not update reference count;
-//!If updateRefCount is 1, update reference count only when VR is in a physical register
-//!If updateRefCount is 2, update reference count
-int checkVirtualReg(int reg, LowOpndRegType type, int updateRefCount) {
- if(currentBB == NULL) return PhysicalReg_Null;
- int index = searchCompileTable(LowOpndRegType_virtual | type, reg);
- if(index < 0) {
- ALOGE("virtual reg %d type %d not found in checkVirtualReg", reg, type);
- return PhysicalReg_Null;
- }
- //reduce reference count
- if(compileTable[index].physicalReg != PhysicalReg_Null) {
- if(updateRefCount != 0) decreaseRefCount(index);
- return compileTable[index].physicalReg;
- }
- if(updateRefCount == 2) decreaseRefCount(index);
- return PhysicalReg_Null;
-}
-//!check whether a temporary can share the same physical register with a VR
-
-//!This is called in get_virtual_reg
-//!If this function returns false, new register will be allocated for this temporary
-bool checkTempReg2(int reg, int type, bool isPhysical, int physicalRegForVR) {
- if(currentBB == NULL) return false;
- if(isPhysical) return false;
-
- int newType = convertType(type, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int k;
- for(k = 0; k < num_temp_regs_per_bytecode; k++) {
- if(infoByteCodeTemp[k].physicalType == newType &&
- infoByteCodeTemp[k].regNum == reg) {
-#ifdef DEBUG_MOVE_OPT
- ALOGI("MOVE_OPT checkTempRegs for %d %d returns %d %d",
- reg, newType, infoByteCodeTemp[k].shareWithVR, infoByteCodeTemp[k].is8Bit);
-#endif
- if(!infoByteCodeTemp[k].is8Bit) return infoByteCodeTemp[k].shareWithVR;
- //is8Bit true for gp type only
- if(!infoByteCodeTemp[k].shareWithVR) return false;
- //both true
- if(physicalRegForVR >= PhysicalReg_EAX && physicalRegForVR <= PhysicalReg_EDX) return true;
-#ifdef DEBUG_MOVE_OPT
- ALOGI("MOVE_OPT registerAllocMove not used for 8-bit register");
-#endif
- return false;
- }
- }
- ALOGE("checkTempReg2 %d %d", reg, newType);
- return false;
-}
-//!check whether a temporary can share the same physical register with a VR
-
-//!This is called in set_virtual_reg
-int checkTempReg(int reg, int type, bool isPhysical, int vrNum) {
- if(currentBB == NULL) return PhysicalReg_Null;
-
- int newType = convertType(type, reg, isPhysical);
- if(newType & LowOpndRegType_scratch) reg = reg - PhysicalReg_SCRATCH_1 + 1;
- int index = searchCompileTable(newType, reg);
- if(index < 0) {
- ALOGE("temp reg %d type %d not found in checkTempReg", reg, newType);
- return PhysicalReg_Null;
- }
-
- //a temporary register can share the same physical reg with a VR if registerAllocMove is called
- //this will cause problem with move bytecode
- //get_VR(v1, t1) t1 and v1 point to the same physical reg
- //set_VR(t1, v2) t1 and v2 point to the same physical reg
- //this will cause v1 and v2 point to the same physical reg
- //FIX: if this temp reg shares a physical reg with another reg
- if(compileTable[index].physicalReg != PhysicalReg_Null) {
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(k == index) continue;
- if(compileTable[k].physicalReg == compileTable[index].physicalReg) {
- return PhysicalReg_Null; //will allocate a register for VR
- }
- }
- decreaseRefCount(index);
- return compileTable[index].physicalReg;
- }
- if(compileTable[index].spill_loc_index >= 0) {
- //registerAlloc will call unspillLogicalReg (load from memory)
-#ifdef DEBUG_REGALLOC
- ALOGW("in checkTempReg, the temporary register %d %d was spilled", reg, type);
-#endif
- int regAll = registerAlloc(type, reg, isPhysical, true/* updateRefCount */);
- return regAll;
- }
- return PhysicalReg_Null;
-}
-//!check whether a variable has exposed usage in a basic block
-
-//!It calls hasExposedUsage2
-bool hasExposedUsage(LowOpndRegType type, int regNum, BasicBlock_O1* bb) {
- int index = searchVirtualInfoOfBB(type, regNum, bb);
- if(index >= 0 && hasExposedUsage2(bb, index)) {
- return true;
- }
- return false;
-}
-//!check whether a variable has exposed usage in other basic blocks
-
-//!
-bool hasOtherExposedUsage(OpndSize size, int regNum, BasicBlock_O1* bb) {
- return true; //assume the worst case
-}
-
-//! handles constant VRs at end of a basic block
-
-//!If a VR is constant at end of a basic block and (it has exposed usage in other basic blocks or reaches a GG VR), dump immediate to memory
-void constVREndOfBB() {
- BasicBlock_O1* bb = currentBB;
- int k, k2;
- //go through GG VRs, update a bool array
- int constUsedByGG[MAX_CONST_REG];
- for(k = 0; k < num_const_vr; k++)
- constUsedByGG[k] = 0;
- for(k = 0; k < num_compile_entries; k++) {
- if(isVirtualReg(compileTable[k].physicalType) && compileTable[k].gType == GLOBALTYPE_GG) {
- OpndSize size = getRegSize(compileTable[k].physicalType);
- int regNum = compileTable[k].regNum;
- int indexL = -1;
- int indexH = -1;
- for(k2 = 0; k2 < num_const_vr; k2++) {
- if(constVRTable[k2].regNum == regNum) {
- indexL = k2;
- continue;
- }
- if(constVRTable[k2].regNum == regNum + 1 && size == OpndSize_64) {
- indexH = k2;
- continue;
- }
- }
- if(indexL >= 0) constUsedByGG[indexL] = 1;
- if(indexH >= 0) constUsedByGG[indexH] = 1;
- } //GG VR
- }
- for(k = 0; k < num_const_vr; k++) {
- if(!constVRTable[k].isConst) continue;
- bool hasExp = false;
- if(constUsedByGG[k] == 0)
- hasExp = hasOtherExposedUsage(OpndSize_32, constVRTable[k].regNum, bb);
- if(constUsedByGG[k] != 0 || hasExp) {
- dumpImmToMem(constVRTable[k].regNum, OpndSize_32, constVRTable[k].value);
- setVRToMemory(constVRTable[k].regNum, OpndSize_32);
-#ifdef DEBUG_ENDOFBB
- ALOGI("ENDOFBB: exposed VR %d is const %d (%x)",
- constVRTable[k].regNum, constVRTable[k].value, constVRTable[k].value);
-#endif
- } else {
-#ifdef DEBUG_ENDOFBB
- ALOGI("ENDOFBB: unexposed VR %d is const %d (%x)",
- constVRTable[k].regNum, constVRTable[k].value, constVRTable[k].value);
-#endif
- }
- }
-}
-
-//!handles GG VRs at end of a basic block
-
-//!make sure all GG VRs are in pre-defined physical registers
-void globalVREndOfBB(const Method* method) {
- //fix: freeReg first to write LL VR back to memory to avoid it gets overwritten by GG VRs
- freeReg(true);
- int k;
- //spill GG VR first if it is not mapped to the specific reg
- //release GLUE regs
- for(k = 0; k < num_compile_entries; k++) {
- if(compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
- compileTable[k].regNum != PhysicalReg_GLUE) {
- compileTable[k].physicalReg = PhysicalReg_Null;
- compileTable[k].spill_loc_index = -1;
- }
- //if part of a GG VR is const, the physical reg is set to null
- if(isVirtualReg(compileTable[k].physicalType) &&
- compileTable[k].gType == GLOBALTYPE_GG && compileTable[k].physicalReg != PhysicalReg_Null &&
- compileTable[k].physicalReg != compileTable[k].physicalReg_prev) {
-#ifdef DEBUG_ENDOFBB
- ALOGW("end of BB GG VR is not mapped to the specific reg: %d %d %d",
- compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg);
- ALOGW("ENDOFBB SPILL VR %d %d", compileTable[k].regNum, compileTable[k].physicalType);
-#endif
- spillLogicalReg(k, true); //the next section will load VR from memory to the specific reg
- }
- }
- syncAllRegs();
- for(k = 0; k < num_compile_entries; k++) {
- if(isVirtualReg(compileTable[k].physicalType)) {
- if(compileTable[k].gType == GLOBALTYPE_GG &&
- compileTable[k].physicalReg == PhysicalReg_Null && (!currentBB->endsWithReturn)) {
-#ifdef DEBUG_ENDOFBB
- ALOGI("ENDOFBB GET GG VR %d %d to physical register %d", compileTable[k].regNum,
- compileTable[k].physicalType, compileTable[k].physicalReg_prev);
-#endif
- compileTable[k].physicalReg = compileTable[k].physicalReg_prev;
- if(allRegs[compileTable[k].physicalReg_prev].isUsed) {
- ALOGE("physical register for GG VR is still used");
- }
- get_virtual_reg_noalloc(compileTable[k].regNum,
- getRegSize(compileTable[k].physicalType),
- compileTable[k].physicalReg_prev,
- true);
- }
- }//not const
- }
- if(indexForGlue >= 0 &&
- compileTable[indexForGlue].physicalReg == PhysicalReg_Null) {
- unspillLogicalReg(indexForGlue, PhysicalReg_EBP); //load %ebp
- }
-}
-
-//! get ready for the next version of a hard-coded register
-
-//!set its physicalReg to Null and update its reference count
-int nextVersionOfHardReg(PhysicalReg pReg, int refCount) {
- int indexT = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_hard, pReg);
- if(indexT < 0)
- return -1;
- compileTable[indexT].physicalReg = PhysicalReg_Null;
-#ifdef DEBUG_REFCOUNT
- ALOGI("REFCOUNT: to %d in nextVersionOfHardReg %d", refCount, pReg);
-#endif
- compileTable[indexT].refCount = refCount;
- return 0;
-}
-
-/** update compileTable with bb->infoBasicBlock[k]
-*/
-void insertFromVirtualInfo(BasicBlock_O1* bb, int k) {
- int index = searchCompileTable(LowOpndRegType_virtual | bb->infoBasicBlock[k].physicalType, bb->infoBasicBlock[k].regNum);
- if(index < 0) {
- /* the virtual register is not in compileTable, insert it */
- index = num_compile_entries;
- compileTable[num_compile_entries].physicalType = (LowOpndRegType_virtual | bb->infoBasicBlock[k].physicalType);
- compileTable[num_compile_entries].regNum = bb->infoBasicBlock[k].regNum;
- compileTable[num_compile_entries].physicalReg = PhysicalReg_Null;
- compileTable[num_compile_entries].bb = bb;
- compileTable[num_compile_entries].indexToInfoBB = k;
- compileTable[num_compile_entries].spill_loc_index = -1;
- compileTable[num_compile_entries].gType = bb->infoBasicBlock[k].gType;
- num_compile_entries++;
- if(num_compile_entries >= COMPILE_TABLE_SIZE) {
- ALOGE("compileTable overflow");
- dvmAbort();
- }
- }
- /* re-set reference count of all VRs */
- compileTable[index].refCount = bb->infoBasicBlock[k].refCount;
- compileTable[index].accessType = bb->infoBasicBlock[k].accessType;
- if(compileTable[index].gType == GLOBALTYPE_GG)
- compileTable[index].physicalReg_prev = bb->infoBasicBlock[k].physicalReg_GG;
-}
-
-/** update compileTable with infoByteCodeTemp[k]
-*/
-void insertFromTempInfo(int k) {
- int index = searchCompileTable(infoByteCodeTemp[k].physicalType, infoByteCodeTemp[k].regNum);
- if(index < 0) {
- /* the temporary is not in compileTable, insert it */
- index = num_compile_entries;
- compileTable[num_compile_entries].physicalType = infoByteCodeTemp[k].physicalType;
- compileTable[num_compile_entries].regNum = infoByteCodeTemp[k].regNum;
- num_compile_entries++;
- if(num_compile_entries >= COMPILE_TABLE_SIZE) {
- ALOGE("compileTable overflow");
- dvmAbort();
- }
- }
- compileTable[index].physicalReg = PhysicalReg_Null;
- compileTable[index].refCount = infoByteCodeTemp[k].refCount;
- compileTable[index].linkageToVR = infoByteCodeTemp[k].linkageToVR;
- compileTable[index].gType = GLOBALTYPE_L;
- compileTable[index].spill_loc_index = -1;
-}
-
-/* insert a glue-related register GLUE_DVMDEX to compileTable */
-void insertGlueReg() {
- compileTable[num_compile_entries].physicalType = LowOpndRegType_gp;
- compileTable[num_compile_entries].regNum = PhysicalReg_GLUE_DVMDEX;
- compileTable[num_compile_entries].refCount = 2;
- compileTable[num_compile_entries].physicalReg = PhysicalReg_Null;
- compileTable[num_compile_entries].bb = NULL;
- compileTable[num_compile_entries].spill_loc_index = -1;
- compileTable[num_compile_entries].accessType = REGACCESS_N;
- compileTable[num_compile_entries].linkageToVR = -1;
- compileTable[num_compile_entries].gType = GLOBALTYPE_L;
-
- num_compile_entries++;
- if(num_compile_entries >= COMPILE_TABLE_SIZE) {
- ALOGE("compileTable overflow");
- dvmAbort();
- }
-}
-
-/** print infoBasicBlock of the given basic block
-*/
-void dumpVirtualInfoOfBasicBlock(BasicBlock_O1* bb) {
- int jj;
- ALOGI("Virtual Info for BB%d --------", bb->bb_index);
- for(jj = 0; jj < bb->num_regs; jj++) {
- ALOGI("regNum %d physicalType %d accessType %d refCount %d def ",
- bb->infoBasicBlock[jj].regNum, bb->infoBasicBlock[jj].physicalType,
- bb->infoBasicBlock[jj].accessType, bb->infoBasicBlock[jj].refCount);
- int k;
- for(k = 0; k < bb->infoBasicBlock[jj].num_reaching_defs; k++)
- ALOGI("[%x %d %d %d] ", bb->infoBasicBlock[jj].reachingDefs[k].offsetPC,
- bb->infoBasicBlock[jj].reachingDefs[k].regNum,
- bb->infoBasicBlock[jj].reachingDefs[k].physicalType,
- bb->infoBasicBlock[jj].reachingDefs[k].accessType);
- ALOGI("");
- }
-}
-
-/** print compileTable
-*/
-void dumpCompileTable() {
- int jj;
- ALOGI("Compile Table for method ----------");
- for(jj = 0; jj < num_compile_entries; jj++) {
- ALOGI("regNum %d physicalType %d refCount %d isConst %d physicalReg %d type %d",
- compileTable[jj].regNum, compileTable[jj].physicalType,
- compileTable[jj].refCount, compileTable[jj].isConst, compileTable[jj].physicalReg, compileTable[jj].gType);
- }
-}
-
-//!check whether a basic block is the start of an exception handler
-
-//!
-bool isFirstOfHandler(BasicBlock_O1* bb) {
- int i;
- for(i = 0; i < num_exception_handlers; i++) {
- if(bb->pc_start == exceptionHandlers[i]) return true;
- }
- return false;
-}
-
-//! create a basic block that starts at src_pc and ends at end_pc
-
-//!
-BasicBlock_O1* createBasicBlock(int src_pc, int end_pc) {
- BasicBlock_O1* bb = (BasicBlock_O1*)malloc(sizeof(BasicBlock_O1));
- if(bb == NULL) {
- ALOGE("out of memory");
- return NULL;
- }
- bb->pc_start = src_pc;
- bb->bb_index = num_bbs_for_method;
- if(bb_entry == NULL) bb_entry = bb;
-
- /* insert the basic block to method_bbs_sorted in ascending order of pc_start */
- int k;
- int index = -1;
- for(k = 0; k < num_bbs_for_method; k++)
- if(method_bbs_sorted[k]->pc_start > src_pc) {
- index = k;
- break;
- }
- if(index == -1)
- method_bbs_sorted[num_bbs_for_method] = bb;
- else {
- /* push the elements from index by 1 */
- for(k = num_bbs_for_method-1; k >= index; k--)
- method_bbs_sorted[k+1] = method_bbs_sorted[k];
- method_bbs_sorted[index] = bb;
- }
- num_bbs_for_method++;
- if(num_bbs_for_method >= MAX_NUM_BBS_PER_METHOD) {
- ALOGE("too many basic blocks");
- dvmAbort();
- }
- return bb;
-}
-
-/* BEGIN code to handle state transfers */
-//! save the current state of register allocator to a state table
-
-//!
-void rememberState(int stateNum) {
-#ifdef DEBUG_STATE
- ALOGI("STATE: remember state %d", stateNum);
-#endif
- int k;
- for(k = 0; k < num_compile_entries; k++) {
- if(stateNum == 1) {
- stateTable1_1[k].physicalReg = compileTable[k].physicalReg;
- stateTable1_1[k].spill_loc_index = compileTable[k].spill_loc_index;
- }
- else if(stateNum == 2) {
- stateTable1_2[k].physicalReg = compileTable[k].physicalReg;
- stateTable1_2[k].spill_loc_index = compileTable[k].spill_loc_index;
- }
- else if(stateNum == 3) {
- stateTable1_3[k].physicalReg = compileTable[k].physicalReg;
- stateTable1_3[k].spill_loc_index = compileTable[k].spill_loc_index;
- }
- else if(stateNum == 4) {
- stateTable1_4[k].physicalReg = compileTable[k].physicalReg;
- stateTable1_4[k].spill_loc_index = compileTable[k].spill_loc_index;
- }
- else ALOGE("state table overflow");
-#ifdef DEBUG_STATE
- ALOGI("logical reg %d %d mapped to physical reg %d with spill index %d refCount %d",
- compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg,
- compileTable[k].spill_loc_index, compileTable[k].refCount);
-#endif
- }
- for(k = 0; k < num_memory_vr; k++) {
- if(stateNum == 1) {
- stateTable2_1[k].regNum = memVRTable[k].regNum;
- stateTable2_1[k].inMemory = memVRTable[k].inMemory;
- }
- else if(stateNum == 2) {
- stateTable2_2[k].regNum = memVRTable[k].regNum;
- stateTable2_2[k].inMemory = memVRTable[k].inMemory;
- }
- else if(stateNum == 3) {
- stateTable2_3[k].regNum = memVRTable[k].regNum;
- stateTable2_3[k].inMemory = memVRTable[k].inMemory;
- }
- else if(stateNum == 4) {
- stateTable2_4[k].regNum = memVRTable[k].regNum;
- stateTable2_4[k].inMemory = memVRTable[k].inMemory;
- }
- else ALOGE("state table overflow");
-#ifdef DEBUG_STATE
- ALOGI("virtual reg %d in memory %d", memVRTable[k].regNum, memVRTable[k].inMemory);
-#endif
- }
-}
-
-//!update current state of register allocator with a state table
-
-//!
-void goToState(int stateNum) {
- int k;
-#ifdef DEBUG_STATE
- ALOGI("STATE: go to state %d", stateNum);
-#endif
- for(k = 0; k < num_compile_entries; k++) {
- if(stateNum == 1) {
- compileTable[k].physicalReg = stateTable1_1[k].physicalReg;
- compileTable[k].spill_loc_index = stateTable1_1[k].spill_loc_index;
- }
- else if(stateNum == 2) {
- compileTable[k].physicalReg = stateTable1_2[k].physicalReg;
- compileTable[k].spill_loc_index = stateTable1_2[k].spill_loc_index;
- }
- else if(stateNum == 3) {
- compileTable[k].physicalReg = stateTable1_3[k].physicalReg;
- compileTable[k].spill_loc_index = stateTable1_3[k].spill_loc_index;
- }
- else if(stateNum == 4) {
- compileTable[k].physicalReg = stateTable1_4[k].physicalReg;
- compileTable[k].spill_loc_index = stateTable1_4[k].spill_loc_index;
- }
- else ALOGE("state table overflow");
- }
- updateSpillIndexUsed();
- syncAllRegs(); //to sync up allRegs CAN'T call freeReg here
- //since it will change the state!!!
- for(k = 0; k < num_memory_vr; k++) {
- if(stateNum == 1) {
- memVRTable[k].regNum = stateTable2_1[k].regNum;
- memVRTable[k].inMemory = stateTable2_1[k].inMemory;
- }
- else if(stateNum == 2) {
- memVRTable[k].regNum = stateTable2_2[k].regNum;
- memVRTable[k].inMemory = stateTable2_2[k].inMemory;
- }
- else if(stateNum == 3) {
- memVRTable[k].regNum = stateTable2_3[k].regNum;
- memVRTable[k].inMemory = stateTable2_3[k].inMemory;
- }
- else if(stateNum == 4) {
- memVRTable[k].regNum = stateTable2_4[k].regNum;
- memVRTable[k].inMemory = stateTable2_4[k].inMemory;
- }
- else ALOGE("state table overflow");
- }
-}
-typedef struct TransferOrder {
- int targetReg;
- int targetSpill;
- int compileIndex;
-} TransferOrder;
-#define MAX_NUM_DEST 20
-//! a source register is used as a source in transfer
-//! it can have a maximum of MAX_NUM_DEST destinations
-typedef struct SourceReg {
- int physicalReg;
- int num_dests; //check bound
- TransferOrder dsts[MAX_NUM_DEST];
-} SourceReg;
-int num_src_regs = 0; //check bound
-//! physical registers that are used as a source in transfer
-//! we allow a maximum of MAX_NUM_DEST sources in a transfer
-SourceReg srcRegs[MAX_NUM_DEST];
-//! tell us whether a source register is handled already
-bool handledSrc[MAX_NUM_DEST];
-//! in what order should the source registers be handled
-int handledOrder[MAX_NUM_DEST];
-//! insert a source register with a single destination
-
-//!
-void insertSrcReg(int srcPhysical, int targetReg, int targetSpill, int index) {
- int k = 0;
- for(k = 0; k < num_src_regs; k++) {
- if(srcRegs[k].physicalReg == srcPhysical) { //increase num_dests
- if(srcRegs[k].num_dests >= MAX_NUM_DEST) {
- ALOGE("exceed number dst regs for a source reg");
- dvmAbort();
- }
- srcRegs[k].dsts[srcRegs[k].num_dests].targetReg = targetReg;
- srcRegs[k].dsts[srcRegs[k].num_dests].targetSpill = targetSpill;
- srcRegs[k].dsts[srcRegs[k].num_dests].compileIndex = index;
- srcRegs[k].num_dests++;
- return;
- }
- }
- if(num_src_regs >= MAX_NUM_DEST) {
- ALOGE("exceed number of source regs");
- dvmAbort();
- }
- srcRegs[num_src_regs].physicalReg = srcPhysical;
- srcRegs[num_src_regs].num_dests = 1;
- srcRegs[num_src_regs].dsts[0].targetReg = targetReg;
- srcRegs[num_src_regs].dsts[0].targetSpill = targetSpill;
- srcRegs[num_src_regs].dsts[0].compileIndex = index;
- num_src_regs++;
-}
-//! check whether a register is a source and the source is not yet handled
-
-//!
-bool dstStillInUse(int dstReg) {
- if(dstReg == PhysicalReg_Null) return false;
- int k;
- int index = -1;
- for(k = 0; k < num_src_regs; k++) {
- if(dstReg == srcRegs[k].physicalReg) {
- index = k;
- break;
- }
- }
- if(index < 0) return false; //not in use
- if(handledSrc[index]) return false; //not in use
- return true;
-}
-//! reset the state of glue variables in a state table
-
-//!
-void resetStateOfGlue(int stateNum, int k) {
-#ifdef DEBUG_STATE
- ALOGI("resetStateOfGlue state %d regNum %d", stateNum, compileTable[k].regNum);
-#endif
- if(stateNum == 1) {
- stateTable1_1[k].physicalReg = PhysicalReg_Null;
- stateTable1_1[k].spill_loc_index = -1;
- }
- else if(stateNum == 2) {
- stateTable1_2[k].physicalReg = PhysicalReg_Null;
- stateTable1_2[k].spill_loc_index = -1;
- }
- else if(stateNum == 3) {
- stateTable1_3[k].physicalReg = PhysicalReg_Null;
- stateTable1_3[k].spill_loc_index = -1;
- }
- else if(stateNum == 4) {
- stateTable1_4[k].physicalReg = PhysicalReg_Null;
- stateTable1_4[k].spill_loc_index = -1;
- }
-}
-//! construct a legal order of the source registers in this transfer
-
-//!
-void constructSrcRegs(int stateNum) {
- int k;
- num_src_regs = 0;
-#ifdef DEBUG_STATE
- ALOGI("IN constructSrcRegs");
-#endif
-
- for(k = 0; k < num_compile_entries; k++) {
-#ifdef DEBUG_STATE
- ALOGI("logical reg %d %d mapped to physical reg %d with spill index %d refCount %d",
- compileTable[k].regNum, compileTable[k].physicalType, compileTable[k].physicalReg,
- compileTable[k].spill_loc_index, compileTable[k].refCount);
-#endif
-
- int pType = compileTable[k].physicalType;
- //ignore hardcoded logical registers
- if((pType & LowOpndRegType_hard) != 0) continue;
- //ignore type _fs
- if((pType & MASK_FOR_TYPE) == LowOpndRegType_fs) continue;
- if((pType & MASK_FOR_TYPE) == LowOpndRegType_fs_s) continue;
-
- //GL VR refCount is zero, can't ignore
- //L VR refCount is zero, ignore
- //GG VR refCount is zero, can't ignore
- //temporary refCount is zero, ignore
-
- //for GLUE variables, if they do not exist, reset the entries in state table
- if(compileTable[k].physicalReg == PhysicalReg_Null &&
- compileTable[k].regNum >= PhysicalReg_GLUE_DVMDEX &&
- compileTable[k].regNum != PhysicalReg_GLUE &&
- compileTable[k].spill_loc_index < 0) {
- resetStateOfGlue(stateNum, k);
- }
-
- /* get the target state */
- int targetReg = PhysicalReg_Null;
- int targetSpill = -1;
- if(stateNum == 1) {
- targetReg = stateTable1_1[k].physicalReg;
- targetSpill = stateTable1_1[k].spill_loc_index;
- }
- else if(stateNum == 2) {
- targetReg = stateTable1_2[k].physicalReg;
- targetSpill = stateTable1_2[k].spill_loc_index;
- }
- else if(stateNum == 3) {
- targetReg = stateTable1_3[k].physicalReg;
- targetSpill = stateTable1_3[k].spill_loc_index;
- }
- else if(stateNum == 4) {
- targetReg = stateTable1_4[k].physicalReg;
- targetSpill = stateTable1_4[k].spill_loc_index;
- }
-
- /* there exists an ordering problem
- for example:
- for a VR, move from memory to a physical reg esi
- for a temporary regsiter, from esi to ecx
- if we handle VR first, content of the temporary reg. will be overwritten
- there are 4 cases:
- I: a variable is currently in memory and its target is in physical reg
- II: a variable is currently in a register and its target is in memory
- III: a variable is currently in a different register
- IV: a variable is currently in a different memory location (for non-VRs)
- for GLUE, since it can only be allocated to %ebp, we don't have case III
- For now, case IV is not handled since it didn't show
- */
- if(compileTable[k].physicalReg != targetReg &&
- isVirtualReg(compileTable[k].physicalType)) {
- /* handles VR for case I to III */
-
- if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- /* handles VR for case I:
- insert a xfer order from PhysicalReg_Null to targetReg */
- insertSrcReg(PhysicalReg_Null, targetReg, targetSpill, k);
-#ifdef DEBUG_STATE
- ALOGI("insert for VR Null %d %d %d", targetReg, targetSpill, k);
-#endif
- }
-
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- /* handles VR for case III
- insert a xfer order from srcReg to targetReg */
- insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
- }
-
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
- /* handles VR for case II
- insert a xfer order from srcReg to memory */
- insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
- }
- }
-
- if(compileTable[k].physicalReg != targetReg &&
- !isVirtualReg(compileTable[k].physicalType)) {
- /* handles non-VR for case I to III */
-
- if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- /* handles non-VR for case I */
- if(compileTable[k].spill_loc_index < 0) {
- /* this variable is freed, no need to transfer */
-#ifdef DEBUG_STATE
- ALOGW("in transferToState spill_loc_index is negative for temporary %d", compileTable[k].regNum);
-#endif
- } else {
- /* insert a xfer order from memory to targetReg */
-#ifdef DEBUG_STATE
- ALOGI("insert Null %d %d %d", targetReg, targetSpill, k);
-#endif
- insertSrcReg(PhysicalReg_Null, targetReg, targetSpill, k);
- }
- }
-
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- /* handles non-VR for case III
- insert a xfer order from srcReg to targetReg */
- insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
- }
-
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
- /* handles non-VR for case II */
- if(targetSpill < 0) {
- /* this variable is freed, no need to transfer */
-#ifdef DEBUG_STATE
- ALOGW("in transferToState spill_loc_index is negative for temporary %d", compileTable[k].regNum);
-#endif
- } else {
- /* insert a xfer order from srcReg to memory */
- insertSrcReg(compileTable[k].physicalReg, targetReg, targetSpill, k);
- }
- }
-
- }
- }//for compile entries
-
- int k2;
-#ifdef DEBUG_STATE
- for(k = 0; k < num_src_regs; k++) {
- ALOGI("SRCREG %d: ", srcRegs[k].physicalReg);
- for(k2 = 0; k2 < srcRegs[k].num_dests; k2++) {
- int index = srcRegs[k].dsts[k2].compileIndex;
- ALOGI("[%d %d %d: %d %d %d] ", srcRegs[k].dsts[k2].targetReg,
- srcRegs[k].dsts[k2].targetSpill, srcRegs[k].dsts[k2].compileIndex,
- compileTable[index].regNum, compileTable[index].physicalType,
- compileTable[index].spill_loc_index);
- }
- ALOGI("");
- }
-#endif
-
- /* construct an order: xfers from srcReg first, then xfers from memory */
- int num_handled = 0;
- int num_in_order = 0;
- for(k = 0; k < num_src_regs; k++) {
- if(srcRegs[k].physicalReg == PhysicalReg_Null) {
- handledSrc[k] = true;
- num_handled++;
- } else {
- handledSrc[k] = false;
- }
- }
- while(num_handled < num_src_regs) {
- int prev_handled = num_handled;
- for(k = 0; k < num_src_regs; k++) {
- if(handledSrc[k]) continue;
- bool canHandleNow = true;
- for(k2 = 0; k2 < srcRegs[k].num_dests; k2++) {
- if(dstStillInUse(srcRegs[k].dsts[k2].targetReg)) {
- canHandleNow = false;
- break;
- }
- }
- if(canHandleNow) {
- handledSrc[k] = true;
- num_handled++;
- handledOrder[num_in_order] = k;
- num_in_order++;
- }
- } //for k
- if(num_handled == prev_handled) {
- ALOGE("no progress in selecting order");
- dvmAbort();
- }
- } //while
- for(k = 0; k < num_src_regs; k++) {
- if(srcRegs[k].physicalReg == PhysicalReg_Null) {
- handledOrder[num_in_order] = k;
- num_in_order++;
- }
- }
- if(num_in_order != num_src_regs) {
- ALOGE("num_in_order != num_src_regs");
- dvmAbort();
- }
-#ifdef DEBUG_STATE
- ALOGI("ORDER: ");
- for(k = 0; k < num_src_regs; k++) {
- ALOGI("%d ", handledOrder[k]);
- }
- ALOGI("");
-#endif
-}
-//! transfer the state of register allocator to a state specified in a state table
-
-//!
-void transferToState(int stateNum) {
- freeReg(false); //do not spill GL
- int k;
-#ifdef DEBUG_STATE
- ALOGI("STATE: transfer to state %d", stateNum);
-#endif
- if(stateNum > 4 || stateNum < 1) ALOGE("state table overflow");
- constructSrcRegs(stateNum);
- int k4, k3;
- for(k4 = 0; k4 < num_src_regs; k4++) {
- int k2 = handledOrder[k4]; //index to srcRegs
- for(k3 = 0; k3 < srcRegs[k2].num_dests; k3++) {
- k = srcRegs[k2].dsts[k3].compileIndex;
- int targetReg = srcRegs[k2].dsts[k3].targetReg;
- int targetSpill = srcRegs[k2].dsts[k3].targetSpill;
- if(compileTable[k].physicalReg != targetReg && isVirtualReg(compileTable[k].physicalType)) {
- OpndSize oSize = getRegSize(compileTable[k].physicalType);
- bool isSS = ((compileTable[k].physicalType & MASK_FOR_TYPE) == LowOpndRegType_ss);
- if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- if(isSS)
- move_ss_mem_to_reg_noalloc(4*compileTable[k].regNum,
- PhysicalReg_FP, true,
- MemoryAccess_VR, compileTable[k].regNum,
- targetReg, true);
- else
- move_mem_to_reg_noalloc(oSize, 4*compileTable[k].regNum,
- PhysicalReg_FP, true,
- MemoryAccess_VR, compileTable[k].regNum,
- targetReg, true);
- }
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- move_reg_to_reg_noalloc((isSS ? OpndSize_64 : oSize),
- compileTable[k].physicalReg, true,
- targetReg, true);
- }
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
- dumpToMem(compileTable[k].regNum, (LowOpndRegType)(compileTable[k].physicalType & MASK_FOR_TYPE),
- compileTable[k].physicalReg);
- }
- } //VR
- if(compileTable[k].physicalReg != targetReg && !isVirtualReg(compileTable[k].physicalType)) {
- OpndSize oSize = getRegSize(compileTable[k].physicalType);
- if(compileTable[k].physicalReg == PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- loadFromSpillRegion(oSize, targetReg,
- compileTable[k].spill_loc_index);
- }
- //both are not null, move from one to the other
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg != PhysicalReg_Null) {
- move_reg_to_reg_noalloc(oSize, compileTable[k].physicalReg, true,
- targetReg, true);
- }
- //current is not null, target is null (move from reg to memory)
- if(compileTable[k].physicalReg != PhysicalReg_Null && targetReg == PhysicalReg_Null) {
- saveToSpillRegion(oSize, compileTable[k].physicalReg, targetSpill);
- }
- } //temporary
- }//for
- }//for
- for(k = 0; k < num_memory_vr; k++) {
- bool targetBool = false;
- int targetReg = -1;
- if(stateNum == 1) {
- targetReg = stateTable2_1[k].regNum;
- targetBool = stateTable2_1[k].inMemory;
- }
- else if(stateNum == 2) {
- targetReg = stateTable2_2[k].regNum;
- targetBool = stateTable2_2[k].inMemory;
- }
- else if(stateNum == 3) {
- targetReg = stateTable2_3[k].regNum;
- targetBool = stateTable2_3[k].inMemory;
- }
- else if(stateNum == 4) {
- targetReg = stateTable2_4[k].regNum;
- targetBool = stateTable2_4[k].inMemory;
- }
- if(targetReg != memVRTable[k].regNum)
- ALOGE("regNum mismatch in transferToState");
- if(targetBool && (!memVRTable[k].inMemory)) {
- //dump to memory, check entries in compileTable: vA gp vA xmm vA ss
-#ifdef DEBUG_STATE
- ALOGW("inMemory mismatch for VR %d in transferToState", targetReg);
-#endif
- bool doneXfer = false;
- int index = searchCompileTable(LowOpndRegType_xmm | LowOpndRegType_virtual, targetReg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
- dumpToMem(targetReg, LowOpndRegType_xmm, compileTable[index].physicalReg);
- doneXfer = true;
- }
- if(!doneXfer) { //vA-1, xmm
- index = searchCompileTable(LowOpndRegType_xmm | LowOpndRegType_virtual, targetReg-1);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
- dumpToMem(targetReg-1, LowOpndRegType_xmm, compileTable[index].physicalReg);
- doneXfer = true;
- }
- }
- if(!doneXfer) { //vA gp
- index = searchCompileTable(LowOpndRegType_gp | LowOpndRegType_virtual, targetReg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
- dumpToMem(targetReg, LowOpndRegType_gp, compileTable[index].physicalReg);
- doneXfer = true;
- }
- }
- if(!doneXfer) { //vA, ss
- index = searchCompileTable(LowOpndRegType_ss | LowOpndRegType_virtual, targetReg);
- if(index >= 0 && compileTable[index].physicalReg != PhysicalReg_Null) {
- dumpToMem(targetReg, LowOpndRegType_ss, compileTable[index].physicalReg);
- doneXfer = true;
- }
- }
- if(!doneXfer) ALOGW("can't match inMemory of VR %d in transferToState", targetReg);
- }
- if((!targetBool) && memVRTable[k].inMemory) {
- //do nothing
- }
- }
-#ifdef DEBUG_STATE
- ALOGI("END transferToState %d", stateNum);
-#endif
- goToState(stateNum);
-}
-/* END code to handle state transfers */