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 22 /* 23 * Take the address of a Dalvik register and store it into rDest. 24 * Clobber any live values associated either with the Dalvik value 25 * or the target register and lock the target fixed register. 26 */ 27 static void loadValueAddressDirect(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 dvmCompilerFlushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg); 35 } else { 36 dvmCompilerFlushReg(cUnit, rlSrc.lowReg); 37 } 38 } 39 dvmCompilerClobber(cUnit, rDest); 40 dvmCompilerLockTemp(cUnit, rDest); 41 opRegRegImm(cUnit, kOpAdd, rDest, r5FP, 42 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2); 43 } 44 45 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) 46 { 47 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 48 RegLocation rlResult = LOC_C_RETURN_WIDE; 49 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; 50 loadValueAddressDirect(cUnit, rlSrc, r2); 51 genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP); 52 storeValueWide(cUnit, rlDest, rlResult); 53 return false; 54 } 55 56 /* 57 * TUNING: On some implementations, it is quicker to pass addresses 58 * to the handlers rather than load the operands into core registers 59 * and then move the values to FP regs in the handlers. Other implementations 60 * may prefer passing data in registers (and the latter approach would 61 * yield cleaner register handling - avoiding the requirement that operands 62 * be flushed to memory prior to the call). 63 */ 64 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, 65 RegLocation rlDest, RegLocation rlSrc1, 66 RegLocation rlSrc2) 67 { 68 TemplateOpcode opcode; 69 70 /* 71 * Don't attempt to optimize register usage since these opcodes call out to 72 * the handlers. 73 */ 74 switch (mir->dalvikInsn.opcode) { 75 case OP_ADD_FLOAT_2ADDR: 76 case OP_ADD_FLOAT: 77 opcode = TEMPLATE_ADD_FLOAT_VFP; 78 break; 79 case OP_SUB_FLOAT_2ADDR: 80 case OP_SUB_FLOAT: 81 opcode = TEMPLATE_SUB_FLOAT_VFP; 82 break; 83 case OP_DIV_FLOAT_2ADDR: 84 case OP_DIV_FLOAT: 85 opcode = TEMPLATE_DIV_FLOAT_VFP; 86 break; 87 case OP_MUL_FLOAT_2ADDR: 88 case OP_MUL_FLOAT: 89 opcode = TEMPLATE_MUL_FLOAT_VFP; 90 break; 91 case OP_REM_FLOAT_2ADDR: 92 case OP_REM_FLOAT: 93 case OP_NEG_FLOAT: { 94 return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2); 95 } 96 default: 97 return true; 98 } 99 loadValueAddressDirect(cUnit, rlDest, r0); 100 loadValueAddressDirect(cUnit, rlSrc1, r1); 101 loadValueAddressDirect(cUnit, rlSrc2, r2); 102 genDispatchToHandler(cUnit, opcode); 103 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); 104 if (rlDest.location == kLocPhysReg) { 105 dvmCompilerClobber(cUnit, rlDest.lowReg); 106 } 107 return false; 108 } 109 110 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, 111 RegLocation rlDest, RegLocation rlSrc1, 112 RegLocation rlSrc2) 113 { 114 TemplateOpcode opcode; 115 116 switch (mir->dalvikInsn.opcode) { 117 case OP_ADD_DOUBLE_2ADDR: 118 case OP_ADD_DOUBLE: 119 opcode = TEMPLATE_ADD_DOUBLE_VFP; 120 break; 121 case OP_SUB_DOUBLE_2ADDR: 122 case OP_SUB_DOUBLE: 123 opcode = TEMPLATE_SUB_DOUBLE_VFP; 124 break; 125 case OP_DIV_DOUBLE_2ADDR: 126 case OP_DIV_DOUBLE: 127 opcode = TEMPLATE_DIV_DOUBLE_VFP; 128 break; 129 case OP_MUL_DOUBLE_2ADDR: 130 case OP_MUL_DOUBLE: 131 opcode = TEMPLATE_MUL_DOUBLE_VFP; 132 break; 133 case OP_REM_DOUBLE_2ADDR: 134 case OP_REM_DOUBLE: 135 case OP_NEG_DOUBLE: { 136 return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, 137 rlSrc2); 138 } 139 default: 140 return true; 141 } 142 loadValueAddressDirect(cUnit, rlDest, r0); 143 loadValueAddressDirect(cUnit, rlSrc1, r1); 144 loadValueAddressDirect(cUnit, rlSrc2, r2); 145 genDispatchToHandler(cUnit, opcode); 146 rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest); 147 if (rlDest.location == kLocPhysReg) { 148 dvmCompilerClobber(cUnit, rlDest.lowReg); 149 dvmCompilerClobber(cUnit, rlDest.highReg); 150 } 151 return false; 152 } 153 154 static bool genConversion(CompilationUnit *cUnit, MIR *mir) 155 { 156 Opcode opcode = mir->dalvikInsn.opcode; 157 bool longSrc = false; 158 bool longDest = false; 159 RegLocation rlSrc; 160 RegLocation rlDest; 161 TemplateOpcode templateOpcode; 162 switch (opcode) { 163 case OP_INT_TO_FLOAT: 164 longSrc = false; 165 longDest = false; 166 templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP; 167 break; 168 case OP_FLOAT_TO_INT: 169 longSrc = false; 170 longDest = false; 171 templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP; 172 break; 173 case OP_DOUBLE_TO_FLOAT: 174 longSrc = true; 175 longDest = false; 176 templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP; 177 break; 178 case OP_FLOAT_TO_DOUBLE: 179 longSrc = false; 180 longDest = true; 181 templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP; 182 break; 183 case OP_INT_TO_DOUBLE: 184 longSrc = false; 185 longDest = true; 186 templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP; 187 break; 188 case OP_DOUBLE_TO_INT: 189 longSrc = true; 190 longDest = false; 191 templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP; 192 break; 193 case OP_LONG_TO_DOUBLE: 194 case OP_FLOAT_TO_LONG: 195 case OP_LONG_TO_FLOAT: 196 case OP_DOUBLE_TO_LONG: 197 return genConversionPortable(cUnit, mir); 198 default: 199 return true; 200 } 201 202 if (longSrc) { 203 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 204 } else { 205 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 206 } 207 208 if (longDest) { 209 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 210 } else { 211 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 212 } 213 loadValueAddressDirect(cUnit, rlDest, r0); 214 loadValueAddressDirect(cUnit, rlSrc, r1); 215 genDispatchToHandler(cUnit, templateOpcode); 216 if (rlDest.wide) { 217 rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest); 218 dvmCompilerClobber(cUnit, rlDest.highReg); 219 } else { 220 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); 221 } 222 dvmCompilerClobber(cUnit, rlDest.lowReg); 223 return false; 224 } 225 226 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, 227 RegLocation rlSrc1, RegLocation rlSrc2) 228 { 229 TemplateOpcode templateOpcode; 230 RegLocation rlResult = dvmCompilerGetReturn(cUnit); 231 bool wide = true; 232 233 switch(mir->dalvikInsn.opcode) { 234 case OP_CMPL_FLOAT: 235 templateOpcode = TEMPLATE_CMPL_FLOAT_VFP; 236 wide = false; 237 break; 238 case OP_CMPG_FLOAT: 239 templateOpcode = TEMPLATE_CMPG_FLOAT_VFP; 240 wide = false; 241 break; 242 case OP_CMPL_DOUBLE: 243 templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP; 244 break; 245 case OP_CMPG_DOUBLE: 246 templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP; 247 break; 248 default: 249 return true; 250 } 251 loadValueAddressDirect(cUnit, rlSrc1, r0); 252 loadValueAddressDirect(cUnit, rlSrc2, r1); 253 genDispatchToHandler(cUnit, templateOpcode); 254 storeValue(cUnit, rlDest, rlResult); 255 return false; 256 } 257