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 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, 18 RegLocation rlDest, RegLocation rlSrc1, 19 RegLocation rlSrc2) 20 { 21 int op = kThumbBkpt; 22 RegLocation rlResult; 23 24 /* 25 * Don't attempt to optimize register usage since these opcodes call out to 26 * the handlers. 27 */ 28 switch (mir->dalvikInsn.opcode) { 29 case OP_ADD_FLOAT_2ADDR: 30 case OP_ADD_FLOAT: 31 op = kThumb2Vadds; 32 break; 33 case OP_SUB_FLOAT_2ADDR: 34 case OP_SUB_FLOAT: 35 op = kThumb2Vsubs; 36 break; 37 case OP_DIV_FLOAT_2ADDR: 38 case OP_DIV_FLOAT: 39 op = kThumb2Vdivs; 40 break; 41 case OP_MUL_FLOAT_2ADDR: 42 case OP_MUL_FLOAT: 43 op = kThumb2Vmuls; 44 break; 45 case OP_REM_FLOAT_2ADDR: 46 case OP_REM_FLOAT: 47 case OP_NEG_FLOAT: { 48 return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, 49 rlSrc2); 50 } 51 default: 52 return true; 53 } 54 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); 55 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); 56 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 57 newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg, 58 rlSrc2.lowReg); 59 storeValue(cUnit, rlDest, rlResult); 60 return false; 61 } 62 63 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, 64 RegLocation rlDest, RegLocation rlSrc1, 65 RegLocation rlSrc2) 66 { 67 int op = kThumbBkpt; 68 RegLocation rlResult; 69 70 switch (mir->dalvikInsn.opcode) { 71 case OP_ADD_DOUBLE_2ADDR: 72 case OP_ADD_DOUBLE: 73 op = kThumb2Vaddd; 74 break; 75 case OP_SUB_DOUBLE_2ADDR: 76 case OP_SUB_DOUBLE: 77 op = kThumb2Vsubd; 78 break; 79 case OP_DIV_DOUBLE_2ADDR: 80 case OP_DIV_DOUBLE: 81 op = kThumb2Vdivd; 82 break; 83 case OP_MUL_DOUBLE_2ADDR: 84 case OP_MUL_DOUBLE: 85 op = kThumb2Vmuld; 86 break; 87 case OP_REM_DOUBLE_2ADDR: 88 case OP_REM_DOUBLE: 89 case OP_NEG_DOUBLE: { 90 return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, 91 rlSrc2); 92 } 93 default: 94 return true; 95 } 96 97 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); 98 assert(rlSrc1.wide); 99 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); 100 assert(rlSrc2.wide); 101 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 102 assert(rlDest.wide); 103 assert(rlResult.wide); 104 newLIR3(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg), 105 S2D(rlSrc1.lowReg, rlSrc1.highReg), 106 S2D(rlSrc2.lowReg, rlSrc2.highReg)); 107 storeValueWide(cUnit, rlDest, rlResult); 108 return false; 109 } 110 111 static bool genConversion(CompilationUnit *cUnit, MIR *mir) 112 { 113 Opcode opcode = mir->dalvikInsn.opcode; 114 int op = kThumbBkpt; 115 bool longSrc = false; 116 bool longDest = false; 117 int srcReg; 118 RegLocation rlSrc; 119 RegLocation rlDest; 120 RegLocation rlResult; 121 122 switch (opcode) { 123 case OP_INT_TO_FLOAT: 124 longSrc = false; 125 longDest = false; 126 op = kThumb2VcvtIF; 127 break; 128 case OP_FLOAT_TO_INT: 129 longSrc = false; 130 longDest = false; 131 op = kThumb2VcvtFI; 132 break; 133 case OP_DOUBLE_TO_FLOAT: 134 longSrc = true; 135 longDest = false; 136 op = kThumb2VcvtDF; 137 break; 138 case OP_FLOAT_TO_DOUBLE: 139 longSrc = false; 140 longDest = true; 141 op = kThumb2VcvtFd; 142 break; 143 case OP_INT_TO_DOUBLE: 144 longSrc = false; 145 longDest = true; 146 op = kThumb2VcvtID; 147 break; 148 case OP_DOUBLE_TO_INT: 149 longSrc = true; 150 longDest = false; 151 op = kThumb2VcvtDI; 152 break; 153 case OP_LONG_TO_DOUBLE: 154 case OP_FLOAT_TO_LONG: 155 case OP_LONG_TO_FLOAT: 156 case OP_DOUBLE_TO_LONG: 157 return genConversionPortable(cUnit, mir); 158 default: 159 return true; 160 } 161 if (longSrc) { 162 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 163 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); 164 srcReg = S2D(rlSrc.lowReg, rlSrc.highReg); 165 } else { 166 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 167 rlSrc = loadValue(cUnit, rlSrc, kFPReg); 168 srcReg = rlSrc.lowReg; 169 } 170 if (longDest) { 171 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 172 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 173 newLIR2(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg), 174 srcReg); 175 storeValueWide(cUnit, rlDest, rlResult); 176 } else { 177 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 178 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 179 newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg); 180 storeValue(cUnit, rlDest, rlResult); 181 } 182 return false; 183 } 184 185 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) 186 { 187 ArmLIR *branch; 188 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 189 RegLocation rlDest = inlinedTargetWide(cUnit, mir, true); 190 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); 191 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true); 192 newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg), 193 S2D(rlSrc.lowReg, rlSrc.highReg)); 194 newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg), 195 S2D(rlResult.lowReg, rlResult.highReg)); 196 newLIR0(cUnit, kThumb2Fmstat); 197 branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq); 198 dvmCompilerClobberCallRegs(cUnit); 199 LOAD_FUNC_ADDR(cUnit, r2, (int) (double (*)(double)) sqrt); 200 newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg)); 201 newLIR1(cUnit, kThumbBlxR, r2); 202 newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg), 203 r0, r1); 204 ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel); 205 label->defMask = ENCODE_ALL; 206 branch->generic.target = (LIR *)label; 207 storeValueWide(cUnit, rlDest, rlResult); 208 return false; 209 } 210 211 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, 212 RegLocation rlSrc1, RegLocation rlSrc2) 213 { 214 bool isDouble; 215 int defaultResult; 216 RegLocation rlResult; 217 218 switch(mir->dalvikInsn.opcode) { 219 case OP_CMPL_FLOAT: 220 isDouble = false; 221 defaultResult = -1; 222 break; 223 case OP_CMPG_FLOAT: 224 isDouble = false; 225 defaultResult = 1; 226 break; 227 case OP_CMPL_DOUBLE: 228 isDouble = true; 229 defaultResult = -1; 230 break; 231 case OP_CMPG_DOUBLE: 232 isDouble = true; 233 defaultResult = 1; 234 break; 235 default: 236 return true; 237 } 238 if (isDouble) { 239 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); 240 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); 241 dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); 242 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 243 loadConstant(cUnit, rlResult.lowReg, defaultResult); 244 newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg), 245 S2D(rlSrc2.lowReg, rlSrc2.highReg)); 246 } else { 247 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); 248 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); 249 dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); 250 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 251 loadConstant(cUnit, rlResult.lowReg, defaultResult); 252 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg); 253 } 254 assert(!FPREG(rlResult.lowReg)); 255 newLIR0(cUnit, kThumb2Fmstat); 256 257 genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, ""); 258 newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg, 259 modifiedImmediate(-defaultResult)); // Must not alter ccodes 260 genBarrier(cUnit); 261 262 genIT(cUnit, kArmCondEq, ""); 263 loadConstant(cUnit, rlResult.lowReg, 0); 264 genBarrier(cUnit); 265 266 storeValue(cUnit, rlDest, rlResult); 267 return false; 268 } 269