1%def fbinop(instr=""): 2 /*: 3 * Generic 32-bit floating-point operation. 4 * 5 * For: add-float, sub-float, mul-float, div-float. 6 * form: <op> f0, f0, f1 7 */ 8 /* binop vAA, vBB, vCC */ 9 srl a4, rINST, 8 # a4 <- AA 10 lbu a2, 2(rPC) # a2 <- BB 11 lbu a3, 3(rPC) # a3 <- CC 12 GET_VREG_FLOAT f0, a2 # f0 <- vBB 13 GET_VREG_FLOAT f1, a3 # f1 <- vCC 14 $instr # f0 <- f0 op f1 15 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 16 GET_INST_OPCODE v0 # extract opcode from rINST 17 SET_VREG_FLOAT f0, a4 # vAA <- f0 18 GOTO_OPCODE v0 # jump to next instruction 19 20%def fbinop2addr(instr=""): 21 /*: 22 * Generic 32-bit "/2addr" floating-point operation. 23 * 24 * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr. 25 * form: <op> f0, f0, f1 26 */ 27 /* binop/2addr vA, vB */ 28 ext a2, rINST, 8, 4 # a2 <- A 29 ext a3, rINST, 12, 4 # a3 <- B 30 GET_VREG_FLOAT f0, a2 # f0 <- vA 31 GET_VREG_FLOAT f1, a3 # f1 <- vB 32 $instr # f0 <- f0 op f1 33 FETCH_ADVANCE_INST 1 # advance rPC, load rINST 34 GET_INST_OPCODE v0 # extract opcode from rINST 35 SET_VREG_FLOAT f0, a2 # vA <- f0 36 GOTO_OPCODE v0 # jump to next instruction 37 38%def fbinopWide(instr=""): 39 /*: 40 * Generic 64-bit floating-point operation. 41 * 42 * For: add-double, sub-double, mul-double, div-double. 43 * form: <op> f0, f0, f1 44 */ 45 /* binop vAA, vBB, vCC */ 46 srl a4, rINST, 8 # a4 <- AA 47 lbu a2, 2(rPC) # a2 <- BB 48 lbu a3, 3(rPC) # a3 <- CC 49 GET_VREG_DOUBLE f0, a2 # f0 <- vBB 50 GET_VREG_DOUBLE f1, a3 # f1 <- vCC 51 $instr # f0 <- f0 op f1 52 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 53 GET_INST_OPCODE v0 # extract opcode from rINST 54 SET_VREG_DOUBLE f0, a4 # vAA <- f0 55 GOTO_OPCODE v0 # jump to next instruction 56 57%def fbinopWide2addr(instr=""): 58 /*: 59 * Generic 64-bit "/2addr" floating-point operation. 60 * 61 * For: add-double/2addr, sub-double/2addr, mul-double/2addr, div-double/2addr. 62 * form: <op> f0, f0, f1 63 */ 64 /* binop/2addr vA, vB */ 65 ext a2, rINST, 8, 4 # a2 <- A 66 ext a3, rINST, 12, 4 # a3 <- B 67 GET_VREG_DOUBLE f0, a2 # f0 <- vA 68 GET_VREG_DOUBLE f1, a3 # f1 <- vB 69 $instr # f0 <- f0 op f1 70 FETCH_ADVANCE_INST 1 # advance rPC, load rINST 71 GET_INST_OPCODE v0 # extract opcode from rINST 72 SET_VREG_DOUBLE f0, a2 # vA <- f0 73 GOTO_OPCODE v0 # jump to next instruction 74 75%def fcmp(gt_bias=""): 76 /* 77 * Compare two floating-point values. Puts 0, 1, or -1 into the 78 * destination register based on the results of the comparison. 79 * 80 * For: cmpl-float, cmpg-float 81 */ 82 /* op vAA, vBB, vCC */ 83 srl a4, rINST, 8 # a4 <- AA 84 lbu a2, 2(rPC) # a2 <- BB 85 lbu a3, 3(rPC) # a3 <- CC 86 GET_VREG_FLOAT f0, a2 # f0 <- vBB 87 GET_VREG_FLOAT f1, a3 # f1 <- vCC 88 cmp.eq.s f2, f0, f1 89 li a0, 0 90 bc1nez f2, 1f # done if vBB == vCC (ordered) 91 .if $gt_bias 92 cmp.lt.s f2, f0, f1 93 li a0, -1 94 bc1nez f2, 1f # done if vBB < vCC (ordered) 95 li a0, 1 # vBB > vCC or unordered 96 .else 97 cmp.lt.s f2, f1, f0 98 li a0, 1 99 bc1nez f2, 1f # done if vBB > vCC (ordered) 100 li a0, -1 # vBB < vCC or unordered 101 .endif 1021: 103 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 104 GET_INST_OPCODE v0 # extract opcode from rINST 105 SET_VREG a0, a4 # vAA <- a0 106 GOTO_OPCODE v0 # jump to next instruction 107 108%def fcmpWide(gt_bias=""): 109 /* 110 * Compare two floating-point values. Puts 0, 1, or -1 into the 111 * destination register based on the results of the comparison. 112 * 113 * For: cmpl-double, cmpg-double 114 */ 115 /* op vAA, vBB, vCC */ 116 srl a4, rINST, 8 # a4 <- AA 117 lbu a2, 2(rPC) # a2 <- BB 118 lbu a3, 3(rPC) # a3 <- CC 119 GET_VREG_DOUBLE f0, a2 # f0 <- vBB 120 GET_VREG_DOUBLE f1, a3 # f1 <- vCC 121 cmp.eq.d f2, f0, f1 122 li a0, 0 123 bc1nez f2, 1f # done if vBB == vCC (ordered) 124 .if $gt_bias 125 cmp.lt.d f2, f0, f1 126 li a0, -1 127 bc1nez f2, 1f # done if vBB < vCC (ordered) 128 li a0, 1 # vBB > vCC or unordered 129 .else 130 cmp.lt.d f2, f1, f0 131 li a0, 1 132 bc1nez f2, 1f # done if vBB > vCC (ordered) 133 li a0, -1 # vBB < vCC or unordered 134 .endif 1351: 136 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 137 GET_INST_OPCODE v0 # extract opcode from rINST 138 SET_VREG a0, a4 # vAA <- a0 139 GOTO_OPCODE v0 # jump to next instruction 140 141%def fcvtFooter(suffix="", valreg=""): 142 /* 143 * Stores a specified register containing the result of conversion 144 * from or to a floating-point type and jumps to the next instruction. 145 * 146 * Expects a1 to contain the destination Dalvik register number. 147 * a1 is set up by fcvtHeader.S. 148 * 149 * For: int-to-float, int-to-double, long-to-float, long-to-double, 150 * float-to-int, float-to-long, float-to-double, double-to-int, 151 * double-to-long, double-to-float, neg-float, neg-double. 152 * 153 * Note that this file can't be included after a break in other files 154 * and in those files its contents appear as a copy. 155 * See: float-to-int, float-to-long, double-to-int, double-to-long. 156 */ 157 GET_INST_OPCODE v0 # extract opcode from rINST 158 SET_VREG$suffix $valreg, a1 159 GOTO_OPCODE v0 # jump to next instruction 160 161%def fcvtHeader(suffix="", valreg=""): 162 /* 163 * Loads a specified register from vB. Used primarily for conversions 164 * from or to a floating-point type. 165 * 166 * Sets up a1 = A and a2 = B. a2 is later used by fcvtFooter.S to 167 * store the result in vA and jump to the next instruction. 168 * 169 * For: int-to-float, int-to-double, long-to-float, long-to-double, 170 * float-to-int, float-to-long, float-to-double, double-to-int, 171 * double-to-long, double-to-float, neg-float, neg-double. 172 */ 173 ext a1, rINST, 8, 4 # a1 <- A 174 srl a2, rINST, 12 # a2 <- B 175 GET_VREG$suffix $valreg, a2 176 FETCH_ADVANCE_INST 1 # advance rPC, load rINST 177 178%def op_add_double(): 179% fbinopWide(instr="add.d f0, f0, f1") 180 181%def op_add_double_2addr(): 182% fbinopWide2addr(instr="add.d f0, f0, f1") 183 184%def op_add_float(): 185% fbinop(instr="add.s f0, f0, f1") 186 187%def op_add_float_2addr(): 188% fbinop2addr(instr="add.s f0, f0, f1") 189 190%def op_cmpg_double(): 191% fcmpWide(gt_bias="1") 192 193%def op_cmpg_float(): 194% fcmp(gt_bias="1") 195 196%def op_cmpl_double(): 197% fcmpWide(gt_bias="0") 198 199%def op_cmpl_float(): 200% fcmp(gt_bias="0") 201 202%def op_div_double(): 203% fbinopWide(instr="div.d f0, f0, f1") 204 205%def op_div_double_2addr(): 206% fbinopWide2addr(instr="div.d f0, f0, f1") 207 208%def op_div_float(): 209% fbinop(instr="div.s f0, f0, f1") 210 211%def op_div_float_2addr(): 212% fbinop2addr(instr="div.s f0, f0, f1") 213 214%def op_double_to_float(): 215 /* 216 * Conversion from or to floating-point happens in a floating-point register. 217 * Therefore we load the input and store the output into or from a 218 * floating-point register irrespective of the type. 219 */ 220% fcvtHeader(suffix="_DOUBLE", valreg="f0") 221 cvt.s.d f0, f0 222% fcvtFooter(suffix="_FLOAT", valreg="f0") 223 224%def op_double_to_int(): 225% fcvtHeader(suffix="_DOUBLE", valreg="f0") 226 trunc.w.d f0, f0 227% fcvtFooter(suffix="_FLOAT", valreg="f0") 228 229%def op_double_to_long(): 230% fcvtHeader(suffix="_DOUBLE", valreg="f0") 231 trunc.l.d f0, f0 232% fcvtFooter(suffix="_DOUBLE", valreg="f0") 233 234%def op_float_to_double(): 235 /* 236 * Conversion from or to floating-point happens in a floating-point register. 237 * Therefore we load the input and store the output into or from a 238 * floating-point register irrespective of the type. 239 */ 240% fcvtHeader(suffix="_FLOAT", valreg="f0") 241 cvt.d.s f0, f0 242% fcvtFooter(suffix="_DOUBLE", valreg="f0") 243 244%def op_float_to_int(): 245% fcvtHeader(suffix="_FLOAT", valreg="f0") 246 trunc.w.s f0, f0 247% fcvtFooter(suffix="_FLOAT", valreg="f0") 248 249%def op_float_to_long(): 250% fcvtHeader(suffix="_FLOAT", valreg="f0") 251 trunc.l.s f0, f0 252% fcvtFooter(suffix="_DOUBLE", valreg="f0") 253 254%def op_int_to_double(): 255 /* 256 * Conversion from or to floating-point happens in a floating-point register. 257 * Therefore we load the input and store the output into or from a 258 * floating-point register irrespective of the type. 259 */ 260% fcvtHeader(suffix="_FLOAT", valreg="f0") 261 cvt.d.w f0, f0 262% fcvtFooter(suffix="_DOUBLE", valreg="f0") 263 264%def op_int_to_float(): 265 /* 266 * Conversion from or to floating-point happens in a floating-point register. 267 * Therefore we load the input and store the output into or from a 268 * floating-point register irrespective of the type. 269 */ 270% fcvtHeader(suffix="_FLOAT", valreg="f0") 271 cvt.s.w f0, f0 272% fcvtFooter(suffix="_FLOAT", valreg="f0") 273 274%def op_long_to_double(): 275 /* 276 * Conversion from or to floating-point happens in a floating-point register. 277 * Therefore we load the input and store the output into or from a 278 * floating-point register irrespective of the type. 279 */ 280% fcvtHeader(suffix="_DOUBLE", valreg="f0") 281 cvt.d.l f0, f0 282% fcvtFooter(suffix="_DOUBLE", valreg="f0") 283 284%def op_long_to_float(): 285 /* 286 * Conversion from or to floating-point happens in a floating-point register. 287 * Therefore we load the input and store the output into or from a 288 * floating-point register irrespective of the type. 289 */ 290% fcvtHeader(suffix="_DOUBLE", valreg="f0") 291 cvt.s.l f0, f0 292% fcvtFooter(suffix="_FLOAT", valreg="f0") 293 294%def op_mul_double(): 295% fbinopWide(instr="mul.d f0, f0, f1") 296 297%def op_mul_double_2addr(): 298% fbinopWide2addr(instr="mul.d f0, f0, f1") 299 300%def op_mul_float(): 301% fbinop(instr="mul.s f0, f0, f1") 302 303%def op_mul_float_2addr(): 304% fbinop2addr(instr="mul.s f0, f0, f1") 305 306%def op_neg_double(): 307% fcvtHeader(suffix="_DOUBLE", valreg="f0") 308 neg.d f0, f0 309% fcvtFooter(suffix="_DOUBLE", valreg="f0") 310 311%def op_neg_float(): 312% fcvtHeader(suffix="_FLOAT", valreg="f0") 313 neg.s f0, f0 314% fcvtFooter(suffix="_FLOAT", valreg="f0") 315 316%def op_rem_double(): 317 /* rem-double vAA, vBB, vCC */ 318 .extern fmod 319 lbu a2, 2(rPC) # a2 <- BB 320 lbu a3, 3(rPC) # a3 <- CC 321 GET_VREG_DOUBLE f12, a2 # f12 <- vBB 322 GET_VREG_DOUBLE f13, a3 # f13 <- vCC 323 jal fmod # f0 <- f12 op f13 324 srl a4, rINST, 8 # a4 <- AA 325 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 326 GET_INST_OPCODE v0 # extract opcode from rINST 327 SET_VREG_DOUBLE f0, a4 # vAA <- f0 328 GOTO_OPCODE v0 # jump to next instruction 329 330%def op_rem_double_2addr(): 331 /* rem-double/2addr vA, vB */ 332 .extern fmod 333 ext a2, rINST, 8, 4 # a2 <- A 334 ext a3, rINST, 12, 4 # a3 <- B 335 GET_VREG_DOUBLE f12, a2 # f12 <- vA 336 GET_VREG_DOUBLE f13, a3 # f13 <- vB 337 jal fmod # f0 <- f12 op f13 338 ext a2, rINST, 8, 4 # a2 <- A 339 FETCH_ADVANCE_INST 1 # advance rPC, load rINST 340 GET_INST_OPCODE v0 # extract opcode from rINST 341 SET_VREG_DOUBLE f0, a2 # vA <- f0 342 GOTO_OPCODE v0 # jump to next instruction 343 344%def op_rem_float(): 345 /* rem-float vAA, vBB, vCC */ 346 .extern fmodf 347 lbu a2, 2(rPC) # a2 <- BB 348 lbu a3, 3(rPC) # a3 <- CC 349 GET_VREG_FLOAT f12, a2 # f12 <- vBB 350 GET_VREG_FLOAT f13, a3 # f13 <- vCC 351 jal fmodf # f0 <- f12 op f13 352 srl a4, rINST, 8 # a4 <- AA 353 FETCH_ADVANCE_INST 2 # advance rPC, load rINST 354 GET_INST_OPCODE v0 # extract opcode from rINST 355 SET_VREG_FLOAT f0, a4 # vAA <- f0 356 GOTO_OPCODE v0 # jump to next instruction 357 358%def op_rem_float_2addr(): 359 /* rem-float/2addr vA, vB */ 360 .extern fmodf 361 ext a2, rINST, 8, 4 # a2 <- A 362 ext a3, rINST, 12, 4 # a3 <- B 363 GET_VREG_FLOAT f12, a2 # f12 <- vA 364 GET_VREG_FLOAT f13, a3 # f13 <- vB 365 jal fmodf # f0 <- f12 op f13 366 ext a2, rINST, 8, 4 # a2 <- A 367 FETCH_ADVANCE_INST 1 # advance rPC, load rINST 368 GET_INST_OPCODE v0 # extract opcode from rINST 369 SET_VREG_FLOAT f0, a2 # vA <- f0 370 GOTO_OPCODE v0 # jump to next instruction 371 372%def op_sub_double(): 373% fbinopWide(instr="sub.d f0, f0, f1") 374 375%def op_sub_double_2addr(): 376% fbinopWide2addr(instr="sub.d f0, f0, f1") 377 378%def op_sub_float(): 379% fbinop(instr="sub.s f0, f0, f1") 380 381%def op_sub_float_2addr(): 382% fbinop2addr(instr="sub.s f0, f0, f1") 383