Home | History | Annotate | Download | only in arm
      1 /*
      2  * Copyright (C) 2011 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 "arm_lir.h"
     18 #include "codegen_arm.h"
     19 #include "dex/quick/mir_to_lir-inl.h"
     20 
     21 namespace art {
     22 
     23 void ArmMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
     24                                  RegLocation rl_src1, RegLocation rl_src2) {
     25   int op = kThumbBkpt;
     26   RegLocation rl_result;
     27 
     28   /*
     29    * Don't attempt to optimize register usage since these opcodes call out to
     30    * the handlers.
     31    */
     32   switch (opcode) {
     33     case Instruction::ADD_FLOAT_2ADDR:
     34     case Instruction::ADD_FLOAT:
     35       op = kThumb2Vadds;
     36       break;
     37     case Instruction::SUB_FLOAT_2ADDR:
     38     case Instruction::SUB_FLOAT:
     39       op = kThumb2Vsubs;
     40       break;
     41     case Instruction::DIV_FLOAT_2ADDR:
     42     case Instruction::DIV_FLOAT:
     43       op = kThumb2Vdivs;
     44       break;
     45     case Instruction::MUL_FLOAT_2ADDR:
     46     case Instruction::MUL_FLOAT:
     47       op = kThumb2Vmuls;
     48       break;
     49     case Instruction::REM_FLOAT_2ADDR:
     50     case Instruction::REM_FLOAT:
     51       FlushAllRegs();   // Send everything to home location
     52       CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
     53                                               false);
     54       rl_result = GetReturn(true);
     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.low_reg, rl_src1.low_reg, rl_src2.low_reg);
     67   StoreValue(rl_dest, rl_result);
     68 }
     69 
     70 void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode,
     71                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     72   int op = kThumbBkpt;
     73   RegLocation rl_result;
     74 
     75   switch (opcode) {
     76     case Instruction::ADD_DOUBLE_2ADDR:
     77     case Instruction::ADD_DOUBLE:
     78       op = kThumb2Vaddd;
     79       break;
     80     case Instruction::SUB_DOUBLE_2ADDR:
     81     case Instruction::SUB_DOUBLE:
     82       op = kThumb2Vsubd;
     83       break;
     84     case Instruction::DIV_DOUBLE_2ADDR:
     85     case Instruction::DIV_DOUBLE:
     86       op = kThumb2Vdivd;
     87       break;
     88     case Instruction::MUL_DOUBLE_2ADDR:
     89     case Instruction::MUL_DOUBLE:
     90       op = kThumb2Vmuld;
     91       break;
     92     case Instruction::REM_DOUBLE_2ADDR:
     93     case Instruction::REM_DOUBLE:
     94       FlushAllRegs();   // Send everything to home location
     95       CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
     96                                               false);
     97       rl_result = GetReturnWide(true);
     98       StoreValueWide(rl_dest, rl_result);
     99       return;
    100     case Instruction::NEG_DOUBLE:
    101       GenNegDouble(rl_dest, rl_src1);
    102       return;
    103     default:
    104       LOG(FATAL) << "Unexpected opcode: " << opcode;
    105   }
    106 
    107   rl_src1 = LoadValueWide(rl_src1, kFPReg);
    108   DCHECK(rl_src1.wide);
    109   rl_src2 = LoadValueWide(rl_src2, kFPReg);
    110   DCHECK(rl_src2.wide);
    111   rl_result = EvalLoc(rl_dest, kFPReg, true);
    112   DCHECK(rl_dest.wide);
    113   DCHECK(rl_result.wide);
    114   NewLIR3(op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
    115           S2d(rl_src2.low_reg, rl_src2.high_reg));
    116   StoreValueWide(rl_dest, rl_result);
    117 }
    118 
    119 void ArmMir2Lir::GenConversion(Instruction::Code opcode,
    120                                RegLocation rl_dest, RegLocation rl_src) {
    121   int op = kThumbBkpt;
    122   int src_reg;
    123   RegLocation rl_result;
    124 
    125   switch (opcode) {
    126     case Instruction::INT_TO_FLOAT:
    127       op = kThumb2VcvtIF;
    128       break;
    129     case Instruction::FLOAT_TO_INT:
    130       op = kThumb2VcvtFI;
    131       break;
    132     case Instruction::DOUBLE_TO_FLOAT:
    133       op = kThumb2VcvtDF;
    134       break;
    135     case Instruction::FLOAT_TO_DOUBLE:
    136       op = kThumb2VcvtFd;
    137       break;
    138     case Instruction::INT_TO_DOUBLE:
    139       op = kThumb2VcvtID;
    140       break;
    141     case Instruction::DOUBLE_TO_INT:
    142       op = kThumb2VcvtDI;
    143       break;
    144     case Instruction::LONG_TO_DOUBLE:
    145       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
    146       return;
    147     case Instruction::FLOAT_TO_LONG:
    148       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
    149       return;
    150     case Instruction::LONG_TO_FLOAT:
    151       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
    152       return;
    153     case Instruction::DOUBLE_TO_LONG:
    154       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
    155       return;
    156     default:
    157       LOG(FATAL) << "Unexpected opcode: " << opcode;
    158   }
    159   if (rl_src.wide) {
    160     rl_src = LoadValueWide(rl_src, kFPReg);
    161     src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
    162   } else {
    163     rl_src = LoadValue(rl_src, kFPReg);
    164     src_reg = rl_src.low_reg;
    165   }
    166   if (rl_dest.wide) {
    167     rl_result = EvalLoc(rl_dest, kFPReg, true);
    168     NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
    169     StoreValueWide(rl_dest, rl_result);
    170   } else {
    171     rl_result = EvalLoc(rl_dest, kFPReg, true);
    172     NewLIR2(op, rl_result.low_reg, src_reg);
    173     StoreValue(rl_dest, rl_result);
    174   }
    175 }
    176 
    177 void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
    178                                      bool is_double) {
    179   LIR* target = &block_label_list_[bb->taken->id];
    180   RegLocation rl_src1;
    181   RegLocation rl_src2;
    182   if (is_double) {
    183     rl_src1 = mir_graph_->GetSrcWide(mir, 0);
    184     rl_src2 = mir_graph_->GetSrcWide(mir, 2);
    185     rl_src1 = LoadValueWide(rl_src1, kFPReg);
    186     rl_src2 = LoadValueWide(rl_src2, kFPReg);
    187     NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
    188             S2d(rl_src2.low_reg, rl_src2.high_reg));
    189   } else {
    190     rl_src1 = mir_graph_->GetSrc(mir, 0);
    191     rl_src2 = mir_graph_->GetSrc(mir, 1);
    192     rl_src1 = LoadValue(rl_src1, kFPReg);
    193     rl_src2 = LoadValue(rl_src2, kFPReg);
    194     NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
    195   }
    196   NewLIR0(kThumb2Fmstat);
    197   ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
    198   switch (ccode) {
    199     case kCondEq:
    200     case kCondNe:
    201       break;
    202     case kCondLt:
    203       if (gt_bias) {
    204         ccode = kCondMi;
    205       }
    206       break;
    207     case kCondLe:
    208       if (gt_bias) {
    209         ccode = kCondLs;
    210       }
    211       break;
    212     case kCondGt:
    213       if (gt_bias) {
    214         ccode = kCondHi;
    215       }
    216       break;
    217     case kCondGe:
    218       if (gt_bias) {
    219         ccode = kCondCs;
    220       }
    221       break;
    222     default:
    223       LOG(FATAL) << "Unexpected ccode: " << ccode;
    224   }
    225   OpCondBranch(ccode, target);
    226 }
    227 
    228 
    229 void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
    230                           RegLocation rl_src1, RegLocation rl_src2) {
    231   bool is_double = false;
    232   int default_result = -1;
    233   RegLocation rl_result;
    234 
    235   switch (opcode) {
    236     case Instruction::CMPL_FLOAT:
    237       is_double = false;
    238       default_result = -1;
    239       break;
    240     case Instruction::CMPG_FLOAT:
    241       is_double = false;
    242       default_result = 1;
    243       break;
    244     case Instruction::CMPL_DOUBLE:
    245       is_double = true;
    246       default_result = -1;
    247       break;
    248     case Instruction::CMPG_DOUBLE:
    249       is_double = true;
    250       default_result = 1;
    251       break;
    252     default:
    253       LOG(FATAL) << "Unexpected opcode: " << opcode;
    254   }
    255   if (is_double) {
    256     rl_src1 = LoadValueWide(rl_src1, kFPReg);
    257     rl_src2 = LoadValueWide(rl_src2, kFPReg);
    258     // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
    259     ClobberSReg(rl_dest.s_reg_low);
    260     rl_result = EvalLoc(rl_dest, kCoreReg, true);
    261     LoadConstant(rl_result.low_reg, default_result);
    262     NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
    263             S2d(rl_src2.low_reg, rl_src2.high_reg));
    264   } else {
    265     rl_src1 = LoadValue(rl_src1, kFPReg);
    266     rl_src2 = LoadValue(rl_src2, kFPReg);
    267     // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
    268     ClobberSReg(rl_dest.s_reg_low);
    269     rl_result = EvalLoc(rl_dest, kCoreReg, true);
    270     LoadConstant(rl_result.low_reg, default_result);
    271     NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
    272   }
    273   DCHECK(!ARM_FPREG(rl_result.low_reg));
    274   NewLIR0(kThumb2Fmstat);
    275 
    276   OpIT((default_result == -1) ? kCondGt : kCondMi, "");
    277   NewLIR2(kThumb2MovImmShift, rl_result.low_reg,
    278           ModifiedImmediate(-default_result));  // Must not alter ccodes
    279   GenBarrier();
    280 
    281   OpIT(kCondEq, "");
    282   LoadConstant(rl_result.low_reg, 0);
    283   GenBarrier();
    284 
    285   StoreValue(rl_dest, rl_result);
    286 }
    287 
    288 void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
    289   RegLocation rl_result;
    290   rl_src = LoadValue(rl_src, kFPReg);
    291   rl_result = EvalLoc(rl_dest, kFPReg, true);
    292   NewLIR2(kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
    293   StoreValue(rl_dest, rl_result);
    294 }
    295 
    296 void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
    297   RegLocation rl_result;
    298   rl_src = LoadValueWide(rl_src, kFPReg);
    299   rl_result = EvalLoc(rl_dest, kFPReg, true);
    300   NewLIR2(kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
    301           S2d(rl_src.low_reg, rl_src.high_reg));
    302   StoreValueWide(rl_dest, rl_result);
    303 }
    304 
    305 bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
    306   DCHECK_EQ(cu_->instruction_set, kThumb2);
    307   LIR *branch;
    308   RegLocation rl_src = info->args[0];
    309   RegLocation rl_dest = InlineTargetWide(info);  // double place for result
    310   rl_src = LoadValueWide(rl_src, kFPReg);
    311   RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
    312   NewLIR2(kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
    313           S2d(rl_src.low_reg, rl_src.high_reg));
    314   NewLIR2(kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
    315           S2d(rl_result.low_reg, rl_result.high_reg));
    316   NewLIR0(kThumb2Fmstat);
    317   branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
    318   ClobberCalleeSave();
    319   LockCallTemps();  // Using fixed registers
    320   int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
    321   NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
    322   NewLIR1(kThumbBlxR, r_tgt);
    323   NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
    324   branch->target = NewLIR0(kPseudoTargetLabel);
    325   StoreValueWide(rl_dest, rl_result);
    326   return true;
    327 }
    328 
    329 
    330 }  // namespace art
    331