11cb0ef41Sopenharmony_ci// Copyright 2018 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/torque/cfg.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/torque/type-oracle.h" 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_cinamespace v8 { 101cb0ef41Sopenharmony_cinamespace internal { 111cb0ef41Sopenharmony_cinamespace torque { 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_civoid Block::SetInputTypes(const Stack<const Type*>& input_types) { 141cb0ef41Sopenharmony_ci if (!input_types_) { 151cb0ef41Sopenharmony_ci input_types_ = input_types; 161cb0ef41Sopenharmony_ci return; 171cb0ef41Sopenharmony_ci } else if (*input_types_ == input_types) { 181cb0ef41Sopenharmony_ci return; 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci DCHECK_EQ(input_types.Size(), input_types_->Size()); 221cb0ef41Sopenharmony_ci Stack<const Type*> merged_types; 231cb0ef41Sopenharmony_ci bool widened = false; 241cb0ef41Sopenharmony_ci auto c2_iterator = input_types.begin(); 251cb0ef41Sopenharmony_ci for (const Type* c1 : *input_types_) { 261cb0ef41Sopenharmony_ci const Type* merged_type = TypeOracle::GetUnionType(c1, *c2_iterator++); 271cb0ef41Sopenharmony_ci if (!merged_type->IsSubtypeOf(c1)) { 281cb0ef41Sopenharmony_ci widened = true; 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci merged_types.Push(merged_type); 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci if (merged_types.Size() == input_types_->Size()) { 331cb0ef41Sopenharmony_ci if (widened) { 341cb0ef41Sopenharmony_ci input_types_ = merged_types; 351cb0ef41Sopenharmony_ci Retype(); 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci return; 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci std::stringstream error; 411cb0ef41Sopenharmony_ci error << "incompatible types at branch:\n"; 421cb0ef41Sopenharmony_ci for (intptr_t i = std::max(input_types_->Size(), input_types.Size()) - 1; 431cb0ef41Sopenharmony_ci i >= 0; --i) { 441cb0ef41Sopenharmony_ci base::Optional<const Type*> left; 451cb0ef41Sopenharmony_ci base::Optional<const Type*> right; 461cb0ef41Sopenharmony_ci if (static_cast<size_t>(i) < input_types.Size()) { 471cb0ef41Sopenharmony_ci left = input_types.Peek(BottomOffset{static_cast<size_t>(i)}); 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci if (static_cast<size_t>(i) < input_types_->Size()) { 501cb0ef41Sopenharmony_ci right = input_types_->Peek(BottomOffset{static_cast<size_t>(i)}); 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci if (left && right && *left == *right) { 531cb0ef41Sopenharmony_ci error << **left << "\n"; 541cb0ef41Sopenharmony_ci } else { 551cb0ef41Sopenharmony_ci if (left) { 561cb0ef41Sopenharmony_ci error << **left; 571cb0ef41Sopenharmony_ci } else { 581cb0ef41Sopenharmony_ci error << "/*missing*/"; 591cb0ef41Sopenharmony_ci } 601cb0ef41Sopenharmony_ci error << " => "; 611cb0ef41Sopenharmony_ci if (right) { 621cb0ef41Sopenharmony_ci error << **right; 631cb0ef41Sopenharmony_ci } else { 641cb0ef41Sopenharmony_ci error << "/*missing*/"; 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci error << "\n"; 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci ReportError(error.str()); 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_civoid CfgAssembler::Bind(Block* block) { 731cb0ef41Sopenharmony_ci DCHECK(current_block_->IsComplete()); 741cb0ef41Sopenharmony_ci DCHECK(block->instructions().empty()); 751cb0ef41Sopenharmony_ci DCHECK(block->HasInputTypes()); 761cb0ef41Sopenharmony_ci current_block_ = block; 771cb0ef41Sopenharmony_ci current_stack_ = block->InputTypes(); 781cb0ef41Sopenharmony_ci cfg_.PlaceBlock(block); 791cb0ef41Sopenharmony_ci} 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_civoid CfgAssembler::Goto(Block* block) { 821cb0ef41Sopenharmony_ci if (block->HasInputTypes()) { 831cb0ef41Sopenharmony_ci DropTo(block->InputTypes().AboveTop()); 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci Emit(GotoInstruction{block}); 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciStackRange CfgAssembler::Goto(Block* block, size_t preserved_slots) { 891cb0ef41Sopenharmony_ci DCHECK(block->HasInputTypes()); 901cb0ef41Sopenharmony_ci DCHECK_GE(CurrentStack().Size(), block->InputTypes().Size()); 911cb0ef41Sopenharmony_ci Emit(DeleteRangeInstruction{ 921cb0ef41Sopenharmony_ci StackRange{block->InputTypes().AboveTop() - preserved_slots, 931cb0ef41Sopenharmony_ci CurrentStack().AboveTop() - preserved_slots}}); 941cb0ef41Sopenharmony_ci StackRange preserved_slot_range = TopRange(preserved_slots); 951cb0ef41Sopenharmony_ci Emit(GotoInstruction{block}); 961cb0ef41Sopenharmony_ci return preserved_slot_range; 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_civoid CfgAssembler::Branch(Block* if_true, Block* if_false) { 1001cb0ef41Sopenharmony_ci Emit(BranchInstruction{if_true, if_false}); 1011cb0ef41Sopenharmony_ci} 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci// Delete the specified range of slots, moving upper slots to fill the gap. 1041cb0ef41Sopenharmony_civoid CfgAssembler::DeleteRange(StackRange range) { 1051cb0ef41Sopenharmony_ci DCHECK_LE(range.end(), current_stack_.AboveTop()); 1061cb0ef41Sopenharmony_ci if (range.Size() == 0) return; 1071cb0ef41Sopenharmony_ci Emit(DeleteRangeInstruction{range}); 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_civoid CfgAssembler::DropTo(BottomOffset new_level) { 1111cb0ef41Sopenharmony_ci DeleteRange(StackRange{new_level, CurrentStack().AboveTop()}); 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ciStackRange CfgAssembler::Peek(StackRange range, 1151cb0ef41Sopenharmony_ci base::Optional<const Type*> type) { 1161cb0ef41Sopenharmony_ci std::vector<const Type*> lowered_types; 1171cb0ef41Sopenharmony_ci if (type) { 1181cb0ef41Sopenharmony_ci lowered_types = LowerType(*type); 1191cb0ef41Sopenharmony_ci DCHECK_EQ(lowered_types.size(), range.Size()); 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci for (size_t i = 0; i < range.Size(); ++i) { 1221cb0ef41Sopenharmony_ci Emit(PeekInstruction{ 1231cb0ef41Sopenharmony_ci range.begin() + i, 1241cb0ef41Sopenharmony_ci type ? lowered_types[i] : base::Optional<const Type*>{}}); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci return TopRange(range.Size()); 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_civoid CfgAssembler::Poke(StackRange destination, StackRange origin, 1301cb0ef41Sopenharmony_ci base::Optional<const Type*> type) { 1311cb0ef41Sopenharmony_ci DCHECK_EQ(destination.Size(), origin.Size()); 1321cb0ef41Sopenharmony_ci DCHECK_LE(destination.end(), origin.begin()); 1331cb0ef41Sopenharmony_ci DCHECK_EQ(origin.end(), CurrentStack().AboveTop()); 1341cb0ef41Sopenharmony_ci std::vector<const Type*> lowered_types; 1351cb0ef41Sopenharmony_ci if (type) { 1361cb0ef41Sopenharmony_ci lowered_types = LowerType(*type); 1371cb0ef41Sopenharmony_ci DCHECK_EQ(lowered_types.size(), origin.Size()); 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci for (intptr_t i = origin.Size() - 1; i >= 0; --i) { 1401cb0ef41Sopenharmony_ci Emit(PokeInstruction{ 1411cb0ef41Sopenharmony_ci destination.begin() + i, 1421cb0ef41Sopenharmony_ci type ? lowered_types[i] : base::Optional<const Type*>{}}); 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci} 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_civoid CfgAssembler::Print(std::string s) { 1471cb0ef41Sopenharmony_ci Emit(PrintConstantStringInstruction{std::move(s)}); 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_civoid CfgAssembler::AssertionFailure(std::string message) { 1511cb0ef41Sopenharmony_ci Emit(AbortInstruction{AbortInstruction::Kind::kAssertionFailure, 1521cb0ef41Sopenharmony_ci std::move(message)}); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_civoid CfgAssembler::Unreachable() { 1561cb0ef41Sopenharmony_ci Emit(AbortInstruction{AbortInstruction::Kind::kUnreachable}); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_civoid CfgAssembler::DebugBreak() { 1601cb0ef41Sopenharmony_ci Emit(AbortInstruction{AbortInstruction::Kind::kDebugBreak}); 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_cistd::vector<std::size_t> CountBlockPredecessors(const ControlFlowGraph& cfg) { 1641cb0ef41Sopenharmony_ci std::vector<std::size_t> count(cfg.NumberOfBlockIds(), 0); 1651cb0ef41Sopenharmony_ci count[cfg.start()->id()] = 1; 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci for (const Block* block : cfg.blocks()) { 1681cb0ef41Sopenharmony_ci std::vector<Block*> successors; 1691cb0ef41Sopenharmony_ci for (const auto& instruction : block->instructions()) { 1701cb0ef41Sopenharmony_ci instruction->AppendSuccessorBlocks(&successors); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci for (Block* successor : successors) { 1731cb0ef41Sopenharmony_ci DCHECK_LT(successor->id(), count.size()); 1741cb0ef41Sopenharmony_ci ++count[successor->id()]; 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci return count; 1791cb0ef41Sopenharmony_ci} 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_civoid CfgAssembler::OptimizeCfg() { 1821cb0ef41Sopenharmony_ci auto predecessor_count = CountBlockPredecessors(cfg_); 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci for (Block* block : cfg_.blocks()) { 1851cb0ef41Sopenharmony_ci if (cfg_.end() && *cfg_.end() == block) continue; 1861cb0ef41Sopenharmony_ci if (predecessor_count[block->id()] == 0) continue; 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci while (!block->instructions().empty()) { 1891cb0ef41Sopenharmony_ci const auto& instruction = block->instructions().back(); 1901cb0ef41Sopenharmony_ci if (!instruction.Is<GotoInstruction>()) break; 1911cb0ef41Sopenharmony_ci Block* destination = instruction.Cast<GotoInstruction>().destination; 1921cb0ef41Sopenharmony_ci if (destination == block) break; 1931cb0ef41Sopenharmony_ci if (cfg_.end() && *cfg_.end() == destination) break; 1941cb0ef41Sopenharmony_ci DCHECK_GT(predecessor_count[destination->id()], 0); 1951cb0ef41Sopenharmony_ci if (predecessor_count[destination->id()] != 1) break; 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci DCHECK_GT(destination->instructions().size(), 0); 1981cb0ef41Sopenharmony_ci block->instructions().pop_back(); 1991cb0ef41Sopenharmony_ci block->instructions().insert(block->instructions().end(), 2001cb0ef41Sopenharmony_ci destination->instructions().begin(), 2011cb0ef41Sopenharmony_ci destination->instructions().end()); 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci --predecessor_count[destination->id()]; 2041cb0ef41Sopenharmony_ci DCHECK_EQ(predecessor_count[destination->id()], 0); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci cfg_.UnplaceBlockIf( 2091cb0ef41Sopenharmony_ci [&](Block* b) { return predecessor_count[b->id()] == 0; }); 2101cb0ef41Sopenharmony_ci} 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_civoid CfgAssembler::ComputeInputDefinitions() { 2131cb0ef41Sopenharmony_ci Worklist<Block*> worklist; 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci // Setup start block. 2161cb0ef41Sopenharmony_ci Stack<DefinitionLocation> parameter_defs; 2171cb0ef41Sopenharmony_ci for (std::size_t i = 0; i < cfg_.ParameterCount(); ++i) { 2181cb0ef41Sopenharmony_ci parameter_defs.Push(DefinitionLocation::Parameter(i)); 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci cfg_.start()->MergeInputDefinitions(parameter_defs, &worklist); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci // Run fixpoint algorithm. 2231cb0ef41Sopenharmony_ci while (!worklist.IsEmpty()) { 2241cb0ef41Sopenharmony_ci Block* block = worklist.Dequeue(); 2251cb0ef41Sopenharmony_ci Stack<DefinitionLocation> definitions = block->InputDefinitions(); 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci // Propagate through block's instructions. 2281cb0ef41Sopenharmony_ci for (const auto& instruction : block->instructions()) { 2291cb0ef41Sopenharmony_ci instruction.RecomputeDefinitionLocations(&definitions, &worklist); 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci } 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci for (Block* block : cfg_.blocks()) { 2341cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!block->IsDead(), block->InputDefinitions().Size() == 2351cb0ef41Sopenharmony_ci block->InputTypes().Size()); 2361cb0ef41Sopenharmony_ci USE(block); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci} 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci} // namespace torque 2411cb0ef41Sopenharmony_ci} // namespace internal 2421cb0ef41Sopenharmony_ci} // namespace v8 243