/*
 * Copyright (C) 2011 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.
 */

#ifndef ART_SRC_COMPILER_RALLOC_H_
#define ART_SRC_COMPILER_RALLOC_H_
/*
 * This file contains target independent register alloction support.
 */

#include "../CompilerUtility.h"
#include "../CompilerIR.h"
#include "../Dataflow.h"
#include "arm/ArmLIR.h"

/*
 * Return most flexible allowed register class based on size.
 * Bug: 2813841
 * Must use a core register for data types narrower than word (due
 * to possible unaligned load/store.
 */
STATIC inline RegisterClass oatRegClassBySize(OpSize size)
{
    return (size == kUnsignedHalf ||
            size == kSignedHalf ||
            size == kUnsignedByte ||
            size == kSignedByte ) ? kCoreReg : kAnyReg;
}

STATIC inline int oatS2VReg(CompilationUnit* cUnit, int sReg)
{
    DCHECK_NE(sReg, INVALID_SREG);
    return DECODE_REG(oatConvertSSARegToDalvik(cUnit, sReg));
}

/*
 * Get the "real" sreg number associated with an sReg slot.  In general,
 * sReg values passed through codegen are the SSA names created by
 * dataflow analysis and refer to slot numbers in the cUnit->regLocation
 * array.  However, renaming is accomplished by simply replacing RegLocation
 * entries in the cUnit->reglocation[] array.  Therefore, when location
 * records for operands are first created, we need to ask the locRecord
 * identified by the dataflow pass what it's new name is.
 */

STATIC inline int oatSRegHi(int lowSreg) {
    return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
}


STATIC inline bool oatLiveOut(CompilationUnit* cUnit, int sReg)
{
    //For now.
    return true;
}

STATIC inline int oatSSASrc(MIR* mir, int num)
{
    DCHECK_GT(mir->ssaRep->numUses, num);
    return mir->ssaRep->uses[num];
}

extern RegLocation oatEvalLoc(CompilationUnit* cUnit, RegLocation loc,
                                      int regClass, bool update);
/* Mark a temp register as dead.  Does not affect allocation state. */
extern void oatClobber(CompilationUnit* cUnit, int reg);

extern RegLocation oatUpdateLoc(CompilationUnit* cUnit,
                                        RegLocation loc);

/* see comments for updateLoc */
extern RegLocation oatUpdateLocWide(CompilationUnit* cUnit,
                                            RegLocation loc);

extern RegLocation oatUpdateRawLoc(CompilationUnit* cUnit,
                                   RegLocation loc);

extern void oatMarkLive(CompilationUnit* cUnit, int reg, int sReg);

extern void oatMarkTemp(CompilationUnit* cUnit, int reg);

extern void oatUnmarkTemp(CompilationUnit* cUnit, int reg);

extern void oatMarkDirty(CompilationUnit* cUnit, RegLocation loc);

extern void oatMarkPair(CompilationUnit* cUnit, int lowReg,
                                int highReg);

extern void oatMarkClean(CompilationUnit* cUnit, RegLocation loc);

extern void oatResetDef(CompilationUnit* cUnit, int reg);

extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl);

/* Set up temp & preserved register pools specialized by target */
extern void oatInitPool(RegisterInfo* regs, int* regNums, int num);

/*
 * Mark the beginning and end LIR of a def sequence.  Note that
 * on entry start points to the LIR prior to the beginning of the
 * sequence.
 */
extern void oatMarkDef(CompilationUnit* cUnit, RegLocation rl,
                               LIR* start, LIR* finish);
/*
 * Mark the beginning and end LIR of a def sequence.  Note that
 * on entry start points to the LIR prior to the beginning of the
 * sequence.
 */
extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl,
                                   LIR* start, LIR* finish);

extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir,
                                 int low, int high);

extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir,
                                  int low, int high);
// Get the LocRecord associated with an SSA name use.
extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num);
extern RegLocation oatGetRawSrc(CompilationUnit* cUnit, MIR* mir, int num);

// Get the LocRecord associated with an SSA name def.
extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir, int num);

extern RegLocation oatGetReturnWide(CompilationUnit* cUnit);

/* Clobber all regs that might be used by an external C call */
extern void oatClobberCallRegs(CompilationUnit* cUnit);

extern RegisterInfo *oatIsTemp(CompilationUnit* cUnit, int reg);

extern RegisterInfo *oatIsPromoted(CompilationUnit* cUnit, int reg);

extern bool oatIsDirty(CompilationUnit* cUnit, int reg);

extern void oatMarkInUse(CompilationUnit* cUnit, int reg);

extern int oatAllocTemp(CompilationUnit* cUnit);

extern int oatAllocTempFloat(CompilationUnit* cUnit);

//REDO: too many assumptions.
extern int oatAllocTempDouble(CompilationUnit* cUnit);

extern void oatFreeTemp(CompilationUnit* cUnit, int reg);

extern void oatResetDefLocWide(CompilationUnit* cUnit, RegLocation rl);

extern void oatResetDefTracking(CompilationUnit* cUnit);

extern RegisterInfo *oatIsLive(CompilationUnit* cUnit, int reg);

/* To be used when explicitly managing register use */
extern void oatLockCallTemps(CompilationUnit* cUnit);

extern void oatFreeCallTemps(CompilationUnit* cUnit);

extern void oatFlushAllRegs(CompilationUnit* cUnit);

extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit);

extern RegLocation oatGetReturn(CompilationUnit* cUnit);

extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit);

/* Clobber any temp associated with an sReg.  Could be in either class */
extern void oatClobberSReg(CompilationUnit* cUnit, int sReg);

/* Return a temp if one is available, -1 otherwise */
extern int oatAllocFreeTemp(CompilationUnit* cUnit);

/* Attempt to allocate a callee-save register */
extern int oatAllocPreservedCoreReg(CompilationUnit* cUnit, int sreg);
extern int oatAllocPreservedFPReg(CompilationUnit* cUnit, int sReg,
                                  bool doubleStart);

/*
 * Similar to oatAllocTemp(), but forces the allocation of a specific
 * register.  No check is made to see if the register was previously
 * allocated.  Use with caution.
 */
extern void oatLockTemp(CompilationUnit* cUnit, int reg);

extern RegLocation oatWideToNarrow(CompilationUnit* cUnit,
                                   RegLocation rl);

/*
 * Free all allocated temps in the temp pools.  Note that this does
 * not affect the "liveness" of a temp register, which will stay
 * live until it is either explicitly killed or reallocated.
 */
extern void oatResetRegPool(CompilationUnit* cUnit);

extern void oatClobberAllRegs(CompilationUnit* cUnit);

extern void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2);

extern void oatFlushReg(CompilationUnit* cUnit, int reg);

/*
 * Architecture-dependent register allocation routines implemented in
 * ${TARGET_ARCH}/${TARGET_ARCH_VARIANT}/Ralloc.c
 */
extern int oatAllocTypedTempPair(CompilationUnit* cUnit,
                                 bool fpHint, int regClass);

extern int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint,
                             int regClass);

extern ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc);

extern void oatRegCopyWide(CompilationUnit* cUnit, int destLo,
                           int destHi, int srcLo, int srcHi);

extern void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
                            int displacement, int rSrc, OpSize size);

extern void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
                                int displacement, int rSrcLo, int rSrcHi);

extern void oatDoPromotion(CompilationUnit* cUnit);
extern int oatVRegOffset(CompilationUnit* cUnit, int reg);
#endif // ART_SRC_COMPILER_RALLOC_H_
