Home | History | Annotate | Download | only in x86
      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_x86.h"
     18 #include "dex/quick/mir_to_lir-inl.h"
     19 #include "x86_lir.h"
     20 
     21 namespace art {
     22 
     23 void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
     24                                  RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     25   X86OpCode op = kX86Nop;
     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 = kX86AddssRR;
     36       break;
     37     case Instruction::SUB_FLOAT_2ADDR:
     38     case Instruction::SUB_FLOAT:
     39       op = kX86SubssRR;
     40       break;
     41     case Instruction::DIV_FLOAT_2ADDR:
     42     case Instruction::DIV_FLOAT:
     43       op = kX86DivssRR;
     44       break;
     45     case Instruction::MUL_FLOAT_2ADDR:
     46     case Instruction::MUL_FLOAT:
     47       op = kX86MulssRR;
     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   int r_dest = rl_result.low_reg;
     67   int r_src1 = rl_src1.low_reg;
     68   int r_src2 = rl_src2.low_reg;
     69   if (r_dest == r_src2) {
     70     r_src2 = AllocTempFloat();
     71     OpRegCopy(r_src2, r_dest);
     72   }
     73   OpRegCopy(r_dest, r_src1);
     74   NewLIR2(op, r_dest, r_src2);
     75   StoreValue(rl_dest, rl_result);
     76 }
     77 
     78 void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
     79                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     80   X86OpCode op = kX86Nop;
     81   RegLocation rl_result;
     82 
     83   switch (opcode) {
     84     case Instruction::ADD_DOUBLE_2ADDR:
     85     case Instruction::ADD_DOUBLE:
     86       op = kX86AddsdRR;
     87       break;
     88     case Instruction::SUB_DOUBLE_2ADDR:
     89     case Instruction::SUB_DOUBLE:
     90       op = kX86SubsdRR;
     91       break;
     92     case Instruction::DIV_DOUBLE_2ADDR:
     93     case Instruction::DIV_DOUBLE:
     94       op = kX86DivsdRR;
     95       break;
     96     case Instruction::MUL_DOUBLE_2ADDR:
     97     case Instruction::MUL_DOUBLE:
     98       op = kX86MulsdRR;
     99       break;
    100     case Instruction::REM_DOUBLE_2ADDR:
    101     case Instruction::REM_DOUBLE:
    102       FlushAllRegs();   // Send everything to home location
    103       CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
    104                                               false);
    105       rl_result = GetReturnWide(true);
    106       StoreValueWide(rl_dest, rl_result);
    107       return;
    108     case Instruction::NEG_DOUBLE:
    109       GenNegDouble(rl_dest, rl_src1);
    110       return;
    111     default:
    112       LOG(FATAL) << "Unexpected opcode: " << opcode;
    113   }
    114   rl_src1 = LoadValueWide(rl_src1, kFPReg);
    115   DCHECK(rl_src1.wide);
    116   rl_src2 = LoadValueWide(rl_src2, kFPReg);
    117   DCHECK(rl_src2.wide);
    118   rl_result = EvalLoc(rl_dest, kFPReg, true);
    119   DCHECK(rl_dest.wide);
    120   DCHECK(rl_result.wide);
    121   int r_dest = S2d(rl_result.low_reg, rl_result.high_reg);
    122   int r_src1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
    123   int r_src2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
    124   if (r_dest == r_src2) {
    125     r_src2 = AllocTempDouble() | X86_FP_DOUBLE;
    126     OpRegCopy(r_src2, r_dest);
    127   }
    128   OpRegCopy(r_dest, r_src1);
    129   NewLIR2(op, r_dest, r_src2);
    130   StoreValueWide(rl_dest, rl_result);
    131 }
    132 
    133 void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
    134                                RegLocation rl_src) {
    135   RegisterClass rcSrc = kFPReg;
    136   X86OpCode op = kX86Nop;
    137   int src_reg;
    138   RegLocation rl_result;
    139   switch (opcode) {
    140     case Instruction::INT_TO_FLOAT:
    141       rcSrc = kCoreReg;
    142       op = kX86Cvtsi2ssRR;
    143       break;
    144     case Instruction::DOUBLE_TO_FLOAT:
    145       rcSrc = kFPReg;
    146       op = kX86Cvtsd2ssRR;
    147       break;
    148     case Instruction::FLOAT_TO_DOUBLE:
    149       rcSrc = kFPReg;
    150       op = kX86Cvtss2sdRR;
    151       break;
    152     case Instruction::INT_TO_DOUBLE:
    153       rcSrc = kCoreReg;
    154       op = kX86Cvtsi2sdRR;
    155       break;
    156     case Instruction::FLOAT_TO_INT: {
    157       rl_src = LoadValue(rl_src, kFPReg);
    158       src_reg = rl_src.low_reg;
    159       // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
    160       ClobberSReg(rl_dest.s_reg_low);
    161       rl_result = EvalLoc(rl_dest, kCoreReg, true);
    162       int temp_reg = AllocTempFloat();
    163 
    164       LoadConstant(rl_result.low_reg, 0x7fffffff);
    165       NewLIR2(kX86Cvtsi2ssRR, temp_reg, rl_result.low_reg);
    166       NewLIR2(kX86ComissRR, src_reg, temp_reg);
    167       LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
    168       LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
    169       NewLIR2(kX86Cvttss2siRR, rl_result.low_reg, src_reg);
    170       LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
    171       branch_na_n->target = NewLIR0(kPseudoTargetLabel);
    172       NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
    173       branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
    174       branch_normal->target = NewLIR0(kPseudoTargetLabel);
    175       StoreValue(rl_dest, rl_result);
    176       return;
    177     }
    178     case Instruction::DOUBLE_TO_INT: {
    179       rl_src = LoadValueWide(rl_src, kFPReg);
    180       src_reg = rl_src.low_reg;
    181       // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
    182       ClobberSReg(rl_dest.s_reg_low);
    183       rl_result = EvalLoc(rl_dest, kCoreReg, true);
    184       int temp_reg = AllocTempDouble() | X86_FP_DOUBLE;
    185 
    186       LoadConstant(rl_result.low_reg, 0x7fffffff);
    187       NewLIR2(kX86Cvtsi2sdRR, temp_reg, rl_result.low_reg);
    188       NewLIR2(kX86ComisdRR, src_reg, temp_reg);
    189       LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
    190       LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
    191       NewLIR2(kX86Cvttsd2siRR, rl_result.low_reg, src_reg);
    192       LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
    193       branch_na_n->target = NewLIR0(kPseudoTargetLabel);
    194       NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
    195       branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
    196       branch_normal->target = NewLIR0(kPseudoTargetLabel);
    197       StoreValue(rl_dest, rl_result);
    198       return;
    199     }
    200     case Instruction::LONG_TO_DOUBLE:
    201       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
    202       return;
    203     case Instruction::LONG_TO_FLOAT:
    204       // TODO: inline by using memory as a 64-bit source. Be careful about promoted registers.
    205       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
    206       return;
    207     case Instruction::FLOAT_TO_LONG:
    208       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
    209       return;
    210     case Instruction::DOUBLE_TO_LONG:
    211       GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
    212       return;
    213     default:
    214       LOG(INFO) << "Unexpected opcode: " << opcode;
    215   }
    216   if (rl_src.wide) {
    217     rl_src = LoadValueWide(rl_src, rcSrc);
    218     src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
    219   } else {
    220     rl_src = LoadValue(rl_src, rcSrc);
    221     src_reg = rl_src.low_reg;
    222   }
    223   if (rl_dest.wide) {
    224     rl_result = EvalLoc(rl_dest, kFPReg, true);
    225     NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
    226     StoreValueWide(rl_dest, rl_result);
    227   } else {
    228     rl_result = EvalLoc(rl_dest, kFPReg, true);
    229     NewLIR2(op, rl_result.low_reg, src_reg);
    230     StoreValue(rl_dest, rl_result);
    231   }
    232 }
    233 
    234 void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
    235                           RegLocation rl_src1, RegLocation rl_src2) {
    236   bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
    237   bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
    238   int src_reg1;
    239   int src_reg2;
    240   if (single) {
    241     rl_src1 = LoadValue(rl_src1, kFPReg);
    242     src_reg1 = rl_src1.low_reg;
    243     rl_src2 = LoadValue(rl_src2, kFPReg);
    244     src_reg2 = rl_src2.low_reg;
    245   } else {
    246     rl_src1 = LoadValueWide(rl_src1, kFPReg);
    247     src_reg1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
    248     rl_src2 = LoadValueWide(rl_src2, kFPReg);
    249     src_reg2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
    250   }
    251   // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
    252   ClobberSReg(rl_dest.s_reg_low);
    253   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    254   LoadConstantNoClobber(rl_result.low_reg, unordered_gt ? 1 : 0);
    255   if (single) {
    256     NewLIR2(kX86UcomissRR, src_reg1, src_reg2);
    257   } else {
    258     NewLIR2(kX86UcomisdRR, src_reg1, src_reg2);
    259   }
    260   LIR* branch = NULL;
    261   if (unordered_gt) {
    262     branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    263   }
    264   // If the result reg can't be byte accessed, use a jump and move instead of a set.
    265   if (rl_result.low_reg >= 4) {
    266     LIR* branch2 = NULL;
    267     if (unordered_gt) {
    268       branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
    269       NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x0);
    270     } else {
    271       branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
    272       NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x1);
    273     }
    274     branch2->target = NewLIR0(kPseudoTargetLabel);
    275   } else {
    276     NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondA /* above - unsigned > */);
    277   }
    278   NewLIR2(kX86Sbb32RI, rl_result.low_reg, 0);
    279   if (unordered_gt) {
    280     branch->target = NewLIR0(kPseudoTargetLabel);
    281   }
    282   StoreValue(rl_dest, rl_result);
    283 }
    284 
    285 void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
    286                                      bool is_double) {
    287   LIR* taken = &block_label_list_[bb->taken->id];
    288   LIR* not_taken = &block_label_list_[bb->fall_through->id];
    289   LIR* branch = NULL;
    290   RegLocation rl_src1;
    291   RegLocation rl_src2;
    292   if (is_double) {
    293     rl_src1 = mir_graph_->GetSrcWide(mir, 0);
    294     rl_src2 = mir_graph_->GetSrcWide(mir, 2);
    295     rl_src1 = LoadValueWide(rl_src1, kFPReg);
    296     rl_src2 = LoadValueWide(rl_src2, kFPReg);
    297     NewLIR2(kX86UcomisdRR, S2d(rl_src1.low_reg, rl_src1.high_reg),
    298             S2d(rl_src2.low_reg, rl_src2.high_reg));
    299   } else {
    300     rl_src1 = mir_graph_->GetSrc(mir, 0);
    301     rl_src2 = mir_graph_->GetSrc(mir, 1);
    302     rl_src1 = LoadValue(rl_src1, kFPReg);
    303     rl_src2 = LoadValue(rl_src2, kFPReg);
    304     NewLIR2(kX86UcomissRR, rl_src1.low_reg, rl_src2.low_reg);
    305   }
    306   ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
    307   switch (ccode) {
    308     case kCondEq:
    309       if (!gt_bias) {
    310         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    311         branch->target = not_taken;
    312       }
    313       break;
    314     case kCondNe:
    315       if (!gt_bias) {
    316         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    317         branch->target = taken;
    318       }
    319       break;
    320     case kCondLt:
    321       if (gt_bias) {
    322         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    323         branch->target = not_taken;
    324       }
    325       ccode = kCondCs;
    326       break;
    327     case kCondLe:
    328       if (gt_bias) {
    329         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    330         branch->target = not_taken;
    331       }
    332       ccode = kCondLs;
    333       break;
    334     case kCondGt:
    335       if (gt_bias) {
    336         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    337         branch->target = taken;
    338       }
    339       ccode = kCondHi;
    340       break;
    341     case kCondGe:
    342       if (gt_bias) {
    343         branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
    344         branch->target = taken;
    345       }
    346       ccode = kCondCc;
    347       break;
    348     default:
    349       LOG(FATAL) << "Unexpected ccode: " << ccode;
    350   }
    351   OpCondBranch(ccode, taken);
    352 }
    353 
    354 void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
    355   RegLocation rl_result;
    356   rl_src = LoadValue(rl_src, kCoreReg);
    357   rl_result = EvalLoc(rl_dest, kCoreReg, true);
    358   OpRegRegImm(kOpAdd, rl_result.low_reg, rl_src.low_reg, 0x80000000);
    359   StoreValue(rl_dest, rl_result);
    360 }
    361 
    362 void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
    363   RegLocation rl_result;
    364   rl_src = LoadValueWide(rl_src, kCoreReg);
    365   rl_result = EvalLoc(rl_dest, kCoreReg, true);
    366   OpRegRegImm(kOpAdd, rl_result.high_reg, rl_src.high_reg, 0x80000000);
    367   OpRegCopy(rl_result.low_reg, rl_src.low_reg);
    368   StoreValueWide(rl_dest, rl_result);
    369 }
    370 
    371 bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
    372   DCHECK_NE(cu_->instruction_set, kThumb2);
    373   return false;
    374 }
    375 
    376 
    377 
    378 }  // namespace art
    379