blob: 6524641adf93abde6d1a1f0f010d6aa58c57f08a [file] [log] [blame]
/*
* 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.
*/
namespace art {
bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
RegLocation rlSrc1, RegLocation rlSrc2)
{
#ifdef __mips_hard_float
int op = kMipsNop;
RegLocation rlResult;
/*
* Don't attempt to optimize register usage since these opcodes call out to
* the handlers.
*/
switch (mir->dalvikInsn.opcode) {
case Instruction::ADD_FLOAT_2ADDR:
case Instruction::ADD_FLOAT:
op = kMipsFadds;
break;
case Instruction::SUB_FLOAT_2ADDR:
case Instruction::SUB_FLOAT:
op = kMipsFsubs;
break;
case Instruction::DIV_FLOAT_2ADDR:
case Instruction::DIV_FLOAT:
op = kMipsFdivs;
break;
case Instruction::MUL_FLOAT_2ADDR:
case Instruction::MUL_FLOAT:
op = kMipsFmuls;
break;
case Instruction::REM_FLOAT_2ADDR:
case Instruction::REM_FLOAT:
case Instruction::NEG_FLOAT: {
return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
}
default:
return true;
}
rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg,
rlSrc2.lowReg);
storeValue(cUnit, rlDest, rlResult);
return false;
#else
return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
#endif
}
static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
RegLocation rlDest, RegLocation rlSrc1,
RegLocation rlSrc2)
{
#ifdef __mips_hard_float
int op = kMipsNop;
RegLocation rlResult;
switch (mir->dalvikInsn.opcode) {
case Instruction::ADD_DOUBLE_2ADDR:
case Instruction::ADD_DOUBLE:
op = kMipsFaddd;
break;
case Instruction::SUB_DOUBLE_2ADDR:
case Instruction::SUB_DOUBLE:
op = kMipsFsubd;
break;
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE:
op = kMipsFdivd;
break;
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::MUL_DOUBLE:
op = kMipsFmuld;
break;
case Instruction::REM_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE:
case Instruction::NEG_DOUBLE: {
return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
}
default:
return true;
}
rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
DCHECK(rlSrc1.wide);
rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
DCHECK(rlSrc2.wide);
rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
DCHECK(rlDest.wide);
DCHECK(rlResult.wide);
newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
S2D(rlSrc1.lowReg, rlSrc1.highReg),
S2D(rlSrc2.lowReg, rlSrc2.highReg));
storeValueWide(cUnit, rlDest, rlResult);
return false;
#else
return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
#endif
}
static bool genConversion(CompilationUnit *cUnit, MIR *mir)
{
#ifdef __mips_hard_float
Instruction::Code opcode = mir->dalvikInsn.opcode;
bool longSrc = false;
bool longDest = false;
RegLocation rlSrc;
RegLocation rlDest;
int op = kMipsNop;
int srcReg;
RegLocation rlResult;
switch (opcode) {
case Instruction::INT_TO_FLOAT:
longSrc = false;
longDest = false;
op = kMipsFcvtsw;
break;
case Instruction::DOUBLE_TO_FLOAT:
longSrc = true;
longDest = false;
op = kMipsFcvtsd;
break;
case Instruction::FLOAT_TO_DOUBLE:
longSrc = false;
longDest = true;
op = kMipsFcvtds;
break;
case Instruction::INT_TO_DOUBLE:
longSrc = false;
longDest = true;
op = kMipsFcvtdw;
break;
case Instruction::FLOAT_TO_INT:
case Instruction::DOUBLE_TO_INT:
case Instruction::LONG_TO_DOUBLE:
case Instruction::FLOAT_TO_LONG:
case Instruction::LONG_TO_FLOAT:
case Instruction::DOUBLE_TO_LONG:
return genConversionPortable(cUnit, mir);
default:
return true;
}
if (longSrc) {
rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
} else {
rlSrc = oatGetSrc(cUnit, mir, 0);
rlSrc = loadValue(cUnit, rlSrc, kFPReg);
srcReg = rlSrc.lowReg;
}
if (longDest) {
rlDest = oatGetDestWide(cUnit, mir, 0, 1);
rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
storeValueWide(cUnit, rlDest, rlResult);
} else {
rlDest = oatGetDest(cUnit, mir, 0);
rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
storeValue(cUnit, rlDest, rlResult);
}
return false;
#else
return genConversionPortable(cUnit, mir);
#endif
}
static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
RegLocation rlSrc1, RegLocation rlSrc2)
{
bool wide = true;
int offset;
switch (mir->dalvikInsn.opcode) {
case Instruction::CMPL_FLOAT:
offset = OFFSETOF_MEMBER(Thread, pCmplFloat);
wide = false;
break;
case Instruction::CMPG_FLOAT:
offset = OFFSETOF_MEMBER(Thread, pCmpgFloat);
wide = false;
break;
case Instruction::CMPL_DOUBLE:
offset = OFFSETOF_MEMBER(Thread, pCmplDouble);
break;
case Instruction::CMPG_DOUBLE:
offset = OFFSETOF_MEMBER(Thread, pCmpgDouble);
break;
default:
return true;
}
oatFlushAllRegs(cUnit);
oatLockCallTemps(cUnit);
if (wide) {
loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
} else {
loadValueDirectFixed(cUnit, rlSrc1, rARG0);
loadValueDirectFixed(cUnit, rlSrc2, rARG1);
}
int rTgt = loadHelper(cUnit, offset);
opReg(cUnit, kOpBlx, rTgt);
RegLocation rlResult = oatGetReturn(cUnit, false);
storeValue(cUnit, rlDest, rlResult);
return false;
}
} // namespace art