11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/compiler/backend/jump-threading.h" 61cb0ef41Sopenharmony_ci#include "src/compiler/backend/code-generator-impl.h" 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_cinamespace v8 { 91cb0ef41Sopenharmony_cinamespace internal { 101cb0ef41Sopenharmony_cinamespace compiler { 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#define TRACE(...) \ 131cb0ef41Sopenharmony_ci do { \ 141cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_jt) PrintF(__VA_ARGS__); \ 151cb0ef41Sopenharmony_ci } while (false) 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cinamespace { 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cistruct JumpThreadingState { 201cb0ef41Sopenharmony_ci bool forwarded; 211cb0ef41Sopenharmony_ci ZoneVector<RpoNumber>& result; 221cb0ef41Sopenharmony_ci ZoneStack<RpoNumber>& stack; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci void Clear(size_t count) { result.assign(count, unvisited()); } 251cb0ef41Sopenharmony_ci void PushIfUnvisited(RpoNumber num) { 261cb0ef41Sopenharmony_ci if (result[num.ToInt()] == unvisited()) { 271cb0ef41Sopenharmony_ci stack.push(num); 281cb0ef41Sopenharmony_ci result[num.ToInt()] = onstack(); 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci } 311cb0ef41Sopenharmony_ci void Forward(RpoNumber to) { 321cb0ef41Sopenharmony_ci RpoNumber from = stack.top(); 331cb0ef41Sopenharmony_ci RpoNumber to_to = result[to.ToInt()]; 341cb0ef41Sopenharmony_ci bool pop = true; 351cb0ef41Sopenharmony_ci if (to == from) { 361cb0ef41Sopenharmony_ci TRACE(" xx %d\n", from.ToInt()); 371cb0ef41Sopenharmony_ci result[from.ToInt()] = from; 381cb0ef41Sopenharmony_ci } else if (to_to == unvisited()) { 391cb0ef41Sopenharmony_ci TRACE(" fw %d -> %d (recurse)\n", from.ToInt(), to.ToInt()); 401cb0ef41Sopenharmony_ci stack.push(to); 411cb0ef41Sopenharmony_ci result[to.ToInt()] = onstack(); 421cb0ef41Sopenharmony_ci pop = false; // recurse. 431cb0ef41Sopenharmony_ci } else if (to_to == onstack()) { 441cb0ef41Sopenharmony_ci TRACE(" fw %d -> %d (cycle)\n", from.ToInt(), to.ToInt()); 451cb0ef41Sopenharmony_ci result[from.ToInt()] = to; // break the cycle. 461cb0ef41Sopenharmony_ci forwarded = true; 471cb0ef41Sopenharmony_ci } else { 481cb0ef41Sopenharmony_ci TRACE(" fw %d -> %d (forward)\n", from.ToInt(), to.ToInt()); 491cb0ef41Sopenharmony_ci result[from.ToInt()] = to_to; // forward the block. 501cb0ef41Sopenharmony_ci forwarded = true; 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci if (pop) stack.pop(); 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci RpoNumber unvisited() { return RpoNumber::FromInt(-1); } 551cb0ef41Sopenharmony_ci RpoNumber onstack() { return RpoNumber::FromInt(-2); } 561cb0ef41Sopenharmony_ci}; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci} // namespace 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_cibool JumpThreading::ComputeForwarding(Zone* local_zone, 611cb0ef41Sopenharmony_ci ZoneVector<RpoNumber>* result, 621cb0ef41Sopenharmony_ci InstructionSequence* code, 631cb0ef41Sopenharmony_ci bool frame_at_start) { 641cb0ef41Sopenharmony_ci ZoneStack<RpoNumber> stack(local_zone); 651cb0ef41Sopenharmony_ci JumpThreadingState state = {false, *result, stack}; 661cb0ef41Sopenharmony_ci state.Clear(code->InstructionBlockCount()); 671cb0ef41Sopenharmony_ci RpoNumber empty_deconstruct_frame_return_block = RpoNumber::Invalid(); 681cb0ef41Sopenharmony_ci int32_t empty_deconstruct_frame_return_size; 691cb0ef41Sopenharmony_ci RpoNumber empty_no_deconstruct_frame_return_block = RpoNumber::Invalid(); 701cb0ef41Sopenharmony_ci int32_t empty_no_deconstruct_frame_return_size; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci // Iterate over the blocks forward, pushing the blocks onto the stack. 731cb0ef41Sopenharmony_ci for (auto const instruction_block : code->instruction_blocks()) { 741cb0ef41Sopenharmony_ci RpoNumber current = instruction_block->rpo_number(); 751cb0ef41Sopenharmony_ci state.PushIfUnvisited(current); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci // Process the stack, which implements DFS through empty blocks. 781cb0ef41Sopenharmony_ci while (!state.stack.empty()) { 791cb0ef41Sopenharmony_ci InstructionBlock* block = code->InstructionBlockAt(state.stack.top()); 801cb0ef41Sopenharmony_ci // Process the instructions in a block up to a non-empty instruction. 811cb0ef41Sopenharmony_ci TRACE("jt [%d] B%d\n", static_cast<int>(stack.size()), 821cb0ef41Sopenharmony_ci block->rpo_number().ToInt()); 831cb0ef41Sopenharmony_ci RpoNumber fw = block->rpo_number(); 841cb0ef41Sopenharmony_ci bool fallthru = true; 851cb0ef41Sopenharmony_ci for (int i = block->code_start(); i < block->code_end(); ++i) { 861cb0ef41Sopenharmony_ci Instruction* instr = code->InstructionAt(i); 871cb0ef41Sopenharmony_ci if (!instr->AreMovesRedundant()) { 881cb0ef41Sopenharmony_ci // can't skip instructions with non redundant moves. 891cb0ef41Sopenharmony_ci TRACE(" parallel move\n"); 901cb0ef41Sopenharmony_ci fallthru = false; 911cb0ef41Sopenharmony_ci } else if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { 921cb0ef41Sopenharmony_ci // can't skip instructions with flags continuations. 931cb0ef41Sopenharmony_ci TRACE(" flags\n"); 941cb0ef41Sopenharmony_ci fallthru = false; 951cb0ef41Sopenharmony_ci } else if (instr->IsNop()) { 961cb0ef41Sopenharmony_ci // skip nops. 971cb0ef41Sopenharmony_ci TRACE(" nop\n"); 981cb0ef41Sopenharmony_ci continue; 991cb0ef41Sopenharmony_ci } else if (instr->arch_opcode() == kArchJmp) { 1001cb0ef41Sopenharmony_ci // try to forward the jump instruction. 1011cb0ef41Sopenharmony_ci TRACE(" jmp\n"); 1021cb0ef41Sopenharmony_ci // if this block deconstructs the frame, we can't forward it. 1031cb0ef41Sopenharmony_ci // TODO(mtrofin): we can still forward if we end up building 1041cb0ef41Sopenharmony_ci // the frame at start. So we should move the decision of whether 1051cb0ef41Sopenharmony_ci // to build a frame or not in the register allocator, and trickle it 1061cb0ef41Sopenharmony_ci // here and to the code generator. 1071cb0ef41Sopenharmony_ci if (frame_at_start || !(block->must_deconstruct_frame() || 1081cb0ef41Sopenharmony_ci block->must_construct_frame())) { 1091cb0ef41Sopenharmony_ci fw = code->InputRpo(instr, 0); 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci fallthru = false; 1121cb0ef41Sopenharmony_ci } else if (instr->IsRet()) { 1131cb0ef41Sopenharmony_ci TRACE(" ret\n"); 1141cb0ef41Sopenharmony_ci if (fallthru) { 1151cb0ef41Sopenharmony_ci CHECK_IMPLIES(block->must_construct_frame(), 1161cb0ef41Sopenharmony_ci block->must_deconstruct_frame()); 1171cb0ef41Sopenharmony_ci // Only handle returns with immediate/constant operands, since 1181cb0ef41Sopenharmony_ci // they must always be the same for all returns in a function. 1191cb0ef41Sopenharmony_ci // Dynamic return values might use different registers at 1201cb0ef41Sopenharmony_ci // different return sites and therefore cannot be shared. 1211cb0ef41Sopenharmony_ci if (instr->InputAt(0)->IsImmediate()) { 1221cb0ef41Sopenharmony_ci int32_t return_size = ImmediateOperand::cast(instr->InputAt(0)) 1231cb0ef41Sopenharmony_ci ->inline_int32_value(); 1241cb0ef41Sopenharmony_ci // Instructions can be shared only for blocks that share 1251cb0ef41Sopenharmony_ci // the same |must_deconstruct_frame| attribute. 1261cb0ef41Sopenharmony_ci if (block->must_deconstruct_frame()) { 1271cb0ef41Sopenharmony_ci if (empty_deconstruct_frame_return_block == 1281cb0ef41Sopenharmony_ci RpoNumber::Invalid()) { 1291cb0ef41Sopenharmony_ci empty_deconstruct_frame_return_block = block->rpo_number(); 1301cb0ef41Sopenharmony_ci empty_deconstruct_frame_return_size = return_size; 1311cb0ef41Sopenharmony_ci } else if (empty_deconstruct_frame_return_size == return_size) { 1321cb0ef41Sopenharmony_ci fw = empty_deconstruct_frame_return_block; 1331cb0ef41Sopenharmony_ci block->clear_must_deconstruct_frame(); 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci } else { 1361cb0ef41Sopenharmony_ci if (empty_no_deconstruct_frame_return_block == 1371cb0ef41Sopenharmony_ci RpoNumber::Invalid()) { 1381cb0ef41Sopenharmony_ci empty_no_deconstruct_frame_return_block = block->rpo_number(); 1391cb0ef41Sopenharmony_ci empty_no_deconstruct_frame_return_size = return_size; 1401cb0ef41Sopenharmony_ci } else if (empty_no_deconstruct_frame_return_size == 1411cb0ef41Sopenharmony_ci return_size) { 1421cb0ef41Sopenharmony_ci fw = empty_no_deconstruct_frame_return_block; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci fallthru = false; 1481cb0ef41Sopenharmony_ci } else { 1491cb0ef41Sopenharmony_ci // can't skip other instructions. 1501cb0ef41Sopenharmony_ci TRACE(" other\n"); 1511cb0ef41Sopenharmony_ci fallthru = false; 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci break; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci if (fallthru) { 1561cb0ef41Sopenharmony_ci int next = 1 + block->rpo_number().ToInt(); 1571cb0ef41Sopenharmony_ci if (next < code->InstructionBlockCount()) fw = RpoNumber::FromInt(next); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci state.Forward(fw); 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci#ifdef DEBUG 1641cb0ef41Sopenharmony_ci for (RpoNumber num : *result) { 1651cb0ef41Sopenharmony_ci DCHECK(num.IsValid()); 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci#endif 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_jt) { 1701cb0ef41Sopenharmony_ci for (int i = 0; i < static_cast<int>(result->size()); i++) { 1711cb0ef41Sopenharmony_ci TRACE("B%d ", i); 1721cb0ef41Sopenharmony_ci int to = (*result)[i].ToInt(); 1731cb0ef41Sopenharmony_ci if (i != to) { 1741cb0ef41Sopenharmony_ci TRACE("-> B%d\n", to); 1751cb0ef41Sopenharmony_ci } else { 1761cb0ef41Sopenharmony_ci TRACE("\n"); 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci return state.forwarded; 1821cb0ef41Sopenharmony_ci} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_civoid JumpThreading::ApplyForwarding(Zone* local_zone, 1851cb0ef41Sopenharmony_ci ZoneVector<RpoNumber> const& result, 1861cb0ef41Sopenharmony_ci InstructionSequence* code) { 1871cb0ef41Sopenharmony_ci if (!FLAG_turbo_jt) return; 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci ZoneVector<bool> skip(static_cast<int>(result.size()), false, local_zone); 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci // Skip empty blocks when the previous block doesn't fall through. 1921cb0ef41Sopenharmony_ci bool prev_fallthru = true; 1931cb0ef41Sopenharmony_ci for (auto const block : code->ao_blocks()) { 1941cb0ef41Sopenharmony_ci RpoNumber block_rpo = block->rpo_number(); 1951cb0ef41Sopenharmony_ci int block_num = block_rpo.ToInt(); 1961cb0ef41Sopenharmony_ci RpoNumber result_rpo = result[block_num]; 1971cb0ef41Sopenharmony_ci skip[block_num] = !prev_fallthru && result_rpo != block_rpo; 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci if (result_rpo != block_rpo) { 2001cb0ef41Sopenharmony_ci // We need the handler information to be propagated, so that branch 2011cb0ef41Sopenharmony_ci // targets are annotated as necessary for control flow integrity 2021cb0ef41Sopenharmony_ci // checks (when enabled). 2031cb0ef41Sopenharmony_ci if (code->InstructionBlockAt(block_rpo)->IsHandler()) { 2041cb0ef41Sopenharmony_ci code->InstructionBlockAt(result_rpo)->MarkHandler(); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci bool fallthru = true; 2091cb0ef41Sopenharmony_ci for (int i = block->code_start(); i < block->code_end(); ++i) { 2101cb0ef41Sopenharmony_ci Instruction* instr = code->InstructionAt(i); 2111cb0ef41Sopenharmony_ci FlagsMode mode = FlagsModeField::decode(instr->opcode()); 2121cb0ef41Sopenharmony_ci if (mode == kFlags_branch) { 2131cb0ef41Sopenharmony_ci fallthru = false; // branches don't fall through to the next block. 2141cb0ef41Sopenharmony_ci } else if (instr->arch_opcode() == kArchJmp || 2151cb0ef41Sopenharmony_ci instr->arch_opcode() == kArchRet) { 2161cb0ef41Sopenharmony_ci if (skip[block_num]) { 2171cb0ef41Sopenharmony_ci // Overwrite a redundant jump with a nop. 2181cb0ef41Sopenharmony_ci TRACE("jt-fw nop @%d\n", i); 2191cb0ef41Sopenharmony_ci instr->OverwriteWithNop(); 2201cb0ef41Sopenharmony_ci // If this block was marked as a handler, it can be unmarked now. 2211cb0ef41Sopenharmony_ci code->InstructionBlockAt(block_rpo)->UnmarkHandler(); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci fallthru = false; // jumps don't fall through to the next block. 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci prev_fallthru = fallthru; 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci // Patch RPO immediates. 2301cb0ef41Sopenharmony_ci InstructionSequence::RpoImmediates& rpo_immediates = code->rpo_immediates(); 2311cb0ef41Sopenharmony_ci for (size_t i = 0; i < rpo_immediates.size(); i++) { 2321cb0ef41Sopenharmony_ci RpoNumber rpo = rpo_immediates[i]; 2331cb0ef41Sopenharmony_ci if (rpo.IsValid()) { 2341cb0ef41Sopenharmony_ci RpoNumber fw = result[rpo.ToInt()]; 2351cb0ef41Sopenharmony_ci if (fw != rpo) rpo_immediates[i] = fw; 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci // Renumber the blocks so that IsNextInAssemblyOrder() will return true, 2401cb0ef41Sopenharmony_ci // even if there are skipped blocks in-between. 2411cb0ef41Sopenharmony_ci int ao = 0; 2421cb0ef41Sopenharmony_ci for (auto const block : code->ao_blocks()) { 2431cb0ef41Sopenharmony_ci block->set_ao_number(RpoNumber::FromInt(ao)); 2441cb0ef41Sopenharmony_ci if (!skip[block->rpo_number().ToInt()]) ao++; 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci} 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_ci#undef TRACE 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci} // namespace compiler 2511cb0ef41Sopenharmony_ci} // namespace internal 2521cb0ef41Sopenharmony_ci} // namespace v8 253