Commit 545943db authored by ahaas's avatar ahaas Committed by Commit bot

[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}
parent 5363486d
This diff is collapsed.
......@@ -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_;
......
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