fp_arm.cc revision 31c2aac7137b69d5622eea09597500731fbee2ef
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.low_reg, rl_src1.low_reg, rl_src2.low_reg); 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.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 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 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 177void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, 178 bool is_double) { 179 LIR* target = &block_label_list_[bb->taken]; 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 229void 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(kThumb2MovI8M, 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 288void 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 296void 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 305bool 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 ClobberCallerSave(); 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