Commit 4319876d authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm][turbofan] Introduce wasm inlining heuristics

We introduce the WasmInliningHeuristics virtual class and implement it
with a trivial heuristics that inlines direct calls based on callee
index only. Other, more meaningful heuristics will be introduced later.

Bug: v8:12166
Change-Id: I74fd8f61e0c97b975827fa062629e9ff7463e058
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3157952
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76816}
parent d90e873e
...@@ -1696,8 +1696,11 @@ struct WasmInliningPhase { ...@@ -1696,8 +1696,11 @@ struct WasmInliningPhase {
data->jsgraph()->Dead(), data->observe_node_manager()); data->jsgraph()->Dead(), data->observe_node_manager());
DeadCodeElimination dead(&graph_reducer, data->graph(), DeadCodeElimination dead(&graph_reducer, data->graph(),
data->mcgraph()->common(), temp_zone); data->mcgraph()->common(), temp_zone);
// For now, hard-code inlining the function at index 0.
InlineByIndex heuristics({0});
WasmInliner inliner(&graph_reducer, env, data->source_positions(), WasmInliner inliner(&graph_reducer, env, data->source_positions(),
data->node_origins(), data->mcgraph(), wire_bytes, 0); data->node_origins(), data->mcgraph(), wire_bytes,
&heuristics);
AddReducer(data, &graph_reducer, &dead); AddReducer(data, &graph_reducer, &dead);
AddReducer(data, &graph_reducer, &inliner); AddReducer(data, &graph_reducer, &inliner);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/compiler/wasm-inlining.h" #include "src/compiler/wasm-inlining.h"
#include "src/compiler/all-nodes.h" #include "src/compiler/all-nodes.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/wasm-compiler.h" #include "src/compiler/wasm-compiler.h"
#include "src/wasm/function-body-decoder.h" #include "src/wasm/function-body-decoder.h"
...@@ -26,7 +27,9 @@ Reduction WasmInliner::Reduce(Node* node) { ...@@ -26,7 +27,9 @@ Reduction WasmInliner::Reduce(Node* node) {
} }
} }
// TODO(12166): Abstract over a heuristics provider. // TODO(12166): Save inlined frames for trap/--trace-wasm purposes. Consider
// tail calls.
// TODO(12166): Inline indirect calls/call_ref.
Reduction WasmInliner::ReduceCall(Node* call) { Reduction WasmInliner::ReduceCall(Node* call) {
DCHECK(call->opcode() == IrOpcode::kCall || DCHECK(call->opcode() == IrOpcode::kCall ||
call->opcode() == IrOpcode::kTailCall); call->opcode() == IrOpcode::kTailCall);
...@@ -36,16 +39,23 @@ Reduction WasmInliner::ReduceCall(Node* call) { ...@@ -36,16 +39,23 @@ Reduction WasmInliner::ReduceCall(Node* call) {
: IrOpcode::kRelocatableInt64Constant; : IrOpcode::kRelocatableInt64Constant;
if (callee->opcode() != reloc_opcode) return NoChange(); if (callee->opcode() != reloc_opcode) return NoChange();
auto info = OpParameter<RelocatablePtrConstantInfo>(callee->op()); auto info = OpParameter<RelocatablePtrConstantInfo>(callee->op());
if (static_cast<uint32_t>(info.value()) != inlinee_index_) return NoChange(); uint32_t inlinee_index = static_cast<uint32_t>(info.value());
if (!heuristics_->DoInline(source_positions_->GetSourcePosition(call),
inlinee_index)) {
return NoChange();
}
CHECK_LT(inlinee_index, module()->functions.size());
const wasm::WasmFunction* inlinee = &module()->functions[inlinee_index];
CHECK_LT(inlinee_index_, module()->functions.size()); base::Vector<const byte> function_bytes = wire_bytes_->GetCode(inlinee->code);
base::Vector<const byte> function_bytes =
wire_bytes_->GetCode(inlinee()->code); const wasm::FunctionBody inlinee_body(inlinee->sig, inlinee->code.offset(),
const wasm::FunctionBody inlinee_body( function_bytes.begin(),
inlinee()->sig, inlinee()->code.offset(), function_bytes.begin(),
function_bytes.end()); function_bytes.end());
wasm::WasmFeatures detected; wasm::WasmFeatures detected;
WasmGraphBuilder builder(env_, zone(), mcgraph_, inlinee_body.sig, spt_); WasmGraphBuilder builder(env_, zone(), mcgraph_, inlinee_body.sig,
source_positions_);
std::vector<WasmLoopInfo> infos; std::vector<WasmLoopInfo> infos;
size_t subgraph_min_node_id = graph()->NodeCount(); size_t subgraph_min_node_id = graph()->NodeCount();
...@@ -56,7 +66,7 @@ Reduction WasmInliner::ReduceCall(Node* call) { ...@@ -56,7 +66,7 @@ Reduction WasmInliner::ReduceCall(Node* call) {
Graph::SubgraphScope scope(graph()); Graph::SubgraphScope scope(graph());
result = wasm::BuildTFGraph(zone()->allocator(), env_->enabled_features, result = wasm::BuildTFGraph(zone()->allocator(), env_->enabled_features,
module(), &builder, &detected, inlinee_body, module(), &builder, &detected, inlinee_body,
&infos, node_origins_, inlinee_index_, &infos, node_origins_, inlinee_index,
wasm::kDoNotInstrumentEndpoints); wasm::kDoNotInstrumentEndpoints);
inlinee_start = graph()->start(); inlinee_start = graph()->start();
inlinee_end = graph()->end(); inlinee_end = graph()->end();
...@@ -64,7 +74,7 @@ Reduction WasmInliner::ReduceCall(Node* call) { ...@@ -64,7 +74,7 @@ Reduction WasmInliner::ReduceCall(Node* call) {
if (result.failed()) return NoChange(); if (result.failed()) return NoChange();
return call->opcode() == IrOpcode::kCall return call->opcode() == IrOpcode::kCall
? InlineCall(call, inlinee_start, inlinee_end, ? InlineCall(call, inlinee_start, inlinee_end, inlinee->sig,
subgraph_min_node_id) subgraph_min_node_id)
: InlineTailCall(call, inlinee_start, inlinee_end); : InlineTailCall(call, inlinee_start, inlinee_end);
} }
...@@ -117,6 +127,7 @@ Reduction WasmInliner::InlineTailCall(Node* call, Node* callee_start, ...@@ -117,6 +127,7 @@ Reduction WasmInliner::InlineTailCall(Node* call, Node* callee_start,
Reduction WasmInliner::InlineCall(Node* call, Node* callee_start, Reduction WasmInliner::InlineCall(Node* call, Node* callee_start,
Node* callee_end, Node* callee_end,
const wasm::FunctionSig* inlinee_sig,
size_t subgraph_min_node_id) { size_t subgraph_min_node_id) {
DCHECK(call->opcode() == IrOpcode::kCall); DCHECK(call->opcode() == IrOpcode::kCall);
...@@ -159,7 +170,7 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start, ...@@ -159,7 +170,7 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start,
// inlinee. It will then be handled like any other return. // inlinee. It will then be handled like any other return.
auto descriptor = CallDescriptorOf(input->op()); auto descriptor = CallDescriptorOf(input->op());
NodeProperties::ChangeOp(input, common()->Call(descriptor)); NodeProperties::ChangeOp(input, common()->Call(descriptor));
int return_arity = static_cast<int>(inlinee()->sig->return_count()); int return_arity = static_cast<int>(inlinee_sig->return_count());
NodeVector return_inputs(zone()); NodeVector return_inputs(zone());
// The first input of a return node is always the 0 constant. // The first input of a return node is always the 0 constant.
return_inputs.push_back(graph()->NewNode(common()->Int32Constant(0))); return_inputs.push_back(graph()->NewNode(common()->Int32Constant(0)));
...@@ -256,7 +267,7 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start, ...@@ -256,7 +267,7 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start,
// Find the correct machine representation for the return values from the // Find the correct machine representation for the return values from the
// inlinee signature. // inlinee signature.
MachineRepresentation repr = MachineRepresentation repr =
inlinee()->sig->GetReturn(i).machine_representation(); inlinee_sig->GetReturn(i).machine_representation();
Node* ith_value_output = graph()->NewNode( Node* ith_value_output = graph()->NewNode(
common()->Phi(repr, return_count), common()->Phi(repr, return_count),
static_cast<int>(ith_values.size()), &ith_values.front()); static_cast<int>(ith_values.size()), &ith_values.front());
...@@ -295,10 +306,6 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start, ...@@ -295,10 +306,6 @@ Reduction WasmInliner::InlineCall(Node* call, Node* callee_start,
const wasm::WasmModule* WasmInliner::module() const { return env_->module; } const wasm::WasmModule* WasmInliner::module() const { return env_->module; }
const wasm::WasmFunction* WasmInliner::inlinee() const {
return &module()->functions[inlinee_index_];
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -30,24 +30,49 @@ namespace compiler { ...@@ -30,24 +30,49 @@ namespace compiler {
class NodeOriginTable; class NodeOriginTable;
class SourcePositionTable; class SourcePositionTable;
// Parent class for classes that provide heuristics on how to inline in wasm.
class WasmInliningHeuristics {
public:
virtual bool DoInline(SourcePosition position,
uint32_t function_index) const = 0;
};
// A simple inlining heuristic that inlines all function calls to a set of given
// function indices.
class InlineByIndex : public WasmInliningHeuristics {
public:
explicit InlineByIndex(uint32_t function_index)
: WasmInliningHeuristics(), function_indices_(function_index) {}
InlineByIndex(std::initializer_list<uint32_t> function_indices)
: WasmInliningHeuristics(), function_indices_(function_indices) {}
bool DoInline(SourcePosition position,
uint32_t function_index) const override {
return function_indices_.count(function_index) > 0;
}
private:
std::unordered_set<uint32_t> function_indices_;
};
// The WasmInliner provides the core graph inlining machinery for Webassembly // The WasmInliner provides the core graph inlining machinery for Webassembly
// graphs. Note that this class only deals with the mechanics of how to inline // graphs. Note that this class only deals with the mechanics of how to inline
// one graph into another, heuristics that decide what and how much to inline // one graph into another; heuristics that decide what and how much to inline
// are beyond its scope. As a current placeholder, only a function at specific // are provided by {WasmInliningHeuristics}.
// given index {inlinee_index} is inlined.
class WasmInliner final : public AdvancedReducer { class WasmInliner final : public AdvancedReducer {
public: public:
WasmInliner(Editor* editor, wasm::CompilationEnv* env, WasmInliner(Editor* editor, wasm::CompilationEnv* env,
SourcePositionTable* spt, NodeOriginTable* node_origins, SourcePositionTable* source_positions,
MachineGraph* mcgraph, const wasm::WireBytesStorage* wire_bytes, NodeOriginTable* node_origins, MachineGraph* mcgraph,
uint32_t inlinee_index) const wasm::WireBytesStorage* wire_bytes,
const WasmInliningHeuristics* heuristics)
: AdvancedReducer(editor), : AdvancedReducer(editor),
env_(env), env_(env),
spt_(spt), source_positions_(source_positions),
node_origins_(node_origins), node_origins_(node_origins),
mcgraph_(mcgraph), mcgraph_(mcgraph),
wire_bytes_(wire_bytes), wire_bytes_(wire_bytes),
inlinee_index_(inlinee_index) {} heuristics_(heuristics) {}
const char* reducer_name() const override { return "WasmInliner"; } const char* reducer_name() const override { return "WasmInliner"; }
...@@ -63,16 +88,17 @@ class WasmInliner final : public AdvancedReducer { ...@@ -63,16 +88,17 @@ class WasmInliner final : public AdvancedReducer {
Reduction ReduceCall(Node* call); Reduction ReduceCall(Node* call);
Reduction InlineCall(Node* call, Node* callee_start, Node* callee_end, Reduction InlineCall(Node* call, Node* callee_start, Node* callee_end,
const wasm::FunctionSig* inlinee_sig,
size_t subgraph_min_node_id); size_t subgraph_min_node_id);
Reduction InlineTailCall(Node* call, Node* callee_start, Node* callee_end); Reduction InlineTailCall(Node* call, Node* callee_start, Node* callee_end);
void RewireFunctionEntry(Node* call, Node* callee_start); void RewireFunctionEntry(Node* call, Node* callee_start);
wasm::CompilationEnv* const env_; wasm::CompilationEnv* const env_;
SourcePositionTable* const spt_; SourcePositionTable* const source_positions_;
NodeOriginTable* const node_origins_; NodeOriginTable* const node_origins_;
MachineGraph* const mcgraph_; MachineGraph* const mcgraph_;
const wasm::WireBytesStorage* const wire_bytes_; const wasm::WireBytesStorage* const wire_bytes_;
const uint32_t inlinee_index_; const WasmInliningHeuristics* const heuristics_;
}; };
} // namespace compiler } // namespace compiler
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment