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