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> s0, s0, s1 7 */ 8 /* floatop vAA, vBB, vCC */ 9 FETCH w0, 1 // r0<- CCBB 10 lsr w1, w0, #8 // r2<- CC 11 and w0, w0, #255 // r1<- BB 12 GET_VREG s1, w1 13 GET_VREG s0, w0 14 $instr // s0<- op 15 lsr w1, wINST, #8 // r1<- AA 16 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 17 GET_INST_OPCODE ip // extract opcode from rINST 18 SET_VREG_FLOAT s0, w1 19 GOTO_OPCODE ip // jump to next instruction 20 21%def fbinopWide(instr="fadd d0, d1, d2", result="d0", r1="d1", r2="d2"): 22 /* 23 * Generic 64-bit floating-point operation. 24 */ 25 /* binop vAA, vBB, vCC */ 26 FETCH w0, 1 // w0<- CCBB 27 lsr w4, wINST, #8 // w4<- AA 28 lsr w2, w0, #8 // w2<- CC 29 and w1, w0, #255 // w1<- BB 30 GET_VREG_DOUBLE $r2, w2 // w2<- vCC 31 GET_VREG_DOUBLE $r1, w1 // w1<- vBB 32 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 33 $instr // $result<- op, w0-w4 changed 34 GET_INST_OPCODE ip // extract opcode from rINST 35 SET_VREG_DOUBLE $result, w4 // vAA<- $result 36 GOTO_OPCODE ip // jump to next instruction 37 38%def fbinop2addr(instr=""): 39 /* 40 * Generic 32-bit floating point "/2addr" binary operation. Provide 41 * an "instr" line that specifies an instruction that performs 42 * "s2 = s0 op s1". 43 * 44 * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr 45 */ 46 /* binop/2addr vA, vB */ 47 lsr w3, wINST, #12 // w3<- B 48 ubfx w9, wINST, #8, #4 // w9<- A 49 GET_VREG s1, w3 50 GET_VREG s0, w9 51 $instr // s2<- op 52 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 53 GET_INST_OPCODE ip // extract opcode from rINST 54 SET_VREG_FLOAT s2, w9 55 GOTO_OPCODE ip // jump to next instruction 56 57%def fbinopWide2addr(instr="fadd d0, d0, d1", r0="d0", r1="d1"): 58 /* 59 * Generic 64-bit floating point "/2addr" binary operation. 60 */ 61 /* binop/2addr vA, vB */ 62 lsr w1, wINST, #12 // w1<- B 63 ubfx w2, wINST, #8, #4 // w2<- A 64 GET_VREG_DOUBLE $r1, w1 // x1<- vB 65 GET_VREG_DOUBLE $r0, w2 // x0<- vA 66 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 67 $instr // result<- op 68 GET_INST_OPCODE ip // extract opcode from rINST 69 SET_VREG_DOUBLE $r0, w2 // vAA<- result 70 GOTO_OPCODE ip // jump to next instruction 71 72%def fcmp(r1="s1", r2="s2", cond="lt"): 73 /* 74 * Compare two floating-point values. Puts 0, 1, or -1 into the 75 * destination register based on the results of the comparison. 76 */ 77 /* op vAA, vBB, vCC */ 78 FETCH w0, 1 // w0<- CCBB 79% if r1.startswith("d"): 80 LOAD_SCALED_VREG_MASK w5, 0xff // w4<- ff * sizeof(vreg) 81 lsr w4, wINST, #8 // w4<- AA 82 EXTRACT_SCALED_VREG w2, w5, w0, 0 // w2<- BB * sizeof(vreg) 83 EXTRACT_SCALED_VREG w3, w5, w0, 8 // w3<- CC * sizeof(vreg) 84 GET_VREG_DOUBLE_PRESCALED $r1, w2 85 GET_VREG_DOUBLE_PRESCALED $r2, w3 86% else: 87 lsr w4, wINST, #8 // w4<- AA 88 and w2, w0, #255 // w2<- BB 89 lsr w3, w0, #8 // w3<- CC 90 GET_VREG $r1, w2 91 GET_VREG $r2, w3 92% #endif 93 fcmp $r1, $r2 94 cset w0, ne 95 cneg w0, w0, $cond 96 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 97 GET_INST_OPCODE ip // extract opcode from rINST 98 SET_VREG w0, w4 // vAA<- w0 99 GOTO_OPCODE ip // jump to next instruction 100 101%def funopNarrow(srcreg="s0", tgtreg="d0", instr=""): 102 /* 103 * Generic 32bit-to-32bit floating point unary operation. Provide an 104 * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg". 105 * 106 * For: int-to-float, float-to-int 107 * TODO: refactor all of the conversions - parameterize width and use same template. 108 */ 109 /* unop vA, vB */ 110 lsr w3, wINST, #12 // w3<- B 111 ubfx w4, wINST, #8, #4 // w4<- A 112 GET_VREG $srcreg, w3 113 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 114 $instr // d0<- op 115 GET_INST_OPCODE ip // extract opcode from wINST 116 SET_VREG_FLOAT $tgtreg, w4 // vA<- d0 117 GOTO_OPCODE ip // jump to next instruction 118 119%def funopNarrower(srcreg="s0", tgtreg="d0", instr=""): 120 /* 121 * Generic 64bit-to-32bit floating point unary operation. Provide an 122 * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg". 123 * 124 * For: int-to-double, float-to-double, float-to-long 125 */ 126 /* unop vA, vB */ 127 lsr w3, wINST, #12 // w3<- B 128 ubfx w4, wINST, #8, #4 // w4<- A 129% if srcreg.startswith("d"): 130 GET_VREG_DOUBLE $srcreg, w3 131% else: 132 GET_VREG_WIDE $srcreg, w3 133% #endif 134 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 135 $instr // d0<- op 136 GET_INST_OPCODE ip // extract opcode from wINST 137 SET_VREG_FLOAT $tgtreg, w4 // vA<- d0 138 GOTO_OPCODE ip // jump to next instruction 139 140%def funopWide(srcreg="s0", tgtreg="d0", instr=""): 141 /* 142 * Generic 64bit-to-64bit floating point unary operation. Provide an 143 * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg". 144 * 145 * For: long-to-double, double-to-long 146 */ 147 /* unop vA, vB */ 148 lsr w3, wINST, #12 // w3<- B 149 ubfx w4, wINST, #8, #4 // w4<- A 150% if srcreg.startswith("d"): 151 GET_VREG_DOUBLE $srcreg, w3 152% else: 153 GET_VREG_WIDE $srcreg, w3 154% #endif 155 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 156 $instr // d0<- op 157 GET_INST_OPCODE ip // extract opcode from wINST 158% if tgtreg.startswith("d"): 159 SET_VREG_DOUBLE $tgtreg, w4 // vA<- d0 160% else: 161 SET_VREG_WIDE $tgtreg, w4 // vA<- d0 162% #endif 163 GOTO_OPCODE ip // jump to next instruction 164 165%def funopWider(srcreg="s0", tgtreg="d0", instr=""): 166 /* 167 * Generic 32bit-to-64bit floating point unary operation. Provide an 168 * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg". 169 * 170 * For: int-to-double, float-to-double, float-to-long 171 */ 172 /* unop vA, vB */ 173 lsr w3, wINST, #12 // w3<- B 174 ubfx w4, wINST, #8, #4 // w4<- A 175 GET_VREG $srcreg, w3 176 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 177 $instr // d0<- op 178 GET_INST_OPCODE ip // extract opcode from wINST 179 SET_VREG_WIDE $tgtreg, w4 // vA<- d0 180 GOTO_OPCODE ip // jump to next instruction 181 182%def op_add_double(): 183% fbinopWide(instr="fadd d0, d1, d2", result="d0", r1="d1", r2="d2") 184 185%def op_add_double_2addr(): 186% fbinopWide2addr(instr="fadd d0, d0, d1", r0="d0", r1="d1") 187 188%def op_add_float(): 189% fbinop(instr="fadd s0, s0, s1") 190 191%def op_add_float_2addr(): 192% fbinop2addr(instr="fadd s2, s0, s1") 193 194%def op_cmpg_double(): 195% fcmp(r1="d1", r2="d2", cond="cc") 196 197%def op_cmpg_float(): 198% fcmp(r1="s1", r2="s2", cond="cc") 199 200%def op_cmpl_double(): 201% fcmp(r1="d1", r2="d2", cond="lt") 202 203%def op_cmpl_float(): 204% fcmp(r1="s1", r2="s2", cond="lt") 205 206%def op_div_double(): 207% fbinopWide(instr="fdiv d0, d1, d2", result="d0", r1="d1", r2="d2") 208 209%def op_div_double_2addr(): 210% fbinopWide2addr(instr="fdiv d0, d0, d1", r0="d0", r1="d1") 211 212%def op_div_float(): 213% fbinop(instr="fdiv s0, s0, s1") 214 215%def op_div_float_2addr(): 216% fbinop2addr(instr="fdiv s2, s0, s1") 217 218%def op_double_to_float(): 219% funopNarrower(instr="fcvt s0, d0", srcreg="d0", tgtreg="s0") 220 221%def op_double_to_int(): 222% funopNarrower(instr="fcvtzs w0, d0", srcreg="d0", tgtreg="w0") 223 224%def op_double_to_long(): 225% funopWide(instr="fcvtzs x0, d0", srcreg="d0", tgtreg="x0") 226 227%def op_float_to_double(): 228% funopWider(instr="fcvt d0, s0", srcreg="s0", tgtreg="d0") 229 230%def op_float_to_int(): 231% funopNarrow(instr="fcvtzs w0, s0", srcreg="s0", tgtreg="w0") 232 233%def op_float_to_long(): 234% funopWider(instr="fcvtzs x0, s0", srcreg="s0", tgtreg="x0") 235 236%def op_int_to_double(): 237% funopWider(instr="scvtf d0, w0", srcreg="w0", tgtreg="d0") 238 239%def op_int_to_float(): 240% funopNarrow(instr="scvtf s0, w0", srcreg="w0", tgtreg="s0") 241 242%def op_long_to_double(): 243% funopWide(instr="scvtf d0, x0", srcreg="x0", tgtreg="d0") 244 245%def op_long_to_float(): 246% funopNarrower(instr="scvtf s0, x0", srcreg="x0", tgtreg="s0") 247 248%def op_mul_double(): 249% fbinopWide(instr="fmul d0, d1, d2", result="d0", r1="d1", r2="d2") 250 251%def op_mul_double_2addr(): 252% fbinopWide2addr(instr="fmul d0, d0, d1", r0="d0", r1="d1") 253 254%def op_mul_float(): 255% fbinop(instr="fmul s0, s0, s1") 256 257%def op_mul_float_2addr(): 258% fbinop2addr(instr="fmul s2, s0, s1") 259 260%def op_neg_double(): 261% unopWide(instr="eor x0, x0, #0x8000000000000000") 262 263%def op_neg_float(): 264% unop(instr="eor w0, w0, #0x80000000") 265 266%def op_rem_double(): 267 /* rem vAA, vBB, vCC */ 268 FETCH w0, 1 // w0<- CCBB 269 lsr w2, w0, #8 // w2<- CC 270 and w1, w0, #255 // w1<- BB 271 GET_VREG_DOUBLE d1, w2 // d1<- vCC 272 GET_VREG_DOUBLE d0, w1 // d0<- vBB 273 bl fmod 274 lsr w4, wINST, #8 // w4<- AA 275 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 276 GET_INST_OPCODE ip // extract opcode from rINST 277 SET_VREG_WIDE d0, w4 // vAA<- result 278 GOTO_OPCODE ip // jump to next instruction 279 /* 11-14 instructions */ 280 281%def op_rem_double_2addr(): 282 /* rem vA, vB */ 283 lsr w1, wINST, #12 // w1<- B 284 ubfx w2, wINST, #8, #4 // w2<- A 285 GET_VREG_DOUBLE d1, w1 // d1<- vB 286 GET_VREG_DOUBLE d0, w2 // d0<- vA 287 bl fmod 288 ubfx w2, wINST, #8, #4 // w2<- A (need to reload - killed across call) 289 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 290 GET_INST_OPCODE ip // extract opcode from rINST 291 SET_VREG_WIDE d0, w2 // vAA<- result 292 GOTO_OPCODE ip // jump to next instruction 293 /* 10-13 instructions */ 294 295%def op_rem_float(): 296/* EABI doesn't define a float remainder function, but libm does */ 297% fbinop(instr="bl fmodf") 298 299%def op_rem_float_2addr(): 300 /* rem vA, vB */ 301 lsr w3, wINST, #12 // w3<- B 302 ubfx w9, wINST, #8, #4 // w9<- A 303 GET_VREG s1, w3 304 GET_VREG s0, w9 305 bl fmodf 306 ubfx w9, wINST, #8, #4 // w9<- A 307 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 308 GET_INST_OPCODE ip // extract opcode from rINST 309 SET_VREG_FLOAT s0, w9 310 GOTO_OPCODE ip // jump to next instruction 311 312%def op_sub_double(): 313% fbinopWide(instr="fsub d0, d1, d2", result="d0", r1="d1", r2="d2") 314 315%def op_sub_double_2addr(): 316% fbinopWide2addr(instr="fsub d0, d0, d1", r0="d0", r1="d1") 317 318%def op_sub_float(): 319% fbinop(instr="fsub s0, s0, s1") 320 321%def op_sub_float_2addr(): 322% fbinop2addr(instr="fsub s2, s0, s1") 323