1// 2// unop vA, vB 3// Format 12x: B|A|op 4// (see floating_point.S for float/double ops) 5// 6 7// neg-int vA, vB 8// Format 12x: B|A|7b 9%def op_neg_int(): 10% generic_unop(instr="negw t1, t1") 11 12// not-int vA, vB 13// Format 12x: B|A|7c 14%def op_not_int(): 15% generic_unop(instr="not t1, t1") 16 17// neg-long vA, vB 18// Format 12x: B|A|7d 19%def op_neg_long(): 20% generic_unop(instr="neg t1, t1", is_wide=True) 21 22// not-long vA, vB 23// Format 12x: B|A|7e 24%def op_not_long(): 25% generic_unop(instr="not t1, t1", is_wide=True) 26 27// int-to-long vA, vB 28// Format 12x: B|A|81 29// Note: Sign extension of int32 into int64. 30// Read from 32-bit vreg and write to 64-bit vreg, hence a custom impl. 31%def op_int_to_long(): 32 srliw t1, xINST, 12 // t1 := B 33 srliw t2, xINST, 8 // t2 := B|A 34% get_vreg("t1", "t1") # t1 := fp[B] with sign extension to 64 bits 35 FETCH_ADVANCE_INST 1 // advance xPC, load xINST 36 and t2, t2, 0xF // t2 := A 37 GET_INST_OPCODE t3 // t3 holds next opcode 38 SET_VREG_WIDE t1, t2, z0=t0 39 // fp[A:A+1] := t1 40 GOTO_OPCODE t3 // continue to next 41 42// long-to-int vA, vB 43// Format 12x: B|A|84 44// Note: Truncation of int64 into int32. 45// Implemented as a read from the low bits from vB, write them to vA. 46// Note: instr is intentionally empty. 47%def op_long_to_int(): 48% generic_unop(instr="") 49 50// int-to-byte vA, vB 51// Format 12x: B|A|8d 52// Note: Truncation of int32 to int8, sign extending the result. 53%def op_int_to_byte(): 54% generic_unop(instr="sext.b t1, t1") 55 56// int-to-byte vA, vB 57// Format 12x: B|A|8e 58// Note: Truncation of int32 to uint16, without sign extension. 59%def op_int_to_char(): 60% generic_unop(instr="zext.h t1, t1") 61 62// int-to-byte vA, vB 63// Format 12x: B|A|8f 64// Note: Truncation of int32 to int16, sign extending the result. 65%def op_int_to_short(): 66% generic_unop(instr="sext.h t1, t1") 67 68// unop boilerplate 69// instr: operand held in t1, result written to t1. 70// instr must not clobber t2. 71// Clobbers: t0, t1, t2 72%def generic_unop(instr, is_wide=False): 73 srliw t1, xINST, 12 // t1 := B 74 srliw t2, xINST, 8 // t2 := B|A 75% get_vreg("t1", "t1", is_wide=is_wide) 76 // t1 := fp[B] 77 and t2, t2, 0xF // t2 := A 78 FETCH_ADVANCE_INST 1 // advance xPC, load xINST 79 $instr // read t1, write result to t1. 80 // do not clobber t2! 81% set_vreg("t1", "t2", z0="t0", is_wide=is_wide) 82 // fp[A] := t1 83 GET_INST_OPCODE t0 // t0 holds next opcode 84 GOTO_OPCODE t0 // continue to next 85 86// 87// binop vAA, vBB, vCC 88// Format 23x: AA|op CC|BB 89// (see floating_point.S for float/double ops) 90// 91 92// add-int vAA, vBB, vCC 93// Format 23x: AA|90 CC|BB 94%def op_add_int(): 95% generic_binop(instr="addw t1, t1, t2") 96 97// sub-int vAA, vBB, vCC 98// Format 23x: AA|91 CC|BB 99%def op_sub_int(): 100% generic_binop(instr="subw t1, t1, t2") 101 102// mul-int vAA, vBB, vCC 103// Format 23x: AA|92 CC|BB 104%def op_mul_int(): 105% generic_binop(instr="mulw t1, t1, t2") 106 107// div-int vAA, vBB, vCC 108// Format 23x: AA|93 CC|BB 109// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws 110// ArithmeticException if b == 0. 111%def op_div_int(): 112% generic_binop(instr="divw t1, t1, t2", divz_throw=True) 113 114// rem-int vAA, vBB, vCC 115// Format 23x: AA|94 CC|BB 116// Note: Twos-complement remainder after division. The sign of the result is the same as that of a, 117// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if 118// b == 0. 119%def op_rem_int(): 120% generic_binop(instr="remw t1, t1, t2", divz_throw=True) 121 122// and-int vAA, vBB, vCC 123// Format 23x: AA|95 CC|BB 124%def op_and_int(): 125% generic_binop(instr="and t1, t1, t2") 126 127// or-int vAA, vBB, vCC 128// Format 23x: AA|96 CC|BB 129%def op_or_int(): 130% generic_binop(instr="or t1, t1, t2") 131 132// xor-int vAA, vBB, vCC 133// Format 23x: AA|97 CC|BB 134%def op_xor_int(): 135% generic_binop(instr="xor t1, t1, t2") 136 137// shl-int vAA, vBB, vCC 138// Format 23x: AA|98 CC|BB 139// Note: SLLW uses t2[4:0] for the shift amount. 140%def op_shl_int(): 141% generic_binop(instr="sllw t1, t1, t2") 142 143// shr-int vAA, vBB, vCC 144// Format 23x: AA|99 CC|BB 145// Note: SRAW uses t2[4:0] for the shift amount. 146%def op_shr_int(): 147% generic_binop(instr="sraw t1, t1, t2") 148 149// ushr-int vAA, vBB, vCC 150// Format 23x: AA|9a CC|BB 151// Note: SRLW uses t2[4:0] for the shift amount. 152%def op_ushr_int(): 153% generic_binop(instr="srlw t1, t1, t2") 154 155// add-long vAA, vBB, vCC 156// Format 23x: AA|9b CC|BB 157%def op_add_long(): 158% generic_binop(instr="add t1, t1, t2", is_wide=True) 159 160// sub-long vAA, vBB, vCC 161// Format 23x: AA|9c CC|BB 162%def op_sub_long(): 163% generic_binop(instr="sub t1, t1, t2", is_wide=True) 164 165// mul-long vAA, vBB, vCC 166// Format 23x: AA|9d CC|BB 167%def op_mul_long(): 168% generic_binop(instr="mul t1, t1, t2", is_wide=True) 169 170// div-long vAA, vBB, vCC 171// Format 23x: AA|9e CC|BB 172// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws 173// ArithmeticException if b == 0. 174%def op_div_long(): 175% generic_binop(instr="div t1, t1, t2", divz_throw=True, is_wide=True) 176 177// rem-long vAA, vBB, vCC 178// Format 23x: AA|9f CC|BB 179// Note: Twos-complement remainder after division. The sign of the result is the same as that of a, 180// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if 181// b == 0. 182%def op_rem_long(): 183% generic_binop(instr="rem t1, t1, t2", divz_throw=True, is_wide=True) 184 185// and-long vAA, vBB, vCC 186// Format 23x: AA|a0 CC|BB 187%def op_and_long(): 188% generic_binop(instr="and t1, t1, t2", is_wide=True) 189 190// or-long vAA, vBB, vCC 191// Format 23x: AA|a1 CC|BB 192%def op_or_long(): 193% generic_binop(instr="or t1, t1, t2", is_wide=True) 194 195// xor-long vAA, vBB, vCC 196// Format 23x: AA|a2 CC|BB 197%def op_xor_long(): 198% generic_binop(instr="xor t1, t1, t2", is_wide=True) 199 200// shl-long vAA, vBB, vCC 201// Format 23x: AA|a3 CC|BB 202// Note: SLL uses t2[5:0] for the shift amount. 203%def op_shl_long(): 204% generic_shift_wide(instr="sll t1, t1, t2") 205 206// shr-long vAA, vBB, vCC 207// Format 23x: AA|a4 CC|BB 208// Note: SRA uses t2[5:0] for the shift amount. 209%def op_shr_long(): 210% generic_shift_wide(instr="sra t1, t1, t2") 211 212// ushr-long vAA, vBB, vCC 213// Format 23x: AA|a5 CC|BB 214// Note: SRL uses t2[5:0] for the shift amount. 215%def op_ushr_long(): 216% generic_shift_wide(instr="srl t1, t1, t2") 217 218// binop boilerplate 219// instr: operands held in t1 and t2, result written to t1. 220// instr must not throw. Exceptions to be thrown prior to instr. 221// instr must not clobber t3. 222// 223// The divz_throw flag generates check-and-throw code for div/0. 224// The is_wide flag ensures vregs are read and written in 64-bit widths. 225// Clobbers: t0, t1, t2, t3 226%def generic_binop(instr, divz_throw=False, is_wide=False): 227 FETCH t1, count=1 // t1 := CC|BB 228 srliw t3, xINST, 8 // t3 := AA 229 srliw t2, t1, 8 // t2 := CC 230 and t1, t1, 0xFF // t1 := BB 231% get_vreg("t2", "t2", is_wide=is_wide) # t2 := fp[CC] 232% get_vreg("t1", "t1", is_wide=is_wide) # t1 := fp[BB] 233% if divz_throw: 234 beqz t2, 1f // Must throw before FETCH_ADVANCE_INST. 235%#: 236 FETCH_ADVANCE_INST 2 // advance xPC, load xINST 237 $instr // read t1 and t2, write result to t1. 238 // do not clobber t3! 239 GET_INST_OPCODE t2 // t2 holds next opcode 240% set_vreg("t1", "t3", z0="t0", is_wide=is_wide) 241 // fp[AA] := t1 242 GOTO_OPCODE t2 // continue to next 2431: 244% if divz_throw: 245 tail common_errDivideByZero 246%#: 247 248// binop wide shift boilerplate 249// instr: operands held in t1 (64-bit) and t2 (32-bit), result written to t1. 250// instr must not clobber t3. 251// Clobbers: t0, t1, t2, t3 252// 253// Note: Contrary to other -long mathematical operations (which take register pairs for both their 254// first and their second source), shl-long, shr-long, and ushr-long take a register pair for their 255// first source (the value to be shifted), but a single register for their second source (the 256// shifting distance). 257%def generic_shift_wide(instr): 258 FETCH t1, count=1 // t1 := CC|BB 259 srliw t3, xINST, 8 // t3 := AA 260 srliw t2, t1, 8 // t2 := CC 261 and t1, t1, 0xFF // t1 := BB 262% get_vreg("t2", "t2") # t2 := fp[CC] 263 GET_VREG_WIDE t1, t1 // t1 := fp[BB] 264 FETCH_ADVANCE_INST 2 // advance xPC, load xINST 265 $instr // read t1 and t2, write result to t1. 266 // do not clobber t3! 267 GET_INST_OPCODE t2 // t2 holds next opcode 268 SET_VREG_WIDE t1, t3, z0=t0 269 // fp[AA] := t1 270 GOTO_OPCODE t2 // continue to next 271 272// 273// binop/2addr vA, vB 274// Format 12x: B|A|op 275// (see floating_point.S for float/double ops) 276// 277 278// add-int/2addr vA, vB 279// Format 12x: B|A|b0 280%def op_add_int_2addr(): 281% generic_binop_2addr(instr="addw t1, t1, t2") 282 283// sub-int/2addr vA, vB 284// Format 12x: B|A|b1 285%def op_sub_int_2addr(): 286% generic_binop_2addr(instr="subw t1, t1, t2") 287 288// mul-int/2addr vA, vB 289// Format 12x: B|A|b2 290%def op_mul_int_2addr(): 291% generic_binop_2addr(instr="mulw t1, t1, t2") 292 293// div-int/2addr vA, vB 294// Format 12x: B|A|b3 295// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws 296// ArithmeticException if b == 0. 297%def op_div_int_2addr(): 298% generic_binop_2addr(instr="divw t1, t1, t2", divz_throw=True) 299 300// rem-int/2addr vA, vB 301// Format 12x: B|A|b4 302// Note: Twos-complement remainder after division. The sign of the result is the same as that of a, 303// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if 304// b == 0. 305%def op_rem_int_2addr(): 306% generic_binop_2addr(instr="remw t1, t1, t2", divz_throw=True) 307 308// and-int/2addr vA, vB 309// Format 12x: B|A|b5 310%def op_and_int_2addr(): 311% generic_binop_2addr(instr="and t1, t1, t2") 312 313// or-int/2addr vA, vB 314// Format 12x: B|A|b6 315%def op_or_int_2addr(): 316% generic_binop_2addr(instr="or t1, t1, t2") 317 318// xor-int/2addr vA, vB 319// Format 12x: B|A|b7 320%def op_xor_int_2addr(): 321% generic_binop_2addr(instr="xor t1, t1, t2") 322 323// shl-int/2addr vA, vB 324// Format 12x: B|A|b8 325%def op_shl_int_2addr(): 326% generic_binop_2addr(instr="sllw t1, t1, t2") 327 328// shr-int/2addr vA, vB 329// Format 12x: B|A|b9 330%def op_shr_int_2addr(): 331% generic_binop_2addr(instr="sraw t1, t1, t2") 332 333// ushr-int/2addr vA, vB 334// Format 12x: B|A|ba 335%def op_ushr_int_2addr(): 336% generic_binop_2addr(instr="srlw t1, t1, t2") 337 338// add-long/2addr vA, vB 339// Format 12x: B|A|bb 340%def op_add_long_2addr(): 341% generic_binop_2addr(instr="add t1, t1, t2", is_wide=True) 342 343// sub-long/2addr vA, vB 344// Format 12x: B|A|bc 345%def op_sub_long_2addr(): 346% generic_binop_2addr(instr="sub t1, t1, t2", is_wide=True) 347 348// mul-long/2addr vA, vB 349// Format 12x: B|A|bd 350%def op_mul_long_2addr(): 351% generic_binop_2addr(instr="mul t1, t1, t2", is_wide=True) 352 353// div-long/2addr vA, vB 354// Format 12x: B|A|be 355%def op_div_long_2addr(): 356% generic_binop_2addr(instr="div t1, t1, t2", divz_throw=True, is_wide=True) 357 358// rem-long/2addr vA, vB 359// Format 12x: B|A|bf 360%def op_rem_long_2addr(): 361% generic_binop_2addr(instr="rem t1, t1, t2", divz_throw=True, is_wide=True) 362 363// and-long/2addr vA, vB 364// Format 12x: B|A|c0 365%def op_and_long_2addr(): 366% generic_binop_2addr(instr="and t1, t1, t2", is_wide=True) 367 368// or-long/2addr vA, vB 369// Format 12x: B|A|c1 370%def op_or_long_2addr(): 371% generic_binop_2addr(instr="or t1, t1, t2", is_wide=True) 372 373// xor-long/2addr vA, vB 374// Format 12x: B|A|c2 375%def op_xor_long_2addr(): 376% generic_binop_2addr(instr="xor t1, t1, t2", is_wide=True) 377 378// shl-long/2addr vA, vB 379// Format 12x: B|A|c3 380// Note: SLL uses t2[5:0] for the shift amount. 381%def op_shl_long_2addr(): 382% generic_shift_wide_2addr(instr="sll t1, t1, t2") 383 384// shr-long/2addr vA, vB 385// Format 12x: B|A|c4 386// Note: SRA uses t2[5:0] for the shift amount. 387%def op_shr_long_2addr(): 388% generic_shift_wide_2addr(instr="sra t1, t1, t2") 389 390// ushr-long/2addr vA, vB 391// Format 12x: B|A|c5 392// Note: SRL uses t2[5:0] for the shift amount. 393%def op_ushr_long_2addr(): 394% generic_shift_wide_2addr(instr="srl t1, t1, t2") 395 396// binop 2addr boilerplate 397// instr: operands held in t1 and t2, result written to t1. 398// instr must not throw. Exceptions to be thrown prior to instr. 399// instr must not clobber t3. 400// 401// The divz_throw flag generates check-and-throw code for div/0. 402// The is_wide flag ensures vregs are read and written in 64-bit widths. 403// Clobbers: t0, t1, t2, t3, t4 404%def generic_binop_2addr(instr, divz_throw=False, is_wide=False): 405 srliw t2, xINST, 12 // t2 := B 406 srliw t3, xINST, 8 // t3 := B|A 407% get_vreg("t2", "t2", is_wide=is_wide) 408 // t2 := fp[B] 409 and t3, t3, 0xF // t3 := A (cached for SET_VREG) 410 mv t4, t3 // t4 := A 411% get_vreg("t1", "t4", is_wide=is_wide) 412 // t1 := fp[A] 413% if divz_throw: 414 beqz t2, 1f // Must throw before FETCH_ADVANCE_INST. 415%#: 416 FETCH_ADVANCE_INST 1 // advance xPC, load xINST 417 $instr // read t1 and t2, write result to t1. 418 // do not clobber t3! 419 GET_INST_OPCODE t2 // t2 holds next opcode 420% set_vreg("t1", "t3", z0="t0", is_wide=is_wide) 421 // fp[A] := t1 422 GOTO_OPCODE t2 // continue to next 4231: 424% if divz_throw: 425 tail common_errDivideByZero 426%#: 427 428// binop wide shift 2addr boilerplate 429// instr: operands held in t1 (64-bit) and t2 (32-bit), result written to t1. 430// instr must not clobber t3. 431// Clobbers: t0, t1, t2, t3, t4 432// 433// Note: Contrary to other -long/2addr mathematical operations (which take register pairs for both 434// their destination/first source and their second source), shl-long/2addr, shr-long/2addr, and 435// ushr-long/2addr take a register pair for their destination/first source (the value to be 436// shifted), but a single register for their second source (the shifting distance). 437%def generic_shift_wide_2addr(instr): 438 srliw t2, xINST, 12 // t2 := B 439 srliw t3, xINST, 8 // t3 := B|A 440% get_vreg("t2", "t2") # t2 := fp[B] 441 and t3, t3, 0xF // t3 := A (cached for SET_VREG_WIDE) 442 mv t4, t3 // t4 := A 443 FETCH_ADVANCE_INST 1 // advance xPC, load xINST 444 GET_VREG_WIDE t1, t4 // t1 := fp[A] 445 $instr // read t1 and t2, write result to t1. 446 // do not clobber t3! 447 GET_INST_OPCODE t2 // t2 holds next opcode 448 SET_VREG_WIDE t1, t3, z0=t0 449 // fp[A] := t1 450 GOTO_OPCODE t2 // continue to next 451 452// 453// binop/lit16 vA, vB, #+CCCC 454// Format 22s: B|A|op CCCC 455// 456 457// add-int/lit16 vA, vB, #+CCCC 458// Format 22s: B|A|d0 CCCC 459%def op_add_int_lit16(): 460% generic_binop_lit16(instr="addw t1, t1, t2") 461 462// rsub-int vA, vB, #+CCCC 463// Format 22s: B|A|d1 CCCC 464// Note: rsub-int does not have a suffix since this version is the main opcode of its family. 465// Note: Twos-complement reverse subtraction. 466%def op_rsub_int(): 467% generic_binop_lit16(instr="subw t1, t2, t1") 468 469// mul-int/lit16 vA, vB, #+CCCC 470// Format 22s: B|A|d2 CCCC 471%def op_mul_int_lit16(): 472% generic_binop_lit16(instr="mulw t1, t1, t2") 473 474// div-int/lit16 vA, vB, #+CCCC 475// Format 22s: B|A|d3 CCCC 476// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws 477// ArithmeticException if b == 0. 478%def op_div_int_lit16(): 479% generic_binop_lit16(instr="divw t1, t1, t2", divz_throw=True) 480 481// rem-int/lit16 vA, vB, #+CCCC 482// Format 22s: B|A|d4 CCCC 483// Note: Twos-complement remainder after division. The sign of the result is the same as that of a, 484// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if 485// b == 0. 486%def op_rem_int_lit16(): 487% generic_binop_lit16(instr="remw t1, t1, t2", divz_throw=True) 488 489// and-int/lit16 vA, vB, #+CCCC 490// Format 22s: B|A|d5 CCCC 491%def op_and_int_lit16(): 492% generic_binop_lit16(instr="and t1, t1, t2") 493 494// or-int/lit16 vA, vB, #+CCCC 495// Format 22s: B|A|d6 CCCC 496%def op_or_int_lit16(): 497% generic_binop_lit16(instr="or t1, t1, t2") 498 499// xor-int/lit16 vA, vB, #+CCCC 500// Format 22s: B|A|d7 CCCC 501%def op_xor_int_lit16(): 502% generic_binop_lit16(instr="xor t1, t1, t2") 503 504// binop lit16 boilerplate 505// instr: operands held in t1 and t2, result written to t1. 506// instr must not throw. Exceptions to be thrown prior to instr. 507// instr must not clobber t3. 508// 509// The divz_throw flag generates check-and-throw code for div/0. 510// Clobbers: t0, t1, t2, t3 511%def generic_binop_lit16(instr, divz_throw=False): 512 FETCH t2, count=1, signed=1 // t2 := ssssCCCC 513 srliw t1, xINST, 12 // t1 := B 514 srliw t3, xINST, 8 // t3 := B|A 515% if divz_throw: 516 beqz t2, 1f // Must throw before FETCH_ADVANCE_INST. 517%#: 518% get_vreg("t1", "t1") # t1 := fp[B] 519 and t3, t3, 0xF // t3 := A 520 FETCH_ADVANCE_INST 2 // advance xPC, load xINST 521 $instr // read t1 and t2, write result to t1. 522 // do not clobber t3! 523 GET_INST_OPCODE t2 // t2 holds next opcode 524% set_vreg("t1", "t3", z0="t0") # fp[A] := t1 525 GOTO_OPCODE t2 // continue to next 5261: 527% if divz_throw: 528 tail common_errDivideByZero 529%#: 530 531// 532// binop/lit8 vAA, vBB, #+CC 533// Format 22b: AA|op CC|BB 534// 535 536// add-int/lit8, vAA, vBB, #+CC 537// Format 22b: AA|d8, CC|BB 538%def op_add_int_lit8(): 539% generic_binop_lit8(instr="addw t1, t1, t2") 540 541// rsub-int/lit8, vAA, vBB, #+CC 542// Format 22b: AA|d9, CC|BB 543// Note: Twos-complement reverse subtraction. 544%def op_rsub_int_lit8(): 545% generic_binop_lit8(instr="subw t1, t2, t1") 546 547// mul-int/lit8, vAA, vBB, #+CC 548// Format 22b: AA|da, CC|BB 549%def op_mul_int_lit8(): 550% generic_binop_lit8(instr="mulw t1, t1, t2") 551 552// div-int/lit8, vAA, vBB, #+CC 553// Format 22b: AA|db, CC|BB 554// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws 555// ArithmeticException if b == 0. 556%def op_div_int_lit8(): 557% generic_binop_lit8(instr="divw t1, t1, t2", divz_throw=True) 558 559// rem-int/lit8, vAA, vBB, #+CC 560// Format 22b: AA|dc, CC|BB 561// Note: Twos-complement remainder after division. The sign of the result is the same as that of a, 562// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if 563// b == 0. 564%def op_rem_int_lit8(): 565% generic_binop_lit8(instr="remw t1, t1, t2", divz_throw=True) 566 567// and-int/lit8, vAA, vBB, #+CC 568// Format 22b: AA|dd, CC|BB 569%def op_and_int_lit8(): 570% generic_binop_lit8(instr="and t1, t1, t2") 571 572// or-int/lit8, vAA, vBB, #+CC 573// Format 22b: AA|de, CC|BB 574%def op_or_int_lit8(): 575% generic_binop_lit8(instr="or t1, t1, t2") 576 577// xor-int/lit8, vAA, vBB, #+CC 578// Format 22b: AA|df, CC|BB 579%def op_xor_int_lit8(): 580% generic_binop_lit8(instr="xor t1, t1, t2") 581 582// shl-int/lit8, vAA, vBB, #+CC 583// Format 22b: AA|e0, CC|BB 584// Note: SLLW uses t2[4:0] for the shift amount. 585%def op_shl_int_lit8(): 586% generic_binop_lit8(instr="sllw t1, t1, t2") 587 588// shr-int/lit8, vAA, vBB, #+CC 589// Format 22b: AA|e1, CC|BB 590// Note: SRAW uses t2[4:0] for the shift amount. 591%def op_shr_int_lit8(): 592% generic_binop_lit8(instr="sraw t1, t1, t2") 593 594// ushr-int/lit8, vAA, vBB, #+CC 595// Format 22b: AA|e2, CC|BB 596// Note: SRLW uses t2[4:0] for the shift amount. 597%def op_ushr_int_lit8(): 598% generic_binop_lit8(instr="srlw t1, t1, t2") 599 600// binop lit8 boilerplate 601// instr: operands held in t1 and t2, result written to t1. 602// instr must not throw. Exceptions to be thrown prior to instr. 603// instr must not clobber t3. 604// 605// The divz_throw flag generates check-and-throw code for div/0. 606// Clobbers: t0, t1, t2, t3 607%def generic_binop_lit8(instr, divz_throw=False): 608 FETCH t1, count=1, signed=1 // t1 := ssssCC|BB 609 srliw t3, xINST, 8 // t3 := AA 610 sraiw t2, t1, 8 // t2 := ssssssCC 611 andi t1, t1, 0xFF // t1 := BB 612% if divz_throw: 613 beqz t2, 1f // Must throw before FETCH_ADVANCE_INST. 614%#: 615% get_vreg("t1", "t1") # t1 := fp[BB] 616 FETCH_ADVANCE_INST 2 // advance xPC, load xINST 617 $instr // read t1 and t2, write result to t1. 618 // do not clobber t3! 619 GET_INST_OPCODE t2 // t2 holds next opcode 620% set_vreg("t1", "t3", z0="t0") # fp[AA] := t1 621 GOTO_OPCODE t2 // continue to next 6221: 623% if divz_throw: 624 tail common_errDivideByZero 625%#: 626