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