summaryrefslogtreecommitdiff
path: root/vm/compiler/codegen/arm/FP/ThumbVFP.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen/arm/FP/ThumbVFP.cpp')
-rw-r--r--vm/compiler/codegen/arm/FP/ThumbVFP.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/FP/ThumbVFP.cpp b/vm/compiler/codegen/arm/FP/ThumbVFP.cpp
new file mode 100644
index 0000000..f685f24
--- /dev/null
+++ b/vm/compiler/codegen/arm/FP/ThumbVFP.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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;
+}