OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits.h> // For LONG_MIN, LONG_MAX. | 5 #include <limits.h> // For LONG_MIN, LONG_MAX. |
6 | 6 |
7 #if V8_TARGET_ARCH_MIPS64 | 7 #if V8_TARGET_ARCH_MIPS64 |
8 | 8 |
9 #include "src/base/division-by-constant.h" | 9 #include "src/base/division-by-constant.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 1837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1848 DCHECK(nan || target); | 1848 DCHECK(nan || target); |
1849 // Check for unordered (NaN) cases. | 1849 // Check for unordered (NaN) cases. |
1850 if (nan) { | 1850 if (nan) { |
1851 bool long_branch = nan->is_bound() ? is_near(nan) : is_trampoline_emitted(); | 1851 bool long_branch = nan->is_bound() ? is_near(nan) : is_trampoline_emitted(); |
1852 if (kArchVariant != kMips64r6) { | 1852 if (kArchVariant != kMips64r6) { |
1853 if (long_branch) { | 1853 if (long_branch) { |
1854 Label skip; | 1854 Label skip; |
1855 c(UN, sizeField, cmp1, cmp2); | 1855 c(UN, sizeField, cmp1, cmp2); |
1856 bc1f(&skip); | 1856 bc1f(&skip); |
1857 nop(); | 1857 nop(); |
1858 J(nan, bd); | 1858 BranchLong(nan, bd); |
1859 bind(&skip); | 1859 bind(&skip); |
1860 } else { | 1860 } else { |
1861 c(UN, sizeField, cmp1, cmp2); | 1861 c(UN, sizeField, cmp1, cmp2); |
1862 bc1t(nan); | 1862 bc1t(nan); |
1863 if (bd == PROTECT) { | 1863 if (bd == PROTECT) { |
1864 nop(); | 1864 nop(); |
1865 } | 1865 } |
1866 } | 1866 } |
1867 } else { | 1867 } else { |
1868 // Use kDoubleCompareReg for comparison result. It has to be unavailable | 1868 // Use kDoubleCompareReg for comparison result. It has to be unavailable |
1869 // to lithium | 1869 // to lithium |
1870 // register allocator. | 1870 // register allocator. |
1871 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg)); | 1871 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg)); |
1872 if (long_branch) { | 1872 if (long_branch) { |
1873 Label skip; | 1873 Label skip; |
1874 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); | 1874 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); |
1875 bc1eqz(&skip, kDoubleCompareReg); | 1875 bc1eqz(&skip, kDoubleCompareReg); |
1876 nop(); | 1876 nop(); |
1877 J(nan, bd); | 1877 BranchLong(nan, bd); |
1878 bind(&skip); | 1878 bind(&skip); |
1879 } else { | 1879 } else { |
1880 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); | 1880 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2); |
1881 bc1nez(nan, kDoubleCompareReg); | 1881 bc1nez(nan, kDoubleCompareReg); |
1882 if (bd == PROTECT) { | 1882 if (bd == PROTECT) { |
1883 nop(); | 1883 nop(); |
1884 } | 1884 } |
1885 } | 1885 } |
1886 } | 1886 } |
1887 } | 1887 } |
1888 | 1888 |
1889 if (target) { | 1889 if (target) { |
1890 bool long_branch = | 1890 bool long_branch = |
1891 target->is_bound() ? is_near(target) : is_trampoline_emitted(); | 1891 target->is_bound() ? is_near(target) : is_trampoline_emitted(); |
1892 if (long_branch) { | 1892 if (long_branch) { |
1893 Label skip; | 1893 Label skip; |
1894 Condition neg_cond = NegateFpuCondition(cond); | 1894 Condition neg_cond = NegateFpuCondition(cond); |
1895 BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd); | 1895 BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd); |
1896 J(target, bd); | 1896 BranchLong(target, bd); |
1897 bind(&skip); | 1897 bind(&skip); |
1898 } else { | 1898 } else { |
1899 BranchShortF(sizeField, target, cond, cmp1, cmp2, bd); | 1899 BranchShortF(sizeField, target, cond, cmp1, cmp2, bd); |
1900 } | 1900 } |
1901 } | 1901 } |
1902 } | 1902 } |
1903 | 1903 |
1904 | 1904 |
1905 void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target, | 1905 void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target, |
1906 Condition cc, FPURegister cmp1, | 1906 Condition cc, FPURegister cmp1, |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2305 | 2305 |
2306 | 2306 |
2307 // Emulated condtional branches do not emit a nop in the branch delay slot. | 2307 // Emulated condtional branches do not emit a nop in the branch delay slot. |
2308 // | 2308 // |
2309 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. | 2309 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. |
2310 #define BRANCH_ARGS_CHECK(cond, rs, rt) DCHECK( \ | 2310 #define BRANCH_ARGS_CHECK(cond, rs, rt) DCHECK( \ |
2311 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ | 2311 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ |
2312 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) | 2312 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) |
2313 | 2313 |
2314 | 2314 |
2315 void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { | 2315 void MacroAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) { |
| 2316 DCHECK(kArchVariant == kMips64r6 ? is_int26(offset) : is_int16(offset)); |
2316 BranchShort(offset, bdslot); | 2317 BranchShort(offset, bdslot); |
2317 } | 2318 } |
2318 | 2319 |
2319 | 2320 |
2320 void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs, | 2321 void MacroAssembler::Branch(int32_t offset, Condition cond, Register rs, |
2321 const Operand& rt, | 2322 const Operand& rt, BranchDelaySlot bdslot) { |
2322 BranchDelaySlot bdslot) { | 2323 bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot); |
2323 BranchShort(offset, cond, rs, rt, bdslot); | 2324 DCHECK(is_near); |
| 2325 USE(is_near); |
2324 } | 2326 } |
2325 | 2327 |
2326 | 2328 |
2327 void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) { | 2329 void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) { |
2328 if (L->is_bound()) { | 2330 if (L->is_bound()) { |
2329 if (is_near(L)) { | 2331 if (is_near_branch(L)) { |
2330 BranchShort(L, bdslot); | 2332 BranchShort(L, bdslot); |
2331 } else { | 2333 } else { |
2332 J(L, bdslot); | 2334 BranchLong(L, bdslot); |
2333 } | 2335 } |
2334 } else { | 2336 } else { |
2335 if (is_trampoline_emitted()) { | 2337 if (is_trampoline_emitted()) { |
2336 J(L, bdslot); | 2338 BranchLong(L, bdslot); |
2337 } else { | 2339 } else { |
2338 BranchShort(L, bdslot); | 2340 BranchShort(L, bdslot); |
2339 } | 2341 } |
2340 } | 2342 } |
2341 } | 2343 } |
2342 | 2344 |
2343 | 2345 |
2344 void MacroAssembler::Branch(Label* L, Condition cond, Register rs, | 2346 void MacroAssembler::Branch(Label* L, Condition cond, Register rs, |
2345 const Operand& rt, | 2347 const Operand& rt, |
2346 BranchDelaySlot bdslot) { | 2348 BranchDelaySlot bdslot) { |
2347 if (L->is_bound()) { | 2349 if (L->is_bound()) { |
2348 if (is_near(L)) { | 2350 if (!BranchShortCheck(0, L, cond, rs, rt, bdslot)) { |
2349 BranchShort(L, cond, rs, rt, bdslot); | |
2350 } else { | |
2351 if (cond != cc_always) { | 2351 if (cond != cc_always) { |
2352 Label skip; | 2352 Label skip; |
2353 Condition neg_cond = NegateCondition(cond); | 2353 Condition neg_cond = NegateCondition(cond); |
2354 BranchShort(&skip, neg_cond, rs, rt); | 2354 BranchShort(&skip, neg_cond, rs, rt); |
2355 J(L, bdslot); | 2355 BranchLong(L, bdslot); |
2356 bind(&skip); | 2356 bind(&skip); |
2357 } else { | 2357 } else { |
2358 J(L, bdslot); | 2358 BranchLong(L, bdslot); |
2359 } | 2359 } |
2360 } | 2360 } |
2361 } else { | 2361 } else { |
2362 if (is_trampoline_emitted()) { | 2362 if (is_trampoline_emitted()) { |
2363 if (cond != cc_always) { | 2363 if (cond != cc_always) { |
2364 Label skip; | 2364 Label skip; |
2365 Condition neg_cond = NegateCondition(cond); | 2365 Condition neg_cond = NegateCondition(cond); |
2366 BranchShort(&skip, neg_cond, rs, rt); | 2366 BranchShort(&skip, neg_cond, rs, rt); |
2367 J(L, bdslot); | 2367 BranchLong(L, bdslot); |
2368 bind(&skip); | 2368 bind(&skip); |
2369 } else { | 2369 } else { |
2370 J(L, bdslot); | 2370 BranchLong(L, bdslot); |
2371 } | 2371 } |
2372 } else { | 2372 } else { |
2373 BranchShort(L, cond, rs, rt, bdslot); | 2373 BranchShort(L, cond, rs, rt, bdslot); |
2374 } | 2374 } |
2375 } | 2375 } |
2376 } | 2376 } |
2377 | 2377 |
2378 | 2378 |
2379 void MacroAssembler::Branch(Label* L, | 2379 void MacroAssembler::Branch(Label* L, |
2380 Condition cond, | 2380 Condition cond, |
2381 Register rs, | 2381 Register rs, |
2382 Heap::RootListIndex index, | 2382 Heap::RootListIndex index, |
2383 BranchDelaySlot bdslot) { | 2383 BranchDelaySlot bdslot) { |
2384 LoadRoot(at, index); | 2384 LoadRoot(at, index); |
2385 Branch(L, cond, rs, Operand(at), bdslot); | 2385 Branch(L, cond, rs, Operand(at), bdslot); |
2386 } | 2386 } |
2387 | 2387 |
2388 | 2388 |
2389 void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) { | 2389 void MacroAssembler::BranchShortHelper(int16_t offset, Label* L, |
| 2390 BranchDelaySlot bdslot) { |
| 2391 DCHECK(L == nullptr || offset == 0); |
| 2392 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
2390 b(offset); | 2393 b(offset); |
2391 | 2394 |
2392 // Emit a nop in the branch delay slot if required. | 2395 // Emit a nop in the branch delay slot if required. |
2393 if (bdslot == PROTECT) | 2396 if (bdslot == PROTECT) |
2394 nop(); | 2397 nop(); |
2395 } | 2398 } |
2396 | 2399 |
2397 | 2400 |
2398 void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, | 2401 void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) { |
2399 const Operand& rt, | 2402 DCHECK(L == nullptr || offset == 0); |
2400 BranchDelaySlot bdslot) { | 2403 offset = GetOffset(offset, L, OffsetSize::kOffset26); |
2401 BRANCH_ARGS_CHECK(cond, rs, rt); | 2404 bc(offset); |
2402 DCHECK(!rs.is(zero_reg)); | 2405 } |
| 2406 |
| 2407 |
| 2408 void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) { |
| 2409 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
| 2410 DCHECK(is_int26(offset)); |
| 2411 BranchShortHelperR6(offset, nullptr); |
| 2412 } else { |
| 2413 DCHECK(is_int16(offset)); |
| 2414 BranchShortHelper(offset, nullptr, bdslot); |
| 2415 } |
| 2416 } |
| 2417 |
| 2418 |
| 2419 void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) { |
| 2420 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
| 2421 BranchShortHelperR6(0, L); |
| 2422 } else { |
| 2423 BranchShortHelper(0, L, bdslot); |
| 2424 } |
| 2425 } |
| 2426 |
| 2427 |
| 2428 static inline bool IsZero(const Operand& rt) { |
| 2429 if (rt.is_reg()) { |
| 2430 return rt.rm().is(zero_reg); |
| 2431 } else { |
| 2432 return rt.immediate() == 0; |
| 2433 } |
| 2434 } |
| 2435 |
| 2436 |
| 2437 int32_t MacroAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) { |
| 2438 if (L) { |
| 2439 offset = branch_offset_helper(L, bits) >> 2; |
| 2440 } else { |
| 2441 DCHECK(is_intn(offset, bits)); |
| 2442 } |
| 2443 return offset; |
| 2444 } |
| 2445 |
| 2446 |
| 2447 Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt, |
| 2448 Register scratch) { |
2403 Register r2 = no_reg; | 2449 Register r2 = no_reg; |
2404 Register scratch = at; | |
2405 | |
2406 if (rt.is_reg()) { | 2450 if (rt.is_reg()) { |
2407 // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or | 2451 r2 = rt.rm_; |
2408 // rt. | 2452 } else { |
| 2453 r2 = scratch; |
| 2454 li(r2, rt); |
| 2455 } |
| 2456 |
| 2457 return r2; |
| 2458 } |
| 2459 |
| 2460 |
| 2461 bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L, |
| 2462 Condition cond, Register rs, |
| 2463 const Operand& rt) { |
| 2464 DCHECK(L == nullptr || offset == 0); |
| 2465 Register scratch = rs.is(at) ? t8 : at; |
| 2466 OffsetSize bits = OffsetSize::kOffset16; |
| 2467 |
| 2468 // Be careful to always use shifted_branch_offset only just before the |
| 2469 // branch instruction, as the location will be remember for patching the |
| 2470 // target. |
| 2471 { |
2409 BlockTrampolinePoolScope block_trampoline_pool(this); | 2472 BlockTrampolinePoolScope block_trampoline_pool(this); |
2410 r2 = rt.rm_; | |
2411 switch (cond) { | 2473 switch (cond) { |
2412 case cc_always: | 2474 case cc_always: |
2413 b(offset); | 2475 bits = OffsetSize::kOffset26; |
| 2476 if (!is_near(L, bits)) return false; |
| 2477 offset = GetOffset(offset, L, bits); |
| 2478 bc(offset); |
2414 break; | 2479 break; |
2415 case eq: | 2480 case eq: |
2416 beq(rs, r2, offset); | 2481 if (rs.code() == rt.rm_.reg_code) { |
| 2482 // Pre R6 beq is used here to make the code patchable. Otherwise bc |
| 2483 // should be used which has no condition field so is not patchable. |
| 2484 bits = OffsetSize::kOffset16; |
| 2485 if (!is_near(L, bits)) return false; |
| 2486 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2487 offset = GetOffset(offset, L, bits); |
| 2488 beq(rs, scratch, offset); |
| 2489 nop(); |
| 2490 } else if (IsZero(rt)) { |
| 2491 bits = OffsetSize::kOffset21; |
| 2492 if (!is_near(L, bits)) return false; |
| 2493 offset = GetOffset(offset, L, bits); |
| 2494 beqzc(rs, offset); |
| 2495 } else { |
| 2496 // We don't want any other register but scratch clobbered. |
| 2497 bits = OffsetSize::kOffset16; |
| 2498 if (!is_near(L, bits)) return false; |
| 2499 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2500 offset = GetOffset(offset, L, bits); |
| 2501 beqc(rs, scratch, offset); |
| 2502 } |
2417 break; | 2503 break; |
2418 case ne: | 2504 case ne: |
2419 bne(rs, r2, offset); | 2505 if (rs.code() == rt.rm_.reg_code) { |
2420 break; | 2506 // Pre R6 bne is used here to make the code patchable. Otherwise we |
| 2507 // should not generate any instruction. |
| 2508 bits = OffsetSize::kOffset16; |
| 2509 if (!is_near(L, bits)) return false; |
| 2510 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2511 offset = GetOffset(offset, L, bits); |
| 2512 bne(rs, scratch, offset); |
| 2513 nop(); |
| 2514 } else if (IsZero(rt)) { |
| 2515 bits = OffsetSize::kOffset21; |
| 2516 if (!is_near(L, bits)) return false; |
| 2517 offset = GetOffset(offset, L, bits); |
| 2518 bnezc(rs, offset); |
| 2519 } else { |
| 2520 // We don't want any other register but scratch clobbered. |
| 2521 bits = OffsetSize::kOffset16; |
| 2522 if (!is_near(L, bits)) return false; |
| 2523 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2524 offset = GetOffset(offset, L, bits); |
| 2525 bnec(rs, scratch, offset); |
| 2526 } |
| 2527 break; |
| 2528 |
2421 // Signed comparison. | 2529 // Signed comparison. |
2422 case greater: | 2530 case greater: |
2423 if (r2.is(zero_reg)) { | 2531 // rs > rt |
2424 bgtz(rs, offset); | 2532 if (rs.code() == rt.rm_.reg_code) { |
2425 } else { | 2533 break; // No code needs to be emitted. |
2426 slt(scratch, r2, rs); | 2534 } else if (rs.is(zero_reg)) { |
2427 bne(scratch, zero_reg, offset); | 2535 bits = OffsetSize::kOffset16; |
| 2536 if (!is_near(L, bits)) return false; |
| 2537 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2538 offset = GetOffset(offset, L, bits); |
| 2539 bltzc(scratch, offset); |
| 2540 } else if (IsZero(rt)) { |
| 2541 bits = OffsetSize::kOffset16; |
| 2542 if (!is_near(L, bits)) return false; |
| 2543 offset = GetOffset(offset, L, bits); |
| 2544 bgtzc(rs, offset); |
| 2545 } else { |
| 2546 bits = OffsetSize::kOffset16; |
| 2547 if (!is_near(L, bits)) return false; |
| 2548 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2549 DCHECK(!rs.is(scratch)); |
| 2550 offset = GetOffset(offset, L, bits); |
| 2551 bltc(scratch, rs, offset); |
2428 } | 2552 } |
2429 break; | 2553 break; |
2430 case greater_equal: | 2554 case greater_equal: |
2431 if (r2.is(zero_reg)) { | 2555 // rs >= rt |
2432 bgez(rs, offset); | 2556 if (rs.code() == rt.rm_.reg_code) { |
2433 } else { | 2557 bits = OffsetSize::kOffset26; |
2434 slt(scratch, rs, r2); | 2558 if (!is_near(L, bits)) return false; |
2435 beq(scratch, zero_reg, offset); | 2559 offset = GetOffset(offset, L, bits); |
| 2560 bc(offset); |
| 2561 } else if (rs.is(zero_reg)) { |
| 2562 bits = OffsetSize::kOffset16; |
| 2563 if (!is_near(L, bits)) return false; |
| 2564 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2565 offset = GetOffset(offset, L, bits); |
| 2566 blezc(scratch, offset); |
| 2567 } else if (IsZero(rt)) { |
| 2568 bits = OffsetSize::kOffset16; |
| 2569 if (!is_near(L, bits)) return false; |
| 2570 offset = GetOffset(offset, L, bits); |
| 2571 bgezc(rs, offset); |
| 2572 } else { |
| 2573 bits = OffsetSize::kOffset16; |
| 2574 if (!is_near(L, bits)) return false; |
| 2575 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2576 DCHECK(!rs.is(scratch)); |
| 2577 offset = GetOffset(offset, L, bits); |
| 2578 bgec(rs, scratch, offset); |
2436 } | 2579 } |
2437 break; | 2580 break; |
2438 case less: | 2581 case less: |
2439 if (r2.is(zero_reg)) { | 2582 // rs < rt |
2440 bltz(rs, offset); | 2583 if (rs.code() == rt.rm_.reg_code) { |
2441 } else { | 2584 break; // No code needs to be emitted. |
2442 slt(scratch, rs, r2); | 2585 } else if (rs.is(zero_reg)) { |
2443 bne(scratch, zero_reg, offset); | 2586 bits = OffsetSize::kOffset16; |
| 2587 if (!is_near(L, bits)) return false; |
| 2588 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2589 offset = GetOffset(offset, L, bits); |
| 2590 bgtzc(scratch, offset); |
| 2591 } else if (IsZero(rt)) { |
| 2592 bits = OffsetSize::kOffset16; |
| 2593 if (!is_near(L, bits)) return false; |
| 2594 offset = GetOffset(offset, L, bits); |
| 2595 bltzc(rs, offset); |
| 2596 } else { |
| 2597 bits = OffsetSize::kOffset16; |
| 2598 if (!is_near(L, bits)) return false; |
| 2599 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2600 DCHECK(!rs.is(scratch)); |
| 2601 offset = GetOffset(offset, L, bits); |
| 2602 bltc(rs, scratch, offset); |
2444 } | 2603 } |
2445 break; | 2604 break; |
2446 case less_equal: | 2605 case less_equal: |
2447 if (r2.is(zero_reg)) { | 2606 // rs <= rt |
2448 blez(rs, offset); | 2607 if (rs.code() == rt.rm_.reg_code) { |
2449 } else { | 2608 bits = OffsetSize::kOffset26; |
2450 slt(scratch, r2, rs); | 2609 if (!is_near(L, bits)) return false; |
2451 beq(scratch, zero_reg, offset); | 2610 offset = GetOffset(offset, L, bits); |
2452 } | 2611 bc(offset); |
2453 break; | 2612 } else if (rs.is(zero_reg)) { |
| 2613 bits = OffsetSize::kOffset16; |
| 2614 if (!is_near(L, bits)) return false; |
| 2615 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2616 offset = GetOffset(offset, L, bits); |
| 2617 bgezc(scratch, offset); |
| 2618 } else if (IsZero(rt)) { |
| 2619 bits = OffsetSize::kOffset16; |
| 2620 if (!is_near(L, bits)) return false; |
| 2621 offset = GetOffset(offset, L, bits); |
| 2622 blezc(rs, offset); |
| 2623 } else { |
| 2624 bits = OffsetSize::kOffset16; |
| 2625 if (!is_near(L, bits)) return false; |
| 2626 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2627 DCHECK(!rs.is(scratch)); |
| 2628 offset = GetOffset(offset, L, bits); |
| 2629 bgec(scratch, rs, offset); |
| 2630 } |
| 2631 break; |
| 2632 |
2454 // Unsigned comparison. | 2633 // Unsigned comparison. |
2455 case Ugreater: | 2634 case Ugreater: |
2456 if (r2.is(zero_reg)) { | 2635 // rs > rt |
2457 bne(rs, zero_reg, offset); | 2636 if (rs.code() == rt.rm_.reg_code) { |
2458 } else { | 2637 break; // No code needs to be emitted. |
2459 sltu(scratch, r2, rs); | 2638 } else if (rs.is(zero_reg)) { |
2460 bne(scratch, zero_reg, offset); | 2639 bits = OffsetSize::kOffset21; |
| 2640 if (!is_near(L, bits)) return false; |
| 2641 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2642 offset = GetOffset(offset, L, bits); |
| 2643 bnezc(scratch, offset); |
| 2644 } else if (IsZero(rt)) { |
| 2645 bits = OffsetSize::kOffset21; |
| 2646 if (!is_near(L, bits)) return false; |
| 2647 offset = GetOffset(offset, L, bits); |
| 2648 bnezc(rs, offset); |
| 2649 } else { |
| 2650 bits = OffsetSize::kOffset16; |
| 2651 if (!is_near(L, bits)) return false; |
| 2652 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2653 DCHECK(!rs.is(scratch)); |
| 2654 offset = GetOffset(offset, L, bits); |
| 2655 bltuc(scratch, rs, offset); |
2461 } | 2656 } |
2462 break; | 2657 break; |
2463 case Ugreater_equal: | 2658 case Ugreater_equal: |
2464 if (r2.is(zero_reg)) { | 2659 // rs >= rt |
2465 b(offset); | 2660 if (rs.code() == rt.rm_.reg_code) { |
2466 } else { | 2661 bits = OffsetSize::kOffset26; |
2467 sltu(scratch, rs, r2); | 2662 if (!is_near(L, bits)) return false; |
2468 beq(scratch, zero_reg, offset); | 2663 offset = GetOffset(offset, L, bits); |
| 2664 bc(offset); |
| 2665 } else if (rs.is(zero_reg)) { |
| 2666 bits = OffsetSize::kOffset21; |
| 2667 if (!is_near(L, bits)) return false; |
| 2668 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2669 offset = GetOffset(offset, L, bits); |
| 2670 beqzc(scratch, offset); |
| 2671 } else if (IsZero(rt)) { |
| 2672 bits = OffsetSize::kOffset26; |
| 2673 if (!is_near(L, bits)) return false; |
| 2674 offset = GetOffset(offset, L, bits); |
| 2675 bc(offset); |
| 2676 } else { |
| 2677 bits = OffsetSize::kOffset16; |
| 2678 if (!is_near(L, bits)) return false; |
| 2679 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2680 DCHECK(!rs.is(scratch)); |
| 2681 offset = GetOffset(offset, L, bits); |
| 2682 bgeuc(rs, scratch, offset); |
2469 } | 2683 } |
2470 break; | 2684 break; |
2471 case Uless: | 2685 case Uless: |
2472 if (r2.is(zero_reg)) { | 2686 // rs < rt |
2473 // No code needs to be emitted. | 2687 if (rs.code() == rt.rm_.reg_code) { |
2474 return; | 2688 break; // No code needs to be emitted. |
2475 } else { | 2689 } else if (rs.is(zero_reg)) { |
2476 sltu(scratch, rs, r2); | 2690 bits = OffsetSize::kOffset21; |
2477 bne(scratch, zero_reg, offset); | 2691 if (!is_near(L, bits)) return false; |
| 2692 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2693 offset = GetOffset(offset, L, bits); |
| 2694 bnezc(scratch, offset); |
| 2695 } else if (IsZero(rt)) { |
| 2696 break; // No code needs to be emitted. |
| 2697 } else { |
| 2698 bits = OffsetSize::kOffset16; |
| 2699 if (!is_near(L, bits)) return false; |
| 2700 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2701 DCHECK(!rs.is(scratch)); |
| 2702 offset = GetOffset(offset, L, bits); |
| 2703 bltuc(rs, scratch, offset); |
2478 } | 2704 } |
2479 break; | 2705 break; |
2480 case Uless_equal: | 2706 case Uless_equal: |
2481 if (r2.is(zero_reg)) { | 2707 // rs <= rt |
2482 beq(rs, zero_reg, offset); | 2708 if (rs.code() == rt.rm_.reg_code) { |
2483 } else { | 2709 bits = OffsetSize::kOffset26; |
2484 sltu(scratch, r2, rs); | 2710 if (!is_near(L, bits)) return false; |
2485 beq(scratch, zero_reg, offset); | 2711 offset = GetOffset(offset, L, bits); |
| 2712 bc(offset); |
| 2713 } else if (rs.is(zero_reg)) { |
| 2714 bits = OffsetSize::kOffset26; |
| 2715 if (!is_near(L, bits)) return false; |
| 2716 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2717 offset = GetOffset(offset, L, bits); |
| 2718 bc(offset); |
| 2719 } else if (IsZero(rt)) { |
| 2720 bits = OffsetSize::kOffset21; |
| 2721 if (!is_near(L, bits)) return false; |
| 2722 offset = GetOffset(offset, L, bits); |
| 2723 beqzc(rs, offset); |
| 2724 } else { |
| 2725 bits = OffsetSize::kOffset16; |
| 2726 if (!is_near(L, bits)) return false; |
| 2727 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 2728 DCHECK(!rs.is(scratch)); |
| 2729 offset = GetOffset(offset, L, bits); |
| 2730 bgeuc(scratch, rs, offset); |
2486 } | 2731 } |
2487 break; | 2732 break; |
2488 default: | 2733 default: |
2489 UNREACHABLE(); | 2734 UNREACHABLE(); |
2490 } | 2735 } |
2491 } else { | 2736 } |
2492 // Be careful to always use shifted_branch_offset only just before the | 2737 CheckTrampolinePoolQuick(1); |
2493 // branch instruction, as the location will be remember for patching the | 2738 return true; |
2494 // target. | 2739 } |
| 2740 |
| 2741 |
| 2742 bool MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond, |
| 2743 Register rs, const Operand& rt, |
| 2744 BranchDelaySlot bdslot) { |
| 2745 DCHECK(L == nullptr || offset == 0); |
| 2746 if (!is_near(L, OffsetSize::kOffset16)) return false; |
| 2747 |
| 2748 Register scratch = at; |
| 2749 int32_t offset32; |
| 2750 |
| 2751 // Be careful to always use shifted_branch_offset only just before the |
| 2752 // branch instruction, as the location will be remember for patching the |
| 2753 // target. |
| 2754 { |
2495 BlockTrampolinePoolScope block_trampoline_pool(this); | 2755 BlockTrampolinePoolScope block_trampoline_pool(this); |
2496 switch (cond) { | 2756 switch (cond) { |
2497 case cc_always: | 2757 case cc_always: |
2498 b(offset); | 2758 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
| 2759 b(offset32); |
2499 break; | 2760 break; |
2500 case eq: | 2761 case eq: |
2501 if (rt.imm64_ == 0) { | 2762 if (IsZero(rt)) { |
2502 beq(rs, zero_reg, offset); | 2763 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
| 2764 beq(rs, zero_reg, offset32); |
2503 } else { | 2765 } else { |
2504 // We don't want any other register but scratch clobbered. | 2766 // We don't want any other register but scratch clobbered. |
2505 DCHECK(!scratch.is(rs)); | 2767 scratch = GetRtAsRegisterHelper(rt, scratch); |
2506 r2 = scratch; | 2768 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2507 li(r2, rt); | 2769 beq(rs, scratch, offset32); |
2508 beq(rs, r2, offset); | |
2509 } | 2770 } |
2510 break; | 2771 break; |
2511 case ne: | 2772 case ne: |
2512 if (rt.imm64_ == 0) { | 2773 if (IsZero(rt)) { |
2513 bne(rs, zero_reg, offset); | 2774 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
| 2775 bne(rs, zero_reg, offset32); |
2514 } else { | 2776 } else { |
2515 // We don't want any other register but scratch clobbered. | 2777 // We don't want any other register but scratch clobbered. |
2516 DCHECK(!scratch.is(rs)); | 2778 scratch = GetRtAsRegisterHelper(rt, scratch); |
2517 r2 = scratch; | 2779 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2518 li(r2, rt); | 2780 bne(rs, scratch, offset32); |
2519 bne(rs, r2, offset); | 2781 } |
2520 } | 2782 break; |
2521 break; | 2783 |
2522 // Signed comparison. | 2784 // Signed comparison. |
2523 case greater: | 2785 case greater: |
2524 if (rt.imm64_ == 0) { | 2786 if (IsZero(rt)) { |
2525 bgtz(rs, offset); | 2787 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2526 } else { | 2788 bgtz(rs, offset32); |
2527 r2 = scratch; | 2789 } else { |
2528 li(r2, rt); | 2790 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
2529 slt(scratch, r2, rs); | 2791 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2530 bne(scratch, zero_reg, offset); | 2792 bne(scratch, zero_reg, offset32); |
2531 } | 2793 } |
2532 break; | 2794 break; |
2533 case greater_equal: | 2795 case greater_equal: |
2534 if (rt.imm64_ == 0) { | 2796 if (IsZero(rt)) { |
2535 bgez(rs, offset); | 2797 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2536 } else if (is_int16(rt.imm64_)) { | 2798 bgez(rs, offset32); |
2537 slti(scratch, rs, static_cast<int32_t>(rt.imm64_)); | 2799 } else { |
2538 beq(scratch, zero_reg, offset); | 2800 Slt(scratch, rs, rt); |
2539 } else { | 2801 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2540 r2 = scratch; | 2802 beq(scratch, zero_reg, offset32); |
2541 li(r2, rt); | |
2542 slt(scratch, rs, r2); | |
2543 beq(scratch, zero_reg, offset); | |
2544 } | 2803 } |
2545 break; | 2804 break; |
2546 case less: | 2805 case less: |
2547 if (rt.imm64_ == 0) { | 2806 if (IsZero(rt)) { |
2548 bltz(rs, offset); | 2807 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2549 } else if (is_int16(rt.imm64_)) { | 2808 bltz(rs, offset32); |
2550 slti(scratch, rs, static_cast<int32_t>(rt.imm64_)); | 2809 } else { |
2551 bne(scratch, zero_reg, offset); | 2810 Slt(scratch, rs, rt); |
2552 } else { | 2811 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2553 r2 = scratch; | 2812 bne(scratch, zero_reg, offset32); |
2554 li(r2, rt); | |
2555 slt(scratch, rs, r2); | |
2556 bne(scratch, zero_reg, offset); | |
2557 } | 2813 } |
2558 break; | 2814 break; |
2559 case less_equal: | 2815 case less_equal: |
2560 if (rt.imm64_ == 0) { | 2816 if (IsZero(rt)) { |
2561 blez(rs, offset); | 2817 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2562 } else { | 2818 blez(rs, offset32); |
2563 r2 = scratch; | 2819 } else { |
2564 li(r2, rt); | 2820 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
2565 slt(scratch, r2, rs); | 2821 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2566 beq(scratch, zero_reg, offset); | 2822 beq(scratch, zero_reg, offset32); |
2567 } | 2823 } |
2568 break; | 2824 break; |
| 2825 |
2569 // Unsigned comparison. | 2826 // Unsigned comparison. |
2570 case Ugreater: | 2827 case Ugreater: |
2571 if (rt.imm64_ == 0) { | 2828 if (IsZero(rt)) { |
2572 bne(rs, zero_reg, offset); | 2829 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2573 } else { | 2830 bne(rs, zero_reg, offset32); |
2574 r2 = scratch; | 2831 } else { |
2575 li(r2, rt); | 2832 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
2576 sltu(scratch, r2, rs); | 2833 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2577 bne(scratch, zero_reg, offset); | 2834 bne(scratch, zero_reg, offset32); |
2578 } | 2835 } |
2579 break; | 2836 break; |
2580 case Ugreater_equal: | 2837 case Ugreater_equal: |
2581 if (rt.imm64_ == 0) { | 2838 if (IsZero(rt)) { |
2582 b(offset); | 2839 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2583 } else if (is_int16(rt.imm64_)) { | 2840 b(offset32); |
2584 sltiu(scratch, rs, static_cast<int32_t>(rt.imm64_)); | 2841 } else { |
2585 beq(scratch, zero_reg, offset); | 2842 Sltu(scratch, rs, rt); |
2586 } else { | 2843 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2587 r2 = scratch; | 2844 beq(scratch, zero_reg, offset32); |
2588 li(r2, rt); | |
2589 sltu(scratch, rs, r2); | |
2590 beq(scratch, zero_reg, offset); | |
2591 } | 2845 } |
2592 break; | 2846 break; |
2593 case Uless: | 2847 case Uless: |
2594 if (rt.imm64_ == 0) { | 2848 if (IsZero(rt)) { |
2595 // No code needs to be emitted. | 2849 return true; // No code needs to be emitted. |
2596 return; | 2850 } else { |
2597 } else if (is_int16(rt.imm64_)) { | 2851 Sltu(scratch, rs, rt); |
2598 sltiu(scratch, rs, static_cast<int32_t>(rt.imm64_)); | 2852 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2599 bne(scratch, zero_reg, offset); | 2853 bne(scratch, zero_reg, offset32); |
2600 } else { | |
2601 r2 = scratch; | |
2602 li(r2, rt); | |
2603 sltu(scratch, rs, r2); | |
2604 bne(scratch, zero_reg, offset); | |
2605 } | 2854 } |
2606 break; | 2855 break; |
2607 case Uless_equal: | 2856 case Uless_equal: |
2608 if (rt.imm64_ == 0) { | 2857 if (IsZero(rt)) { |
2609 beq(rs, zero_reg, offset); | 2858 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2610 } else { | 2859 beq(rs, zero_reg, offset32); |
2611 r2 = scratch; | 2860 } else { |
2612 li(r2, rt); | 2861 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
2613 sltu(scratch, r2, rs); | 2862 offset32 = GetOffset(offset, L, OffsetSize::kOffset16); |
2614 beq(scratch, zero_reg, offset); | 2863 beq(scratch, zero_reg, offset32); |
2615 } | 2864 } |
2616 break; | 2865 break; |
2617 default: | 2866 default: |
2618 UNREACHABLE(); | 2867 UNREACHABLE(); |
2619 } | 2868 } |
2620 } | 2869 } |
| 2870 |
2621 // Emit a nop in the branch delay slot if required. | 2871 // Emit a nop in the branch delay slot if required. |
2622 if (bdslot == PROTECT) | 2872 if (bdslot == PROTECT) |
2623 nop(); | 2873 nop(); |
2624 } | 2874 |
2625 | 2875 return true; |
2626 | 2876 } |
2627 void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) { | 2877 |
2628 // We use branch_offset as an argument for the branch instructions to be sure | 2878 |
2629 // it is called just before generating the branch instruction, as needed. | 2879 bool MacroAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond, |
2630 | 2880 Register rs, const Operand& rt, |
2631 b(shifted_branch_offset(L, false)); | 2881 BranchDelaySlot bdslot) { |
2632 | 2882 BRANCH_ARGS_CHECK(cond, rs, rt); |
2633 // Emit a nop in the branch delay slot if required. | 2883 |
2634 if (bdslot == PROTECT) | 2884 if (!L) { |
2635 nop(); | 2885 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
| 2886 DCHECK(is_int26(offset)); |
| 2887 return BranchShortHelperR6(offset, nullptr, cond, rs, rt); |
| 2888 } else { |
| 2889 DCHECK(is_int16(offset)); |
| 2890 return BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot); |
| 2891 } |
| 2892 } else { |
| 2893 DCHECK(offset == 0); |
| 2894 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
| 2895 return BranchShortHelperR6(0, L, cond, rs, rt); |
| 2896 } else { |
| 2897 return BranchShortHelper(0, L, cond, rs, rt, bdslot); |
| 2898 } |
| 2899 } |
| 2900 return false; |
| 2901 } |
| 2902 |
| 2903 |
| 2904 void MacroAssembler::BranchShort(int32_t offset, Condition cond, Register rs, |
| 2905 const Operand& rt, BranchDelaySlot bdslot) { |
| 2906 BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot); |
2636 } | 2907 } |
2637 | 2908 |
2638 | 2909 |
2639 void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, | 2910 void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, |
2640 const Operand& rt, | 2911 const Operand& rt, BranchDelaySlot bdslot) { |
2641 BranchDelaySlot bdslot) { | 2912 BranchShortCheck(0, L, cond, rs, rt, bdslot); |
2642 BRANCH_ARGS_CHECK(cond, rs, rt); | 2913 } |
2643 | 2914 |
2644 int32_t offset = 0; | 2915 |
2645 Register r2 = no_reg; | 2916 void MacroAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) { |
2646 Register scratch = at; | |
2647 if (rt.is_reg()) { | |
2648 BlockTrampolinePoolScope block_trampoline_pool(this); | |
2649 r2 = rt.rm_; | |
2650 // Be careful to always use shifted_branch_offset only just before the | |
2651 // branch instruction, as the location will be remember for patching the | |
2652 // target. | |
2653 switch (cond) { | |
2654 case cc_always: | |
2655 offset = shifted_branch_offset(L, false); | |
2656 b(offset); | |
2657 break; | |
2658 case eq: | |
2659 offset = shifted_branch_offset(L, false); | |
2660 beq(rs, r2, offset); | |
2661 break; | |
2662 case ne: | |
2663 offset = shifted_branch_offset(L, false); | |
2664 bne(rs, r2, offset); | |
2665 break; | |
2666 // Signed comparison. | |
2667 case greater: | |
2668 if (r2.is(zero_reg)) { | |
2669 offset = shifted_branch_offset(L, false); | |
2670 bgtz(rs, offset); | |
2671 } else { | |
2672 slt(scratch, r2, rs); | |
2673 offset = shifted_branch_offset(L, false); | |
2674 bne(scratch, zero_reg, offset); | |
2675 } | |
2676 break; | |
2677 case greater_equal: | |
2678 if (r2.is(zero_reg)) { | |
2679 offset = shifted_branch_offset(L, false); | |
2680 bgez(rs, offset); | |
2681 } else { | |
2682 slt(scratch, rs, r2); | |
2683 offset = shifted_branch_offset(L, false); | |
2684 beq(scratch, zero_reg, offset); | |
2685 } | |
2686 break; | |
2687 case less: | |
2688 if (r2.is(zero_reg)) { | |
2689 offset = shifted_branch_offset(L, false); | |
2690 bltz(rs, offset); | |
2691 } else { | |
2692 slt(scratch, rs, r2); | |
2693 offset = shifted_branch_offset(L, false); | |
2694 bne(scratch, zero_reg, offset); | |
2695 } | |
2696 break; | |
2697 case less_equal: | |
2698 if (r2.is(zero_reg)) { | |
2699 offset = shifted_branch_offset(L, false); | |
2700 blez(rs, offset); | |
2701 } else { | |
2702 slt(scratch, r2, rs); | |
2703 offset = shifted_branch_offset(L, false); | |
2704 beq(scratch, zero_reg, offset); | |
2705 } | |
2706 break; | |
2707 // Unsigned comparison. | |
2708 case Ugreater: | |
2709 if (r2.is(zero_reg)) { | |
2710 offset = shifted_branch_offset(L, false); | |
2711 bne(rs, zero_reg, offset); | |
2712 } else { | |
2713 sltu(scratch, r2, rs); | |
2714 offset = shifted_branch_offset(L, false); | |
2715 bne(scratch, zero_reg, offset); | |
2716 } | |
2717 break; | |
2718 case Ugreater_equal: | |
2719 if (r2.is(zero_reg)) { | |
2720 offset = shifted_branch_offset(L, false); | |
2721 b(offset); | |
2722 } else { | |
2723 sltu(scratch, rs, r2); | |
2724 offset = shifted_branch_offset(L, false); | |
2725 beq(scratch, zero_reg, offset); | |
2726 } | |
2727 break; | |
2728 case Uless: | |
2729 if (r2.is(zero_reg)) { | |
2730 // No code needs to be emitted. | |
2731 return; | |
2732 } else { | |
2733 sltu(scratch, rs, r2); | |
2734 offset = shifted_branch_offset(L, false); | |
2735 bne(scratch, zero_reg, offset); | |
2736 } | |
2737 break; | |
2738 case Uless_equal: | |
2739 if (r2.is(zero_reg)) { | |
2740 offset = shifted_branch_offset(L, false); | |
2741 beq(rs, zero_reg, offset); | |
2742 } else { | |
2743 sltu(scratch, r2, rs); | |
2744 offset = shifted_branch_offset(L, false); | |
2745 beq(scratch, zero_reg, offset); | |
2746 } | |
2747 break; | |
2748 default: | |
2749 UNREACHABLE(); | |
2750 } | |
2751 } else { | |
2752 // Be careful to always use shifted_branch_offset only just before the | |
2753 // branch instruction, as the location will be remember for patching the | |
2754 // target. | |
2755 BlockTrampolinePoolScope block_trampoline_pool(this); | |
2756 switch (cond) { | |
2757 case cc_always: | |
2758 offset = shifted_branch_offset(L, false); | |
2759 b(offset); | |
2760 break; | |
2761 case eq: | |
2762 if (rt.imm64_ == 0) { | |
2763 offset = shifted_branch_offset(L, false); | |
2764 beq(rs, zero_reg, offset); | |
2765 } else { | |
2766 DCHECK(!scratch.is(rs)); | |
2767 r2 = scratch; | |
2768 li(r2, rt); | |
2769 offset = shifted_branch_offset(L, false); | |
2770 beq(rs, r2, offset); | |
2771 } | |
2772 break; | |
2773 case ne: | |
2774 if (rt.imm64_ == 0) { | |
2775 offset = shifted_branch_offset(L, false); | |
2776 bne(rs, zero_reg, offset); | |
2777 } else { | |
2778 DCHECK(!scratch.is(rs)); | |
2779 r2 = scratch; | |
2780 li(r2, rt); | |
2781 offset = shifted_branch_offset(L, false); | |
2782 bne(rs, r2, offset); | |
2783 } | |
2784 break; | |
2785 // Signed comparison. | |
2786 case greater: | |
2787 if (rt.imm64_ == 0) { | |
2788 offset = shifted_branch_offset(L, false); | |
2789 bgtz(rs, offset); | |
2790 } else { | |
2791 DCHECK(!scratch.is(rs)); | |
2792 r2 = scratch; | |
2793 li(r2, rt); | |
2794 slt(scratch, r2, rs); | |
2795 offset = shifted_branch_offset(L, false); | |
2796 bne(scratch, zero_reg, offset); | |
2797 } | |
2798 break; | |
2799 case greater_equal: | |
2800 if (rt.imm64_ == 0) { | |
2801 offset = shifted_branch_offset(L, false); | |
2802 bgez(rs, offset); | |
2803 } else if (is_int16(rt.imm64_)) { | |
2804 slti(scratch, rs, static_cast<int32_t>(rt.imm64_)); | |
2805 offset = shifted_branch_offset(L, false); | |
2806 beq(scratch, zero_reg, offset); | |
2807 } else { | |
2808 DCHECK(!scratch.is(rs)); | |
2809 r2 = scratch; | |
2810 li(r2, rt); | |
2811 slt(scratch, rs, r2); | |
2812 offset = shifted_branch_offset(L, false); | |
2813 beq(scratch, zero_reg, offset); | |
2814 } | |
2815 break; | |
2816 case less: | |
2817 if (rt.imm64_ == 0) { | |
2818 offset = shifted_branch_offset(L, false); | |
2819 bltz(rs, offset); | |
2820 } else if (is_int16(rt.imm64_)) { | |
2821 slti(scratch, rs, static_cast<int32_t>(rt.imm64_)); | |
2822 offset = shifted_branch_offset(L, false); | |
2823 bne(scratch, zero_reg, offset); | |
2824 } else { | |
2825 DCHECK(!scratch.is(rs)); | |
2826 r2 = scratch; | |
2827 li(r2, rt); | |
2828 slt(scratch, rs, r2); | |
2829 offset = shifted_branch_offset(L, false); | |
2830 bne(scratch, zero_reg, offset); | |
2831 } | |
2832 break; | |
2833 case less_equal: | |
2834 if (rt.imm64_ == 0) { | |
2835 offset = shifted_branch_offset(L, false); | |
2836 blez(rs, offset); | |
2837 } else { | |
2838 DCHECK(!scratch.is(rs)); | |
2839 r2 = scratch; | |
2840 li(r2, rt); | |
2841 slt(scratch, r2, rs); | |
2842 offset = shifted_branch_offset(L, false); | |
2843 beq(scratch, zero_reg, offset); | |
2844 } | |
2845 break; | |
2846 // Unsigned comparison. | |
2847 case Ugreater: | |
2848 if (rt.imm64_ == 0) { | |
2849 offset = shifted_branch_offset(L, false); | |
2850 bne(rs, zero_reg, offset); | |
2851 } else { | |
2852 DCHECK(!scratch.is(rs)); | |
2853 r2 = scratch; | |
2854 li(r2, rt); | |
2855 sltu(scratch, r2, rs); | |
2856 offset = shifted_branch_offset(L, false); | |
2857 bne(scratch, zero_reg, offset); | |
2858 } | |
2859 break; | |
2860 case Ugreater_equal: | |
2861 if (rt.imm64_ == 0) { | |
2862 offset = shifted_branch_offset(L, false); | |
2863 b(offset); | |
2864 } else if (is_int16(rt.imm64_)) { | |
2865 sltiu(scratch, rs, static_cast<int32_t>(rt.imm64_)); | |
2866 offset = shifted_branch_offset(L, false); | |
2867 beq(scratch, zero_reg, offset); | |
2868 } else { | |
2869 DCHECK(!scratch.is(rs)); | |
2870 r2 = scratch; | |
2871 li(r2, rt); | |
2872 sltu(scratch, rs, r2); | |
2873 offset = shifted_branch_offset(L, false); | |
2874 beq(scratch, zero_reg, offset); | |
2875 } | |
2876 break; | |
2877 case Uless: | |
2878 if (rt.imm64_ == 0) { | |
2879 // No code needs to be emitted. | |
2880 return; | |
2881 } else if (is_int16(rt.imm64_)) { | |
2882 sltiu(scratch, rs, static_cast<int32_t>(rt.imm64_)); | |
2883 offset = shifted_branch_offset(L, false); | |
2884 bne(scratch, zero_reg, offset); | |
2885 } else { | |
2886 DCHECK(!scratch.is(rs)); | |
2887 r2 = scratch; | |
2888 li(r2, rt); | |
2889 sltu(scratch, rs, r2); | |
2890 offset = shifted_branch_offset(L, false); | |
2891 bne(scratch, zero_reg, offset); | |
2892 } | |
2893 break; | |
2894 case Uless_equal: | |
2895 if (rt.imm64_ == 0) { | |
2896 offset = shifted_branch_offset(L, false); | |
2897 beq(rs, zero_reg, offset); | |
2898 } else { | |
2899 DCHECK(!scratch.is(rs)); | |
2900 r2 = scratch; | |
2901 li(r2, rt); | |
2902 sltu(scratch, r2, rs); | |
2903 offset = shifted_branch_offset(L, false); | |
2904 beq(scratch, zero_reg, offset); | |
2905 } | |
2906 break; | |
2907 default: | |
2908 UNREACHABLE(); | |
2909 } | |
2910 } | |
2911 // Check that offset could actually hold on an int16_t. | |
2912 DCHECK(is_int16(offset)); | |
2913 // Emit a nop in the branch delay slot if required. | |
2914 if (bdslot == PROTECT) | |
2915 nop(); | |
2916 } | |
2917 | |
2918 | |
2919 void MacroAssembler::BranchAndLink(int16_t offset, BranchDelaySlot bdslot) { | |
2920 BranchAndLinkShort(offset, bdslot); | 2917 BranchAndLinkShort(offset, bdslot); |
2921 } | 2918 } |
2922 | 2919 |
2923 | 2920 |
2924 void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs, | 2921 void MacroAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs, |
2925 const Operand& rt, | 2922 const Operand& rt, BranchDelaySlot bdslot) { |
2926 BranchDelaySlot bdslot) { | 2923 bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt, bdslot); |
2927 BranchAndLinkShort(offset, cond, rs, rt, bdslot); | 2924 DCHECK(is_near); |
| 2925 USE(is_near); |
2928 } | 2926 } |
2929 | 2927 |
2930 | 2928 |
2931 void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) { | 2929 void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) { |
2932 if (L->is_bound()) { | 2930 if (L->is_bound()) { |
2933 if (is_near(L)) { | 2931 if (is_near_branch(L)) { |
2934 BranchAndLinkShort(L, bdslot); | 2932 BranchAndLinkShort(L, bdslot); |
2935 } else { | 2933 } else { |
2936 Jal(L, bdslot); | 2934 BranchAndLinkLong(L, bdslot); |
2937 } | 2935 } |
2938 } else { | 2936 } else { |
2939 if (is_trampoline_emitted()) { | 2937 if (is_trampoline_emitted()) { |
2940 Jal(L, bdslot); | 2938 BranchAndLinkLong(L, bdslot); |
2941 } else { | 2939 } else { |
2942 BranchAndLinkShort(L, bdslot); | 2940 BranchAndLinkShort(L, bdslot); |
2943 } | 2941 } |
2944 } | 2942 } |
2945 } | 2943 } |
2946 | 2944 |
2947 | 2945 |
2948 void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, | 2946 void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, |
2949 const Operand& rt, | 2947 const Operand& rt, |
2950 BranchDelaySlot bdslot) { | 2948 BranchDelaySlot bdslot) { |
2951 if (L->is_bound()) { | 2949 if (L->is_bound()) { |
2952 if (is_near(L)) { | 2950 if (!BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot)) { |
2953 BranchAndLinkShort(L, cond, rs, rt, bdslot); | |
2954 } else { | |
2955 Label skip; | 2951 Label skip; |
2956 Condition neg_cond = NegateCondition(cond); | 2952 Condition neg_cond = NegateCondition(cond); |
2957 BranchShort(&skip, neg_cond, rs, rt); | 2953 BranchShort(&skip, neg_cond, rs, rt); |
2958 Jal(L, bdslot); | 2954 BranchAndLinkLong(L, bdslot); |
2959 bind(&skip); | 2955 bind(&skip); |
2960 } | 2956 } |
2961 } else { | 2957 } else { |
2962 if (is_trampoline_emitted()) { | 2958 if (is_trampoline_emitted()) { |
2963 Label skip; | 2959 Label skip; |
2964 Condition neg_cond = NegateCondition(cond); | 2960 Condition neg_cond = NegateCondition(cond); |
2965 BranchShort(&skip, neg_cond, rs, rt); | 2961 BranchShort(&skip, neg_cond, rs, rt); |
2966 Jal(L, bdslot); | 2962 BranchAndLinkLong(L, bdslot); |
2967 bind(&skip); | 2963 bind(&skip); |
2968 } else { | 2964 } else { |
2969 BranchAndLinkShort(L, cond, rs, rt, bdslot); | 2965 BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot); |
2970 } | 2966 } |
2971 } | 2967 } |
2972 } | 2968 } |
2973 | 2969 |
2974 | 2970 |
2975 // We need to use a bgezal or bltzal, but they can't be used directly with the | 2971 void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, |
2976 // slt instructions. We could use sub or add instead but we would miss overflow | 2972 BranchDelaySlot bdslot) { |
2977 // cases, so we keep slt and add an intermediate third instruction. | 2973 DCHECK(L == nullptr || offset == 0); |
2978 void MacroAssembler::BranchAndLinkShort(int16_t offset, | 2974 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
2979 BranchDelaySlot bdslot) { | |
2980 bal(offset); | 2975 bal(offset); |
2981 | 2976 |
2982 // Emit a nop in the branch delay slot if required. | 2977 // Emit a nop in the branch delay slot if required. |
2983 if (bdslot == PROTECT) | 2978 if (bdslot == PROTECT) |
2984 nop(); | 2979 nop(); |
2985 } | 2980 } |
2986 | 2981 |
2987 | 2982 |
2988 void MacroAssembler::BranchAndLinkShort(int16_t offset, Condition cond, | 2983 void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) { |
2989 Register rs, const Operand& rt, | 2984 DCHECK(L == nullptr || offset == 0); |
| 2985 offset = GetOffset(offset, L, OffsetSize::kOffset26); |
| 2986 balc(offset); |
| 2987 } |
| 2988 |
| 2989 |
| 2990 void MacroAssembler::BranchAndLinkShort(int32_t offset, |
2990 BranchDelaySlot bdslot) { | 2991 BranchDelaySlot bdslot) { |
2991 BRANCH_ARGS_CHECK(cond, rs, rt); | 2992 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
2992 Register r2 = no_reg; | 2993 DCHECK(is_int26(offset)); |
2993 Register scratch = at; | 2994 BranchAndLinkShortHelperR6(offset, nullptr); |
2994 | 2995 } else { |
2995 if (rt.is_reg()) { | 2996 DCHECK(is_int16(offset)); |
2996 r2 = rt.rm_; | 2997 BranchAndLinkShortHelper(offset, nullptr, bdslot); |
2997 } else if (cond != cc_always) { | 2998 } |
2998 r2 = scratch; | 2999 } |
2999 li(r2, rt); | 3000 |
3000 } | 3001 |
3001 | 3002 void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { |
3002 { | 3003 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
3003 BlockTrampolinePoolScope block_trampoline_pool(this); | 3004 BranchAndLinkShortHelperR6(0, L); |
3004 switch (cond) { | 3005 } else { |
3005 case cc_always: | 3006 BranchAndLinkShortHelper(0, L, bdslot); |
3006 bal(offset); | 3007 } |
3007 break; | 3008 } |
3008 case eq: | 3009 |
3009 bne(rs, r2, 2); | 3010 |
3010 nop(); | 3011 bool MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L, |
3011 bal(offset); | 3012 Condition cond, Register rs, |
3012 break; | 3013 const Operand& rt) { |
3013 case ne: | 3014 DCHECK(L == nullptr || offset == 0); |
3014 beq(rs, r2, 2); | 3015 Register scratch = rs.is(at) ? t8 : at; |
3015 nop(); | 3016 OffsetSize bits = OffsetSize::kOffset16; |
3016 bal(offset); | 3017 |
3017 break; | 3018 BlockTrampolinePoolScope block_trampoline_pool(this); |
3018 | 3019 DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset)); |
3019 // Signed comparison. | 3020 switch (cond) { |
3020 case greater: | 3021 case cc_always: |
3021 // rs > rt | 3022 bits = OffsetSize::kOffset26; |
3022 slt(scratch, r2, rs); | 3023 if (!is_near(L, bits)) return false; |
3023 beq(scratch, zero_reg, 2); | 3024 offset = GetOffset(offset, L, bits); |
3024 nop(); | 3025 balc(offset); |
3025 bal(offset); | 3026 break; |
3026 break; | 3027 case eq: |
3027 case greater_equal: | 3028 if (!is_near(L, bits)) return false; |
3028 // rs >= rt | 3029 Subu(scratch, rs, rt); |
3029 slt(scratch, rs, r2); | 3030 offset = GetOffset(offset, L, bits); |
3030 bne(scratch, zero_reg, 2); | 3031 beqzalc(scratch, offset); |
3031 nop(); | 3032 break; |
3032 bal(offset); | 3033 case ne: |
3033 break; | 3034 if (!is_near(L, bits)) return false; |
3034 case less: | 3035 Subu(scratch, rs, rt); |
3035 // rs < r2 | 3036 offset = GetOffset(offset, L, bits); |
3036 slt(scratch, rs, r2); | 3037 bnezalc(scratch, offset); |
3037 bne(scratch, zero_reg, 2); | 3038 break; |
3038 nop(); | 3039 |
3039 bal(offset); | 3040 // Signed comparison. |
3040 break; | 3041 case greater: |
3041 case less_equal: | 3042 // rs > rt |
3042 // rs <= r2 | 3043 if (rs.code() == rt.rm_.reg_code) { |
3043 slt(scratch, r2, rs); | 3044 break; // No code needs to be emitted. |
3044 bne(scratch, zero_reg, 2); | 3045 } else if (rs.is(zero_reg)) { |
3045 nop(); | 3046 if (!is_near(L, bits)) return false; |
3046 bal(offset); | 3047 scratch = GetRtAsRegisterHelper(rt, scratch); |
3047 break; | 3048 offset = GetOffset(offset, L, bits); |
3048 | 3049 bltzalc(scratch, offset); |
3049 | 3050 } else if (IsZero(rt)) { |
3050 // Unsigned comparison. | 3051 if (!is_near(L, bits)) return false; |
3051 case Ugreater: | 3052 offset = GetOffset(offset, L, bits); |
3052 // rs > rt | 3053 bgtzalc(rs, offset); |
3053 sltu(scratch, r2, rs); | 3054 } else { |
3054 beq(scratch, zero_reg, 2); | 3055 if (!is_near(L, bits)) return false; |
3055 nop(); | 3056 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
3056 bal(offset); | 3057 offset = GetOffset(offset, L, bits); |
3057 break; | 3058 bnezalc(scratch, offset); |
3058 case Ugreater_equal: | 3059 } |
3059 // rs >= rt | 3060 break; |
3060 sltu(scratch, rs, r2); | 3061 case greater_equal: |
3061 bne(scratch, zero_reg, 2); | 3062 // rs >= rt |
3062 nop(); | 3063 if (rs.code() == rt.rm_.reg_code) { |
3063 bal(offset); | 3064 bits = OffsetSize::kOffset26; |
3064 break; | 3065 if (!is_near(L, bits)) return false; |
3065 case Uless: | 3066 offset = GetOffset(offset, L, bits); |
3066 // rs < r2 | 3067 balc(offset); |
3067 sltu(scratch, rs, r2); | 3068 } else if (rs.is(zero_reg)) { |
3068 bne(scratch, zero_reg, 2); | 3069 if (!is_near(L, bits)) return false; |
3069 nop(); | 3070 scratch = GetRtAsRegisterHelper(rt, scratch); |
3070 bal(offset); | 3071 offset = GetOffset(offset, L, bits); |
3071 break; | 3072 blezalc(scratch, offset); |
3072 case Uless_equal: | 3073 } else if (IsZero(rt)) { |
3073 // rs <= r2 | 3074 if (!is_near(L, bits)) return false; |
3074 sltu(scratch, r2, rs); | 3075 offset = GetOffset(offset, L, bits); |
3075 bne(scratch, zero_reg, 2); | 3076 bgezalc(rs, offset); |
3076 nop(); | 3077 } else { |
3077 bal(offset); | 3078 if (!is_near(L, bits)) return false; |
3078 break; | 3079 Slt(scratch, rs, rt); |
3079 default: | 3080 offset = GetOffset(offset, L, bits); |
3080 UNREACHABLE(); | 3081 beqzalc(scratch, offset); |
3081 } | 3082 } |
3082 } | 3083 break; |
| 3084 case less: |
| 3085 // rs < rt |
| 3086 if (rs.code() == rt.rm_.reg_code) { |
| 3087 break; // No code needs to be emitted. |
| 3088 } else if (rs.is(zero_reg)) { |
| 3089 if (!is_near(L, bits)) return false; |
| 3090 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 3091 offset = GetOffset(offset, L, bits); |
| 3092 bgtzalc(scratch, offset); |
| 3093 } else if (IsZero(rt)) { |
| 3094 if (!is_near(L, bits)) return false; |
| 3095 offset = GetOffset(offset, L, bits); |
| 3096 bltzalc(rs, offset); |
| 3097 } else { |
| 3098 if (!is_near(L, bits)) return false; |
| 3099 Slt(scratch, rs, rt); |
| 3100 offset = GetOffset(offset, L, bits); |
| 3101 bnezalc(scratch, offset); |
| 3102 } |
| 3103 break; |
| 3104 case less_equal: |
| 3105 // rs <= r2 |
| 3106 if (rs.code() == rt.rm_.reg_code) { |
| 3107 bits = OffsetSize::kOffset26; |
| 3108 if (!is_near(L, bits)) return false; |
| 3109 offset = GetOffset(offset, L, bits); |
| 3110 balc(offset); |
| 3111 } else if (rs.is(zero_reg)) { |
| 3112 if (!is_near(L, bits)) return false; |
| 3113 scratch = GetRtAsRegisterHelper(rt, scratch); |
| 3114 offset = GetOffset(offset, L, bits); |
| 3115 bgezalc(scratch, offset); |
| 3116 } else if (IsZero(rt)) { |
| 3117 if (!is_near(L, bits)) return false; |
| 3118 offset = GetOffset(offset, L, bits); |
| 3119 blezalc(rs, offset); |
| 3120 } else { |
| 3121 if (!is_near(L, bits)) return false; |
| 3122 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3123 offset = GetOffset(offset, L, bits); |
| 3124 beqzalc(scratch, offset); |
| 3125 } |
| 3126 break; |
| 3127 |
| 3128 |
| 3129 // Unsigned comparison. |
| 3130 case Ugreater: |
| 3131 // rs > r2 |
| 3132 if (!is_near(L, bits)) return false; |
| 3133 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3134 offset = GetOffset(offset, L, bits); |
| 3135 bnezalc(scratch, offset); |
| 3136 break; |
| 3137 case Ugreater_equal: |
| 3138 // rs >= r2 |
| 3139 if (!is_near(L, bits)) return false; |
| 3140 Sltu(scratch, rs, rt); |
| 3141 offset = GetOffset(offset, L, bits); |
| 3142 beqzalc(scratch, offset); |
| 3143 break; |
| 3144 case Uless: |
| 3145 // rs < r2 |
| 3146 if (!is_near(L, bits)) return false; |
| 3147 Sltu(scratch, rs, rt); |
| 3148 offset = GetOffset(offset, L, bits); |
| 3149 bnezalc(scratch, offset); |
| 3150 break; |
| 3151 case Uless_equal: |
| 3152 // rs <= r2 |
| 3153 if (!is_near(L, bits)) return false; |
| 3154 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3155 offset = GetOffset(offset, L, bits); |
| 3156 beqzalc(scratch, offset); |
| 3157 break; |
| 3158 default: |
| 3159 UNREACHABLE(); |
| 3160 } |
| 3161 return true; |
| 3162 } |
| 3163 |
| 3164 |
| 3165 // Pre r6 we need to use a bgezal or bltzal, but they can't be used directly |
| 3166 // with the slt instructions. We could use sub or add instead but we would miss |
| 3167 // overflow cases, so we keep slt and add an intermediate third instruction. |
| 3168 bool MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, |
| 3169 Condition cond, Register rs, |
| 3170 const Operand& rt, |
| 3171 BranchDelaySlot bdslot) { |
| 3172 DCHECK(L == nullptr || offset == 0); |
| 3173 if (!is_near(L, OffsetSize::kOffset16)) return false; |
| 3174 |
| 3175 Register scratch = t8; |
| 3176 BlockTrampolinePoolScope block_trampoline_pool(this); |
| 3177 |
| 3178 switch (cond) { |
| 3179 case cc_always: |
| 3180 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3181 bal(offset); |
| 3182 break; |
| 3183 case eq: |
| 3184 bne(rs, GetRtAsRegisterHelper(rt, scratch), 2); |
| 3185 nop(); |
| 3186 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3187 bal(offset); |
| 3188 break; |
| 3189 case ne: |
| 3190 beq(rs, GetRtAsRegisterHelper(rt, scratch), 2); |
| 3191 nop(); |
| 3192 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3193 bal(offset); |
| 3194 break; |
| 3195 |
| 3196 // Signed comparison. |
| 3197 case greater: |
| 3198 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3199 addiu(scratch, scratch, -1); |
| 3200 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3201 bgezal(scratch, offset); |
| 3202 break; |
| 3203 case greater_equal: |
| 3204 Slt(scratch, rs, rt); |
| 3205 addiu(scratch, scratch, -1); |
| 3206 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3207 bltzal(scratch, offset); |
| 3208 break; |
| 3209 case less: |
| 3210 Slt(scratch, rs, rt); |
| 3211 addiu(scratch, scratch, -1); |
| 3212 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3213 bgezal(scratch, offset); |
| 3214 break; |
| 3215 case less_equal: |
| 3216 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3217 addiu(scratch, scratch, -1); |
| 3218 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3219 bltzal(scratch, offset); |
| 3220 break; |
| 3221 |
| 3222 // Unsigned comparison. |
| 3223 case Ugreater: |
| 3224 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3225 addiu(scratch, scratch, -1); |
| 3226 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3227 bgezal(scratch, offset); |
| 3228 break; |
| 3229 case Ugreater_equal: |
| 3230 Sltu(scratch, rs, rt); |
| 3231 addiu(scratch, scratch, -1); |
| 3232 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3233 bltzal(scratch, offset); |
| 3234 break; |
| 3235 case Uless: |
| 3236 Sltu(scratch, rs, rt); |
| 3237 addiu(scratch, scratch, -1); |
| 3238 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3239 bgezal(scratch, offset); |
| 3240 break; |
| 3241 case Uless_equal: |
| 3242 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| 3243 addiu(scratch, scratch, -1); |
| 3244 offset = GetOffset(offset, L, OffsetSize::kOffset16); |
| 3245 bltzal(scratch, offset); |
| 3246 break; |
| 3247 |
| 3248 default: |
| 3249 UNREACHABLE(); |
| 3250 } |
| 3251 |
3083 // Emit a nop in the branch delay slot if required. | 3252 // Emit a nop in the branch delay slot if required. |
3084 if (bdslot == PROTECT) | 3253 if (bdslot == PROTECT) |
3085 nop(); | 3254 nop(); |
3086 } | 3255 |
3087 | 3256 return true; |
3088 | 3257 } |
3089 void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { | 3258 |
3090 bal(shifted_branch_offset(L, false)); | 3259 |
3091 | 3260 bool MacroAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L, |
3092 // Emit a nop in the branch delay slot if required. | 3261 Condition cond, Register rs, |
3093 if (bdslot == PROTECT) | 3262 const Operand& rt, |
3094 nop(); | 3263 BranchDelaySlot bdslot) { |
3095 } | |
3096 | |
3097 | |
3098 void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs, | |
3099 const Operand& rt, | |
3100 BranchDelaySlot bdslot) { | |
3101 BRANCH_ARGS_CHECK(cond, rs, rt); | 3264 BRANCH_ARGS_CHECK(cond, rs, rt); |
3102 | 3265 |
3103 int32_t offset = 0; | 3266 if (!L) { |
3104 Register r2 = no_reg; | 3267 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
3105 Register scratch = at; | 3268 DCHECK(is_int26(offset)); |
3106 if (rt.is_reg()) { | 3269 return BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt); |
3107 r2 = rt.rm_; | 3270 } else { |
3108 } else if (cond != cc_always) { | 3271 DCHECK(is_int16(offset)); |
3109 r2 = scratch; | 3272 return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot); |
3110 li(r2, rt); | |
3111 } | |
3112 | |
3113 { | |
3114 BlockTrampolinePoolScope block_trampoline_pool(this); | |
3115 switch (cond) { | |
3116 case cc_always: | |
3117 offset = shifted_branch_offset(L, false); | |
3118 bal(offset); | |
3119 break; | |
3120 case eq: | |
3121 bne(rs, r2, 2); | |
3122 nop(); | |
3123 offset = shifted_branch_offset(L, false); | |
3124 bal(offset); | |
3125 break; | |
3126 case ne: | |
3127 beq(rs, r2, 2); | |
3128 nop(); | |
3129 offset = shifted_branch_offset(L, false); | |
3130 bal(offset); | |
3131 break; | |
3132 | |
3133 // Signed comparison. | |
3134 case greater: | |
3135 // rs > rt | |
3136 slt(scratch, r2, rs); | |
3137 beq(scratch, zero_reg, 2); | |
3138 nop(); | |
3139 offset = shifted_branch_offset(L, false); | |
3140 bal(offset); | |
3141 break; | |
3142 case greater_equal: | |
3143 // rs >= rt | |
3144 slt(scratch, rs, r2); | |
3145 bne(scratch, zero_reg, 2); | |
3146 nop(); | |
3147 offset = shifted_branch_offset(L, false); | |
3148 bal(offset); | |
3149 break; | |
3150 case less: | |
3151 // rs < r2 | |
3152 slt(scratch, rs, r2); | |
3153 bne(scratch, zero_reg, 2); | |
3154 nop(); | |
3155 offset = shifted_branch_offset(L, false); | |
3156 bal(offset); | |
3157 break; | |
3158 case less_equal: | |
3159 // rs <= r2 | |
3160 slt(scratch, r2, rs); | |
3161 bne(scratch, zero_reg, 2); | |
3162 nop(); | |
3163 offset = shifted_branch_offset(L, false); | |
3164 bal(offset); | |
3165 break; | |
3166 | |
3167 | |
3168 // Unsigned comparison. | |
3169 case Ugreater: | |
3170 // rs > rt | |
3171 sltu(scratch, r2, rs); | |
3172 beq(scratch, zero_reg, 2); | |
3173 nop(); | |
3174 offset = shifted_branch_offset(L, false); | |
3175 bal(offset); | |
3176 break; | |
3177 case Ugreater_equal: | |
3178 // rs >= rt | |
3179 sltu(scratch, rs, r2); | |
3180 bne(scratch, zero_reg, 2); | |
3181 nop(); | |
3182 offset = shifted_branch_offset(L, false); | |
3183 bal(offset); | |
3184 break; | |
3185 case Uless: | |
3186 // rs < r2 | |
3187 sltu(scratch, rs, r2); | |
3188 bne(scratch, zero_reg, 2); | |
3189 nop(); | |
3190 offset = shifted_branch_offset(L, false); | |
3191 bal(offset); | |
3192 break; | |
3193 case Uless_equal: | |
3194 // rs <= r2 | |
3195 sltu(scratch, r2, rs); | |
3196 bne(scratch, zero_reg, 2); | |
3197 nop(); | |
3198 offset = shifted_branch_offset(L, false); | |
3199 bal(offset); | |
3200 break; | |
3201 | |
3202 default: | |
3203 UNREACHABLE(); | |
3204 } | 3273 } |
3205 } | 3274 } else { |
3206 // Check that offset could actually hold on an int16_t. | 3275 DCHECK(offset == 0); |
3207 DCHECK(is_int16(offset)); | 3276 if (kArchVariant == kMips64r6 && bdslot == PROTECT) { |
3208 | 3277 return BranchAndLinkShortHelperR6(0, L, cond, rs, rt); |
3209 // Emit a nop in the branch delay slot if required. | 3278 } else { |
3210 if (bdslot == PROTECT) | 3279 return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot); |
3211 nop(); | 3280 } |
3212 } | 3281 } |
3213 | 3282 return false; |
3214 | 3283 } |
| 3284 |
| 3285 |
3215 void MacroAssembler::Jump(Register target, | 3286 void MacroAssembler::Jump(Register target, |
3216 Condition cond, | 3287 Condition cond, |
3217 Register rs, | 3288 Register rs, |
3218 const Operand& rt, | 3289 const Operand& rt, |
3219 BranchDelaySlot bd) { | 3290 BranchDelaySlot bd) { |
3220 BlockTrampolinePoolScope block_trampoline_pool(this); | 3291 BlockTrampolinePoolScope block_trampoline_pool(this); |
3221 if (cond == cc_always) { | 3292 if (cond == cc_always) { |
3222 jr(target); | 3293 jr(target); |
3223 } else { | 3294 } else { |
3224 BRANCH_ARGS_CHECK(cond, rs, rt); | 3295 BRANCH_ARGS_CHECK(cond, rs, rt); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3291 return size * kInstrSize; | 3362 return size * kInstrSize; |
3292 } | 3363 } |
3293 | 3364 |
3294 | 3365 |
3295 // Note: To call gcc-compiled C code on mips, you must call thru t9. | 3366 // Note: To call gcc-compiled C code on mips, you must call thru t9. |
3296 void MacroAssembler::Call(Register target, | 3367 void MacroAssembler::Call(Register target, |
3297 Condition cond, | 3368 Condition cond, |
3298 Register rs, | 3369 Register rs, |
3299 const Operand& rt, | 3370 const Operand& rt, |
3300 BranchDelaySlot bd) { | 3371 BranchDelaySlot bd) { |
| 3372 #ifdef DEBUG |
| 3373 int size = IsPrevInstrCompactBranch() ? kInstrSize : 0; |
| 3374 #endif |
| 3375 |
3301 BlockTrampolinePoolScope block_trampoline_pool(this); | 3376 BlockTrampolinePoolScope block_trampoline_pool(this); |
3302 Label start; | 3377 Label start; |
3303 bind(&start); | 3378 bind(&start); |
3304 if (cond == cc_always) { | 3379 if (cond == cc_always) { |
3305 jalr(target); | 3380 jalr(target); |
3306 } else { | 3381 } else { |
3307 BRANCH_ARGS_CHECK(cond, rs, rt); | 3382 BRANCH_ARGS_CHECK(cond, rs, rt); |
3308 Branch(2, NegateCondition(cond), rs, rt); | 3383 Branch(2, NegateCondition(cond), rs, rt); |
3309 jalr(target); | 3384 jalr(target); |
3310 } | 3385 } |
3311 // Emit a nop in the branch delay slot if required. | 3386 // Emit a nop in the branch delay slot if required. |
3312 if (bd == PROTECT) | 3387 if (bd == PROTECT) |
3313 nop(); | 3388 nop(); |
3314 | 3389 |
3315 DCHECK_EQ(CallSize(target, cond, rs, rt, bd), | 3390 #ifdef DEBUG |
3316 SizeOfCodeGeneratedSince(&start)); | 3391 CHECK_EQ(size + CallSize(target, cond, rs, rt, bd), |
| 3392 SizeOfCodeGeneratedSince(&start)); |
| 3393 #endif |
3317 } | 3394 } |
3318 | 3395 |
3319 | 3396 |
3320 int MacroAssembler::CallSize(Address target, | 3397 int MacroAssembler::CallSize(Address target, |
3321 RelocInfo::Mode rmode, | 3398 RelocInfo::Mode rmode, |
3322 Condition cond, | 3399 Condition cond, |
3323 Register rs, | 3400 Register rs, |
3324 const Operand& rt, | 3401 const Operand& rt, |
3325 BranchDelaySlot bd) { | 3402 BranchDelaySlot bd) { |
3326 int size = CallSize(t9, cond, rs, rt, bd); | 3403 int size = CallSize(t9, cond, rs, rt, bd); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3384 | 3461 |
3385 | 3462 |
3386 void MacroAssembler::Ret(Condition cond, | 3463 void MacroAssembler::Ret(Condition cond, |
3387 Register rs, | 3464 Register rs, |
3388 const Operand& rt, | 3465 const Operand& rt, |
3389 BranchDelaySlot bd) { | 3466 BranchDelaySlot bd) { |
3390 Jump(ra, cond, rs, rt, bd); | 3467 Jump(ra, cond, rs, rt, bd); |
3391 } | 3468 } |
3392 | 3469 |
3393 | 3470 |
3394 void MacroAssembler::J(Label* L, BranchDelaySlot bdslot) { | 3471 void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) { |
3395 BlockTrampolinePoolScope block_trampoline_pool(this); | 3472 if (kArchVariant == kMips64r6 && bdslot == PROTECT && |
3396 { | 3473 (!L->is_bound() || is_near_r6(L))) { |
3397 BlockGrowBufferScope block_buf_growth(this); | 3474 BranchShortHelperR6(0, L); |
3398 // Buffer growth (and relocation) must be blocked for internal references | 3475 } else { |
3399 // until associated instructions are emitted and available to be patched. | 3476 EmitForbiddenSlotInstruction(); |
3400 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); | 3477 BlockTrampolinePoolScope block_trampoline_pool(this); |
3401 j(L); | 3478 { |
| 3479 BlockGrowBufferScope block_buf_growth(this); |
| 3480 // Buffer growth (and relocation) must be blocked for internal references |
| 3481 // until associated instructions are emitted and available to be patched. |
| 3482 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); |
| 3483 j(L); |
| 3484 } |
| 3485 // Emit a nop in the branch delay slot if required. |
| 3486 if (bdslot == PROTECT) nop(); |
3402 } | 3487 } |
3403 // Emit a nop in the branch delay slot if required. | |
3404 if (bdslot == PROTECT) nop(); | |
3405 } | 3488 } |
3406 | 3489 |
3407 | 3490 |
3408 void MacroAssembler::Jal(Label* L, BranchDelaySlot bdslot) { | 3491 void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) { |
3409 BlockTrampolinePoolScope block_trampoline_pool(this); | 3492 if (kArchVariant == kMips64r6 && bdslot == PROTECT && |
3410 { | 3493 (!L->is_bound() || is_near_r6(L))) { |
3411 BlockGrowBufferScope block_buf_growth(this); | 3494 BranchAndLinkShortHelperR6(0, L); |
3412 // Buffer growth (and relocation) must be blocked for internal references | 3495 } else { |
3413 // until associated instructions are emitted and available to be patched. | 3496 EmitForbiddenSlotInstruction(); |
3414 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); | 3497 BlockTrampolinePoolScope block_trampoline_pool(this); |
3415 jal(L); | 3498 { |
| 3499 BlockGrowBufferScope block_buf_growth(this); |
| 3500 // Buffer growth (and relocation) must be blocked for internal references |
| 3501 // until associated instructions are emitted and available to be patched. |
| 3502 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED); |
| 3503 jal(L); |
| 3504 } |
| 3505 // Emit a nop in the branch delay slot if required. |
| 3506 if (bdslot == PROTECT) nop(); |
3416 } | 3507 } |
3417 // Emit a nop in the branch delay slot if required. | |
3418 if (bdslot == PROTECT) nop(); | |
3419 } | 3508 } |
3420 | 3509 |
3421 | 3510 |
3422 void MacroAssembler::Jr(Label* L, BranchDelaySlot bdslot) { | 3511 void MacroAssembler::Jr(Label* L, BranchDelaySlot bdslot) { |
3423 BlockTrampolinePoolScope block_trampoline_pool(this); | 3512 BlockTrampolinePoolScope block_trampoline_pool(this); |
3424 | 3513 |
3425 uint64_t imm64; | 3514 uint64_t imm64; |
3426 imm64 = jump_address(L); | 3515 imm64 = jump_address(L); |
3427 { BlockGrowBufferScope block_buf_growth(this); | 3516 { BlockGrowBufferScope block_buf_growth(this); |
3428 // Buffer growth (and relocation) must be blocked for internal references | 3517 // Buffer growth (and relocation) must be blocked for internal references |
(...skipping 2915 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6344 void CodePatcher::Emit(Instr instr) { | 6433 void CodePatcher::Emit(Instr instr) { |
6345 masm()->emit(instr); | 6434 masm()->emit(instr); |
6346 } | 6435 } |
6347 | 6436 |
6348 | 6437 |
6349 void CodePatcher::Emit(Address addr) { | 6438 void CodePatcher::Emit(Address addr) { |
6350 // masm()->emit(reinterpret_cast<Instr>(addr)); | 6439 // masm()->emit(reinterpret_cast<Instr>(addr)); |
6351 } | 6440 } |
6352 | 6441 |
6353 | 6442 |
6354 void CodePatcher::ChangeBranchCondition(Condition cond) { | 6443 void CodePatcher::ChangeBranchCondition(Instr current_instr, |
6355 Instr instr = Assembler::instr_at(masm_.pc_); | 6444 uint32_t new_opcode) { |
6356 DCHECK(Assembler::IsBranch(instr)); | 6445 current_instr = (current_instr & ~kOpcodeMask) | new_opcode; |
6357 uint32_t opcode = Assembler::GetOpcodeField(instr); | 6446 masm_.emit(current_instr); |
6358 // Currently only the 'eq' and 'ne' cond values are supported and the simple | |
6359 // branch instructions (with opcode being the branch type). | |
6360 // There are some special cases (see Assembler::IsBranch()) so extending this | |
6361 // would be tricky. | |
6362 DCHECK(opcode == BEQ || | |
6363 opcode == BNE || | |
6364 opcode == BLEZ || | |
6365 opcode == BGTZ || | |
6366 opcode == BEQL || | |
6367 opcode == BNEL || | |
6368 opcode == BLEZL || | |
6369 opcode == BGTZL); | |
6370 opcode = (cond == eq) ? BEQ : BNE; | |
6371 instr = (instr & ~kOpcodeMask) | opcode; | |
6372 masm_.emit(instr); | |
6373 } | 6447 } |
6374 | 6448 |
6375 | 6449 |
6376 void MacroAssembler::TruncatingDiv(Register result, | 6450 void MacroAssembler::TruncatingDiv(Register result, |
6377 Register dividend, | 6451 Register dividend, |
6378 int32_t divisor) { | 6452 int32_t divisor) { |
6379 DCHECK(!dividend.is(result)); | 6453 DCHECK(!dividend.is(result)); |
6380 DCHECK(!dividend.is(at)); | 6454 DCHECK(!dividend.is(at)); |
6381 DCHECK(!result.is(at)); | 6455 DCHECK(!result.is(at)); |
6382 base::MagicNumbersForDivision<uint32_t> mag = | 6456 base::MagicNumbersForDivision<uint32_t> mag = |
(...skipping 10 matching lines...) Expand all Loading... |
6393 if (mag.shift > 0) sra(result, result, mag.shift); | 6467 if (mag.shift > 0) sra(result, result, mag.shift); |
6394 srl(at, dividend, 31); | 6468 srl(at, dividend, 31); |
6395 Addu(result, result, Operand(at)); | 6469 Addu(result, result, Operand(at)); |
6396 } | 6470 } |
6397 | 6471 |
6398 | 6472 |
6399 } // namespace internal | 6473 } // namespace internal |
6400 } // namespace v8 | 6474 } // namespace v8 |
6401 | 6475 |
6402 #endif // V8_TARGET_ARCH_MIPS64 | 6476 #endif // V8_TARGET_ARCH_MIPS64 |
OLD | NEW |