fp_arm.cc revision 7934ac288acfb2552bb0b06ec1f61e5820d924a4
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(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false); 53 rl_result = GetReturn(true); 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.low_reg, rl_src1.low_reg, rl_src2.low_reg); 66 StoreValue(rl_dest, rl_result); 67} 68 69void 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(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false); 95 rl_result = GetReturnWide(true); 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, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg), 113 S2d(rl_src2.low_reg, rl_src2.high_reg)); 114 StoreValueWide(rl_dest, rl_result); 115} 116 117void ArmMir2Lir::GenConversion(Instruction::Code opcode, 118 RegLocation rl_dest, RegLocation rl_src) { 119 int op = kThumbBkpt; 120 int src_reg; 121 RegLocation rl_result; 122 123 switch (opcode) { 124 case Instruction::INT_TO_FLOAT: 125 op = kThumb2VcvtIF; 126 break; 127 case Instruction::FLOAT_TO_INT: 128 op = kThumb2VcvtFI; 129 break; 130 case Instruction::DOUBLE_TO_FLOAT: 131 op = kThumb2VcvtDF; 132 break; 133 case Instruction::FLOAT_TO_DOUBLE: 134 op = kThumb2VcvtFd; 135 break; 136 case Instruction::INT_TO_DOUBLE: 137 op = kThumb2VcvtID; 138 break; 139 case Instruction::DOUBLE_TO_INT: 140 op = kThumb2VcvtDI; 141 break; 142 case Instruction::LONG_TO_DOUBLE: 143 GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src); 144 return; 145 case Instruction::FLOAT_TO_LONG: 146 GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src); 147 return; 148 case Instruction::LONG_TO_FLOAT: 149 GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src); 150 return; 151 case Instruction::DOUBLE_TO_LONG: 152 GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src); 153 return; 154 default: 155 LOG(FATAL) << "Unexpected opcode: " << opcode; 156 } 157 if (rl_src.wide) { 158 rl_src = LoadValueWide(rl_src, kFPReg); 159 src_reg = S2d(rl_src.low_reg, rl_src.high_reg); 160 } else { 161 rl_src = LoadValue(rl_src, kFPReg); 162 src_reg = rl_src.low_reg; 163 } 164 if (rl_dest.wide) { 165 rl_result = EvalLoc(rl_dest, kFPReg, true); 166 NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg); 167 StoreValueWide(rl_dest, rl_result); 168 } else { 169 rl_result = EvalLoc(rl_dest, kFPReg, true); 170 NewLIR2(op, rl_result.low_reg, src_reg); 171 StoreValue(rl_dest, rl_result); 172 } 173} 174 175void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, 176 bool is_double) { 177 LIR* target = &block_label_list_[bb->taken->id]; 178 RegLocation rl_src1; 179 RegLocation rl_src2; 180 if (is_double) { 181 rl_src1 = mir_graph_->GetSrcWide(mir, 0); 182 rl_src2 = mir_graph_->GetSrcWide(mir, 2); 183 rl_src1 = LoadValueWide(rl_src1, kFPReg); 184 rl_src2 = LoadValueWide(rl_src2, kFPReg); 185 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg), 186 S2d(rl_src2.low_reg, rl_src2.high_reg)); 187 } else { 188 rl_src1 = mir_graph_->GetSrc(mir, 0); 189 rl_src2 = mir_graph_->GetSrc(mir, 1); 190 rl_src1 = LoadValue(rl_src1, kFPReg); 191 rl_src2 = LoadValue(rl_src2, kFPReg); 192 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg); 193 } 194 NewLIR0(kThumb2Fmstat); 195 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]); 196 switch (ccode) { 197 case kCondEq: 198 case kCondNe: 199 break; 200 case kCondLt: 201 if (gt_bias) { 202 ccode = kCondMi; 203 } 204 break; 205 case kCondLe: 206 if (gt_bias) { 207 ccode = kCondLs; 208 } 209 break; 210 case kCondGt: 211 if (gt_bias) { 212 ccode = kCondHi; 213 } 214 break; 215 case kCondGe: 216 if (gt_bias) { 217 ccode = kCondCs; 218 } 219 break; 220 default: 221 LOG(FATAL) << "Unexpected ccode: " << ccode; 222 } 223 OpCondBranch(ccode, target); 224} 225 226 227void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, 228 RegLocation rl_src1, RegLocation rl_src2) { 229 bool is_double = false; 230 int default_result = -1; 231 RegLocation rl_result; 232 233 switch (opcode) { 234 case Instruction::CMPL_FLOAT: 235 is_double = false; 236 default_result = -1; 237 break; 238 case Instruction::CMPG_FLOAT: 239 is_double = false; 240 default_result = 1; 241 break; 242 case Instruction::CMPL_DOUBLE: 243 is_double = true; 244 default_result = -1; 245 break; 246 case Instruction::CMPG_DOUBLE: 247 is_double = true; 248 default_result = 1; 249 break; 250 default: 251 LOG(FATAL) << "Unexpected opcode: " << opcode; 252 } 253 if (is_double) { 254 rl_src1 = LoadValueWide(rl_src1, kFPReg); 255 rl_src2 = LoadValueWide(rl_src2, kFPReg); 256 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc() 257 ClobberSReg(rl_dest.s_reg_low); 258 rl_result = EvalLoc(rl_dest, kCoreReg, true); 259 LoadConstant(rl_result.low_reg, default_result); 260 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg), 261 S2d(rl_src2.low_reg, rl_src2.high_reg)); 262 } else { 263 rl_src1 = LoadValue(rl_src1, kFPReg); 264 rl_src2 = LoadValue(rl_src2, kFPReg); 265 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc() 266 ClobberSReg(rl_dest.s_reg_low); 267 rl_result = EvalLoc(rl_dest, kCoreReg, true); 268 LoadConstant(rl_result.low_reg, default_result); 269 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg); 270 } 271 DCHECK(!ARM_FPREG(rl_result.low_reg)); 272 NewLIR0(kThumb2Fmstat); 273 274 OpIT((default_result == -1) ? kCondGt : kCondMi, ""); 275 NewLIR2(kThumb2MovImmShift, rl_result.low_reg, 276 ModifiedImmediate(-default_result)); // Must not alter ccodes 277 GenBarrier(); 278 279 OpIT(kCondEq, ""); 280 LoadConstant(rl_result.low_reg, 0); 281 GenBarrier(); 282 283 StoreValue(rl_dest, rl_result); 284} 285 286void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) { 287 RegLocation rl_result; 288 rl_src = LoadValue(rl_src, kFPReg); 289 rl_result = EvalLoc(rl_dest, kFPReg, true); 290 NewLIR2(kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg); 291 StoreValue(rl_dest, rl_result); 292} 293 294void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { 295 RegLocation rl_result; 296 rl_src = LoadValueWide(rl_src, kFPReg); 297 rl_result = EvalLoc(rl_dest, kFPReg, true); 298 NewLIR2(kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg), 299 S2d(rl_src.low_reg, rl_src.high_reg)); 300 StoreValueWide(rl_dest, rl_result); 301} 302 303bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) { 304 DCHECK_EQ(cu_->instruction_set, kThumb2); 305 LIR *branch; 306 RegLocation rl_src = info->args[0]; 307 RegLocation rl_dest = InlineTargetWide(info); // double place for result 308 rl_src = LoadValueWide(rl_src, kFPReg); 309 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 310 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg), 311 S2d(rl_src.low_reg, rl_src.high_reg)); 312 NewLIR2(kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg), 313 S2d(rl_result.low_reg, rl_result.high_reg)); 314 NewLIR0(kThumb2Fmstat); 315 branch = NewLIR2(kThumbBCond, 0, kArmCondEq); 316 ClobberCalleeSave(); 317 LockCallTemps(); // Using fixed registers 318 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pSqrt)); 319 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg)); 320 NewLIR1(kThumbBlxR, r_tgt); 321 NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1); 322 branch->target = NewLIR0(kPseudoTargetLabel); 323 StoreValueWide(rl_dest, rl_result); 324 return true; 325} 326 327 328} // namespace art 329