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(kQuickFmodf, rl_src1, rl_src2, false); 53 rl_result = GetReturn(kFPReg); 54 StoreValue(rl_dest, rl_result); 55 return; 56 case Instruction::NEG_FLOAT: 57 GenNegFloat(rl_dest, rl_src1); 58 return; 59 default: 60 LOG(FATAL) << "Unexpected opcode: " << opcode; 61 } 62 rl_src1 = LoadValue(rl_src1, kFPReg); 63 rl_src2 = LoadValue(rl_src2, kFPReg); 64 rl_result = EvalLoc(rl_dest, kFPReg, true); 65 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 66 StoreValue(rl_dest, rl_result); 67 } 68 69 void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode, 70 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 71 int op = kThumbBkpt; 72 RegLocation rl_result; 73 74 switch (opcode) { 75 case Instruction::ADD_DOUBLE_2ADDR: 76 case Instruction::ADD_DOUBLE: 77 op = kThumb2Vaddd; 78 break; 79 case Instruction::SUB_DOUBLE_2ADDR: 80 case Instruction::SUB_DOUBLE: 81 op = kThumb2Vsubd; 82 break; 83 case Instruction::DIV_DOUBLE_2ADDR: 84 case Instruction::DIV_DOUBLE: 85 op = kThumb2Vdivd; 86 break; 87 case Instruction::MUL_DOUBLE_2ADDR: 88 case Instruction::MUL_DOUBLE: 89 op = kThumb2Vmuld; 90 break; 91 case Instruction::REM_DOUBLE_2ADDR: 92 case Instruction::REM_DOUBLE: 93 FlushAllRegs(); // Send everything to home location 94 CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false); 95 rl_result = GetReturnWide(kFPReg); 96 StoreValueWide(rl_dest, rl_result); 97 return; 98 case Instruction::NEG_DOUBLE: 99 GenNegDouble(rl_dest, rl_src1); 100 return; 101 default: 102 LOG(FATAL) << "Unexpected opcode: " << opcode; 103 } 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 ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) { 117 int op = kThumbBkpt; 118 int src_reg; 119 RegLocation rl_result; 120 121 switch (opcode) { 122 case Instruction::INT_TO_FLOAT: 123 op = kThumb2VcvtIF; 124 break; 125 case Instruction::FLOAT_TO_INT: 126 op = kThumb2VcvtFI; 127 break; 128 case Instruction::DOUBLE_TO_FLOAT: 129 op = kThumb2VcvtDF; 130 break; 131 case Instruction::FLOAT_TO_DOUBLE: 132 op = kThumb2VcvtFd; 133 break; 134 case Instruction::INT_TO_DOUBLE: 135 op = kThumb2VcvtF64S32; 136 break; 137 case Instruction::DOUBLE_TO_INT: 138 op = kThumb2VcvtDI; 139 break; 140 case Instruction::LONG_TO_DOUBLE: { 141 rl_src = LoadValueWide(rl_src, kFPReg); 142 RegisterInfo* info = GetRegInfo(rl_src.reg); 143 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg(); 144 DCHECK(src_low.Valid()); 145 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg(); 146 DCHECK(src_high.Valid()); 147 rl_result = EvalLoc(rl_dest, kFPReg, true); 148 RegStorage tmp1 = AllocTempDouble(); 149 RegStorage tmp2 = AllocTempDouble(); 150 151 NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg()); 152 NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg()); 153 LoadConstantWide(tmp2, 0x41f0000000000000LL); 154 NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg()); 155 FreeTemp(tmp1); 156 FreeTemp(tmp2); 157 StoreValueWide(rl_dest, rl_result); 158 return; 159 } 160 case Instruction::FLOAT_TO_LONG: 161 GenConversionCall(kQuickF2l, rl_dest, rl_src); 162 return; 163 case Instruction::LONG_TO_FLOAT: { 164 rl_src = LoadValueWide(rl_src, kFPReg); 165 RegisterInfo* info = GetRegInfo(rl_src.reg); 166 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg(); 167 DCHECK(src_low.Valid()); 168 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg(); 169 DCHECK(src_high.Valid()); 170 rl_result = EvalLoc(rl_dest, kFPReg, true); 171 // Allocate temp registers. 172 RegStorage high_val = AllocTempDouble(); 173 RegStorage low_val = AllocTempDouble(); 174 RegStorage const_val = AllocTempDouble(); 175 // Long to double. 176 NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg()); 177 NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg()); 178 LoadConstantWide(const_val, INT64_C(0x41f0000000000000)); 179 NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg()); 180 // Double to float. 181 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg()); 182 // Free temp registers. 183 FreeTemp(high_val); 184 FreeTemp(low_val); 185 FreeTemp(const_val); 186 // Store result. 187 StoreValue(rl_dest, rl_result); 188 return; 189 } 190 case Instruction::DOUBLE_TO_LONG: 191 GenConversionCall(kQuickD2l, rl_dest, rl_src); 192 return; 193 default: 194 LOG(FATAL) << "Unexpected opcode: " << opcode; 195 } 196 if (rl_src.wide) { 197 rl_src = LoadValueWide(rl_src, kFPReg); 198 src_reg = rl_src.reg.GetReg(); 199 } else { 200 rl_src = LoadValue(rl_src, kFPReg); 201 src_reg = rl_src.reg.GetReg(); 202 } 203 if (rl_dest.wide) { 204 rl_result = EvalLoc(rl_dest, kFPReg, true); 205 NewLIR2(op, rl_result.reg.GetReg(), src_reg); 206 StoreValueWide(rl_dest, rl_result); 207 } else { 208 rl_result = EvalLoc(rl_dest, kFPReg, true); 209 NewLIR2(op, rl_result.reg.GetReg(), src_reg); 210 StoreValue(rl_dest, rl_result); 211 } 212 } 213 214 void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, 215 bool is_double) { 216 LIR* target = &block_label_list_[bb->taken]; 217 RegLocation rl_src1; 218 RegLocation rl_src2; 219 if (is_double) { 220 rl_src1 = mir_graph_->GetSrcWide(mir, 0); 221 rl_src2 = mir_graph_->GetSrcWide(mir, 2); 222 rl_src1 = LoadValueWide(rl_src1, kFPReg); 223 rl_src2 = LoadValueWide(rl_src2, kFPReg); 224 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 225 } else { 226 rl_src1 = mir_graph_->GetSrc(mir, 0); 227 rl_src2 = mir_graph_->GetSrc(mir, 1); 228 rl_src1 = LoadValue(rl_src1, kFPReg); 229 rl_src2 = LoadValue(rl_src2, kFPReg); 230 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 231 } 232 NewLIR0(kThumb2Fmstat); 233 ConditionCode ccode = mir->meta.ccode; 234 switch (ccode) { 235 case kCondEq: 236 case kCondNe: 237 break; 238 case kCondLt: 239 if (gt_bias) { 240 ccode = kCondMi; 241 } 242 break; 243 case kCondLe: 244 if (gt_bias) { 245 ccode = kCondLs; 246 } 247 break; 248 case kCondGt: 249 if (gt_bias) { 250 ccode = kCondHi; 251 } 252 break; 253 case kCondGe: 254 if (gt_bias) { 255 ccode = kCondUge; 256 } 257 break; 258 default: 259 LOG(FATAL) << "Unexpected ccode: " << ccode; 260 } 261 OpCondBranch(ccode, target); 262 } 263 264 265 void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, 266 RegLocation rl_src1, RegLocation rl_src2) { 267 bool is_double = false; 268 int default_result = -1; 269 RegLocation rl_result; 270 271 switch (opcode) { 272 case Instruction::CMPL_FLOAT: 273 is_double = false; 274 default_result = -1; 275 break; 276 case Instruction::CMPG_FLOAT: 277 is_double = false; 278 default_result = 1; 279 break; 280 case Instruction::CMPL_DOUBLE: 281 is_double = true; 282 default_result = -1; 283 break; 284 case Instruction::CMPG_DOUBLE: 285 is_double = true; 286 default_result = 1; 287 break; 288 default: 289 LOG(FATAL) << "Unexpected opcode: " << opcode; 290 } 291 if (is_double) { 292 rl_src1 = LoadValueWide(rl_src1, kFPReg); 293 rl_src2 = LoadValueWide(rl_src2, kFPReg); 294 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc() 295 ClobberSReg(rl_dest.s_reg_low); 296 rl_result = EvalLoc(rl_dest, kCoreReg, true); 297 LoadConstant(rl_result.reg, default_result); 298 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 299 } else { 300 rl_src1 = LoadValue(rl_src1, kFPReg); 301 rl_src2 = LoadValue(rl_src2, kFPReg); 302 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc() 303 ClobberSReg(rl_dest.s_reg_low); 304 rl_result = EvalLoc(rl_dest, kCoreReg, true); 305 LoadConstant(rl_result.reg, default_result); 306 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 307 } 308 DCHECK(!rl_result.reg.IsFloat()); 309 NewLIR0(kThumb2Fmstat); 310 311 LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, ""); 312 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(), 313 ModifiedImmediate(-default_result)); // Must not alter ccodes 314 OpEndIT(it); 315 316 it = OpIT(kCondEq, ""); 317 LoadConstant(rl_result.reg, 0); 318 OpEndIT(it); 319 320 StoreValue(rl_dest, rl_result); 321 } 322 323 void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) { 324 RegLocation rl_result; 325 rl_src = LoadValue(rl_src, kFPReg); 326 rl_result = EvalLoc(rl_dest, kFPReg, true); 327 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 328 StoreValue(rl_dest, rl_result); 329 } 330 331 void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { 332 RegLocation rl_result; 333 rl_src = LoadValueWide(rl_src, kFPReg); 334 rl_result = EvalLoc(rl_dest, kFPReg, true); 335 NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 336 StoreValueWide(rl_dest, rl_result); 337 } 338 339 static RegisterClass RegClassForAbsFP(RegLocation rl_src, RegLocation rl_dest) { 340 // If src is in a core reg or, unlikely, dest has been promoted to a core reg, use core reg. 341 if ((rl_src.location == kLocPhysReg && !rl_src.reg.IsFloat()) || 342 (rl_dest.location == kLocPhysReg && !rl_dest.reg.IsFloat())) { 343 return kCoreReg; 344 } 345 // If src is in an fp reg or dest has been promoted to an fp reg, use fp reg. 346 if (rl_src.location == kLocPhysReg || rl_dest.location == kLocPhysReg) { 347 return kFPReg; 348 } 349 // With both src and dest in the stack frame we have to perform load+abs+store. Whether this 350 // is faster using a core reg or fp reg depends on the particular CPU. Without further 351 // investigation and testing we prefer core register. (If the result is subsequently used in 352 // another fp operation, the dalvik reg will probably get promoted and that should be handled 353 // by the cases above.) 354 return kCoreReg; 355 } 356 357 bool ArmMir2Lir::GenInlinedAbsFloat(CallInfo* info) { 358 if (info->result.location == kLocInvalid) { 359 return true; // Result is unused: inlining successful, no code generated. 360 } 361 RegLocation rl_dest = info->result; 362 RegLocation rl_src = UpdateLoc(info->args[0]); 363 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest); 364 rl_src = LoadValue(rl_src, reg_class); 365 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true); 366 if (reg_class == kFPReg) { 367 NewLIR2(kThumb2Vabss, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 368 } else { 369 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff); 370 } 371 StoreValue(rl_dest, rl_result); 372 return true; 373 } 374 375 bool ArmMir2Lir::GenInlinedAbsDouble(CallInfo* info) { 376 if (info->result.location == kLocInvalid) { 377 return true; // Result is unused: inlining successful, no code generated. 378 } 379 RegLocation rl_dest = info->result; 380 RegLocation rl_src = UpdateLocWide(info->args[0]); 381 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest); 382 rl_src = LoadValueWide(rl_src, reg_class); 383 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true); 384 if (reg_class == kFPReg) { 385 NewLIR2(kThumb2Vabsd, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 386 } else if (rl_result.reg.GetLow().GetReg() != rl_src.reg.GetHigh().GetReg()) { 387 // No inconvenient overlap. 388 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow()); 389 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x7fffffff); 390 } else { 391 // Inconvenient overlap, use a temp register to preserve the high word of the source. 392 RegStorage rs_tmp = AllocTemp(); 393 OpRegCopy(rs_tmp, rl_src.reg.GetHigh()); 394 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow()); 395 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rs_tmp, 0x7fffffff); 396 FreeTemp(rs_tmp); 397 } 398 StoreValueWide(rl_dest, rl_result); 399 return true; 400 } 401 402 bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) { 403 DCHECK_EQ(cu_->instruction_set, kThumb2); 404 RegLocation rl_src = info->args[0]; 405 RegLocation rl_dest = InlineTargetWide(info); // double place for result 406 rl_src = LoadValueWide(rl_src, kFPReg); 407 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 408 NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 409 StoreValueWide(rl_dest, rl_result); 410 return true; 411 } 412 413 414 } // namespace art 415