[torque] Reduce generated CSA variables and labels

This CL significantly reduces the size of CSA files generated from
torque by introducing only those Phis at block entry that are
required and otherwise uses defined values directly.

To do so it does:
- Define a DefinitionLocation that represents where a value is
  defined.
- For each block compute all the definitions that reach that
  block and introduce a phi iff the reaching definitions for a value
  are not the same for all predecessor blocks.
- In CSAGenerator map all DefinitionLocations to variables, such that
  if the same value is used in multiple blocks, it is mapped to the
  same variable without the need to pass it along the jump. This
  reduces both the arguments passed to Goto, Branch, ... and the
  variables that need to be passed to Bind when the block's label is
  bound. This reduces the number of temporary variables
  significantly. Temporaries are declared outside of blocks now
  in order to be accessible from other blocks.

Drive-by changes:
- Sequences of SetSourcePosition calls are merged if no output is
  generated between them.
- Dead blocks are no longer generated in release builds.

Bug: v8:9861
Change-Id: I5c30e5376e93c424c3ebfc5144a08592d77ae61f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2037444
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66225}
This commit is contained in:
Nico Hartmann 2020-02-11 15:14:39 +01:00 committed by Commit Bot
parent 5c7b4d2a01
commit 89b248b6f8
9 changed files with 1084 additions and 285 deletions

View File

@ -625,6 +625,16 @@ class V8_EXPORT_PRIVATE CodeAssembler {
if_false->AddInputs(args...);
Branch(condition, if_true->plain_label(), if_false->plain_label());
}
template <class... T, class... U>
void Branch(TNode<BoolT> condition,
CodeAssemblerParameterizedLabel<T...>* if_true,
std::vector<Node*> args_true,
CodeAssemblerParameterizedLabel<U...>* if_false,
std::vector<Node*> args_false) {
if_true->AddInputsVector(std::move(args_true));
if_false->AddInputsVector(std::move(args_false));
Branch(condition, if_true->plain_label(), if_false->plain_label());
}
template <class... T, class... Args>
void Goto(CodeAssemblerParameterizedLabel<T...>* label, Args... args) {
@ -1354,6 +1364,9 @@ class CodeAssemblerParameterizedLabel
private:
friend class CodeAssembler;
void AddInputsVector(std::vector<Node*> inputs) {
CodeAssemblerParameterizedLabelBase::AddInputs(std::move(inputs));
}
void AddInputs(TNode<Types>... inputs) {
CodeAssemblerParameterizedLabelBase::AddInputs(
std::vector<Node*>{inputs...});

View File

@ -209,6 +209,34 @@ void CfgAssembler::OptimizeCfg() {
[&](Block* b) { return predecessor_count[b->id()] == 0; });
}
void CfgAssembler::ComputeInputDefinitions() {
Worklist<Block*> worklist;
// Setup start block.
Stack<DefinitionLocation> parameter_defs;
for (std::size_t i = 0; i < cfg_.ParameterCount(); ++i) {
parameter_defs.Push(DefinitionLocation::Parameter(i));
}
cfg_.start()->MergeInputDefinitions(parameter_defs, &worklist);
// Run fixpoint algorithm.
while (!worklist.IsEmpty()) {
Block* block = worklist.Dequeue();
Stack<DefinitionLocation> definitions = block->InputDefinitions();
// Propagate through block's instructions.
for (const auto& instruction : block->instructions()) {
instruction.RecomputeDefinitionLocations(&definitions, &worklist);
}
}
for (Block* block : cfg_.blocks()) {
DCHECK_IMPLIES(!block->IsDead(), block->InputDefinitions().Size() ==
block->InputTypes().Size());
USE(block);
}
}
} // namespace torque
} // namespace internal
} // namespace v8

View File

@ -53,10 +53,42 @@ class Block {
size_t id() const { return id_; }
bool IsDeferred() const { return is_deferred_; }
void MergeInputDefinitions(const Stack<DefinitionLocation>& input_definitions,
Worklist<Block*>* worklist) {
if (!input_definitions_) {
input_definitions_ = input_definitions;
if (worklist) worklist->Enqueue(this);
return;
}
DCHECK_EQ(input_definitions_->Size(), input_definitions.Size());
bool changed = false;
for (BottomOffset i = 0; i < input_definitions.AboveTop(); ++i) {
auto& current = input_definitions_->Peek(i);
auto& input = input_definitions.Peek(i);
if (current == input) continue;
if (current == DefinitionLocation::Phi(this, i.offset)) continue;
input_definitions_->Poke(i, DefinitionLocation::Phi(this, i.offset));
changed = true;
}
if (changed && worklist) worklist->Enqueue(this);
}
bool HasInputDefinitions() const {
return input_definitions_ != base::nullopt;
}
const Stack<DefinitionLocation>& InputDefinitions() const {
DCHECK(HasInputDefinitions());
return *input_definitions_;
}
bool IsDead() const { return !HasInputDefinitions(); }
private:
ControlFlowGraph* cfg_;
std::vector<Instruction> instructions_;
base::Optional<Stack<const Type*>> input_types_;
base::Optional<Stack<DefinitionLocation>> input_definitions_;
const size_t id_;
bool is_deferred_;
};
@ -95,6 +127,9 @@ class ControlFlowGraph {
}
const std::vector<Block*>& blocks() const { return placed_blocks_; }
size_t NumberOfBlockIds() const { return next_block_id_; }
std::size_t ParameterCount() const {
return start_ ? start_->InputTypes().Size() : 0;
}
private:
std::list<Block> blocks_;
@ -116,6 +151,7 @@ class CfgAssembler {
}
OptimizeCfg();
DCHECK(CfgIsComplete());
ComputeInputDefinitions();
return cfg_;
}
@ -167,6 +203,7 @@ class CfgAssembler {
void PrintCurrentStack(std::ostream& s) { s << "stack: " << current_stack_; }
void OptimizeCfg();
void ComputeInputDefinitions();
private:
friend class CfgAssemblerScopedTemporaryBlock;

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,8 @@ class CSAGenerator {
CSAGenerator(const ControlFlowGraph& cfg, std::ostream& out,
base::Optional<Builtin::Kind> linkage = base::nullopt)
: cfg_(cfg),
out_(out),
out_(&out),
out_decls_(&out),
linkage_(linkage),
previous_position_(SourcePosition::Invalid()) {}
base::Optional<Stack<std::string>> EmitGraph(Stack<std::string> parameters);
@ -31,22 +32,56 @@ class CSAGenerator {
private:
const ControlFlowGraph& cfg_;
std::ostream& out_;
std::ostream* out_;
std::ostream* out_decls_;
size_t fresh_id_ = 0;
base::Optional<Builtin::Kind> linkage_;
SourcePosition previous_position_;
std::map<DefinitionLocation, std::string> location_map_;
std::string DefinitionToVariable(const DefinitionLocation& location) {
if (location.IsPhi()) {
std::stringstream stream;
stream << "phi_bb" << location.GetPhiBlock()->id() << "_"
<< location.GetPhiIndex();
return stream.str();
} else if (location.IsParameter()) {
auto it = location_map_.find(location);
DCHECK_NE(it, location_map_.end());
return it->second;
} else {
DCHECK(location.IsInstruction());
auto it = location_map_.find(location);
if (it == location_map_.end()) {
it = location_map_.insert(std::make_pair(location, FreshNodeName()))
.first;
}
return it->second;
}
}
void SetDefinitionVariable(const DefinitionLocation& definition,
const std::string& str) {
DCHECK_EQ(location_map_.find(definition), location_map_.end());
location_map_.insert(std::make_pair(definition, str));
}
std::ostream& out() { return *out_; }
std::ostream& decls() { return *out_decls_; }
bool IsEmptyInstruction(const Instruction& instruction);
void EmitSourcePosition(SourcePosition pos, bool always_emit = false);
std::string PreCallableExceptionPreparation(
base::Optional<Block*> catch_block);
void PostCallableExceptionPreparation(const std::string& catch_name,
const Type* return_type,
base::Optional<Block*> catch_block,
Stack<std::string>* stack);
void PostCallableExceptionPreparation(
const std::string& catch_name, const Type* return_type,
base::Optional<Block*> catch_block, Stack<std::string>* stack,
const base::Optional<DefinitionLocation>& exception_object_definition);
std::string FreshNodeName() { return "tmp" + std::to_string(fresh_id_++); }
std::string FreshCatchName() { return "catch" + std::to_string(fresh_id_++); }
std::string FreshLabelName() { return "label" + std::to_string(fresh_id_++); }
std::string BlockName(const Block* block) {
return "block" + std::to_string(block->id());
}

View File

@ -137,7 +137,7 @@ void ImplementationVisitor::Visit(NamespaceConstant* decl) {
assembler_ = base::nullopt;
source_out() << "return ";
source_out() << " return ";
CSAGenerator::EmitCSAValue(return_result, values, source_out());
source_out() << ";\n";
source_out() << "}\n\n";

View File

@ -48,6 +48,11 @@ void PeekInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->Push(type);
}
void PeekInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Push(locations->Peek(slot));
}
void PokeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const Type* type = stack->Top();
@ -59,26 +64,71 @@ void PokeInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->Pop();
}
void PokeInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Poke(slot, locations->Pop());
}
void DeleteRangeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->DeleteRange(range);
}
void DeleteRangeInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->DeleteRange(range);
}
void PushUninitializedInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
stack->Push(type);
}
void PushUninitializedInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Push(GetValueDefinition());
}
DefinitionLocation PushUninitializedInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
void PushBuiltinPointerInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
stack->Push(type);
}
void PushBuiltinPointerInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Push(GetValueDefinition());
}
DefinitionLocation PushBuiltinPointerInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
void NamespaceConstantInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
stack->PushMany(LowerType(constant->type()));
}
void NamespaceConstantInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(GetValueDefinition(i));
}
}
std::size_t NamespaceConstantInstruction::GetValueDefinitionCount() const {
return LowerType(constant->type()).size();
}
DefinitionLocation NamespaceConstantInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
void InstructionBase::InvalidateTransientTypes(
Stack<const Type*>* stack) const {
auto current = stack->begin();
@ -113,6 +163,26 @@ void CallIntrinsicInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->PushMany(LowerType(intrinsic->signature().return_type));
}
void CallIntrinsicInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
auto parameter_types =
LowerParameterTypes(intrinsic->signature().parameter_types);
locations->PopMany(parameter_types.size());
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(DefinitionLocation::Instruction(this, i));
}
}
std::size_t CallIntrinsicInstruction::GetValueDefinitionCount() const {
return LowerType(intrinsic->signature().return_type).size();
}
DefinitionLocation CallIntrinsicInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
@ -140,6 +210,39 @@ void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->PushMany(LowerType(macro->signature().return_type));
}
void CallCsaMacroInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
auto parameter_types =
LowerParameterTypes(macro->signature().parameter_types);
locations->PopMany(parameter_types.size());
if (catch_block) {
locations->Push(*GetExceptionObjectDefinition());
(*catch_block)->MergeInputDefinitions(*locations, worklist);
locations->Pop();
}
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(GetValueDefinition(i));
}
}
base::Optional<DefinitionLocation>
CallCsaMacroInstruction::GetExceptionObjectDefinition() const {
if (!catch_block) return base::nullopt;
return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
}
std::size_t CallCsaMacroInstruction::GetValueDefinitionCount() const {
return LowerType(macro->signature().return_type).size();
}
DefinitionLocation CallCsaMacroInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
void CallCsaMacroAndBranchInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
@ -188,6 +291,78 @@ void CallCsaMacroAndBranchInstruction::TypeInstruction(
}
}
void CallCsaMacroAndBranchInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
auto parameter_types =
LowerParameterTypes(macro->signature().parameter_types);
locations->PopMany(parameter_types.size());
for (std::size_t label_index = 0; label_index < label_blocks.size();
++label_index) {
const std::size_t count = GetLabelValueDefinitionCount(label_index);
for (std::size_t i = 0; i < count; ++i) {
locations->Push(GetLabelValueDefinition(label_index, i));
}
label_blocks[label_index]->MergeInputDefinitions(*locations, worklist);
locations->PopMany(count);
}
if (catch_block) {
locations->Push(*GetExceptionObjectDefinition());
(*catch_block)->MergeInputDefinitions(*locations, worklist);
locations->Pop();
}
if (macro->signature().return_type != TypeOracle::GetNeverType()) {
if (return_continuation) {
const std::size_t count = GetValueDefinitionCount();
for (std::size_t i = 0; i < count; ++i) {
locations->Push(GetValueDefinition(i));
}
(*return_continuation)->MergeInputDefinitions(*locations, worklist);
locations->PopMany(count);
}
}
}
std::size_t CallCsaMacroAndBranchInstruction::GetLabelCount() const {
return label_blocks.size();
}
std::size_t CallCsaMacroAndBranchInstruction::GetLabelValueDefinitionCount(
std::size_t label) const {
DCHECK_LT(label, GetLabelCount());
return LowerParameterTypes(macro->signature().labels[label].types).size();
}
DefinitionLocation CallCsaMacroAndBranchInstruction::GetLabelValueDefinition(
std::size_t label, std::size_t index) const {
DCHECK_LT(index, GetLabelValueDefinitionCount(label));
std::size_t offset = GetValueDefinitionCount() + (catch_block ? 1 : 0);
for (std::size_t label_index = 0; label_index < label; ++label_index) {
offset += GetLabelValueDefinitionCount(label_index);
}
return DefinitionLocation::Instruction(this, offset + index);
}
std::size_t CallCsaMacroAndBranchInstruction::GetValueDefinitionCount() const {
if (macro->signature().return_type == TypeOracle::GetNeverType()) return 0;
if (!return_continuation) return 0;
return LowerType(macro->signature().return_type).size();
}
DefinitionLocation CallCsaMacroAndBranchInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
base::Optional<DefinitionLocation>
CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const {
if (!catch_block) return base::nullopt;
return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
}
void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
@ -208,6 +383,37 @@ void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->PushMany(LowerType(builtin->signature().return_type));
}
void CallBuiltinInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->PopMany(argc);
if (catch_block) {
locations->Push(*GetExceptionObjectDefinition());
(*catch_block)->MergeInputDefinitions(*locations, worklist);
locations->Pop();
}
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(GetValueDefinition(i));
}
}
std::size_t CallBuiltinInstruction::GetValueDefinitionCount() const {
return LowerType(builtin->signature().return_type).size();
}
DefinitionLocation CallBuiltinInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
base::Optional<DefinitionLocation>
CallBuiltinInstruction::GetExceptionObjectDefinition() const {
if (!catch_block) return base::nullopt;
return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
}
void CallBuiltinPointerInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
@ -216,12 +422,31 @@ void CallBuiltinPointerInstruction::TypeInstruction(
if (argument_types != LowerParameterTypes(f->parameter_types())) {
ReportError("wrong argument types");
}
DCHECK_EQ(type, f);
// TODO(tebbi): Only invalidate transient types if the function pointer type
// is transitioning.
InvalidateTransientTypes(stack);
stack->PushMany(LowerType(f->return_type()));
}
void CallBuiltinPointerInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->PopMany(argc + 1);
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(GetValueDefinition(i));
}
}
std::size_t CallBuiltinPointerInstruction::GetValueDefinitionCount() const {
return LowerType(type->return_type()).size();
}
DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
@ -246,6 +471,42 @@ void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
}
}
void CallRuntimeInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->PopMany(argc);
if (catch_block) {
locations->Push(*GetExceptionObjectDefinition());
(*catch_block)->MergeInputDefinitions(*locations, worklist);
locations->Pop();
}
const Type* return_type = runtime_function->signature().return_type;
if (return_type != TypeOracle::GetNeverType()) {
for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
locations->Push(GetValueDefinition(i));
}
}
}
std::size_t CallRuntimeInstruction::GetValueDefinitionCount() const {
const Type* return_type = runtime_function->signature().return_type;
if (return_type == TypeOracle::GetNeverType()) return 0;
return LowerType(return_type).size();
}
DefinitionLocation CallRuntimeInstruction::GetValueDefinition(
std::size_t index) const {
DCHECK_LT(index, GetValueDefinitionCount());
return DefinitionLocation::Instruction(this, index);
}
base::Optional<DefinitionLocation>
CallRuntimeInstruction::GetExceptionObjectDefinition() const {
if (!catch_block) return base::nullopt;
return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
}
void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
const Type* condition_type = stack->Pop();
@ -256,17 +517,35 @@ void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
if_false->SetInputTypes(*stack);
}
void BranchInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
if_true->MergeInputDefinitions(*locations, worklist);
if_false->MergeInputDefinitions(*locations, worklist);
}
void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
if_true->SetInputTypes(*stack);
if_false->SetInputTypes(*stack);
}
void ConstexprBranchInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
if_true->MergeInputDefinitions(*locations, worklist);
if_false->MergeInputDefinitions(*locations, worklist);
}
void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
destination->SetInputTypes(*stack);
}
void GotoInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
destination->MergeInputDefinitions(*locations, worklist);
}
void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
if (variable_names.size() != stack->Size()) {
@ -274,22 +553,45 @@ void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
}
}
void GotoExternalInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
void ReturnInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
cfg->SetReturnType(stack->Pop());
}
void ReturnInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
}
void PrintConstantStringInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {}
void PrintConstantStringInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
void AbortInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {}
void AbortInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
stack->Poke(stack->AboveTop() - 1, destination_type);
}
void UnsafeCastInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Poke(locations->AboveTop() - 1, GetValueDefinition());
}
DefinitionLocation UnsafeCastInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
void LoadReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectType(TypeOracle::GetIntPtrType(), stack->Pop());
@ -298,6 +600,17 @@ void LoadReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->Push(type);
}
void LoadReferenceInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
locations->Pop();
locations->Push(GetValueDefinition());
}
DefinitionLocation LoadReferenceInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
void StoreReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectSubtype(stack->Pop(), type);
@ -305,12 +618,29 @@ void StoreReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
ExpectSubtype(stack->Pop(), TypeOracle::GetHeapObjectType());
}
void StoreReferenceInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
locations->Pop();
locations->Pop();
}
void LoadBitFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectType(bit_field_struct_type, stack->Pop());
stack->Push(bit_field.name_and_type.type);
}
void LoadBitFieldInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
locations->Push(GetValueDefinition());
}
DefinitionLocation LoadBitFieldInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
void StoreBitFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectSubtype(bit_field.name_and_type.type, stack->Pop());
@ -318,6 +648,17 @@ void StoreBitFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
stack->Push(bit_field_struct_type);
}
void StoreBitFieldInstruction::RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
locations->Pop();
locations->Pop();
locations->Push(GetValueDefinition());
}
DefinitionLocation StoreBitFieldInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0);
}
bool CallRuntimeInstruction::IsBlockTerminator() const {
return is_tailcall || runtime_function->signature().return_type ==
TypeOracle::GetNeverType();

View File

@ -50,11 +50,14 @@ class RuntimeFunction;
V(AbortInstruction) \
V(UnsafeCastInstruction)
#define TORQUE_INSTRUCTION_BOILERPLATE() \
static const InstructionKind kKind; \
std::unique_ptr<InstructionBase> Clone() const override; \
void Assign(const InstructionBase& other) override; \
void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \
#define TORQUE_INSTRUCTION_BOILERPLATE() \
static const InstructionKind kKind; \
std::unique_ptr<InstructionBase> Clone() const override; \
void Assign(const InstructionBase& other) override; \
void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) \
const override; \
void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations, \
Worklist<Block*>* worklist) \
const override;
enum class InstructionKind {
@ -63,6 +66,115 @@ enum class InstructionKind {
#undef ENUM_ITEM
};
struct InstructionBase;
class DefinitionLocation {
public:
enum class Kind {
kInvalid,
kParameter,
kPhi,
kInstruction,
};
DefinitionLocation() : kind_(Kind::kInvalid), location_(nullptr), index_(0) {}
static DefinitionLocation Parameter(std::size_t index) {
return DefinitionLocation(Kind::kParameter, nullptr, index);
}
static DefinitionLocation Phi(const Block* block, std::size_t index) {
return DefinitionLocation(Kind::kPhi, block, index);
}
static DefinitionLocation Instruction(const InstructionBase* instruction,
std::size_t index = 0) {
return DefinitionLocation(Kind::kInstruction, instruction, index);
}
Kind GetKind() const { return kind_; }
bool IsValid() const { return kind_ != Kind::kInvalid; }
bool IsParameter() const { return kind_ == Kind::kParameter; }
bool IsPhi() const { return kind_ == Kind::kPhi; }
bool IsInstruction() const { return kind_ == Kind::kInstruction; }
std::size_t GetParameterIndex() const {
DCHECK(IsParameter());
return index_;
}
const Block* GetPhiBlock() const {
DCHECK(IsPhi());
return reinterpret_cast<const Block*>(location_);
}
bool IsPhiFromBlock(const Block* block) const {
return IsPhi() && GetPhiBlock() == block;
}
std::size_t GetPhiIndex() const {
DCHECK(IsPhi());
return index_;
}
const InstructionBase* GetInstruction() const {
DCHECK(IsInstruction());
return reinterpret_cast<const InstructionBase*>(location_);
}
std::size_t GetInstructionIndex() const {
DCHECK(IsInstruction());
return index_;
}
bool operator==(const DefinitionLocation& other) const {
if (kind_ != other.kind_) return false;
if (location_ != other.location_) return false;
return index_ == other.index_;
}
bool operator!=(const DefinitionLocation& other) const {
return !operator==(other);
}
bool operator<(const DefinitionLocation& other) const {
if (kind_ != other.kind_) {
return static_cast<int>(kind_) < static_cast<int>(other.kind_);
}
if (location_ != other.location_) {
return location_ < other.location_;
}
return index_ < other.index_;
}
private:
DefinitionLocation(Kind kind, const void* location, std::size_t index)
: kind_(kind), location_(location), index_(index) {}
Kind kind_;
const void* location_;
std::size_t index_;
};
inline std::ostream& operator<<(std::ostream& stream,
const DefinitionLocation& loc) {
switch (loc.GetKind()) {
case DefinitionLocation::Kind::kInvalid:
return stream << "DefinitionLocation::Invalid()";
case DefinitionLocation::Kind::kParameter:
return stream << "DefinitionLocation::Parameter("
<< loc.GetParameterIndex() << ")";
case DefinitionLocation::Kind::kPhi:
return stream << "DefinitionLocation::Phi(" << std::hex
<< (uint64_t)loc.GetPhiBlock() << std::dec << ", "
<< loc.GetPhiIndex() << ")";
case DefinitionLocation::Kind::kInstruction:
return stream << "DefinitionLocation::Instruction(" << std::hex
<< (uint64_t)loc.GetInstruction() << std::dec << ", "
<< loc.GetInstructionIndex() << ")";
}
}
struct InstructionBase {
InstructionBase() : pos(CurrentSourcePosition::Get()) {}
virtual std::unique_ptr<InstructionBase> Clone() const = 0;
@ -71,6 +183,9 @@ struct InstructionBase {
virtual void TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const = 0;
virtual void RecomputeDefinitionLocations(
Stack<DefinitionLocation>* locations,
Worklist<Block*>* worklist) const = 0;
void InvalidateTransientTypes(Stack<const Type*>* stack) const;
virtual bool IsBlockTerminator() const { return false; }
virtual void AppendSuccessorBlocks(std::vector<Block*>* block_list) const {}
@ -141,6 +256,10 @@ class Instruction {
void TypeInstruction(Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
return instruction_->TypeInstruction(stack, cfg);
}
void RecomputeDefinitionLocations(Stack<DefinitionLocation>* locations,
Worklist<Block*>* worklist) const {
instruction_->RecomputeDefinitionLocations(locations, worklist);
}
InstructionBase* operator->() { return instruction_.get(); }
const InstructionBase* operator->() const { return instruction_.get(); }
@ -183,6 +302,8 @@ struct PushUninitializedInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit PushUninitializedInstruction(const Type* type) : type(type) {}
DefinitionLocation GetValueDefinition() const;
const Type* type;
};
@ -193,6 +314,8 @@ struct PushBuiltinPointerInstruction : InstructionBase {
DCHECK(type->IsBuiltinPointerType());
}
DefinitionLocation GetValueDefinition() const;
std::string external_name;
const Type* type;
};
@ -202,12 +325,18 @@ struct NamespaceConstantInstruction : InstructionBase {
explicit NamespaceConstantInstruction(NamespaceConstant* constant)
: constant(constant) {}
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
NamespaceConstant* constant;
};
struct LoadReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
explicit LoadReferenceInstruction(const Type* type) : type(type) {}
DefinitionLocation GetValueDefinition() const;
const Type* type;
};
@ -224,6 +353,9 @@ struct LoadBitFieldInstruction : InstructionBase {
BitField bit_field)
: bit_field_struct_type(bit_field_struct_type),
bit_field(std::move(bit_field)) {}
DefinitionLocation GetValueDefinition() const;
const BitFieldStructType* bit_field_struct_type;
BitField bit_field;
};
@ -236,6 +368,9 @@ struct StoreBitFieldInstruction : InstructionBase {
BitField bit_field)
: bit_field_struct_type(bit_field_struct_type),
bit_field(std::move(bit_field)) {}
DefinitionLocation GetValueDefinition() const;
const BitFieldStructType* bit_field_struct_type;
BitField bit_field;
};
@ -249,6 +384,9 @@ struct CallIntrinsicInstruction : InstructionBase {
specialization_types(std::move(specialization_types)),
constexpr_arguments(constexpr_arguments) {}
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
Intrinsic* intrinsic;
TypeVector specialization_types;
std::vector<std::string> constexpr_arguments;
@ -266,6 +404,10 @@ struct CallCsaMacroInstruction : InstructionBase {
if (catch_block) block_list->push_back(*catch_block);
}
base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
Macro* macro;
std::vector<std::string> constexpr_arguments;
base::Optional<Block*> catch_block;
@ -290,6 +432,14 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase {
for (Block* block : label_blocks) block_list->push_back(block);
}
std::size_t GetLabelCount() const;
std::size_t GetLabelValueDefinitionCount(std::size_t label) const;
DefinitionLocation GetLabelValueDefinition(std::size_t label,
std::size_t index) const;
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
Macro* macro;
std::vector<std::string> constexpr_arguments;
base::Optional<Block*> return_continuation;
@ -310,6 +460,10 @@ struct CallBuiltinInstruction : InstructionBase {
if (catch_block) block_list->push_back(*catch_block);
}
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
bool is_tailcall;
Builtin* builtin;
size_t argc;
@ -323,6 +477,9 @@ struct CallBuiltinPointerInstruction : InstructionBase {
const BuiltinPointerType* type, size_t argc)
: is_tailcall(is_tailcall), type(type), argc(argc) {}
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
bool is_tailcall;
const BuiltinPointerType* type;
size_t argc;
@ -342,6 +499,10 @@ struct CallRuntimeInstruction : InstructionBase {
if (catch_block) block_list->push_back(*catch_block);
}
std::size_t GetValueDefinitionCount() const;
DefinitionLocation GetValueDefinition(std::size_t index) const;
base::Optional<DefinitionLocation> GetExceptionObjectDefinition() const;
bool is_tailcall;
RuntimeFunction* runtime_function;
size_t argc;
@ -434,6 +595,8 @@ struct UnsafeCastInstruction : InstructionBase {
explicit UnsafeCastInstruction(const Type* destination_type)
: destination_type(destination_type) {}
DefinitionLocation GetValueDefinition() const;
const Type* destination_type;
};

View File

@ -6,10 +6,10 @@
#define V8_TORQUE_UTILS_H_
#include <ostream>
#include <queue>
#include <streambuf>
#include <string>
#include <unordered_set>
#include <vector>
#include "src/base/functional.h"
#include "src/base/optional.h"
@ -172,6 +172,13 @@ void PrintCommaSeparatedList(std::ostream& os, const T& list) {
struct BottomOffset {
size_t offset;
BottomOffset(std::nullptr_t zero = 0) // NOLINT(runtime/explicit)
: offset(0) {}
explicit BottomOffset(std::size_t offset) : offset(offset) {}
BottomOffset& operator=(std::size_t offset) {
this->offset = offset;
return *this;
}
BottomOffset& operator++() {
++offset;
return *this;
@ -488,6 +495,36 @@ class ResidueClass {
static const size_t kMaxModulusLog2 = 8 * sizeof(size_t);
};
template <typename T>
class Worklist {
public:
bool IsEmpty() const {
DCHECK_EQ(queue_.size(), contained_.size());
return queue_.empty();
}
bool Enqueue(T value) {
if (contained_.find(value) != contained_.end()) return false;
queue_.push(value);
contained_.insert(value);
DCHECK_EQ(queue_.size(), contained_.size());
return true;
}
T Dequeue() {
DCHECK(!IsEmpty());
T value = queue_.front();
queue_.pop();
contained_.erase(value);
DCHECK_EQ(queue_.size(), contained_.size());
return value;
}
private:
std::queue<T> queue_;
std::unordered_set<T> contained_;
};
} // namespace torque
} // namespace internal
} // namespace v8