diff options
| author | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
|---|---|---|
| committer | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
| commit | a8b91c52fd8a90b784835dfe1f8898035266c4dd (patch) | |
| tree | 8a9bb58ee3b78c10cf88a3bac21b7f96d75cd1f7 /vm/compiler/codegen/mips/FP/MipsFP.cpp | |
| parent | a14639df65cc0aefafcddda5aae8b591204e45f9 (diff) | |
[MIPS] Dalvik fast interpreter support and JIT implementation
Change-Id: I9bb4f6875b7061d3ffaee73f204026cb8ba3ed39
Signed-off-by: Raghu Gandham <raghu@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Douglas Leung <douglas@mips.com>
Signed-off-by: Don Padgett <don@mips.com>
Diffstat (limited to 'vm/compiler/codegen/mips/FP/MipsFP.cpp')
| -rw-r--r-- | vm/compiler/codegen/mips/FP/MipsFP.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/vm/compiler/codegen/mips/FP/MipsFP.cpp b/vm/compiler/codegen/mips/FP/MipsFP.cpp new file mode 100644 index 000000000..cf44b0e9c --- /dev/null +++ b/vm/compiler/codegen/mips/FP/MipsFP.cpp @@ -0,0 +1,409 @@ +/* + * 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. + */ + +extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit, + int reg1, int reg2); +extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg); + +/* First, flush any registers associated with this value */ +static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc, + int rDest) +{ + rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) : + dvmCompilerUpdateLoc(cUnit, rlSrc); + if (rlSrc.location == kLocPhysReg) { + if (rlSrc.wide) { + dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg, + rlSrc.highReg); + } else { + dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg); + } + } + opRegRegImm(cUnit, kOpAdd, rDest, rFP, + dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2); +} + +static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) +{ + RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); +#ifdef __mips_hard_float + RegLocation rlResult = LOC_C_RETURN_WIDE_ALT; +#else + RegLocation rlResult = LOC_C_RETURN_WIDE; +#endif + RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; + loadValueAddress(cUnit, rlSrc, r_A2); + 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 + * yeild 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) +{ +#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 OP_ADD_FLOAT_2ADDR: + case OP_ADD_FLOAT: + op = kMipsFadds; + break; + case OP_SUB_FLOAT_2ADDR: + case OP_SUB_FLOAT: + op = kMipsFsubs; + break; + case OP_DIV_FLOAT_2ADDR: + case OP_DIV_FLOAT: + op = kMipsFdivs; + break; + case OP_MUL_FLOAT_2ADDR: + case OP_MUL_FLOAT: + op = kMipsFmuls; + break; + case OP_REM_FLOAT_2ADDR: + case OP_REM_FLOAT: + case OP_NEG_FLOAT: { + return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); + } + default: + return true; + } + rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); + rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); + rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); + storeValue(cUnit, rlDest, rlResult); + + return false; +#else + 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; + } + loadValueAddress(cUnit, rlDest, r_A0); + dvmCompilerClobber(cUnit, r_A0); + loadValueAddress(cUnit, rlSrc1, r_A1); + dvmCompilerClobber(cUnit, r_A1); + loadValueAddress(cUnit, rlSrc2, r_A2); + genDispatchToHandler(cUnit, opcode); + rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); + if (rlDest.location == kLocPhysReg) { + dvmCompilerClobber(cUnit, rlDest.lowReg); + } + return false; +#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 OP_ADD_DOUBLE_2ADDR: + case OP_ADD_DOUBLE: + op = kMipsFaddd; + break; + case OP_SUB_DOUBLE_2ADDR: + case OP_SUB_DOUBLE: + op = kMipsFsubd; + break; + case OP_DIV_DOUBLE_2ADDR: + case OP_DIV_DOUBLE: + op = kMipsFdivd; + break; + case OP_MUL_DOUBLE_2ADDR: + case OP_MUL_DOUBLE: + op = kMipsFmuld; + break; + case OP_REM_DOUBLE_2ADDR: + case OP_REM_DOUBLE: + case OP_NEG_DOUBLE: { + return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); + } + default: + return true; + } + rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); + assert(rlSrc1.wide); + rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); + assert(rlSrc2.wide); + rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); + assert(rlDest.wide); + assert(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 + 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; + } + loadValueAddress(cUnit, rlDest, r_A0); + dvmCompilerClobber(cUnit, r_A0); + loadValueAddress(cUnit, rlSrc1, r_A1); + dvmCompilerClobber(cUnit, r_A1); + loadValueAddress(cUnit, rlSrc2, r_A2); + genDispatchToHandler(cUnit, opcode); + rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest); + if (rlDest.location == kLocPhysReg) { + dvmCompilerClobber(cUnit, rlDest.lowReg); + dvmCompilerClobber(cUnit, rlDest.highReg); + } + return false; +#endif +} + +static bool genConversion(CompilationUnit *cUnit, MIR *mir) +{ + Opcode opcode = mir->dalvikInsn.opcode; + bool longSrc = false; + bool longDest = false; + RegLocation rlSrc; + RegLocation rlDest; +#ifdef __mips_hard_float + int op = kMipsNop; + int srcReg; + RegLocation rlResult; + + switch (opcode) { + case OP_INT_TO_FLOAT: + longSrc = false; + longDest = false; + op = kMipsFcvtsw; + break; + case OP_DOUBLE_TO_FLOAT: + longSrc = true; + longDest = false; + op = kMipsFcvtsd; + break; + case OP_FLOAT_TO_DOUBLE: + longSrc = false; + longDest = true; + op = kMipsFcvtds; + break; + case OP_INT_TO_DOUBLE: + longSrc = false; + longDest = true; + op = kMipsFcvtdw; + break; + case OP_FLOAT_TO_INT: + case OP_DOUBLE_TO_INT: + 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); + rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); + srcReg = S2D(rlSrc.lowReg, rlSrc.highReg); + } else { + rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); + rlSrc = loadValue(cUnit, rlSrc, kFPReg); + srcReg = rlSrc.lowReg; + } + if (longDest) { + rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); + rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg); + storeValueWide(cUnit, rlDest, rlResult); + } else { + rlDest = dvmCompilerGetDest(cUnit, mir, 0); + rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); + newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg); + storeValue(cUnit, rlDest, rlResult); + } + return false; +#else + 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); + } + loadValueAddress(cUnit, rlDest, r_A0); + dvmCompilerClobber(cUnit, r_A0); + loadValueAddress(cUnit, rlSrc, r_A1); + 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; +#endif +} + +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; + } + loadValueAddress(cUnit, rlSrc1, r_A0); + dvmCompilerClobber(cUnit, r_A0); + loadValueAddress(cUnit, rlSrc2, r_A1); + genDispatchToHandler(cUnit, templateOpcode); + storeValue(cUnit, rlDest, rlResult); + return false; +} |
