Commit 6cf8f54d authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Fix interpreter entry for i64 return type

Fix two issues in the interpreter entry for 64 bit return values on
32 bit platforms. First, the effect chain was slightly incorrect, second
the order of the returned values was wrong.

Also add a test case for this.
Tested on x64, ia32 and s390.

Plus drive-by fix in Int64Lowering to reuse global constants for
big-endian/little-endian disambiguation.

R=titzer@chromium.org
BUG=v8:5822

Review-Url: https://codereview.chromium.org/2731713002
Cr-Commit-Position: refs/heads/master@{#43654}
parent 269983f3
...@@ -74,6 +74,8 @@ void Int64Lowering::LowerGraph() { ...@@ -74,6 +74,8 @@ void Int64Lowering::LowerGraph() {
} }
} }
namespace {
static int GetParameterIndexAfterLowering( static int GetParameterIndexAfterLowering(
Signature<MachineRepresentation>* signature, int old_index) { Signature<MachineRepresentation>* signature, int old_index) {
int result = old_index; int result = old_index;
...@@ -85,6 +87,19 @@ static int GetParameterIndexAfterLowering( ...@@ -85,6 +87,19 @@ static int GetParameterIndexAfterLowering(
return result; return result;
} }
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;
}
} // namespace
// static
int Int64Lowering::GetParameterCountAfterLowering( int Int64Lowering::GetParameterCountAfterLowering(
Signature<MachineRepresentation>* signature) { Signature<MachineRepresentation>* signature) {
// GetParameterIndexAfterLowering(parameter_count) returns the parameter count // GetParameterIndexAfterLowering(parameter_count) returns the parameter count
...@@ -93,15 +108,10 @@ int Int64Lowering::GetParameterCountAfterLowering( ...@@ -93,15 +108,10 @@ int Int64Lowering::GetParameterCountAfterLowering(
signature, static_cast<int>(signature->parameter_count())); signature, static_cast<int>(signature->parameter_count()));
} }
static int GetReturnCountAfterLowering( // static
Signature<MachineRepresentation>* signature) { bool Int64Lowering::IsI64AsTwoParameters(MachineOperatorBuilder* machine,
int result = static_cast<int>(signature->return_count()); MachineRepresentation type) {
for (int i = 0; i < static_cast<int>(signature->return_count()); i++) { return machine->Is32() && type == MachineRepresentation::kWord64;
if (signature->GetReturn(i) == MachineRepresentation::kWord64) {
result++;
}
}
return result;
} }
void Int64Lowering::GetIndexNodes(Node* index, Node*& index_low, void Int64Lowering::GetIndexNodes(Node* index, Node*& index_low,
...@@ -120,14 +130,6 @@ void Int64Lowering::GetIndexNodes(Node* index, Node*& index_low, ...@@ -120,14 +130,6 @@ void Int64Lowering::GetIndexNodes(Node* index, Node*& index_low,
#endif #endif
} }
#if defined(V8_TARGET_LITTLE_ENDIAN)
const int Int64Lowering::kLowerWordOffset = 0;
const int Int64Lowering::kHigherWordOffset = 4;
#elif defined(V8_TARGET_BIG_ENDIAN)
const int Int64Lowering::kLowerWordOffset = 4;
const int Int64Lowering::kHigherWordOffset = 0;
#endif
void Int64Lowering::LowerNode(Node* node) { void Int64Lowering::LowerNode(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kInt64Constant: { case IrOpcode::kInt64Constant: {
...@@ -561,7 +563,8 @@ void Int64Lowering::LowerNode(Node* node) { ...@@ -561,7 +563,8 @@ void Int64Lowering::LowerNode(Node* node) {
StoreRepresentation(MachineRepresentation::kWord32, StoreRepresentation(MachineRepresentation::kWord32,
WriteBarrierKind::kNoWriteBarrier)), WriteBarrierKind::kNoWriteBarrier)),
stack_slot, stack_slot,
graph()->NewNode(common()->Int32Constant(kHigherWordOffset)), graph()->NewNode(
common()->Int32Constant(kInt64UpperHalfMemoryOffset)),
GetReplacementHigh(input), graph()->start(), graph()->start()); GetReplacementHigh(input), graph()->start(), graph()->start());
Node* store_low_word = graph()->NewNode( Node* store_low_word = graph()->NewNode(
...@@ -569,7 +572,8 @@ void Int64Lowering::LowerNode(Node* node) { ...@@ -569,7 +572,8 @@ void Int64Lowering::LowerNode(Node* node) {
StoreRepresentation(MachineRepresentation::kWord32, StoreRepresentation(MachineRepresentation::kWord32,
WriteBarrierKind::kNoWriteBarrier)), WriteBarrierKind::kNoWriteBarrier)),
stack_slot, stack_slot,
graph()->NewNode(common()->Int32Constant(kLowerWordOffset)), graph()->NewNode(
common()->Int32Constant(kInt64LowerHalfMemoryOffset)),
GetReplacementLow(input), store_high_word, graph()->start()); GetReplacementLow(input), store_high_word, graph()->start());
Node* load = Node* load =
...@@ -597,13 +601,15 @@ void Int64Lowering::LowerNode(Node* node) { ...@@ -597,13 +601,15 @@ void Int64Lowering::LowerNode(Node* node) {
Node* high_node = graph()->NewNode( Node* high_node = graph()->NewNode(
machine()->Load(MachineType::Int32()), stack_slot, machine()->Load(MachineType::Int32()), stack_slot,
graph()->NewNode(common()->Int32Constant(kHigherWordOffset)), store, graph()->NewNode(
graph()->start()); common()->Int32Constant(kInt64UpperHalfMemoryOffset)),
store, graph()->start());
Node* low_node = graph()->NewNode( Node* low_node = graph()->NewNode(
machine()->Load(MachineType::Int32()), stack_slot, machine()->Load(MachineType::Int32()), stack_slot,
graph()->NewNode(common()->Int32Constant(kLowerWordOffset)), store, graph()->NewNode(
graph()->start()); common()->Int32Constant(kInt64LowerHalfMemoryOffset)),
store, graph()->start());
ReplaceNode(node, low_node, high_node); ReplaceNode(node, low_node, high_node);
break; break;
} }
......
...@@ -27,8 +27,10 @@ class V8_EXPORT_PRIVATE Int64Lowering { ...@@ -27,8 +27,10 @@ class V8_EXPORT_PRIVATE Int64Lowering {
static int GetParameterCountAfterLowering( static int GetParameterCountAfterLowering(
Signature<MachineRepresentation>* signature); Signature<MachineRepresentation>* signature);
static const int kLowerWordOffset; // Determine whether the given type is i64 and has to be passed via two
static const int kHigherWordOffset; // parameters on the given machine.
static bool IsI64AsTwoParameters(MachineOperatorBuilder* machine,
MachineRepresentation type);
private: private:
enum class State : uint8_t { kUnvisited, kOnStack, kVisited }; enum class State : uint8_t { kUnvisited, kOnStack, kVisited };
......
...@@ -2971,12 +2971,11 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry( ...@@ -2971,12 +2971,11 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry(
// Now store all our arguments to the buffer. // Now store all our arguments to the buffer.
int param_index = 0; int param_index = 0;
int offset = 0; int offset = 0;
for (int i = 0; i < wasm_count; i++) { for (int i = 0; i < wasm_count; i++) {
Node* param = Param(param_index++); Node* param = Param(param_index++);
bool is_i64_as_two_params = if (Int64Lowering::IsI64AsTwoParameters(jsgraph()->machine(),
jsgraph()->machine()->Is32() && sig->GetParam(i) == wasm::kWasmI64; sig->GetParam(i))) {
if (is_i64_as_two_params) {
StoreRepresentation store_rep(wasm::kWasmI32, StoreRepresentation store_rep(wasm::kWasmI32,
WriteBarrierKind::kNoWriteBarrier); WriteBarrierKind::kNoWriteBarrier);
*effect_ = *effect_ =
...@@ -3018,26 +3017,24 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry( ...@@ -3018,26 +3017,24 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry(
arraysize(parameters), effect_, *control_); arraysize(parameters), effect_, *control_);
// Read back the return value. // Read back the return value.
if (jsgraph()->machine()->Is32() && sig->return_count() > 0 && if (sig->return_count() == 0) {
sig->GetReturn() == wasm::kWasmI64) { Return(Int32Constant(0));
} else if (Int64Lowering::IsI64AsTwoParameters(jsgraph()->machine(),
sig->GetReturn())) {
MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(wasm::kWasmI32); MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(wasm::kWasmI32);
Node* lower = Node* lower =
graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
Int32Constant(0), *effect_, *control_); Int32Constant(0), *effect_, *control_);
Node* upper = Node* upper =
graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer, graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
Int32Constant(sizeof(int32_t)), *effect_, *control_); Int32Constant(sizeof(int32_t)), lower, *control_);
Return(upper, lower); *effect_ = upper;
Return(lower, upper);
} else { } else {
Node* val; MachineType load_rep = wasm::WasmOpcodes::MachineTypeFor(sig->GetReturn());
if (sig->return_count() == 0) { Node* val =
val = Int32Constant(0); graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
} else { Int32Constant(0), *effect_, *control_);
MachineType load_rep =
wasm::WasmOpcodes::MachineTypeFor(sig->GetReturn());
val = graph()->NewNode(jsgraph()->machine()->Load(load_rep), arg_buffer,
Int32Constant(0), *effect_, *control_);
}
Return(val); Return(val);
} }
} }
......
...@@ -87,6 +87,7 @@ static ArgPassingHelper<T> GetHelper( ...@@ -87,6 +87,7 @@ static ArgPassingHelper<T> GetHelper(
} // namespace } // namespace
// Pass int32_t, return int32_t.
TEST(TestArgumentPassing_int32) { TEST(TestArgumentPassing_int32) {
WasmRunner<int32_t, int32_t> runner(kExecuteCompiled); WasmRunner<int32_t, int32_t> runner(kExecuteCompiled);
WasmFunctionCompiler& f2 = runner.NewFunction<int32_t, int32_t>(); WasmFunctionCompiler& f2 = runner.NewFunction<int32_t, int32_t>();
...@@ -103,7 +104,8 @@ TEST(TestArgumentPassing_int32) { ...@@ -103,7 +104,8 @@ TEST(TestArgumentPassing_int32) {
for (int32_t v : test_values) helper.CheckCall(v); for (int32_t v : test_values) helper.CheckCall(v);
} }
TEST(TestArgumentPassing_int64) { // Pass int64_t, return double.
TEST(TestArgumentPassing_double_int64) {
WasmRunner<double, int32_t, int32_t> runner(kExecuteCompiled); WasmRunner<double, int32_t, int32_t> runner(kExecuteCompiled);
WasmFunctionCompiler& f2 = runner.NewFunction<double, int64_t>(); WasmFunctionCompiler& f2 = runner.NewFunction<double, int64_t>();
...@@ -138,6 +140,27 @@ TEST(TestArgumentPassing_int64) { ...@@ -138,6 +140,27 @@ TEST(TestArgumentPassing_int64) {
} }
} }
// Pass double, return int64_t.
TEST(TestArgumentPassing_int64_double) {
// Outer function still returns double.
WasmRunner<double, double> runner(kExecuteCompiled);
WasmFunctionCompiler& f2 = runner.NewFunction<int64_t, double>();
auto helper = GetHelper(
runner, f2,
{// Return (int64_t)<0>.
WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(0))},
{// Call f2 with param <0>, convert returned value back to double.
WASM_F64_SCONVERT_I64(WASM_SEQ(
WASM_GET_LOCAL(0), WASM_CALL_FUNCTION0(f2.function_index())))},
[](double d) { return d; });
for (int64_t i : compiler::ValueHelper::int64_vector()) {
helper.CheckCall(i);
}
}
// Pass float, return double.
TEST(TestArgumentPassing_float_double) { TEST(TestArgumentPassing_float_double) {
WasmRunner<double, float> runner(kExecuteCompiled); WasmRunner<double, float> runner(kExecuteCompiled);
WasmFunctionCompiler& f2 = runner.NewFunction<double, float>(); WasmFunctionCompiler& f2 = runner.NewFunction<double, float>();
...@@ -156,6 +179,7 @@ TEST(TestArgumentPassing_float_double) { ...@@ -156,6 +179,7 @@ TEST(TestArgumentPassing_float_double) {
for (float f : test_values) helper.CheckCall(f); for (float f : test_values) helper.CheckCall(f);
} }
// Pass two doubles, return double.
TEST(TestArgumentPassing_double_double) { TEST(TestArgumentPassing_double_double) {
WasmRunner<double, double, double> runner(kExecuteCompiled); WasmRunner<double, double, double> runner(kExecuteCompiled);
WasmFunctionCompiler& f2 = runner.NewFunction<double, double, double>(); WasmFunctionCompiler& f2 = runner.NewFunction<double, double, double>();
...@@ -176,11 +200,13 @@ TEST(TestArgumentPassing_double_double) { ...@@ -176,11 +200,13 @@ TEST(TestArgumentPassing_double_double) {
} }
} }
// Pass int32_t, int64_t, float and double, return double.
TEST(TestArgumentPassing_AllTypes) { TEST(TestArgumentPassing_AllTypes) {
// The second and third argument will be combined to an i64. // The second and third argument will be combined to an i64.
WasmRunner<double, int, int, int, float, double> runner(kExecuteCompiled); WasmRunner<double, int32_t, int32_t, int32_t, float, double> runner(
kExecuteCompiled);
WasmFunctionCompiler& f2 = WasmFunctionCompiler& f2 =
runner.NewFunction<double, int, int64_t, float, double>(); runner.NewFunction<double, int32_t, int64_t, float, double>();
auto helper = GetHelper( auto helper = GetHelper(
runner, f2, runner, f2,
......
...@@ -610,12 +610,12 @@ TEST_F(Int64LoweringTest, F64ReinterpretI64) { ...@@ -610,12 +610,12 @@ TEST_F(Int64LoweringTest, F64ReinterpretI64) {
IsStore(StoreRepresentation(MachineRepresentation::kWord32, IsStore(StoreRepresentation(MachineRepresentation::kWord32,
WriteBarrierKind::kNoWriteBarrier), WriteBarrierKind::kNoWriteBarrier),
AllOf(CaptureEq(&stack_slot_capture), stack_slot_matcher), AllOf(CaptureEq(&stack_slot_capture), stack_slot_matcher),
IsInt32Constant(Int64Lowering::kLowerWordOffset), IsInt32Constant(kInt64LowerHalfMemoryOffset),
IsInt32Constant(low_word_value(0)), IsInt32Constant(low_word_value(0)),
IsStore(StoreRepresentation(MachineRepresentation::kWord32, IsStore(StoreRepresentation(MachineRepresentation::kWord32,
WriteBarrierKind::kNoWriteBarrier), WriteBarrierKind::kNoWriteBarrier),
AllOf(CaptureEq(&stack_slot_capture), stack_slot_matcher), AllOf(CaptureEq(&stack_slot_capture), stack_slot_matcher),
IsInt32Constant(Int64Lowering::kHigherWordOffset), IsInt32Constant(kInt64UpperHalfMemoryOffset),
IsInt32Constant(high_word_value(0)), start(), start()), IsInt32Constant(high_word_value(0)), start(), start()),
start()); start());
...@@ -647,11 +647,11 @@ TEST_F(Int64LoweringTest, I64ReinterpretF64) { ...@@ -647,11 +647,11 @@ TEST_F(Int64LoweringTest, I64ReinterpretF64) {
graph()->end()->InputAt(1), graph()->end()->InputAt(1),
IsReturn2(IsLoad(MachineType::Int32(), IsReturn2(IsLoad(MachineType::Int32(),
AllOf(CaptureEq(&stack_slot), stack_slot_matcher), AllOf(CaptureEq(&stack_slot), stack_slot_matcher),
IsInt32Constant(Int64Lowering::kLowerWordOffset), IsInt32Constant(kInt64LowerHalfMemoryOffset),
AllOf(CaptureEq(&store), store_matcher), start()), AllOf(CaptureEq(&store), store_matcher), start()),
IsLoad(MachineType::Int32(), IsLoad(MachineType::Int32(),
AllOf(CaptureEq(&stack_slot), stack_slot_matcher), AllOf(CaptureEq(&stack_slot), stack_slot_matcher),
IsInt32Constant(Int64Lowering::kHigherWordOffset), IsInt32Constant(kInt64UpperHalfMemoryOffset),
AllOf(CaptureEq(&store), store_matcher), start()), AllOf(CaptureEq(&store), store_matcher), start()),
start(), start())); start(), start()));
} }
......
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