fp_arm.cc revision 00e1ec6581b5b7b46ca4c314c2854e9caa647dd2
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 21namespace art { 22 23void 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.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 67 StoreValue(rl_dest, rl_result); 68} 69 70void 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.reg.GetReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetReg(), rl_src1.reg.GetHighReg()), 115 S2d(rl_src2.reg.GetReg(), rl_src2.reg.GetHighReg())); 116 StoreValueWide(rl_dest, rl_result); 117} 118 119void 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 rl_src = LoadValueWide(rl_src, kFPReg); 146 src_reg = S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg()); 147 rl_result = EvalLoc(rl_dest, kFPReg, true); 148 // TODO: clean up AllocTempDouble so that its result has the double bits set. 149 int tmp1 = AllocTempDouble(); 150 int tmp2 = AllocTempDouble(); 151 152 NewLIR2(kThumb2VcvtF64S32, tmp1 | ARM_FP_DOUBLE, (src_reg & ~ARM_FP_DOUBLE) + 1); 153 NewLIR2(kThumb2VcvtF64U32, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), (src_reg & ~ARM_FP_DOUBLE)); 154 LoadConstantWide(tmp2, tmp2 + 1, 0x41f0000000000000LL); 155 NewLIR3(kThumb2VmlaF64, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), tmp1 | ARM_FP_DOUBLE, 156 tmp2 | ARM_FP_DOUBLE); 157 FreeTemp(tmp1); 158 FreeTemp(tmp2); 159 StoreValueWide(rl_dest, rl_result); 160 return; 161 } 162 case Instruction::FLOAT_TO_LONG: 163 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); 164 return; 165 case Instruction::LONG_TO_FLOAT: 166 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); 167 return; 168 case Instruction::DOUBLE_TO_LONG: 169 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); 170 return; 171 default: 172 LOG(FATAL) << "Unexpected opcode: " << opcode; 173 } 174 if (rl_src.wide) { 175 rl_src = LoadValueWide(rl_src, kFPReg); 176 src_reg = S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg()); 177 } else { 178 rl_src = LoadValue(rl_src, kFPReg); 179 src_reg = rl_src.reg.GetReg(); 180 } 181 if (rl_dest.wide) { 182 rl_result = EvalLoc(rl_dest, kFPReg, true); 183 NewLIR2(op, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), src_reg); 184 StoreValueWide(rl_dest, rl_result); 185 } else { 186 rl_result = EvalLoc(rl_dest, kFPReg, true); 187 NewLIR2(op, rl_result.reg.GetReg(), src_reg); 188 StoreValue(rl_dest, rl_result); 189 } 190} 191 192void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, 193 bool is_double) { 194 LIR* target = &block_label_list_[bb->taken]; 195 RegLocation rl_src1; 196 RegLocation rl_src2; 197 if (is_double) { 198 rl_src1 = mir_graph_->GetSrcWide(mir, 0); 199 rl_src2 = mir_graph_->GetSrcWide(mir, 2); 200 rl_src1 = LoadValueWide(rl_src1, kFPReg); 201 rl_src2 = LoadValueWide(rl_src2, kFPReg); 202 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetReg(), rl_src2.reg.GetHighReg()), 203 S2d(rl_src2.reg.GetReg(), rl_src2.reg.GetHighReg())); 204 } else { 205 rl_src1 = mir_graph_->GetSrc(mir, 0); 206 rl_src2 = mir_graph_->GetSrc(mir, 1); 207 rl_src1 = LoadValue(rl_src1, kFPReg); 208 rl_src2 = LoadValue(rl_src2, kFPReg); 209 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 210 } 211 NewLIR0(kThumb2Fmstat); 212 ConditionCode ccode = mir->meta.ccode; 213 switch (ccode) { 214 case kCondEq: 215 case kCondNe: 216 break; 217 case kCondLt: 218 if (gt_bias) { 219 ccode = kCondMi; 220 } 221 break; 222 case kCondLe: 223 if (gt_bias) { 224 ccode = kCondLs; 225 } 226 break; 227 case kCondGt: 228 if (gt_bias) { 229 ccode = kCondHi; 230 } 231 break; 232 case kCondGe: 233 if (gt_bias) { 234 ccode = kCondUge; 235 } 236 break; 237 default: 238 LOG(FATAL) << "Unexpected ccode: " << ccode; 239 } 240 OpCondBranch(ccode, target); 241} 242 243 244void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, 245 RegLocation rl_src1, RegLocation rl_src2) { 246 bool is_double = false; 247 int default_result = -1; 248 RegLocation rl_result; 249 250 switch (opcode) { 251 case Instruction::CMPL_FLOAT: 252 is_double = false; 253 default_result = -1; 254 break; 255 case Instruction::CMPG_FLOAT: 256 is_double = false; 257 default_result = 1; 258 break; 259 case Instruction::CMPL_DOUBLE: 260 is_double = true; 261 default_result = -1; 262 break; 263 case Instruction::CMPG_DOUBLE: 264 is_double = true; 265 default_result = 1; 266 break; 267 default: 268 LOG(FATAL) << "Unexpected opcode: " << opcode; 269 } 270 if (is_double) { 271 rl_src1 = LoadValueWide(rl_src1, kFPReg); 272 rl_src2 = LoadValueWide(rl_src2, kFPReg); 273 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc() 274 ClobberSReg(rl_dest.s_reg_low); 275 rl_result = EvalLoc(rl_dest, kCoreReg, true); 276 LoadConstant(rl_result.reg.GetReg(), default_result); 277 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetReg(), rl_src2.reg.GetHighReg()), 278 S2d(rl_src2.reg.GetReg(), rl_src2.reg.GetHighReg())); 279 } else { 280 rl_src1 = LoadValue(rl_src1, kFPReg); 281 rl_src2 = LoadValue(rl_src2, kFPReg); 282 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc() 283 ClobberSReg(rl_dest.s_reg_low); 284 rl_result = EvalLoc(rl_dest, kCoreReg, true); 285 LoadConstant(rl_result.reg.GetReg(), default_result); 286 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 287 } 288 DCHECK(!ARM_FPREG(rl_result.reg.GetReg())); 289 NewLIR0(kThumb2Fmstat); 290 291 OpIT((default_result == -1) ? kCondGt : kCondMi, ""); 292 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(), 293 ModifiedImmediate(-default_result)); // Must not alter ccodes 294 GenBarrier(); 295 296 OpIT(kCondEq, ""); 297 LoadConstant(rl_result.reg.GetReg(), 0); 298 GenBarrier(); 299 300 StoreValue(rl_dest, rl_result); 301} 302 303void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) { 304 RegLocation rl_result; 305 rl_src = LoadValue(rl_src, kFPReg); 306 rl_result = EvalLoc(rl_dest, kFPReg, true); 307 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 308 StoreValue(rl_dest, rl_result); 309} 310 311void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { 312 RegLocation rl_result; 313 rl_src = LoadValueWide(rl_src, kFPReg); 314 rl_result = EvalLoc(rl_dest, kFPReg, true); 315 NewLIR2(kThumb2Vnegd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), 316 S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg())); 317 StoreValueWide(rl_dest, rl_result); 318} 319 320bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) { 321 DCHECK_EQ(cu_->instruction_set, kThumb2); 322 LIR *branch; 323 RegLocation rl_src = info->args[0]; 324 RegLocation rl_dest = InlineTargetWide(info); // double place for result 325 rl_src = LoadValueWide(rl_src, kFPReg); 326 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 327 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), 328 S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg())); 329 NewLIR2(kThumb2Vcmpd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), 330 S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg())); 331 NewLIR0(kThumb2Fmstat); 332 branch = NewLIR2(kThumbBCond, 0, kArmCondEq); 333 ClobberCallerSave(); 334 LockCallTemps(); // Using fixed registers 335 int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt)); 336 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg())); 337 NewLIR1(kThumbBlxR, r_tgt); 338 NewLIR3(kThumb2Fmdrr, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), r0, r1); 339 branch->target = NewLIR0(kPseudoTargetLabel); 340 StoreValueWide(rl_dest, rl_result); 341 return true; 342} 343 344 345} // namespace art 346