[wasm] Run Int64Lowering on inlined code
On 32-bit architectures, we need to run Int64Lowering on the inlinee code to make it compatible with the caller code. Since Int64Lowering now runs while a GraphReducer is active, only one of them can use node marks to store node states. Therefore, we move the Int64Lowering node states to an internal map. Bug: v8:12166 Change-Id: I53b85442d503e71fa533e06568f4b9db572a4401 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3283072 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#77941}
This commit is contained in:
parent
f74ea020d5
commit
f6edda0987
@ -31,7 +31,7 @@ Int64Lowering::Int64Lowering(
|
||||
machine_(machine),
|
||||
common_(common),
|
||||
simplified_(simplified),
|
||||
state_(graph, 3),
|
||||
state_(),
|
||||
stack_(zone),
|
||||
replacements_(nullptr),
|
||||
signature_(signature),
|
||||
@ -48,19 +48,21 @@ void Int64Lowering::LowerGraph() {
|
||||
return;
|
||||
}
|
||||
stack_.push_back({graph()->end(), 0});
|
||||
state_.Set(graph()->end(), State::kOnStack);
|
||||
state_[graph()->end()] = State::kOnStack;
|
||||
|
||||
while (!stack_.empty()) {
|
||||
NodeState& top = stack_.back();
|
||||
if (top.input_index == top.node->InputCount()) {
|
||||
// All inputs of top have already been lowered, now lower top.
|
||||
stack_.pop_back();
|
||||
state_.Set(top.node, State::kVisited);
|
||||
state_[top.node] = State::kVisited;
|
||||
LowerNode(top.node);
|
||||
} else {
|
||||
// Push the next input onto the stack.
|
||||
Node* input = top.node->InputAt(top.input_index++);
|
||||
if (state_.Get(input) == State::kUnvisited) {
|
||||
static_assert(State() == State::kUnvisited,
|
||||
"Default value for State has to be kUnvisited");
|
||||
if (state_[input] == State::kUnvisited) {
|
||||
if (input->opcode() == IrOpcode::kPhi) {
|
||||
// To break cycles with phi nodes we push phis on a separate stack so
|
||||
// that they are processed after all other nodes.
|
||||
@ -72,7 +74,7 @@ void Int64Lowering::LowerGraph() {
|
||||
} else {
|
||||
stack_.push_back({input, 0});
|
||||
}
|
||||
state_.Set(input, State::kOnStack);
|
||||
state_[input] = State::kOnStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ class V8_EXPORT_PRIVATE Int64Lowering {
|
||||
MachineOperatorBuilder* machine_;
|
||||
CommonOperatorBuilder* common_;
|
||||
SimplifiedOperatorBuilder* simplified_;
|
||||
NodeMarker<State> state_;
|
||||
std::unordered_map<Node*, State> state_;
|
||||
ZoneDeque<NodeState> stack_;
|
||||
Replacement* replacements_;
|
||||
Signature<MachineRepresentation>* signature_;
|
||||
|
@ -8205,6 +8205,40 @@ CallDescriptor* GetWasmCallDescriptor(Zone* zone, const wasm::FunctionSig* fsig,
|
||||
}
|
||||
|
||||
namespace {
|
||||
const wasm::FunctionSig* ReplaceTypeInSig(Zone* zone,
|
||||
const wasm::FunctionSig* sig,
|
||||
wasm::ValueType from,
|
||||
wasm::ValueType to,
|
||||
size_t num_replacements) {
|
||||
size_t param_occurences =
|
||||
std::count(sig->parameters().begin(), sig->parameters().end(), from);
|
||||
size_t return_occurences =
|
||||
std::count(sig->returns().begin(), sig->returns().end(), from);
|
||||
if (param_occurences == 0 && return_occurences == 0) return sig;
|
||||
|
||||
wasm::FunctionSig::Builder builder(
|
||||
zone, sig->return_count() + return_occurences * (num_replacements - 1),
|
||||
sig->parameter_count() + param_occurences * (num_replacements - 1));
|
||||
|
||||
for (wasm::ValueType ret : sig->returns()) {
|
||||
if (ret == from) {
|
||||
for (size_t i = 0; i < num_replacements; i++) builder.AddReturn(to);
|
||||
} else {
|
||||
builder.AddReturn(ret);
|
||||
}
|
||||
}
|
||||
|
||||
for (wasm::ValueType param : sig->parameters()) {
|
||||
if (param == from) {
|
||||
for (size_t i = 0; i < num_replacements; i++) builder.AddParam(to);
|
||||
} else {
|
||||
builder.AddParam(param);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
Zone* zone, const CallDescriptor* call_descriptor, size_t num_replacements,
|
||||
wasm::ValueType input_type, wasm::ValueType output_type) {
|
||||
@ -8272,28 +8306,8 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
|
||||
int return_slots = rets.NumStackSlots();
|
||||
|
||||
wasm::FunctionSig::Builder sig(
|
||||
zone,
|
||||
call_descriptor->wasm_sig()->return_count() + return_count -
|
||||
call_descriptor->ReturnCount(),
|
||||
call_descriptor->wasm_sig()->parameter_count() + parameter_count -
|
||||
call_descriptor->ParameterCount());
|
||||
|
||||
for (wasm::ValueType ret : call_descriptor->wasm_sig()->returns()) {
|
||||
if (ret == input_type) {
|
||||
for (size_t i = 0; i < num_replacements; i++) sig.AddReturn(output_type);
|
||||
} else {
|
||||
sig.AddReturn(ret);
|
||||
}
|
||||
}
|
||||
|
||||
for (wasm::ValueType param : call_descriptor->wasm_sig()->parameters()) {
|
||||
if (param == input_type) {
|
||||
for (size_t i = 0; i < num_replacements; i++) sig.AddParam(output_type);
|
||||
} else {
|
||||
sig.AddParam(param);
|
||||
}
|
||||
}
|
||||
auto sig = ReplaceTypeInSig(zone, call_descriptor->wasm_sig(), input_type,
|
||||
output_type, num_replacements);
|
||||
|
||||
return zone->New<CallDescriptor>( // --
|
||||
call_descriptor->kind(), // kind
|
||||
@ -8307,12 +8321,20 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
|
||||
call_descriptor->flags(), // flags
|
||||
call_descriptor->debug_name(), // debug name
|
||||
call_descriptor->GetStackArgumentOrder(), // stack order
|
||||
sig.Build(), // signature
|
||||
sig, // signature
|
||||
call_descriptor->AllocatableRegisters(), // allocatable registers
|
||||
return_slots); // return slot count
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
const wasm::FunctionSig* WasmGraphBuilder::Int64LoweredSig(
|
||||
Zone* zone, const wasm::FunctionSig* sig) {
|
||||
return (kSystemPointerSize == 4)
|
||||
? ReplaceTypeInSig(zone, sig, wasm::kWasmI64, wasm::kWasmI32, 2)
|
||||
: sig;
|
||||
}
|
||||
|
||||
CallDescriptor* GetI32WasmCallDescriptor(
|
||||
Zone* zone, const CallDescriptor* call_descriptor) {
|
||||
return ReplaceTypeInCallDescriptorWith(zone, call_descriptor, 2,
|
||||
|
@ -544,6 +544,9 @@ class WasmGraphBuilder {
|
||||
|
||||
void RemoveBytecodePositionDecorator();
|
||||
|
||||
static const wasm::FunctionSig* Int64LoweredSig(Zone* zone,
|
||||
const wasm::FunctionSig* sig);
|
||||
|
||||
protected:
|
||||
V8_EXPORT_PRIVATE WasmGraphBuilder(wasm::CompilationEnv* env, Zone* zone,
|
||||
MachineGraph* mcgraph,
|
||||
|
@ -129,18 +129,21 @@ void WasmInliner::Finalize() {
|
||||
const wasm::FunctionSig* real_sig =
|
||||
CallDescriptorOf(call->op())->wasm_sig();
|
||||
|
||||
// DCHECK that the real signature is a subtype of the formal one.
|
||||
DCHECK_EQ(real_sig->parameter_count(), inlinee->sig->parameter_count());
|
||||
DCHECK_EQ(real_sig->return_count(), inlinee->sig->return_count());
|
||||
#if DEBUG
|
||||
// Check that the real signature is a subtype of the formal one.
|
||||
const wasm::FunctionSig* formal_sig =
|
||||
WasmGraphBuilder::Int64LoweredSig(zone(), inlinee->sig);
|
||||
CHECK_EQ(real_sig->parameter_count(), formal_sig->parameter_count());
|
||||
CHECK_EQ(real_sig->return_count(), formal_sig->return_count());
|
||||
for (size_t i = 0; i < real_sig->parameter_count(); i++) {
|
||||
DCHECK(wasm::IsSubtypeOf(real_sig->GetParam(i), inlinee->sig->GetParam(i),
|
||||
module()));
|
||||
CHECK(wasm::IsSubtypeOf(real_sig->GetParam(i), formal_sig->GetParam(i),
|
||||
module()));
|
||||
}
|
||||
for (size_t i = 0; i < real_sig->return_count(); i++) {
|
||||
DCHECK(wasm::IsSubtypeOf(inlinee->sig->GetReturn(i),
|
||||
real_sig->GetReturn(i), module()));
|
||||
CHECK(wasm::IsSubtypeOf(formal_sig->GetReturn(i), real_sig->GetReturn(i),
|
||||
module()));
|
||||
}
|
||||
// End DCHECK.
|
||||
#endif
|
||||
|
||||
const wasm::FunctionBody inlinee_body(real_sig, inlinee->code.offset(),
|
||||
function_bytes.begin(),
|
||||
@ -151,24 +154,25 @@ void WasmInliner::Finalize() {
|
||||
std::vector<WasmLoopInfo> infos;
|
||||
|
||||
size_t subgraph_min_node_id = graph()->NodeCount();
|
||||
wasm::DecodeResult result;
|
||||
Node* inlinee_start;
|
||||
Node* inlinee_end;
|
||||
{
|
||||
Graph::SubgraphScope scope(graph());
|
||||
result = wasm::BuildTFGraph(
|
||||
wasm::DecodeResult result = wasm::BuildTFGraph(
|
||||
zone()->allocator(), env_->enabled_features, module(), &builder,
|
||||
&detected, inlinee_body, &infos, node_origins_,
|
||||
candidate.inlinee_index, wasm::kInlinedFunction);
|
||||
if (result.failed()) {
|
||||
// This can happen if the inlinee has never been compiled before and is
|
||||
// invalid. Return, as there is no point to keep optimizing.
|
||||
TRACE("failed to compile]\n")
|
||||
return;
|
||||
}
|
||||
|
||||
builder.LowerInt64(WasmGraphBuilder::kCalledFromWasm);
|
||||
inlinee_start = graph()->start();
|
||||
inlinee_end = graph()->end();
|
||||
}
|
||||
if (result.failed()) {
|
||||
// This can happen if the inlinee has never been compiled before and is
|
||||
// invalid. Return, as there is no point to keep optimizing.
|
||||
TRACE("failed to compile]\n")
|
||||
return;
|
||||
}
|
||||
|
||||
size_t additional_nodes = graph()->NodeCount() - subgraph_min_node_id;
|
||||
if (current_graph_size_ + additional_nodes >
|
||||
|
@ -319,3 +319,23 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
let instance = builder.instantiate({});
|
||||
assertEquals(11, instance.exports.main(10));
|
||||
})();
|
||||
|
||||
(function Int64Lowering() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
let kSig_l_li = makeSig([kWasmI64, kWasmI32], [kWasmI64]);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
||||
let callee = builder.addFunction("callee", kSig_l_li)
|
||||
.addBody([
|
||||
kExprLocalGet, 0, kExprLocalGet, 1, kExprI64SConvertI32, kExprI64Add]);
|
||||
|
||||
builder.addFunction("main", kSig_l_li)
|
||||
.addBody([
|
||||
kExprLocalGet, 0, kExprLocalGet, 1, kExprCallFunction, callee.index])
|
||||
.exportFunc();
|
||||
|
||||
let instance = builder.instantiate({});
|
||||
assertEquals(BigInt(21), instance.exports.main(BigInt(10), 11));
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user