Files
sdk/runtime/vm/compiler/backend/block_builder.h
T
Alexander Markov 5117c45770 [vm/compiler] Combine argument type with static and inferred parameter types during inlining
Previously, when preparing a Parameter stub during inlining, compiler
unconditionally used argument type (from the caller). This type
could be less accurate than static or inferred parameter type of
the callee. For example, the argument could originate from inlined generic ListIterator.current:

  v24 <- LoadField(v23 . _current@9040228) T{X0??}

and static type could be 'int'.

This change combines argument type from callee with a parameter type
from caller during inlining. In order to get parameter type for
optional parameters, ParameterInstr is extended to hold real parameter
index and ParameterIndex::ComputeType is extended to work on
parameters which are not passed directly.

Also, this change fixes the incorrect non-nullable receiver type for
Object and Null methods.

TEST=runtime/tests/vm/dart/regress_51790_il_test.dart
Fixes https://github.com/dart-lang/sdk/issues/51790

Change-Id: I19fff19833a6148ed36a16895626e4e1d8ae62d3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290602
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
2023-03-26 03:42:30 +00:00

169 lines
5.7 KiB
C++

// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_
#define RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_
#if defined(DART_PRECOMPILED_RUNTIME)
#error "AOT runtime should not use compiler sources (including header files)"
#endif // defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/il.h"
namespace dart {
namespace compiler {
// Helper class for building basic blocks in SSA form.
class BlockBuilder : public ValueObject {
public:
BlockBuilder(FlowGraph* flow_graph, BlockEntryInstr* entry)
: flow_graph_(flow_graph),
source_(InstructionSource(flow_graph_->function().token_pos(),
flow_graph->inlining_id())),
entry_(entry),
current_(entry),
dummy_env_(new Environment(0, 0, 0, flow_graph->function(), nullptr)) {
// Some graph transformations use environments from block entries.
entry->SetEnvironment(dummy_env_);
}
Definition* AddToInitialDefinitions(Definition* def) {
flow_graph_->AllocateSSAIndex(def);
auto normal_entry = flow_graph_->graph_entry()->normal_entry();
flow_graph_->AddToInitialDefinitions(normal_entry, def);
return def;
}
template <typename T>
T* AddDefinition(T* def) {
flow_graph_->AllocateSSAIndex(def);
AddInstruction(def);
return def;
}
template <typename T>
T* AddInstruction(T* instr) {
if (instr->ComputeCanDeoptimize() ||
instr->ComputeCanDeoptimizeAfterCall() ||
instr->CanBecomeDeoptimizationTarget()) {
// All instructions that can deoptimize must have an environment attached
// to them.
instr->SetEnvironment(dummy_env_);
}
current_ = current_->AppendInstruction(instr);
return instr;
}
const Function& function() const { return flow_graph_->function(); }
ReturnInstr* AddReturn(Value* value) {
const auto& function = flow_graph_->function();
const auto representation = FlowGraph::ReturnRepresentationOf(function);
ReturnInstr* instr = new ReturnInstr(
Source(), value, CompilerState::Current().GetNextDeoptId(),
representation);
AddInstruction(instr);
entry_->set_last_instruction(instr);
return instr;
}
Definition* AddParameter(intptr_t index, bool with_frame) {
const auto& function = flow_graph_->function();
const intptr_t param_offset = FlowGraph::ParameterOffsetAt(function, index);
const auto representation =
FlowGraph::ParameterRepresentationAt(function, index);
return AddParameter(index, param_offset, with_frame, representation);
}
Definition* AddParameter(intptr_t index,
intptr_t param_offset,
bool with_frame,
Representation representation) {
auto normal_entry = flow_graph_->graph_entry()->normal_entry();
return AddToInitialDefinitions(new ParameterInstr(
/*env_index=*/index, /*param_index=*/index, param_offset, normal_entry,
representation, with_frame ? FPREG : SPREG));
}
TokenPosition TokenPos() const { return source_.token_pos; }
const InstructionSource& Source() const { return source_; }
Definition* AddNullDefinition() {
return flow_graph_->GetConstant(Object::ZoneHandle());
}
Definition* AddUnboxInstr(Representation rep, Value* value, bool is_checked) {
Definition* unboxed_value =
AddDefinition(UnboxInstr::Create(rep, value, DeoptId::kNone));
if (is_checked) {
// The type of |value| has already been checked and it is safe to
// adjust reaching type. This is done manually because there is no type
// propagation when building intrinsics.
unboxed_value->AsUnbox()->value()->SetReachingType(
TypeForRepresentation(rep));
}
return unboxed_value;
}
Definition* AddUnboxInstr(Representation rep,
Definition* boxed,
bool is_checked) {
return AddUnboxInstr(rep, new Value(boxed), is_checked);
}
BranchInstr* AddBranch(ComparisonInstr* comp,
TargetEntryInstr* true_successor,
TargetEntryInstr* false_successor) {
auto branch =
new BranchInstr(comp, CompilerState::Current().GetNextDeoptId());
// Some graph transformations use environments from branches.
branch->SetEnvironment(dummy_env_);
current_->AppendInstruction(branch);
current_ = nullptr;
*branch->true_successor_address() = true_successor;
*branch->false_successor_address() = false_successor;
return branch;
}
void AddPhi(PhiInstr* phi) {
flow_graph_->AllocateSSAIndex(phi);
phi->mark_alive();
entry_->AsJoinEntry()->InsertPhi(phi);
}
private:
static CompileType* TypeForRepresentation(Representation rep) {
switch (rep) {
case kUnboxedDouble:
return new CompileType(CompileType::FromCid(kDoubleCid));
case kUnboxedFloat32x4:
return new CompileType(CompileType::FromCid(kFloat32x4Cid));
case kUnboxedInt32x4:
return new CompileType(CompileType::FromCid(kInt32x4Cid));
case kUnboxedFloat64x2:
return new CompileType(CompileType::FromCid(kFloat64x2Cid));
case kUnboxedUint32:
case kUnboxedInt64:
return new CompileType(CompileType::Int());
default:
UNREACHABLE();
return nullptr;
}
}
FlowGraph* const flow_graph_;
const InstructionSource source_;
BlockEntryInstr* entry_;
Instruction* current_;
Environment* dummy_env_;
};
} // namespace compiler
} // namespace dart
#endif // RUNTIME_VM_COMPILER_BACKEND_BLOCK_BUILDER_H_