/*
* 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.
*/
/*
* This file is included by Codegen-armv5te-vfp.c, and implements architecture
* variant-specific code.
*/
/*
* Take the address of a Dalvik register and store it into rDest.
* Clobber any live values associated either with the Dalvik value
* or the target register and lock the target fixed register.
*/
static void loadValueAddressDirect(CompilationUnit *cUnit, RegLocation rlSrc,
int rDest)
{
rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
dvmCompilerUpdateLoc(cUnit, rlSrc);
if (rlSrc.location == kLocPhysReg) {
if (rlSrc.wide) {
dvmCompilerFlushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg);
} else {
dvmCompilerFlushReg(cUnit, rlSrc.lowReg);
}
}
dvmCompilerClobber(cUnit, rDest);
dvmCompilerLockTemp(cUnit, rDest);
opRegRegImm(cUnit, kOpAdd, rDest, r5FP,
dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
}
static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
{
RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
RegLocation rlResult = LOC_C_RETURN_WIDE;
RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
loadValueAddressDirect(cUnit, rlSrc, r2);
genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
/*
* TUNING: On some implementations, it is quicker to pass addresses
* to the handlers rather than load the operands into core registers
* and then move the values to FP regs in the handlers. Other implementations
* may prefer passing data in registers (and the latter approach would
* yield cleaner register handling - avoiding the requirement that operands
* be flushed to memory prior to the call).
*/
static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
RegLocation rlDest, RegLocation rlSrc1,
RegLocation rlSrc2)
{
TemplateOpcode opcode;
/*
* Don't attempt to optimize register usage since these opcodes call out to
* the handlers.
*/
switch (mir->dalvikInsn.opcode) {
case OP_ADD_FLOAT_2ADDR:
case OP_ADD_FLOAT:
opcode = TEMPLATE_ADD_FLOAT_VFP;
break;
case OP_SUB_FLOAT_2ADDR:
case OP_SUB_FLOAT:
opcode = TEMPLATE_SUB_FLOAT_VFP;
break;
case OP_DIV_FLOAT_2ADDR:
case OP_DIV_FLOAT:
opcode = TEMPLATE_DIV_FLOAT_VFP;
break;
case OP_MUL_FLOAT_2ADDR:
case OP_MUL_FLOAT:
opcode = TEMPLATE_MUL_FLOAT_VFP;
break;
case OP_REM_FLOAT_2ADDR:
case OP_REM_FLOAT:
case OP_NEG_FLOAT: {
return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
}
default:
return true;
}
loadValueAddressDirect(cUnit, rlDest, r0);
loadValueAddressDirect(cUnit, rlSrc1, r1);
loadValueAddressDirect(cUnit, rlSrc2, r2);
genDispatchToHandler(cUnit, opcode);
rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
if (rlDest.location == kLocPhysReg) {
dvmCompilerClobber(cUnit, rlDest.lowReg);
}
return false;
}
static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
RegLocation rlDest, RegLocation rlSrc1,
RegLocation rlSrc2)
{
TemplateOpcode opcode;
switch (mir->dalvikInsn.opcode) {
case OP_ADD_DOUBLE_2ADDR:
case OP_ADD_DOUBLE:
opcode = TEMPLATE_ADD_DOUBLE_VFP;
break;
case OP_SUB_DOUBLE_2ADDR:
case OP_SUB_DOUBLE:
opcode = TEMPLATE_SUB_DOUBLE_VFP;
break;
case OP_DIV_DOUBLE_2ADDR:
case OP_DIV_DOUBLE:
opcode = TEMPLATE_DIV_DOUBLE_VFP;
break;
case OP_MUL_DOUBLE_2ADDR:
case OP_MUL_DOUBLE:
opcode = TEMPLATE_MUL_DOUBLE_VFP;
break;
case OP_REM_DOUBLE_2ADDR:
case OP_REM_DOUBLE:
case OP_NEG_DOUBLE: {
return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
rlSrc2);
}
default:
return true;
}
loadValueAddressDirect(cUnit, rlDest, r0);
loadValueAddressDirect(cUnit, rlSrc1, r1);
loadValueAddressDirect(cUnit, rlSrc2, r2);
genDispatchToHandler(cUnit, opcode);
rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
if (rlDest.location == kLocPhysReg) {
dvmCompilerClobber(cUnit, rlDest.lowReg);
dvmCompilerClobber(cUnit, rlDest.highReg);
}
return false;
}
static bool genConversion(CompilationUnit *cUnit, MIR *mir)
{
Opcode opcode = mir->dalvikInsn.opcode;
bool longSrc = false;
bool longDest = false;
RegLocation rlSrc;
RegLocation rlDest;
TemplateOpcode templateOpcode;
switch (opcode) {
case OP_INT_TO_FLOAT:
longSrc = false;
longDest = false;
templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
break;
case OP_FLOAT_TO_INT:
longSrc = false;
longDest = false;
templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
break;
case OP_DOUBLE_TO_FLOAT:
longSrc = true;
longDest = false;
templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
break;
case OP_FLOAT_TO_DOUBLE:
longSrc = false;
longDest = true;
templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
break;
case OP_INT_TO_DOUBLE:
longSrc = false;
longDest = true;
templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
break;
case OP_DOUBLE_TO_INT:
longSrc = true;
longDest = false;
templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
break;
case OP_LONG_TO_DOUBLE:
case OP_FLOAT_TO_LONG:
case OP_LONG_TO_FLOAT:
case OP_DOUBLE_TO_LONG:
return genConversionPortable(cUnit, mir);
default:
return true;
}
if (longSrc) {
rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
} else {
rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
}
if (longDest) {
rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
} else {
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
}
loadValueAddressDirect(cUnit, rlDest, r0);
loadValueAddressDirect(cUnit, rlSrc, r1);
genDispatchToHandler(cUnit, templateOpcode);
if (rlDest.wide) {
rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
dvmCompilerClobber(cUnit, rlDest.highReg);
} else {
rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
}
dvmCompilerClobber(cUnit, rlDest.lowReg);
return false;
}
static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
RegLocation rlSrc1, RegLocation rlSrc2)
{
TemplateOpcode templateOpcode;
RegLocation rlResult = dvmCompilerGetReturn(cUnit);
bool wide = true;
switch(mir->dalvikInsn.opcode) {
case OP_CMPL_FLOAT:
templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
wide = false;
break;
case OP_CMPG_FLOAT:
templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
wide = false;
break;
case OP_CMPL_DOUBLE:
templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
break;
case OP_CMPG_DOUBLE:
templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
break;
default:
return true;
}
loadValueAddressDirect(cUnit, rlSrc1, r0);
loadValueAddressDirect(cUnit, rlSrc2, r1);
genDispatchToHandler(cUnit, templateOpcode);
storeValue(cUnit, rlDest, rlResult);
return false;
}