[wasm] Int64 lowering for return values
R=titzer@chromium.org Change-Id: Ie8c361efb48b56dc65719f09dfc79d505e0f3459 Reviewed-on: https://chromium-review.googlesource.com/735610 Commit-Queue: Andreas Rossberg <rossberg@chromium.org> Reviewed-by: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#49000}
This commit is contained in:
parent
07de62ca18
commit
776d6e9d5c
@ -75,7 +75,24 @@ void Int64Lowering::LowerGraph() {
|
||||
|
||||
namespace {
|
||||
|
||||
static int GetParameterIndexAfterLowering(
|
||||
int GetReturnIndexAfterLowering(
|
||||
CallDescriptor* descriptor, int old_index) {
|
||||
int result = old_index;
|
||||
for (int i = 0; i < old_index; i++) {
|
||||
if (descriptor->GetReturnType(i).representation() ==
|
||||
MachineRepresentation::kWord64) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetReturnCountAfterLowering(CallDescriptor* descriptor) {
|
||||
return GetReturnIndexAfterLowering(
|
||||
descriptor, static_cast<int>(descriptor->ReturnCount()));
|
||||
}
|
||||
|
||||
int GetParameterIndexAfterLowering(
|
||||
Signature<MachineRepresentation>* signature, int old_index) {
|
||||
int result = old_index;
|
||||
for (int i = 0; i < old_index; i++) {
|
||||
@ -276,13 +293,12 @@ void Int64Lowering::LowerNode(Node* node) {
|
||||
++new_index;
|
||||
NodeProperties::ChangeOp(node, common()->Parameter(new_index));
|
||||
|
||||
Node* high_node = nullptr;
|
||||
if (signature()->GetParam(old_index) ==
|
||||
MachineRepresentation::kWord64) {
|
||||
high_node = graph()->NewNode(common()->Parameter(new_index + 1),
|
||||
graph()->start());
|
||||
Node* high_node = graph()->NewNode(common()->Parameter(new_index + 1),
|
||||
graph()->start());
|
||||
ReplaceNode(node, node, high_node);
|
||||
}
|
||||
ReplaceNode(node, node, high_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -313,21 +329,48 @@ void Int64Lowering::LowerNode(Node* node) {
|
||||
case IrOpcode::kCall: {
|
||||
CallDescriptor* descriptor =
|
||||
const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
|
||||
if (DefaultLowering(node) ||
|
||||
(descriptor->ReturnCount() == 1 &&
|
||||
descriptor->GetReturnType(0) == MachineType::Int64())) {
|
||||
bool returns_require_lowering =
|
||||
GetReturnCountAfterLowering(descriptor) !=
|
||||
static_cast<int>(descriptor->ReturnCount());
|
||||
if (DefaultLowering(node) || returns_require_lowering) {
|
||||
// We have to adjust the call descriptor.
|
||||
NodeProperties::ChangeOp(
|
||||
node, common()->Call(GetI32WasmCallDescriptor(zone(), descriptor)));
|
||||
}
|
||||
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, graph()->start());
|
||||
Node* high_node =
|
||||
graph()->NewNode(common()->Projection(1), node, graph()->start());
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
if (returns_require_lowering) {
|
||||
size_t return_arity = descriptor->ReturnCount();
|
||||
if (return_arity == 1) {
|
||||
// We access the additional return values through projections.
|
||||
Node* low_node =
|
||||
graph()->NewNode(common()->Projection(0), node, graph()->start());
|
||||
Node* high_node =
|
||||
graph()->NewNode(common()->Projection(1), node, graph()->start());
|
||||
ReplaceNode(node, low_node, high_node);
|
||||
} else {
|
||||
ZoneVector<Node*> projections(return_arity, zone());
|
||||
NodeProperties::CollectValueProjections(node, projections.data(),
|
||||
return_arity);
|
||||
for (size_t old_index = 0, new_index = 0; old_index < return_arity;
|
||||
++old_index, ++new_index) {
|
||||
Node* use_node = projections[old_index];
|
||||
DCHECK_EQ(ProjectionIndexOf(use_node->op()), old_index);
|
||||
DCHECK_EQ(GetReturnIndexAfterLowering(descriptor,
|
||||
static_cast<int>(old_index)),
|
||||
static_cast<int>(new_index));
|
||||
if (new_index != old_index) {
|
||||
NodeProperties::ChangeOp(
|
||||
use_node, common()->Projection(new_index));
|
||||
}
|
||||
if (descriptor->GetReturnType(old_index).representation() ==
|
||||
MachineRepresentation::kWord64) {
|
||||
Node* high_node = graph()->NewNode(
|
||||
common()->Projection(new_index + 1), node,
|
||||
graph()->start());
|
||||
ReplaceNode(use_node, use_node, high_node);
|
||||
++new_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -812,18 +855,6 @@ void Int64Lowering::LowerNode(Node* node) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kProjection: {
|
||||
Node* call = node->InputAt(0);
|
||||
DCHECK_EQ(IrOpcode::kCall, call->opcode());
|
||||
CallDescriptor* descriptor =
|
||||
const_cast<CallDescriptor*>(CallDescriptorOf(call->op()));
|
||||
for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
|
||||
if (descriptor->GetReturnType(i) == MachineType::Int64()) {
|
||||
UNREACHABLE(); // TODO(titzer): implement multiple i64 returns.
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kWord64ReverseBytes: {
|
||||
Node* input = node->InputAt(0);
|
||||
ReplaceNode(node, graph()->NewNode(machine()->Word32ReverseBytes().op(),
|
||||
|
@ -276,6 +276,23 @@ Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void NodeProperties::CollectValueProjections(Node* node, Node** projections,
|
||||
size_t projection_count) {
|
||||
#ifdef DEBUG
|
||||
for (size_t index = 0; index < projection_count; ++index) {
|
||||
DCHECK_NULL(projections[index]);
|
||||
}
|
||||
#endif
|
||||
for (Edge const edge : node->use_edges()) {
|
||||
if (!IsValueEdge(edge)) continue;
|
||||
Node* use = edge.from();
|
||||
DCHECK_EQ(IrOpcode::kProjection, use->opcode());
|
||||
projections[ProjectionIndexOf(use->op())] = use;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void NodeProperties::CollectControlProjections(Node* node, Node** projections,
|
||||
size_t projection_count) {
|
||||
|
@ -122,6 +122,9 @@ class V8_EXPORT_PRIVATE NodeProperties final {
|
||||
// Collect the output-value projection for the given output index.
|
||||
static Node* FindProjection(Node* node, size_t projection_index);
|
||||
|
||||
// Collect the value projections from a node.
|
||||
static void CollectValueProjections(Node* node, Node** proj, size_t count);
|
||||
|
||||
// Collect the branch-related projections from a node, such as IfTrue,
|
||||
// IfFalse, IfSuccess, IfException, IfValue and IfDefault.
|
||||
// - Branch: [ IfTrue, IfFalse ]
|
||||
|
@ -47,7 +47,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == ia32 ===================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS esi, eax, edx, ecx, ebx
|
||||
#define GP_RETURN_REGISTERS eax, edx
|
||||
#define GP_RETURN_REGISTERS eax, edx, ecx
|
||||
#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
|
||||
#define FP_RETURN_REGISTERS xmm1, xmm2
|
||||
|
||||
@ -56,7 +56,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == x64 ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS rsi, rax, rdx, rcx, rbx, rdi
|
||||
#define GP_RETURN_REGISTERS rax, rdx
|
||||
#define GP_RETURN_REGISTERS rax, rdx, rcx
|
||||
#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
|
||||
#define FP_RETURN_REGISTERS xmm1, xmm2
|
||||
|
||||
@ -65,7 +65,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == arm ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r3, r0, r1, r2
|
||||
#define GP_RETURN_REGISTERS r0, r1
|
||||
#define GP_RETURN_REGISTERS r0, r1, r3
|
||||
#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
|
||||
#define FP_RETURN_REGISTERS d0, d1
|
||||
|
||||
@ -74,7 +74,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == arm64 ====================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS x7, x0, x1, x2, x3, x4, x5, x6
|
||||
#define GP_RETURN_REGISTERS x0, x1
|
||||
#define GP_RETURN_REGISTERS x0, x1, x2
|
||||
#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
|
||||
#define FP_RETURN_REGISTERS d0, d1
|
||||
|
||||
@ -101,7 +101,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == ppc & ppc64 ============================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r10, r3, r4, r5, r6, r7, r8, r9
|
||||
#define GP_RETURN_REGISTERS r3, r4
|
||||
#define GP_RETURN_REGISTERS r3, r4, r5
|
||||
#define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
|
||||
#define FP_RETURN_REGISTERS d1, d2
|
||||
|
||||
@ -110,7 +110,7 @@ LinkageLocation stackloc(int i, MachineType type) {
|
||||
// == s390x ==================================================================
|
||||
// ===========================================================================
|
||||
#define GP_PARAM_REGISTERS r6, r2, r3, r4, r5
|
||||
#define GP_RETURN_REGISTERS r2, r3
|
||||
#define GP_RETURN_REGISTERS r2, r3, r4
|
||||
#define FP_PARAM_REGISTERS d0, d2, d4, d6
|
||||
#define FP_RETURN_REGISTERS d0, d2, d4, d6
|
||||
|
||||
|
@ -1453,7 +1453,7 @@ class ThreadImpl {
|
||||
// ^ 0 ^ sp_
|
||||
DCHECK_LE(dest, sp_);
|
||||
DCHECK_LE(dest + arity, sp_);
|
||||
if (arity) memcpy(dest, sp_ - arity, arity * sizeof(*sp_));
|
||||
if (arity) memmove(dest, sp_ - arity, arity * sizeof(*sp_));
|
||||
sp_ = dest + arity;
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig) {
|
||||
for (auto type : sig->all()) {
|
||||
if (type == wasm::kWasmI64 || type == wasm::kWasmS128) return false;
|
||||
}
|
||||
return true;
|
||||
return sig->return_count() <= 1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -923,6 +923,25 @@ WASM_EXEC_TEST(CallI64Parameter) {
|
||||
}
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(CallI64Return) {
|
||||
ValueType return_types[3]; // TODO(rossberg): support more in the future
|
||||
for (int i = 0; i < 3; i++) return_types[i] = kWasmI64;
|
||||
return_types[1] = kWasmI32;
|
||||
FunctionSig sig(2, 1, return_types);
|
||||
|
||||
WasmRunner<int64_t> r(execution_mode);
|
||||
// Build the target function.
|
||||
WasmFunctionCompiler& t = r.NewFunction(&sig);
|
||||
BUILD(t, WASM_GET_LOCAL(0), WASM_I32V(7));
|
||||
|
||||
// Build the first calling function.
|
||||
BUILD(r,
|
||||
WASM_CALL_FUNCTION(
|
||||
t.function_index(), WASM_I64V(0xbcd12340000000b)), WASM_DROP);
|
||||
|
||||
CHECK_EQ(0xbcd12340000000b, r.Call());
|
||||
}
|
||||
|
||||
void TestI64Binop(WasmExecutionMode execution_mode, WasmOpcode opcode,
|
||||
int64_t expected, int64_t a, int64_t b) {
|
||||
{
|
||||
|
@ -231,3 +231,92 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(instance.exports.main(8, 3), 5);
|
||||
assertEquals(instance.exports.main(0, 3), 3);
|
||||
})();
|
||||
|
||||
(function MultiResultTest() {
|
||||
print("MultiResultTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_i_ii = builder.addType(kSig_i_ii);
|
||||
let sig_iii_ii = builder.addType(kSig_iii_ii);
|
||||
|
||||
builder.addFunction("callee", kSig_iii_ii)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 1,
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 1,
|
||||
kExprI32Sub]);
|
||||
builder.addFunction("main", kSig_i_ii)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 1,
|
||||
kExprCallFunction, 0,
|
||||
kExprI32Mul,
|
||||
kExprI32Add])
|
||||
.exportAs("main");
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
assertEquals(instance.exports.main(0, 0), 0);
|
||||
assertEquals(instance.exports.main(1, 0), 1);
|
||||
assertEquals(instance.exports.main(2, 0), 2);
|
||||
assertEquals(instance.exports.main(0, 1), -1);
|
||||
assertEquals(instance.exports.main(0, 2), -4);
|
||||
assertEquals(instance.exports.main(3, 4), -1);
|
||||
assertEquals(instance.exports.main(4, 3), 7);
|
||||
})();
|
||||
|
||||
(function MultiReturnTest() {
|
||||
print("MultiReturnTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_i_i = builder.addType(kSig_i_i);
|
||||
let sig_ii_i = builder.addType(kSig_ii_i);
|
||||
|
||||
builder.addFunction("callee", kSig_ii_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 0,
|
||||
kExprI32Add,
|
||||
kExprReturn]);
|
||||
builder.addFunction("main", kSig_i_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprCallFunction, 0,
|
||||
kExprI32Mul])
|
||||
.exportAs("main");
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
assertEquals(instance.exports.main(0), 0);
|
||||
assertEquals(instance.exports.main(1), 2);
|
||||
assertEquals(instance.exports.main(2), 8);
|
||||
assertEquals(instance.exports.main(10), 200);
|
||||
})();
|
||||
|
||||
(function MultiBrReturnTest() {
|
||||
print("MultiBrReturnTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_i_i = builder.addType(kSig_i_i);
|
||||
let sig_ii_i = builder.addType(kSig_ii_i);
|
||||
|
||||
builder.addFunction("callee", kSig_ii_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 0,
|
||||
kExprI32Add,
|
||||
kExprBr, 0]);
|
||||
builder.addFunction("main", kSig_i_i)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprCallFunction, 0,
|
||||
kExprI32Mul])
|
||||
.exportAs("main");
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
assertEquals(instance.exports.main(0), 0);
|
||||
assertEquals(instance.exports.main(1), 2);
|
||||
assertEquals(instance.exports.main(2), 8);
|
||||
assertEquals(instance.exports.main(10), 200);
|
||||
})();
|
||||
|
@ -126,7 +126,9 @@ let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
|
||||
let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]);
|
||||
let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]);
|
||||
let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]);
|
||||
let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]);
|
||||
let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]);
|
||||
let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]);
|
||||
|
||||
let kSig_v_f = makeSig([kWasmF32], []);
|
||||
let kSig_f_f = makeSig([kWasmF32], [kWasmF32]);
|
||||
|
Loading…
Reference in New Issue
Block a user