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