[wasm] WasmRunner can run tests with I64 parameters and return value.
I extended the Int64Lowering to lower calls, loads, stores, returns, and parameters and apply the lowering on both the test function TF graph and the WasmRunner TF graph. The lowering of calls also requires an adjustment of the call descriptor. R=titzer@chromium.org Review URL: https://codereview.chromium.org/1704033002 Cr-Commit-Position: refs/heads/master@{#34121}
This commit is contained in:
parent
5363486d8e
commit
545943db15
@ -5,8 +5,12 @@
|
||||
#include "src/compiler/int64-lowering.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/wasm/wasm-module.h"
|
||||
#include "src/zone.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -14,17 +18,23 @@ namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
|
||||
CommonOperatorBuilder* common, Zone* zone)
|
||||
: graph_(graph),
|
||||
CommonOperatorBuilder* common, Zone* zone,
|
||||
Signature<MachineRepresentation>* signature)
|
||||
: zone_(zone),
|
||||
graph_(graph),
|
||||
machine_(machine),
|
||||
common_(common),
|
||||
state_(graph, 4),
|
||||
stack_(zone),
|
||||
replacements_(zone->NewArray<Replacement>(graph->NodeCount())) {
|
||||
replacements_(zone->NewArray<Replacement>(graph->NodeCount())),
|
||||
signature_(signature) {
|
||||
memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
|
||||
}
|
||||
|
||||
void Int64Lowering::ReduceGraph() {
|
||||
void Int64Lowering::LowerGraph() {
|
||||
if (4 != kPointerSize) {
|
||||
return;
|
||||
}
|
||||
stack_.push(graph()->end());
|
||||
state_.Set(graph()->end(), State::kOnStack);
|
||||
|
||||
@ -34,7 +44,7 @@ void Int64Lowering::ReduceGraph() {
|
||||
stack_.pop();
|
||||
state_.Set(top, State::kVisited);
|
||||
// All inputs of top have already been reduced, now reduce top.
|
||||
ReduceNode(top);
|
||||
LowerNode(top);
|
||||
} else {
|
||||
// Push all children onto the stack.
|
||||
for (Node* input : top->inputs()) {
|
||||
@ -48,7 +58,35 @@ void Int64Lowering::ReduceGraph() {
|
||||
}
|
||||
}
|
||||
|
||||
void Int64Lowering::ReduceNode(Node* node) {
|
||||
static int GetParameterIndexAfterLowering(
|
||||
Signature<MachineRepresentation>* signature, int old_index) {
|
||||
int result = old_index;
|
||||
for (int i = 0; i < old_index; i++) {
|
||||
if (signature->GetParam(i) == MachineRepresentation::kWord64) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int GetParameterCountAfterLowering(
|
||||
Signature<MachineRepresentation>* signature) {
|
||||
return GetParameterIndexAfterLowering(
|
||||
signature, static_cast<int>(signature->parameter_count()));
|
||||
}
|
||||
|
||||
static int GetReturnCountAfterLowering(
|
||||
Signature<MachineRepresentation>* signature) {
|
||||
int result = static_cast<int>(signature->return_count());
|
||||
for (int i = 0; i < static_cast<int>(signature->return_count()); i++) {
|
||||
if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Int64Lowering::LowerNode(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kInt64Constant: {
|
||||
int64_t value = OpParameter<int64_t>(node);
|
||||
@ -56,48 +94,207 @@ void Int64Lowering::ReduceNode(Node* node) {
|
||||
common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
|
||||
Node* high_node = graph()->NewNode(
|
||||
common()->Int32Constant(static_cast<int32_t>(value >> 32)));
|
||||
replacements_[node->id()].low = low_node;
|
||||
replacements_[node->id()].high = high_node;
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kLoad: {
|
||||
LoadRepresentation load_rep = LoadRepresentationOf(node->op());
|
||||
|
||||
if (load_rep.representation() == MachineRepresentation::kWord64) {
|
||||
Node* base = node->InputAt(0);
|
||||
Node* index = node->InputAt(1);
|
||||
Node* index_high =
|
||||
graph()->NewNode(machine()->Int32Add(), index,
|
||||
graph()->NewNode(common()->Int32Constant(4)));
|
||||
|
||||
const Operator* load_op = machine()->Load(MachineType::Int32());
|
||||
Node* high_node;
|
||||
if (node->InputCount() > 2) {
|
||||
Node* effect_high = node->InputAt(2);
|
||||
Node* control_high = node->InputAt(3);
|
||||
high_node = graph()->NewNode(load_op, base, index_high, effect_high,
|
||||
control_high);
|
||||
// change the effect change from old_node --> old_effect to
|
||||
// old_node --> high_node --> old_effect.
|
||||
node->ReplaceInput(2, high_node);
|
||||
} else {
|
||||
high_node = graph()->NewNode(load_op, base, index_high);
|
||||
}
|
||||
NodeProperties::ChangeOp(node, load_op);
|
||||
ReplaceNode(node, node, high_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kStore: {
|
||||
StoreRepresentation store_rep = StoreRepresentationOf(node->op());
|
||||
if (store_rep.representation() == MachineRepresentation::kWord64) {
|
||||
// We change the original store node to store the low word, and create
|
||||
// a new store node to store the high word. The effect and control edges
|
||||
// are copied from the original store to the new store node, the effect
|
||||
// edge of the original store is redirected to the new store.
|
||||
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
|
||||
|
||||
Node* base = node->InputAt(0);
|
||||
Node* index = node->InputAt(1);
|
||||
Node* index_high =
|
||||
graph()->NewNode(machine()->Int32Add(), index,
|
||||
graph()->NewNode(common()->Int32Constant(4)));
|
||||
|
||||
Node* value = node->InputAt(2);
|
||||
DCHECK(HasReplacementLow(value));
|
||||
DCHECK(HasReplacementHigh(value));
|
||||
|
||||
const Operator* store_op = machine()->Store(StoreRepresentation(
|
||||
MachineRepresentation::kWord32, write_barrier_kind));
|
||||
|
||||
Node* high_node;
|
||||
if (node->InputCount() > 3) {
|
||||
Node* effect_high = node->InputAt(3);
|
||||
Node* control_high = node->InputAt(4);
|
||||
high_node = graph()->NewNode(store_op, base, index_high,
|
||||
GetReplacementHigh(value), effect_high,
|
||||
control_high);
|
||||
node->ReplaceInput(3, high_node);
|
||||
|
||||
} else {
|
||||
high_node = graph()->NewNode(store_op, base, index_high,
|
||||
GetReplacementHigh(value));
|
||||
}
|
||||
|
||||
node->ReplaceInput(2, GetReplacementLow(value));
|
||||
NodeProperties::ChangeOp(node, store_op);
|
||||
ReplaceNode(node, node, high_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kWord64And: {
|
||||
DCHECK(node->InputCount() == 2);
|
||||
Node* left = node->InputAt(0);
|
||||
DCHECK(replacements_[left->id()].low);
|
||||
Node* left_low = replacements_[left->id()].low;
|
||||
Node* left_high = replacements_[left->id()].high;
|
||||
|
||||
Node* right = node->InputAt(1);
|
||||
DCHECK(replacements_[right->id()].low);
|
||||
Node* right_low = replacements_[right->id()].low;
|
||||
Node* right_high = replacements_[right->id()].high;
|
||||
|
||||
replacements_[node->id()].low =
|
||||
graph()->NewNode(machine()->Word32And(), left_low, right_low);
|
||||
replacements_[node->id()].high =
|
||||
graph()->NewNode(machine()->Word32And(), left_high, right_high);
|
||||
Node* low_node =
|
||||
graph()->NewNode(machine()->Word32And(), GetReplacementLow(left),
|
||||
GetReplacementLow(right));
|
||||
Node* high_node =
|
||||
graph()->NewNode(machine()->Word32And(), GetReplacementHigh(left),
|
||||
GetReplacementHigh(right));
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kTruncateInt64ToInt32: {
|
||||
DCHECK(node->InputCount() == 1);
|
||||
Node* input = node->InputAt(0);
|
||||
DCHECK(replacements_[input->id()].low);
|
||||
replacements_[node->id()].low = replacements_[input->id()].low;
|
||||
ReplaceNode(node, GetReplacementLow(input), nullptr);
|
||||
node->NullAllInputs();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Also the inputs of nodes can change which do not expect int64 inputs.
|
||||
for (int i = 0; i < node->InputCount(); i++) {
|
||||
Node* input = node->InputAt(i);
|
||||
// The input has changed altough it was not an int64 input. This can
|
||||
// happen e.g. if the input node is IrOpcode::kTruncateInt64ToInt32. We
|
||||
// use the low word replacement as the new input.
|
||||
if (replacements_[input->id()].low) {
|
||||
node->ReplaceInput(i, replacements_[input->id()].low);
|
||||
}
|
||||
case IrOpcode::kStart: {
|
||||
int parameter_count = GetParameterCountAfterLowering(signature());
|
||||
// Only exchange the node if the parameter count actually changed.
|
||||
if (parameter_count != signature()->parameter_count()) {
|
||||
int delta =
|
||||
parameter_count - static_cast<int>(signature()->parameter_count());
|
||||
int new_output_count = node->op()->ValueOutputCount() + delta;
|
||||
NodeProperties::ChangeOp(node, common()->Start(new_output_count));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kParameter: {
|
||||
DCHECK(node->InputCount() == 1);
|
||||
// Only exchange the node if the parameter count actually changed. We do
|
||||
// not even have to do the default lowering because the the start node,
|
||||
// the only input of a parameter node, only changes if the parameter count
|
||||
// changes.
|
||||
if (GetParameterCountAfterLowering(signature()) !=
|
||||
signature()->parameter_count()) {
|
||||
int old_index = ParameterIndexOf(node->op());
|
||||
int new_index = GetParameterIndexAfterLowering(signature(), old_index);
|
||||
Node* low_node =
|
||||
graph()->NewNode(common()->Parameter(new_index), graph()->start());
|
||||
|
||||
Node* high_node = nullptr;
|
||||
if (signature()->GetParam(old_index) ==
|
||||
MachineRepresentation::kWord64) {
|
||||
high_node = graph()->NewNode(common()->Parameter(new_index + 1),
|
||||
graph()->start());
|
||||
}
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kReturn: {
|
||||
DefaultLowering(node);
|
||||
int new_return_count = GetReturnCountAfterLowering(signature());
|
||||
if (signature()->return_count() != new_return_count) {
|
||||
NodeProperties::ChangeOp(node, common()->Return(new_return_count));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kCall: {
|
||||
CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
|
||||
if (DefaultLowering(node) ||
|
||||
(descriptor->ReturnCount() == 1 &&
|
||||
descriptor->GetReturnType(0) == MachineType::Int64())) {
|
||||
// We have to adjust the call descriptor.
|
||||
const Operator* op = common()->Call(
|
||||
wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), descriptor));
|
||||
NodeProperties::ChangeOp(node, op);
|
||||
}
|
||||
if (descriptor->ReturnCount() == 1 &&
|
||||
descriptor->GetReturnType(0) == MachineType::Int64()) {
|
||||
// We access the additional return values through projections.
|
||||
Node* low_node = graph()->NewNode(common()->Projection(0), node);
|
||||
Node* high_node = graph()->NewNode(common()->Projection(1), node);
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { DefaultLowering(node); }
|
||||
}
|
||||
}
|
||||
|
||||
bool Int64Lowering::DefaultLowering(Node* node) {
|
||||
bool something_changed = false;
|
||||
for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
|
||||
Node* input = node->InputAt(i);
|
||||
if (HasReplacementLow(input)) {
|
||||
something_changed = true;
|
||||
node->ReplaceInput(i, GetReplacementLow(input));
|
||||
}
|
||||
if (HasReplacementHigh(input)) {
|
||||
something_changed = true;
|
||||
node->InsertInput(zone(), i + 1, GetReplacementHigh(input));
|
||||
}
|
||||
}
|
||||
return something_changed;
|
||||
}
|
||||
|
||||
void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
|
||||
// if new_low == nullptr, then also new_high == nullptr.
|
||||
DCHECK(new_low != nullptr || new_high == nullptr);
|
||||
replacements_[old->id()].low = new_low;
|
||||
replacements_[old->id()].high = new_high;
|
||||
}
|
||||
|
||||
bool Int64Lowering::HasReplacementLow(Node* node) {
|
||||
return replacements_[node->id()].low != nullptr;
|
||||
}
|
||||
|
||||
Node* Int64Lowering::GetReplacementLow(Node* node) {
|
||||
Node* result = replacements_[node->id()].low;
|
||||
DCHECK(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Int64Lowering::HasReplacementHigh(Node* node) {
|
||||
return replacements_[node->id()].high != nullptr;
|
||||
}
|
||||
|
||||
Node* Int64Lowering::GetReplacementHigh(Node* node) {
|
||||
Node* result = replacements_[node->id()].high;
|
||||
DCHECK(result);
|
||||
return result;
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -18,12 +18,10 @@ namespace compiler {
|
||||
class Int64Lowering {
|
||||
public:
|
||||
Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
|
||||
CommonOperatorBuilder* common, Zone* zone);
|
||||
CommonOperatorBuilder* common, Zone* zone,
|
||||
Signature<MachineRepresentation>* signature);
|
||||
|
||||
void ReduceGraph();
|
||||
Graph* graph() const { return graph_; }
|
||||
MachineOperatorBuilder* machine() const { return machine_; }
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
void LowerGraph();
|
||||
|
||||
private:
|
||||
enum class State : uint8_t { kUnvisited, kOnStack, kInputsPushed, kVisited };
|
||||
@ -33,15 +31,29 @@ class Int64Lowering {
|
||||
Node* high;
|
||||
};
|
||||
|
||||
void ReduceTop();
|
||||
void ReduceNode(Node* node);
|
||||
Zone* zone() const { return zone_; }
|
||||
Graph* graph() const { return graph_; }
|
||||
MachineOperatorBuilder* machine() const { return machine_; }
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
Signature<MachineRepresentation>* signature() const { return signature_; }
|
||||
|
||||
void LowerNode(Node* node);
|
||||
bool DefaultLowering(Node* node);
|
||||
|
||||
void ReplaceNode(Node* old, Node* new_low, Node* new_high);
|
||||
bool HasReplacementLow(Node* node);
|
||||
Node* GetReplacementLow(Node* node);
|
||||
bool HasReplacementHigh(Node* node);
|
||||
Node* GetReplacementHigh(Node* node);
|
||||
|
||||
Zone* zone_;
|
||||
Graph* const graph_;
|
||||
MachineOperatorBuilder* machine_;
|
||||
CommonOperatorBuilder* common_;
|
||||
NodeMarker<State> state_;
|
||||
ZoneStack<Node*> stack_;
|
||||
Replacement* replacements_;
|
||||
Signature<MachineRepresentation>* signature_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -1484,8 +1484,9 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args) {
|
||||
args[params + 1] = *effect_;
|
||||
args[params + 2] = *control_;
|
||||
|
||||
const Operator* op = jsgraph()->common()->Call(
|
||||
module_->GetWasmCallDescriptor(jsgraph()->zone(), sig));
|
||||
CallDescriptor* descriptor =
|
||||
module_->GetWasmCallDescriptor(jsgraph()->zone(), sig);
|
||||
const Operator* op = jsgraph()->common()->Call(descriptor);
|
||||
Node* call = graph()->NewNode(op, static_cast<int>(count), args);
|
||||
|
||||
*effect_ = call;
|
||||
@ -1909,11 +1910,12 @@ Node* WasmGraphBuilder::String(const char* string) {
|
||||
Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
|
||||
|
||||
void WasmGraphBuilder::Int64LoweringForTesting() {
|
||||
#if !WASM_64
|
||||
Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(), jsgraph()->common(),
|
||||
jsgraph()->zone());
|
||||
r.ReduceGraph();
|
||||
#endif
|
||||
if (kPointerSize == 4) {
|
||||
Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(),
|
||||
jsgraph()->common(), jsgraph()->zone(),
|
||||
function_signature_);
|
||||
r.LowerGraph();
|
||||
}
|
||||
}
|
||||
|
||||
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
|
||||
@ -2127,8 +2129,11 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
|
||||
}
|
||||
|
||||
// Run the compiler pipeline to generate machine code.
|
||||
CallDescriptor* descriptor = const_cast<CallDescriptor*>(
|
||||
module_env->GetWasmCallDescriptor(&zone, function.sig));
|
||||
CallDescriptor* descriptor =
|
||||
module_env->GetWasmCallDescriptor(&zone, function.sig);
|
||||
if (kPointerSize == 4) {
|
||||
descriptor = module_env->GetI32WasmCallDescriptor(&zone, descriptor);
|
||||
}
|
||||
Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
|
||||
// add flags here if a meaningful name is helpful for debugging.
|
||||
bool debugging =
|
||||
|
@ -191,15 +191,7 @@ struct Allocator {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
// General code uses the above configuration data.
|
||||
CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
|
||||
FunctionSig* fsig) {
|
||||
MachineSignature::Builder msig(zone, fsig->return_count(),
|
||||
fsig->parameter_count());
|
||||
LocationSignature::Builder locations(zone, fsig->return_count(),
|
||||
fsig->parameter_count());
|
||||
|
||||
static Allocator GetReturnRegisters() {
|
||||
#ifdef GP_RETURN_REGISTERS
|
||||
static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
|
||||
static const int kGPReturnRegistersCount =
|
||||
@ -221,14 +213,10 @@ CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
|
||||
Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount,
|
||||
kFPReturnRegisters, kFPReturnRegistersCount);
|
||||
|
||||
// Add return location(s).
|
||||
const int return_count = static_cast<int>(locations.return_count_);
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
LocalType ret = fsig->GetReturn(i);
|
||||
msig.AddReturn(MachineTypeFor(ret));
|
||||
locations.AddReturn(rets.Next(ret));
|
||||
}
|
||||
return rets;
|
||||
}
|
||||
|
||||
static Allocator GetParameterRegisters() {
|
||||
#ifdef GP_PARAM_REGISTERS
|
||||
static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
|
||||
static const int kGPParamRegistersCount =
|
||||
@ -250,6 +238,29 @@ CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
|
||||
Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters,
|
||||
kFPParamRegistersCount);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
// General code uses the above configuration data.
|
||||
CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
|
||||
FunctionSig* fsig) {
|
||||
MachineSignature::Builder msig(zone, fsig->return_count(),
|
||||
fsig->parameter_count());
|
||||
LocationSignature::Builder locations(zone, fsig->return_count(),
|
||||
fsig->parameter_count());
|
||||
|
||||
Allocator rets = GetReturnRegisters();
|
||||
|
||||
// Add return location(s).
|
||||
const int return_count = static_cast<int>(locations.return_count_);
|
||||
for (int i = 0; i < return_count; i++) {
|
||||
LocalType ret = fsig->GetReturn(i);
|
||||
msig.AddReturn(MachineTypeFor(ret));
|
||||
locations.AddReturn(rets.Next(ret));
|
||||
}
|
||||
|
||||
Allocator params = GetParameterRegisters();
|
||||
|
||||
// Add register and/or stack parameter(s).
|
||||
const int parameter_count = static_cast<int>(fsig->parameter_count());
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
@ -276,8 +287,82 @@ CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
|
||||
kCalleeSaveRegisters, // callee-saved registers
|
||||
kCalleeSaveFPRegisters, // callee-saved fp regs
|
||||
CallDescriptor::kUseNativeStack, // flags
|
||||
"c-call");
|
||||
"wasm-call");
|
||||
}
|
||||
|
||||
CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
|
||||
Zone* zone, CallDescriptor* descriptor) {
|
||||
const MachineSignature* signature = descriptor->GetMachineSignature();
|
||||
size_t parameter_count = signature->parameter_count();
|
||||
size_t return_count = signature->return_count();
|
||||
for (size_t i = 0; i < signature->parameter_count(); i++) {
|
||||
if (signature->GetParam(i) == MachineType::Int64()) {
|
||||
// For each int64 input we get two int32 inputs.
|
||||
parameter_count++;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < signature->return_count(); i++) {
|
||||
if (signature->GetReturn(i) == MachineType::Int64()) {
|
||||
// For each int64 return we get two int32 returns.
|
||||
return_count++;
|
||||
}
|
||||
}
|
||||
if (parameter_count == signature->parameter_count() &&
|
||||
return_count == signature->return_count()) {
|
||||
// If there is no int64 parameter or return value, we can just return the
|
||||
// original descriptor.
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
MachineSignature::Builder msig(zone, return_count, parameter_count);
|
||||
LocationSignature::Builder locations(zone, return_count, parameter_count);
|
||||
|
||||
Allocator rets = GetReturnRegisters();
|
||||
|
||||
for (size_t i = 0; i < signature->return_count(); i++) {
|
||||
if (signature->GetReturn(i) == MachineType::Int64()) {
|
||||
// For each int64 return we get two int32 returns.
|
||||
msig.AddReturn(MachineType::Int32());
|
||||
msig.AddReturn(MachineType::Int32());
|
||||
locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
|
||||
locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
|
||||
} else {
|
||||
msig.AddReturn(signature->GetReturn(i));
|
||||
locations.AddReturn(rets.Next(signature->GetReturn(i).representation()));
|
||||
}
|
||||
}
|
||||
|
||||
Allocator params = GetParameterRegisters();
|
||||
|
||||
for (size_t i = 0; i < signature->parameter_count(); i++) {
|
||||
if (signature->GetParam(i) == MachineType::Int64()) {
|
||||
// For each int64 input we get two int32 inputs.
|
||||
msig.AddParam(MachineType::Int32());
|
||||
msig.AddParam(MachineType::Int32());
|
||||
locations.AddParam(params.Next(MachineRepresentation::kWord32));
|
||||
locations.AddParam(params.Next(MachineRepresentation::kWord32));
|
||||
} else {
|
||||
msig.AddParam(signature->GetParam(i));
|
||||
locations.AddParam(params.Next(signature->GetParam(i).representation()));
|
||||
}
|
||||
}
|
||||
|
||||
return new (zone) CallDescriptor( // --
|
||||
descriptor->kind(), // kind
|
||||
descriptor->GetInputType(0), // target MachineType
|
||||
descriptor->GetInputLocation(0), // target location
|
||||
msig.Build(), // machine_sig
|
||||
locations.Build(), // location_sig
|
||||
params.stack_offset, // stack_parameter_count
|
||||
descriptor->properties(), // properties
|
||||
descriptor->CalleeSavedRegisters(), // callee-saved registers
|
||||
descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
|
||||
descriptor->flags(), // flags
|
||||
descriptor->debug_name());
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -191,6 +191,8 @@ struct ModuleEnv {
|
||||
Handle<FixedArray> GetFunctionTable();
|
||||
|
||||
compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, FunctionSig* sig);
|
||||
static compiler::CallDescriptor* GetI32WasmCallDescriptor(
|
||||
Zone* zone, compiler::CallDescriptor* descriptor);
|
||||
compiler::CallDescriptor* GetCallDescriptor(Zone* zone, uint32_t index);
|
||||
};
|
||||
|
||||
|
@ -2473,6 +2473,50 @@ TEST(Run_WasmCallF64StackParameter) {
|
||||
CHECK_EQ(256.5, result);
|
||||
}
|
||||
|
||||
TEST(Run_WasmCallI64Parameter) {
|
||||
// Build the target function.
|
||||
LocalType param_types[20];
|
||||
for (int i = 0; i < 20; i++) param_types[i] = kAstI64;
|
||||
param_types[3] = kAstI32;
|
||||
param_types[4] = kAstI32;
|
||||
FunctionSig sig(1, 19, param_types);
|
||||
for (int i = 0; i < 19; i++) {
|
||||
TestingModule module;
|
||||
WasmFunctionCompiler t(&sig);
|
||||
if (i == 2 || i == 3) {
|
||||
continue;
|
||||
} else {
|
||||
BUILD(t, WASM_GET_LOCAL(i));
|
||||
}
|
||||
uint32_t index = t.CompileAndAdd(&module);
|
||||
|
||||
// Build the calling function.
|
||||
WasmRunner<int32_t> r;
|
||||
r.env()->module = &module;
|
||||
BUILD(r,
|
||||
WASM_I32_CONVERT_I64(WASM_CALL_FUNCTION(
|
||||
index, WASM_I64(0xbcd12340000000b), WASM_I64(0xbcd12340000000c),
|
||||
WASM_I32(0xd), WASM_I32_CONVERT_I64(WASM_I64(0xbcd12340000000e)),
|
||||
WASM_I64(0xbcd12340000000f), WASM_I64(0xbcd1234000000010),
|
||||
WASM_I64(0xbcd1234000000011), WASM_I64(0xbcd1234000000012),
|
||||
WASM_I64(0xbcd1234000000013), WASM_I64(0xbcd1234000000014),
|
||||
WASM_I64(0xbcd1234000000015), WASM_I64(0xbcd1234000000016),
|
||||
WASM_I64(0xbcd1234000000017), WASM_I64(0xbcd1234000000018),
|
||||
WASM_I64(0xbcd1234000000019), WASM_I64(0xbcd123400000001a),
|
||||
WASM_I64(0xbcd123400000001b), WASM_I64(0xbcd123400000001c),
|
||||
WASM_I64(0xbcd123400000001d))));
|
||||
|
||||
CHECK_EQ(i + 0xb, r.Call());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Run_WasmI64And) {
|
||||
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
|
||||
BUILD(r, WASM_I64_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||
FOR_INT64_INPUTS(i) {
|
||||
FOR_INT64_INPUTS(j) { CHECK_EQ((*i) & (*j), r.Call(*i, *j)); }
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Run_WasmCallVoid) {
|
||||
const byte kMemOffset = 8;
|
||||
|
@ -46,6 +46,7 @@
|
||||
CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
|
||||
#define CHECK_TRAP(x) CHECK_TRAP32(x)
|
||||
|
||||
#define WASM_RUNNER_MAX_NUM_PARAMETERS 4
|
||||
#define WASM_WRAPPER_RETURN_VALUE 8754
|
||||
|
||||
namespace {
|
||||
@ -260,10 +261,12 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
|
||||
: GraphAndBuilders(main_zone()),
|
||||
inner_code_node_(nullptr),
|
||||
signature_(nullptr) {
|
||||
Signature<MachineType>::Builder sig_builder(zone(), 1, 5);
|
||||
// One additional parameter for the pointer to the return value memory.
|
||||
Signature<MachineType>::Builder sig_builder(
|
||||
zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
|
||||
|
||||
sig_builder.AddReturn(MachineType::Int32());
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
|
||||
sig_builder.AddParam(MachineType::Pointer());
|
||||
}
|
||||
signature_ = sig_builder.Build();
|
||||
@ -278,7 +281,8 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
|
||||
// the actual test function.
|
||||
|
||||
// Function, effect, and control.
|
||||
Node** parameters = zone()->template NewArray<Node*>(4 + 3);
|
||||
Node** parameters =
|
||||
zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3);
|
||||
graph()->SetStart(graph()->NewNode(common()->Start(6)));
|
||||
Node* effect = graph()->start();
|
||||
int parameter_count = 0;
|
||||
@ -329,7 +333,8 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
|
||||
machine()->Store(
|
||||
StoreRepresentation(MachineTypeForC<ReturnType>().representation(),
|
||||
WriteBarrierKind::kNoWriteBarrier)),
|
||||
graph()->NewNode(common()->Parameter(4), graph()->start()),
|
||||
graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS),
|
||||
graph()->start()),
|
||||
graph()->NewNode(common()->Int32Constant(0)), call, effect,
|
||||
graph()->start());
|
||||
Node* r = graph()->NewNode(
|
||||
@ -351,6 +356,20 @@ class WasmFunctionWrapper : public HandleAndZoneScope,
|
||||
CallDescriptor* descriptor =
|
||||
Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
|
||||
|
||||
if (kPointerSize == 4) {
|
||||
// One additional parameter for the pointer of the return value.
|
||||
Signature<MachineRepresentation>::Builder rep_builder(
|
||||
zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
|
||||
|
||||
rep_builder.AddReturn(MachineRepresentation::kWord32);
|
||||
for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
|
||||
rep_builder.AddParam(MachineRepresentation::kWord32);
|
||||
}
|
||||
Int64Lowering r(graph(), machine(), common(), zone(),
|
||||
rep_builder.Build());
|
||||
r.LowerGraph();
|
||||
}
|
||||
|
||||
CompilationInfo info("testing", isolate, graph()->zone());
|
||||
code_ =
|
||||
Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
|
||||
@ -418,9 +437,13 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
|
||||
|
||||
Handle<Code> Compile(ModuleEnv* module) {
|
||||
InitializeDescriptor();
|
||||
CallDescriptor* desc = descriptor_;
|
||||
if (kPointerSize == 4) {
|
||||
desc = module->GetI32WasmCallDescriptor(this->zone(), desc);
|
||||
}
|
||||
CompilationInfo info("wasm compile", this->isolate(), this->zone());
|
||||
Handle<Code> result =
|
||||
Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph());
|
||||
Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
if (!result.is_null() && FLAG_print_opt_code) {
|
||||
OFStream os(stdout);
|
||||
@ -529,7 +552,7 @@ class WasmRunner {
|
||||
}
|
||||
|
||||
private:
|
||||
LocalType storage_[5];
|
||||
LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
|
||||
FunctionSig signature_;
|
||||
WasmFunctionCompiler compiler_;
|
||||
WasmFunctionWrapper<ReturnType> wrapper_;
|
||||
|
Loading…
Reference in New Issue
Block a user