Home | History | Annotate | Download | only in FP
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * This file is included by Codegen-armv5te-vfp.c, and implements architecture
     19  * variant-specific code.
     20  */
     21 
     22 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
     23                                               int reg1, int reg2);
     24 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
     25 
     26 /* First, flush any registers associated with this value */
     27 static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
     28                              int rDest)
     29 {
     30      rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
     31                           dvmCompilerUpdateLoc(cUnit, rlSrc);
     32      if (rlSrc.location == kLocPhysReg) {
     33          if (rlSrc.wide) {
     34              dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
     35                                                rlSrc.highReg);
     36          } else {
     37              dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
     38          }
     39      }
     40      opRegRegImm(cUnit, kOpAdd, rDest, rFP,
     41                  dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
     42 }
     43 
     44 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
     45 {
     46     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
     47 #ifdef __mips_hard_float
     48     RegLocation rlResult = LOC_C_RETURN_WIDE_ALT;
     49 #else
     50     RegLocation rlResult = LOC_C_RETURN_WIDE;
     51 #endif
     52     RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
     53     loadValueAddress(cUnit, rlSrc, r_A2);
     54     genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
     55     storeValueWide(cUnit, rlDest, rlResult);
     56     return false;
     57 }
     58 
     59 /*
     60  * TUNING: On some implementations, it is quicker to pass addresses
     61  * to the handlers rather than load the operands into core registers
     62  * and then move the values to FP regs in the handlers.  Other implementations
     63  * may prefer passing data in registers (and the latter approach would
     64  * yeild cleaner register handling - avoiding the requirement that operands
     65  * be flushed to memory prior to the call).
     66  */
     67 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
     68                             RegLocation rlDest, RegLocation rlSrc1,
     69                             RegLocation rlSrc2)
     70 {
     71 #ifdef __mips_hard_float
     72     int op = kMipsNop;
     73     RegLocation rlResult;
     74 
     75     /*
     76      * Don't attempt to optimize register usage since these opcodes call out to
     77      * the handlers.
     78      */
     79     switch (mir->dalvikInsn.opcode) {
     80         case OP_ADD_FLOAT_2ADDR:
     81         case OP_ADD_FLOAT:
     82             op = kMipsFadds;
     83             break;
     84         case OP_SUB_FLOAT_2ADDR:
     85         case OP_SUB_FLOAT:
     86             op = kMipsFsubs;
     87             break;
     88         case OP_DIV_FLOAT_2ADDR:
     89         case OP_DIV_FLOAT:
     90             op = kMipsFdivs;
     91             break;
     92         case OP_MUL_FLOAT_2ADDR:
     93         case OP_MUL_FLOAT:
     94             op = kMipsFmuls;
     95             break;
     96         case OP_REM_FLOAT_2ADDR:
     97         case OP_REM_FLOAT:
     98         case OP_NEG_FLOAT: {
     99             return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
    100         }
    101         default:
    102             return true;
    103     }
    104     rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
    105     rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
    106     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
    107     newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
    108     storeValue(cUnit, rlDest, rlResult);
    109 
    110     return false;
    111 #else
    112     TemplateOpcode opcode;
    113 
    114     /*
    115      * Don't attempt to optimize register usage since these opcodes call out to
    116      * the handlers.
    117      */
    118     switch (mir->dalvikInsn.opcode) {
    119         case OP_ADD_FLOAT_2ADDR:
    120         case OP_ADD_FLOAT:
    121             opcode = TEMPLATE_ADD_FLOAT_VFP;
    122             break;
    123         case OP_SUB_FLOAT_2ADDR:
    124         case OP_SUB_FLOAT:
    125             opcode = TEMPLATE_SUB_FLOAT_VFP;
    126             break;
    127         case OP_DIV_FLOAT_2ADDR:
    128         case OP_DIV_FLOAT:
    129             opcode = TEMPLATE_DIV_FLOAT_VFP;
    130             break;
    131         case OP_MUL_FLOAT_2ADDR:
    132         case OP_MUL_FLOAT:
    133             opcode = TEMPLATE_MUL_FLOAT_VFP;
    134             break;
    135         case OP_REM_FLOAT_2ADDR:
    136         case OP_REM_FLOAT:
    137         case OP_NEG_FLOAT: {
    138             return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
    139         }
    140         default:
    141             return true;
    142     }
    143     loadValueAddress(cUnit, rlDest, r_A0);
    144     dvmCompilerClobber(cUnit, r_A0);
    145     loadValueAddress(cUnit, rlSrc1, r_A1);
    146     dvmCompilerClobber(cUnit, r_A1);
    147     loadValueAddress(cUnit, rlSrc2, r_A2);
    148     genDispatchToHandler(cUnit, opcode);
    149     rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    150     if (rlDest.location == kLocPhysReg) {
    151         dvmCompilerClobber(cUnit, rlDest.lowReg);
    152     }
    153     return false;
    154 #endif
    155 }
    156 
    157 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
    158                              RegLocation rlDest, RegLocation rlSrc1,
    159                              RegLocation rlSrc2)
    160 {
    161 #ifdef __mips_hard_float
    162     int op = kMipsNop;
    163     RegLocation rlResult;
    164 
    165     switch (mir->dalvikInsn.opcode) {
    166         case OP_ADD_DOUBLE_2ADDR:
    167         case OP_ADD_DOUBLE:
    168             op = kMipsFaddd;
    169             break;
    170         case OP_SUB_DOUBLE_2ADDR:
    171         case OP_SUB_DOUBLE:
    172             op = kMipsFsubd;
    173             break;
    174         case OP_DIV_DOUBLE_2ADDR:
    175         case OP_DIV_DOUBLE:
    176             op = kMipsFdivd;
    177             break;
    178         case OP_MUL_DOUBLE_2ADDR:
    179         case OP_MUL_DOUBLE:
    180             op = kMipsFmuld;
    181             break;
    182         case OP_REM_DOUBLE_2ADDR:
    183         case OP_REM_DOUBLE:
    184         case OP_NEG_DOUBLE: {
    185             return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
    186         }
    187         default:
    188             return true;
    189     }
    190     rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
    191     assert(rlSrc1.wide);
    192     rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
    193     assert(rlSrc2.wide);
    194     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
    195     assert(rlDest.wide);
    196     assert(rlResult.wide);
    197     newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
    198             S2D(rlSrc1.lowReg, rlSrc1.highReg),
    199             S2D(rlSrc2.lowReg, rlSrc2.highReg));
    200     storeValueWide(cUnit, rlDest, rlResult);
    201     return false;
    202 #else
    203     TemplateOpcode opcode;
    204 
    205     switch (mir->dalvikInsn.opcode) {
    206         case OP_ADD_DOUBLE_2ADDR:
    207         case OP_ADD_DOUBLE:
    208             opcode = TEMPLATE_ADD_DOUBLE_VFP;
    209             break;
    210         case OP_SUB_DOUBLE_2ADDR:
    211         case OP_SUB_DOUBLE:
    212             opcode = TEMPLATE_SUB_DOUBLE_VFP;
    213             break;
    214         case OP_DIV_DOUBLE_2ADDR:
    215         case OP_DIV_DOUBLE:
    216             opcode = TEMPLATE_DIV_DOUBLE_VFP;
    217             break;
    218         case OP_MUL_DOUBLE_2ADDR:
    219         case OP_MUL_DOUBLE:
    220             opcode = TEMPLATE_MUL_DOUBLE_VFP;
    221             break;
    222         case OP_REM_DOUBLE_2ADDR:
    223         case OP_REM_DOUBLE:
    224         case OP_NEG_DOUBLE: {
    225             return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
    226                                                rlSrc2);
    227         }
    228         default:
    229             return true;
    230     }
    231     loadValueAddress(cUnit, rlDest, r_A0);
    232     dvmCompilerClobber(cUnit, r_A0);
    233     loadValueAddress(cUnit, rlSrc1, r_A1);
    234     dvmCompilerClobber(cUnit, r_A1);
    235     loadValueAddress(cUnit, rlSrc2, r_A2);
    236     genDispatchToHandler(cUnit, opcode);
    237     rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
    238     if (rlDest.location == kLocPhysReg) {
    239         dvmCompilerClobber(cUnit, rlDest.lowReg);
    240         dvmCompilerClobber(cUnit, rlDest.highReg);
    241     }
    242     return false;
    243 #endif
    244 }
    245 
    246 static bool genConversion(CompilationUnit *cUnit, MIR *mir)
    247 {
    248     Opcode opcode = mir->dalvikInsn.opcode;
    249     bool longSrc = false;
    250     bool longDest = false;
    251     RegLocation rlSrc;
    252     RegLocation rlDest;
    253 #ifdef __mips_hard_float
    254     int op = kMipsNop;
    255     int srcReg;
    256     RegLocation rlResult;
    257 
    258     switch (opcode) {
    259         case OP_INT_TO_FLOAT:
    260             longSrc = false;
    261             longDest = false;
    262             op = kMipsFcvtsw;
    263             break;
    264         case OP_DOUBLE_TO_FLOAT:
    265             longSrc = true;
    266             longDest = false;
    267             op = kMipsFcvtsd;
    268             break;
    269         case OP_FLOAT_TO_DOUBLE:
    270             longSrc = false;
    271             longDest = true;
    272             op = kMipsFcvtds;
    273             break;
    274         case OP_INT_TO_DOUBLE:
    275             longSrc = false;
    276             longDest = true;
    277             op = kMipsFcvtdw;
    278             break;
    279         case OP_FLOAT_TO_INT:
    280         case OP_DOUBLE_TO_INT:
    281         case OP_LONG_TO_DOUBLE:
    282         case OP_FLOAT_TO_LONG:
    283         case OP_LONG_TO_FLOAT:
    284         case OP_DOUBLE_TO_LONG:
    285             return genConversionPortable(cUnit, mir);
    286         default:
    287             return true;
    288     }
    289     if (longSrc) {
    290         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    291         rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
    292         srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
    293     } else {
    294         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    295         rlSrc = loadValue(cUnit, rlSrc, kFPReg);
    296         srcReg = rlSrc.lowReg;
    297     }
    298     if (longDest) {
    299         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
    300         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
    301         newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
    302         storeValueWide(cUnit, rlDest, rlResult);
    303     } else {
    304         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
    305         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
    306         newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
    307         storeValue(cUnit, rlDest, rlResult);
    308     }
    309     return false;
    310 #else
    311     TemplateOpcode templateOpcode;
    312     switch (opcode) {
    313         case OP_INT_TO_FLOAT:
    314             longSrc = false;
    315             longDest = false;
    316             templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
    317             break;
    318         case OP_FLOAT_TO_INT:
    319             longSrc = false;
    320             longDest = false;
    321             templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
    322             break;
    323         case OP_DOUBLE_TO_FLOAT:
    324             longSrc = true;
    325             longDest = false;
    326             templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
    327             break;
    328         case OP_FLOAT_TO_DOUBLE:
    329             longSrc = false;
    330             longDest = true;
    331             templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
    332             break;
    333         case OP_INT_TO_DOUBLE:
    334             longSrc = false;
    335             longDest = true;
    336             templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
    337             break;
    338         case OP_DOUBLE_TO_INT:
    339             longSrc = true;
    340             longDest = false;
    341             templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
    342             break;
    343         case OP_LONG_TO_DOUBLE:
    344         case OP_FLOAT_TO_LONG:
    345         case OP_LONG_TO_FLOAT:
    346         case OP_DOUBLE_TO_LONG:
    347             return genConversionPortable(cUnit, mir);
    348         default:
    349             return true;
    350     }
    351 
    352     if (longSrc) {
    353         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    354     } else {
    355         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    356     }
    357 
    358     if (longDest) {
    359         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
    360     } else {
    361         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
    362     }
    363     loadValueAddress(cUnit, rlDest, r_A0);
    364     dvmCompilerClobber(cUnit, r_A0);
    365     loadValueAddress(cUnit, rlSrc, r_A1);
    366     genDispatchToHandler(cUnit, templateOpcode);
    367     if (rlDest.wide) {
    368         rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
    369         dvmCompilerClobber(cUnit, rlDest.highReg);
    370     } else {
    371         rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    372     }
    373     dvmCompilerClobber(cUnit, rlDest.lowReg);
    374     return false;
    375 #endif
    376 }
    377 
    378 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
    379                      RegLocation rlSrc1, RegLocation rlSrc2)
    380 {
    381     TemplateOpcode templateOpcode;
    382     RegLocation rlResult = dvmCompilerGetReturn(cUnit);
    383     bool wide = true;
    384 
    385     switch(mir->dalvikInsn.opcode) {
    386         case OP_CMPL_FLOAT:
    387             templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
    388             wide = false;
    389             break;
    390         case OP_CMPG_FLOAT:
    391             templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
    392             wide = false;
    393             break;
    394         case OP_CMPL_DOUBLE:
    395             templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
    396             break;
    397         case OP_CMPG_DOUBLE:
    398             templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
    399             break;
    400         default:
    401             return true;
    402     }
    403     loadValueAddress(cUnit, rlSrc1, r_A0);
    404     dvmCompilerClobber(cUnit, r_A0);
    405     loadValueAddress(cUnit, rlSrc2, r_A1);
    406     genDispatchToHandler(cUnit, templateOpcode);
    407     storeValue(cUnit, rlDest, rlResult);
    408     return false;
    409 }
    410