/*
* Copyright (C) 2009 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.
*/
#include "Dalvik.h"
#include "CompilerInternals.h"
#include "Dataflow.h"
typedef struct LiveRange {
int ssaName;
bool active;
int first;
int last;
} LiveRange;
int computeLiveRange(LiveRange *list, BasicBlock *bb, int seqNum)
{
MIR *mir;
int i;
if (bb->blockType != kDalvikByteCode &&
bb->blockType != kEntryBlock)
return seqNum;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
SSARepresentation *ssaRep = mir->ssaRep;
mir->seqNum = seqNum;
if (ssaRep) {
for (i=0; i< ssaRep->numUses; i++) {
int reg = ssaRep->uses[i];
list[reg].first = MIN(list[reg].first, seqNum);
list[reg].active = true;
}
for (i=0; i< ssaRep->numDefs; i++) {
int reg = ssaRep->defs[i];
list[reg].last = MAX(list[reg].last, seqNum + 1);
list[reg].active = true;
}
seqNum += 2;
}
}
return seqNum;
}
/*
* Quick & dirty - make FP usage sticky. This is strictly a hint - local
* code generation will handle misses. It might be worthwhile to collaborate
* with dx/dexopt to avoid reusing the same Dalvik temp for values of
* different types.
*/
static void inferTypes(CompilationUnit *cUnit, BasicBlock *bb)
{
MIR *mir;
if (bb->blockType != kDalvikByteCode &&
bb->blockType != kEntryBlock)
return;
for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
SSARepresentation *ssaRep = mir->ssaRep;
if (ssaRep) {
int i;
for (i=0; ssaRep->fpUse && i< ssaRep->numUses; i++) {
if (ssaRep->fpUse[i])
cUnit->regLocation[ssaRep->uses[i]].fp = true;
}
for (i=0; ssaRep->fpDef && i< ssaRep->numDefs; i++) {
if (ssaRep->fpDef[i])
cUnit->regLocation[ssaRep->defs[i]].fp = true;
}
}
}
}
/*
* Determine whether to use simple or aggressive register allocation. In
* general, loops and full methods will get aggressive.
*/
static bool simpleTrace(CompilationUnit *cUnit)
{
//TODO: flesh out
return true;
}
/*
* Target-independent register allocation. Requires target-dependent
* helper functions and assumes free list, temp list and spill region.
* Uses a variant of linear scan and produces a mapping between SSA names
* and location. Location may be original Dalvik register, hardware
* register or spill location.
*
* Method:
* 0. Allocate the structure to hold the SSA name life ranges
* 1. Number each MIR instruction, counting by 2.
* +0 -> The "read" of the operands
* +1 -> The definition of the target resource
* 2. Compute live ranges for all SSA names *not* including the
* subscript 0 original Dalvik names. Phi functions ignored
* at this point.
* 3. Sort the live range list by lowest range start.
* 4. Process and remove all Phi functions.
* o If there is no live range collisions among all operands and
* the target of a Phi function, collapse operands and target
* and rewrite using target SSA name.
* o If there is a collision, introduce copies.
* 5. Allocate in order of increasing live range start.
*/
static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
INVALID_REG, INVALID_SREG};
void dvmCompilerRegAlloc(CompilationUnit *cUnit)
{
int i;
int seqNum = 0;
LiveRange *ranges;
RegLocation *loc;
int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
/* Allocate the location map */
loc = (RegLocation*)dvmCompilerNew(cUnit->numSSARegs * sizeof(*loc), true);
for (i=0; i< cUnit->numSSARegs; i++) {
loc[i] = freshLoc;
loc[i].sRegLow = i;
}
cUnit->regLocation = loc;
/* Do type inference pass */
for (i=0; i < cUnit->numBlocks; i++) {
inferTypes(cUnit, cUnit->blockList[i]);
}
if (simpleTrace(cUnit)) {
/*
* Just rename everything back to subscript 0 names and don't do
* any explicit promotion. Local allocator will opportunistically
* promote on the fly.
*/
for (i=0; i < cUnit->numSSARegs; i++) {
cUnit->regLocation[i].sRegLow =
DECODE_REG(dvmConvertSSARegToDalvik(cUnit, loc[i].sRegLow));
}
} else {
// Compute live ranges
ranges = dvmCompilerNew(cUnit->numSSARegs * sizeof(*ranges), true);
for (i=0; i < cUnit->numSSARegs; i++)
ranges[i].active = false;
seqNum = computeLiveRange(ranges, cUnit->blockList[i], seqNum);
//TODO: phi squash & linear scan promotion
}
}