/*
 * 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.
 */

/*
 * This file contains Mips-specific register allocation support.
 */

#include "../../CompilerUtility.h"
#include "../../CompilerIR.h"
#include "../..//Dataflow.h"
#include "MipsLIR.h"
#include "Codegen.h"
#include "../Ralloc.h"

namespace art {

/*
 * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
 * instructions might call out to C/assembly helper functions.  Until
 * machinery is in place, always spill lr.
 */

void oatAdjustSpillMask(CompilationUnit* cUnit)
{
    cUnit->coreSpillMask |= (1 << r_RA);
    cUnit->numCoreSpills++;
}

/*
 * Mark a callee-save fp register as promoted.  Note that
 * vpush/vpop uses contiguous register lists so we must
 * include any holes in the mask.  Associate holes with
 * Dalvik register INVALID_VREG (0xFFFFU).
 */
void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
{
    LOG(FATAL) << "No support yet for promoted FP regs";
}

void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
{
    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
    DCHECK(info1 && info2 && info1->pair && info2->pair &&
           (info1->partner == info2->reg) &&
           (info2->partner == info1->reg));
    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
        if (!(info1->isTemp && info2->isTemp)) {
            /* Should not happen.  If it does, there's a problem in evalLoc */
            LOG(FATAL) << "Long half-temp, half-promoted";
        }

        info1->dirty = false;
        info2->dirty = false;
        if (oatS2VReg(cUnit, info2->sReg) <
            oatS2VReg(cUnit, info1->sReg))
            info1 = info2;
        int vReg = oatS2VReg(cUnit, info1->sReg);
        oatFlushRegWideImpl(cUnit, rSP,
                                    oatVRegOffset(cUnit, vReg),
                                    info1->reg, info1->partner);
    }
}

void oatFlushReg(CompilationUnit* cUnit, int reg)
{
    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
    if (info->live && info->dirty) {
        info->dirty = false;
        int vReg = oatS2VReg(cUnit, info->sReg);
        oatFlushRegImpl(cUnit, rSP,
                                oatVRegOffset(cUnit, vReg),
                                reg, kWord);
    }
}

/* Give access to the target-dependent FP register encoding to common code */
bool oatIsFpReg(int reg) {
    return FPREG(reg);
}

uint32_t oatFpRegMask() {
    return FP_REG_MASK;
}

/* Clobber all regs that might be used by an external C call */
extern void oatClobberCalleeSave(CompilationUnit *cUnit)
{
    oatClobber(cUnit, r_ZERO);
    oatClobber(cUnit, r_AT);
    oatClobber(cUnit, r_V0);
    oatClobber(cUnit, r_V1);
    oatClobber(cUnit, r_A0);
    oatClobber(cUnit, r_A1);
    oatClobber(cUnit, r_A2);
    oatClobber(cUnit, r_A3);
    oatClobber(cUnit, r_T0);
    oatClobber(cUnit, r_T1);
    oatClobber(cUnit, r_T2);
    oatClobber(cUnit, r_T3);
    oatClobber(cUnit, r_T4);
    oatClobber(cUnit, r_T5);
    oatClobber(cUnit, r_T6);
    oatClobber(cUnit, r_T7);
    oatClobber(cUnit, r_T8);
    oatClobber(cUnit, r_T9);
    oatClobber(cUnit, r_K0);
    oatClobber(cUnit, r_K1);
    oatClobber(cUnit, r_GP);
    oatClobber(cUnit, r_FP);
    oatClobber(cUnit, r_RA);
    oatClobber(cUnit, r_F0);
    oatClobber(cUnit, r_F1);
    oatClobber(cUnit, r_F2);
    oatClobber(cUnit, r_F3);
    oatClobber(cUnit, r_F4);
    oatClobber(cUnit, r_F5);
    oatClobber(cUnit, r_F6);
    oatClobber(cUnit, r_F7);
    oatClobber(cUnit, r_F8);
    oatClobber(cUnit, r_F9);
    oatClobber(cUnit, r_F10);
    oatClobber(cUnit, r_F11);
    oatClobber(cUnit, r_F12);
    oatClobber(cUnit, r_F13);
    oatClobber(cUnit, r_F14);
    oatClobber(cUnit, r_F15);
}

extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
{
    RegLocation res = LOC_C_RETURN_WIDE;
    oatClobber(cUnit, res.lowReg);
    oatClobber(cUnit, res.highReg);
    oatMarkInUse(cUnit, res.lowReg);
    oatMarkInUse(cUnit, res.highReg);
    oatMarkPair(cUnit, res.lowReg, res.highReg);
    return res;
}

extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
{
    RegLocation res = LOC_C_RETURN_WIDE_ALT;
    oatClobber(cUnit, res.lowReg);
    oatClobber(cUnit, res.highReg);
    oatMarkInUse(cUnit, res.lowReg);
    oatMarkInUse(cUnit, res.highReg);
    oatMarkPair(cUnit, res.lowReg, res.highReg);
    return res;
}

extern RegLocation oatGetReturn(CompilationUnit* cUnit)
{
    RegLocation res = LOC_C_RETURN;
    oatClobber(cUnit, res.lowReg);
    oatMarkInUse(cUnit, res.lowReg);
    return res;
}

extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
{
    RegLocation res = LOC_C_RETURN_ALT;
    oatClobber(cUnit, res.lowReg);
    oatMarkInUse(cUnit, res.lowReg);
    return res;
}

extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
{
    return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
                      : &cUnit->regPool->coreRegs[reg];
}

/* To be used when explicitly managing register use */
extern void oatLockCallTemps(CompilationUnit* cUnit)
{
    oatLockTemp(cUnit, rARG0);
    oatLockTemp(cUnit, rARG1);
    oatLockTemp(cUnit, rARG2);
    oatLockTemp(cUnit, rARG3);
}

/* To be used when explicitly managing register use */
extern void oatFreeCallTemps(CompilationUnit* cUnit)
{
    oatFreeTemp(cUnit, rARG0);
    oatFreeTemp(cUnit, rARG1);
    oatFreeTemp(cUnit, rARG2);
    oatFreeTemp(cUnit, rARG3);
}

/* Convert an instruction to a NOP */
void oatNopLIR( LIR* lir)
{
    ((LIR*)lir)->flags.isNop = true;
}

}  // namespace art
