1/* 2 * Copyright (C) 2009 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/* 18 * This file is included by Codegen-armv5te-vfp.c, and implements architecture 19 * variant-specific code. 20 */ 21 22extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit, 23 int reg1, int reg2); 24extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg); 25 26/* First, flush any registers associated with this value */ 27static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc, 28 int rDest) 29{ 30 rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) : 31 dvmCompilerUpdateLoc(cUnit, rlSrc); 32 if (rlSrc.location == kLocPhysReg) { 33 if (rlSrc.wide) { 34 dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg, 35 rlSrc.highReg); 36 } else { 37 dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg); 38 } 39 } 40 opRegRegImm(cUnit, kOpAdd, rDest, rFP, 41 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2); 42} 43 44static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) 45{ 46 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 47#ifdef __mips_hard_float 48 RegLocation rlResult = LOC_C_RETURN_WIDE_ALT; 49#else 50 RegLocation rlResult = LOC_C_RETURN_WIDE; 51#endif 52 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; 53 loadValueAddress(cUnit, rlSrc, r_A2); 54 genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP); 55 storeValueWide(cUnit, rlDest, rlResult); 56 return false; 57} 58 59/* 60 * TUNING: On some implementations, it is quicker to pass addresses 61 * to the handlers rather than load the operands into core registers 62 * and then move the values to FP regs in the handlers. Other implementations 63 * may prefer passing data in registers (and the latter approach would 64 * yeild cleaner register handling - avoiding the requirement that operands 65 * be flushed to memory prior to the call). 66 */ 67static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, 68 RegLocation rlDest, RegLocation rlSrc1, 69 RegLocation rlSrc2) 70{ 71#ifdef __mips_hard_float 72 int op = kMipsNop; 73 RegLocation rlResult; 74 75 /* 76 * Don't attempt to optimize register usage since these opcodes call out to 77 * the handlers. 78 */ 79 switch (mir->dalvikInsn.opcode) { 80 case OP_ADD_FLOAT_2ADDR: 81 case OP_ADD_FLOAT: 82 op = kMipsFadds; 83 break; 84 case OP_SUB_FLOAT_2ADDR: 85 case OP_SUB_FLOAT: 86 op = kMipsFsubs; 87 break; 88 case OP_DIV_FLOAT_2ADDR: 89 case OP_DIV_FLOAT: 90 op = kMipsFdivs; 91 break; 92 case OP_MUL_FLOAT_2ADDR: 93 case OP_MUL_FLOAT: 94 op = kMipsFmuls; 95 break; 96 case OP_REM_FLOAT_2ADDR: 97 case OP_REM_FLOAT: 98 case OP_NEG_FLOAT: { 99 return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); 100 } 101 default: 102 return true; 103 } 104 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); 105 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); 106 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 107 newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); 108 storeValue(cUnit, rlDest, rlResult); 109 110 return false; 111#else 112 TemplateOpcode opcode; 113 114 /* 115 * Don't attempt to optimize register usage since these opcodes call out to 116 * the handlers. 117 */ 118 switch (mir->dalvikInsn.opcode) { 119 case OP_ADD_FLOAT_2ADDR: 120 case OP_ADD_FLOAT: 121 opcode = TEMPLATE_ADD_FLOAT_VFP; 122 break; 123 case OP_SUB_FLOAT_2ADDR: 124 case OP_SUB_FLOAT: 125 opcode = TEMPLATE_SUB_FLOAT_VFP; 126 break; 127 case OP_DIV_FLOAT_2ADDR: 128 case OP_DIV_FLOAT: 129 opcode = TEMPLATE_DIV_FLOAT_VFP; 130 break; 131 case OP_MUL_FLOAT_2ADDR: 132 case OP_MUL_FLOAT: 133 opcode = TEMPLATE_MUL_FLOAT_VFP; 134 break; 135 case OP_REM_FLOAT_2ADDR: 136 case OP_REM_FLOAT: 137 case OP_NEG_FLOAT: { 138 return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); 139 } 140 default: 141 return true; 142 } 143 loadValueAddress(cUnit, rlDest, r_A0); 144 dvmCompilerClobber(cUnit, r_A0); 145 loadValueAddress(cUnit, rlSrc1, r_A1); 146 dvmCompilerClobber(cUnit, r_A1); 147 loadValueAddress(cUnit, rlSrc2, r_A2); 148 genDispatchToHandler(cUnit, opcode); 149 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); 150 if (rlDest.location == kLocPhysReg) { 151 dvmCompilerClobber(cUnit, rlDest.lowReg); 152 } 153 return false; 154#endif 155} 156 157static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, 158 RegLocation rlDest, RegLocation rlSrc1, 159 RegLocation rlSrc2) 160{ 161#ifdef __mips_hard_float 162 int op = kMipsNop; 163 RegLocation rlResult; 164 165 switch (mir->dalvikInsn.opcode) { 166 case OP_ADD_DOUBLE_2ADDR: 167 case OP_ADD_DOUBLE: 168 op = kMipsFaddd; 169 break; 170 case OP_SUB_DOUBLE_2ADDR: 171 case OP_SUB_DOUBLE: 172 op = kMipsFsubd; 173 break; 174 case OP_DIV_DOUBLE_2ADDR: 175 case OP_DIV_DOUBLE: 176 op = kMipsFdivd; 177 break; 178 case OP_MUL_DOUBLE_2ADDR: 179 case OP_MUL_DOUBLE: 180 op = kMipsFmuld; 181 break; 182 case OP_REM_DOUBLE_2ADDR: 183 case OP_REM_DOUBLE: 184 case OP_NEG_DOUBLE: { 185 return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); 186 } 187 default: 188 return true; 189 } 190 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); 191 assert(rlSrc1.wide); 192 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); 193 assert(rlSrc2.wide); 194 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 195 assert(rlDest.wide); 196 assert(rlResult.wide); 197 newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), 198 S2D(rlSrc1.lowReg, rlSrc1.highReg), 199 S2D(rlSrc2.lowReg, rlSrc2.highReg)); 200 storeValueWide(cUnit, rlDest, rlResult); 201 return false; 202#else 203 TemplateOpcode opcode; 204 205 switch (mir->dalvikInsn.opcode) { 206 case OP_ADD_DOUBLE_2ADDR: 207 case OP_ADD_DOUBLE: 208 opcode = TEMPLATE_ADD_DOUBLE_VFP; 209 break; 210 case OP_SUB_DOUBLE_2ADDR: 211 case OP_SUB_DOUBLE: 212 opcode = TEMPLATE_SUB_DOUBLE_VFP; 213 break; 214 case OP_DIV_DOUBLE_2ADDR: 215 case OP_DIV_DOUBLE: 216 opcode = TEMPLATE_DIV_DOUBLE_VFP; 217 break; 218 case OP_MUL_DOUBLE_2ADDR: 219 case OP_MUL_DOUBLE: 220 opcode = TEMPLATE_MUL_DOUBLE_VFP; 221 break; 222 case OP_REM_DOUBLE_2ADDR: 223 case OP_REM_DOUBLE: 224 case OP_NEG_DOUBLE: { 225 return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, 226 rlSrc2); 227 } 228 default: 229 return true; 230 } 231 loadValueAddress(cUnit, rlDest, r_A0); 232 dvmCompilerClobber(cUnit, r_A0); 233 loadValueAddress(cUnit, rlSrc1, r_A1); 234 dvmCompilerClobber(cUnit, r_A1); 235 loadValueAddress(cUnit, rlSrc2, r_A2); 236 genDispatchToHandler(cUnit, opcode); 237 rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest); 238 if (rlDest.location == kLocPhysReg) { 239 dvmCompilerClobber(cUnit, rlDest.lowReg); 240 dvmCompilerClobber(cUnit, rlDest.highReg); 241 } 242 return false; 243#endif 244} 245 246static bool genConversion(CompilationUnit *cUnit, MIR *mir) 247{ 248 Opcode opcode = mir->dalvikInsn.opcode; 249 bool longSrc = false; 250 bool longDest = false; 251 RegLocation rlSrc; 252 RegLocation rlDest; 253#ifdef __mips_hard_float 254 int op = kMipsNop; 255 int srcReg; 256 RegLocation rlResult; 257 258 switch (opcode) { 259 case OP_INT_TO_FLOAT: 260 longSrc = false; 261 longDest = false; 262 op = kMipsFcvtsw; 263 break; 264 case OP_DOUBLE_TO_FLOAT: 265 longSrc = true; 266 longDest = false; 267 op = kMipsFcvtsd; 268 break; 269 case OP_FLOAT_TO_DOUBLE: 270 longSrc = false; 271 longDest = true; 272 op = kMipsFcvtds; 273 break; 274 case OP_INT_TO_DOUBLE: 275 longSrc = false; 276 longDest = true; 277 op = kMipsFcvtdw; 278 break; 279 case OP_FLOAT_TO_INT: 280 case OP_DOUBLE_TO_INT: 281 case OP_LONG_TO_DOUBLE: 282 case OP_FLOAT_TO_LONG: 283 case OP_LONG_TO_FLOAT: 284 case OP_DOUBLE_TO_LONG: 285 return genConversionPortable(cUnit, mir); 286 default: 287 return true; 288 } 289 if (longSrc) { 290 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 291 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); 292 srcReg = S2D(rlSrc.lowReg, rlSrc.highReg); 293 } else { 294 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 295 rlSrc = loadValue(cUnit, rlSrc, kFPReg); 296 srcReg = rlSrc.lowReg; 297 } 298 if (longDest) { 299 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 300 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 301 newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg); 302 storeValueWide(cUnit, rlDest, rlResult); 303 } else { 304 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 305 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 306 newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg); 307 storeValue(cUnit, rlDest, rlResult); 308 } 309 return false; 310#else 311 TemplateOpcode templateOpcode; 312 switch (opcode) { 313 case OP_INT_TO_FLOAT: 314 longSrc = false; 315 longDest = false; 316 templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP; 317 break; 318 case OP_FLOAT_TO_INT: 319 longSrc = false; 320 longDest = false; 321 templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP; 322 break; 323 case OP_DOUBLE_TO_FLOAT: 324 longSrc = true; 325 longDest = false; 326 templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP; 327 break; 328 case OP_FLOAT_TO_DOUBLE: 329 longSrc = false; 330 longDest = true; 331 templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP; 332 break; 333 case OP_INT_TO_DOUBLE: 334 longSrc = false; 335 longDest = true; 336 templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP; 337 break; 338 case OP_DOUBLE_TO_INT: 339 longSrc = true; 340 longDest = false; 341 templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP; 342 break; 343 case OP_LONG_TO_DOUBLE: 344 case OP_FLOAT_TO_LONG: 345 case OP_LONG_TO_FLOAT: 346 case OP_DOUBLE_TO_LONG: 347 return genConversionPortable(cUnit, mir); 348 default: 349 return true; 350 } 351 352 if (longSrc) { 353 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 354 } else { 355 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 356 } 357 358 if (longDest) { 359 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 360 } else { 361 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 362 } 363 loadValueAddress(cUnit, rlDest, r_A0); 364 dvmCompilerClobber(cUnit, r_A0); 365 loadValueAddress(cUnit, rlSrc, r_A1); 366 genDispatchToHandler(cUnit, templateOpcode); 367 if (rlDest.wide) { 368 rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest); 369 dvmCompilerClobber(cUnit, rlDest.highReg); 370 } else { 371 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); 372 } 373 dvmCompilerClobber(cUnit, rlDest.lowReg); 374 return false; 375#endif 376} 377 378static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, 379 RegLocation rlSrc1, RegLocation rlSrc2) 380{ 381 TemplateOpcode templateOpcode; 382 RegLocation rlResult = dvmCompilerGetReturn(cUnit); 383 bool wide = true; 384 385 switch(mir->dalvikInsn.opcode) { 386 case OP_CMPL_FLOAT: 387 templateOpcode = TEMPLATE_CMPL_FLOAT_VFP; 388 wide = false; 389 break; 390 case OP_CMPG_FLOAT: 391 templateOpcode = TEMPLATE_CMPG_FLOAT_VFP; 392 wide = false; 393 break; 394 case OP_CMPL_DOUBLE: 395 templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP; 396 break; 397 case OP_CMPG_DOUBLE: 398 templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP; 399 break; 400 default: 401 return true; 402 } 403 loadValueAddress(cUnit, rlSrc1, r_A0); 404 dvmCompilerClobber(cUnit, r_A0); 405 loadValueAddress(cUnit, rlSrc2, r_A1); 406 genDispatchToHandler(cUnit, templateOpcode); 407 storeValue(cUnit, rlDest, rlResult); 408 return false; 409} 410