[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:
Manos Koukoutos 2021-11-16 11:45:57 +00:00 committed by V8 LUCI CQ
parent f74ea020d5
commit f6edda0987
6 changed files with 96 additions and 45 deletions

View File

@ -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;
}
}
}

View File

@ -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_;

View File

@ -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,

View File

@ -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,

View File

@ -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 >

View File

@ -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));
})();