Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2012 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 #include "codegen_mips.h"
     18 #include "dex/quick/mir_to_lir-inl.h"
     19 #include "entrypoints/quick/quick_entrypoints.h"
     20 #include "mips_lir.h"
     21 
     22 namespace art {
     23 
     24 void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode,
     25                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     26   int op = kMipsNop;
     27   RegLocation rl_result;
     28 
     29   /*
     30    * Don't attempt to optimize register usage since these opcodes call out to
     31    * the handlers.
     32    */
     33   switch (opcode) {
     34     case Instruction::ADD_FLOAT_2ADDR:
     35     case Instruction::ADD_FLOAT:
     36       op = kMipsFadds;
     37       break;
     38     case Instruction::SUB_FLOAT_2ADDR:
     39     case Instruction::SUB_FLOAT:
     40       op = kMipsFsubs;
     41       break;
     42     case Instruction::DIV_FLOAT_2ADDR:
     43     case Instruction::DIV_FLOAT:
     44       op = kMipsFdivs;
     45       break;
     46     case Instruction::MUL_FLOAT_2ADDR:
     47     case Instruction::MUL_FLOAT:
     48       op = kMipsFmuls;
     49       break;
     50     case Instruction::REM_FLOAT_2ADDR:
     51     case Instruction::REM_FLOAT:
     52       FlushAllRegs();   // Send everything to home location
     53       CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
     54       rl_result = GetReturn(kFPReg);
     55       StoreValue(rl_dest, rl_result);
     56       return;
     57     case Instruction::NEG_FLOAT:
     58       GenNegFloat(rl_dest, rl_src1);
     59       return;
     60     default:
     61       LOG(FATAL) << "Unexpected opcode: " << opcode;
     62   }
     63   rl_src1 = LoadValue(rl_src1, kFPReg);
     64   rl_src2 = LoadValue(rl_src2, kFPReg);
     65   rl_result = EvalLoc(rl_dest, kFPReg, true);
     66   NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
     67   StoreValue(rl_dest, rl_result);
     68 }
     69 
     70 void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode,
     71                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     72   int op = kMipsNop;
     73   RegLocation rl_result;
     74 
     75   switch (opcode) {
     76     case Instruction::ADD_DOUBLE_2ADDR:
     77     case Instruction::ADD_DOUBLE:
     78       op = kMipsFaddd;
     79       break;
     80     case Instruction::SUB_DOUBLE_2ADDR:
     81     case Instruction::SUB_DOUBLE:
     82       op = kMipsFsubd;
     83       break;
     84     case Instruction::DIV_DOUBLE_2ADDR:
     85     case Instruction::DIV_DOUBLE:
     86       op = kMipsFdivd;
     87       break;
     88     case Instruction::MUL_DOUBLE_2ADDR:
     89     case Instruction::MUL_DOUBLE:
     90       op = kMipsFmuld;
     91       break;
     92     case Instruction::REM_DOUBLE_2ADDR:
     93     case Instruction::REM_DOUBLE:
     94       FlushAllRegs();   // Send everything to home location
     95       CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false);
     96       rl_result = GetReturnWide(kFPReg);
     97       StoreValueWide(rl_dest, rl_result);
     98       return;
     99     case Instruction::NEG_DOUBLE:
    100       GenNegDouble(rl_dest, rl_src1);
    101       return;
    102     default:
    103       LOG(FATAL) << "Unpexpected opcode: " << opcode;
    104   }
    105   rl_src1 = LoadValueWide(rl_src1, kFPReg);
    106   DCHECK(rl_src1.wide);
    107   rl_src2 = LoadValueWide(rl_src2, kFPReg);
    108   DCHECK(rl_src2.wide);
    109   rl_result = EvalLoc(rl_dest, kFPReg, true);
    110   DCHECK(rl_dest.wide);
    111   DCHECK(rl_result.wide);
    112   NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
    113   StoreValueWide(rl_dest, rl_result);
    114 }
    115 
    116 void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
    117                                 RegLocation rl_src) {
    118   int op = kMipsNop;
    119   RegLocation rl_result;
    120   switch (opcode) {
    121     case Instruction::INT_TO_FLOAT:
    122       op = kMipsFcvtsw;
    123       break;
    124     case Instruction::DOUBLE_TO_FLOAT:
    125       op = kMipsFcvtsd;
    126       break;
    127     case Instruction::FLOAT_TO_DOUBLE:
    128       op = kMipsFcvtds;
    129       break;
    130     case Instruction::INT_TO_DOUBLE:
    131       op = kMipsFcvtdw;
    132       break;
    133     case Instruction::FLOAT_TO_INT:
    134       GenConversionCall(kQuickF2iz, rl_dest, rl_src);
    135       return;
    136     case Instruction::DOUBLE_TO_INT:
    137       GenConversionCall(kQuickD2iz, rl_dest, rl_src);
    138       return;
    139     case Instruction::LONG_TO_DOUBLE:
    140       GenConversionCall(kQuickL2d, rl_dest, rl_src);
    141       return;
    142     case Instruction::FLOAT_TO_LONG:
    143       GenConversionCall(kQuickF2l, rl_dest, rl_src);
    144       return;
    145     case Instruction::LONG_TO_FLOAT:
    146       GenConversionCall(kQuickL2f, rl_dest, rl_src);
    147       return;
    148     case Instruction::DOUBLE_TO_LONG:
    149       GenConversionCall(kQuickD2l, rl_dest, rl_src);
    150       return;
    151     default:
    152       LOG(FATAL) << "Unexpected opcode: " << opcode;
    153   }
    154   if (rl_src.wide) {
    155     rl_src = LoadValueWide(rl_src, kFPReg);
    156   } else {
    157     rl_src = LoadValue(rl_src, kFPReg);
    158   }
    159   rl_result = EvalLoc(rl_dest, kFPReg, true);
    160   NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
    161   if (rl_dest.wide) {
    162     StoreValueWide(rl_dest, rl_result);
    163   } else {
    164     StoreValue(rl_dest, rl_result);
    165   }
    166 }
    167 
    168 void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
    169                            RegLocation rl_src1, RegLocation rl_src2) {
    170   bool wide = true;
    171   QuickEntrypointEnum target;
    172 
    173   switch (opcode) {
    174     case Instruction::CMPL_FLOAT:
    175       target = kQuickCmplFloat;
    176       wide = false;
    177       break;
    178     case Instruction::CMPG_FLOAT:
    179       target = kQuickCmpgFloat;
    180       wide = false;
    181       break;
    182     case Instruction::CMPL_DOUBLE:
    183       target = kQuickCmplDouble;
    184       break;
    185     case Instruction::CMPG_DOUBLE:
    186       target = kQuickCmpgDouble;
    187       break;
    188     default:
    189       LOG(FATAL) << "Unexpected opcode: " << opcode;
    190       target = kQuickCmplFloat;
    191   }
    192   FlushAllRegs();
    193   LockCallTemps();
    194   if (wide) {
    195     RegStorage r_tmp1(RegStorage::k64BitPair, rMIPS_FARG0, rMIPS_FARG1);
    196     RegStorage r_tmp2(RegStorage::k64BitPair, rMIPS_FARG2, rMIPS_FARG3);
    197     LoadValueDirectWideFixed(rl_src1, r_tmp1);
    198     LoadValueDirectWideFixed(rl_src2, r_tmp2);
    199   } else {
    200     LoadValueDirectFixed(rl_src1, rs_rMIPS_FARG0);
    201     LoadValueDirectFixed(rl_src2, rs_rMIPS_FARG2);
    202   }
    203   RegStorage r_tgt = LoadHelper(target);
    204   // NOTE: not a safepoint
    205   OpReg(kOpBlx, r_tgt);
    206   RegLocation rl_result = GetReturn(kCoreReg);
    207   StoreValue(rl_dest, rl_result);
    208 }
    209 
    210 void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir,
    211                                 bool gt_bias, bool is_double) {
    212   UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
    213 }
    214 
    215 void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
    216   RegLocation rl_result;
    217   rl_src = LoadValue(rl_src, kCoreReg);
    218   rl_result = EvalLoc(rl_dest, kCoreReg, true);
    219   OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
    220   StoreValue(rl_dest, rl_result);
    221 }
    222 
    223 void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
    224   RegLocation rl_result;
    225   rl_src = LoadValueWide(rl_src, kCoreReg);
    226   rl_result = EvalLoc(rl_dest, kCoreReg, true);
    227   OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
    228   OpRegCopy(rl_result.reg, rl_src.reg);
    229   StoreValueWide(rl_dest, rl_result);
    230 }
    231 
    232 bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
    233   // TODO: need Mips implementation
    234   return false;
    235 }
    236 
    237 }  // namespace art
    238