2016-02-04 09:40:55 +00:00
|
|
|
// Copyright 2014 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/compiler/int64-lowering.h"
|
|
|
|
#include "src/compiler/common-operator.h"
|
2016-03-16 11:02:28 +00:00
|
|
|
#include "src/compiler/diamond.h"
|
2016-02-04 09:40:55 +00:00
|
|
|
#include "src/compiler/graph.h"
|
2016-02-18 15:18:41 +00:00
|
|
|
#include "src/compiler/linkage.h"
|
2016-02-04 09:40:55 +00:00
|
|
|
#include "src/compiler/machine-operator.h"
|
2016-03-31 17:04:51 +00:00
|
|
|
#include "src/compiler/node-matchers.h"
|
2016-02-18 15:18:41 +00:00
|
|
|
#include "src/compiler/node-properties.h"
|
|
|
|
|
2016-02-04 09:40:55 +00:00
|
|
|
#include "src/compiler/node.h"
|
2016-02-18 15:18:41 +00:00
|
|
|
#include "src/wasm/wasm-module.h"
|
2016-02-04 09:40:55 +00:00
|
|
|
#include "src/zone.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
|
2016-02-18 15:18:41 +00:00
|
|
|
CommonOperatorBuilder* common, Zone* zone,
|
|
|
|
Signature<MachineRepresentation>* signature)
|
|
|
|
: zone_(zone),
|
|
|
|
graph_(graph),
|
2016-02-04 09:40:55 +00:00
|
|
|
machine_(machine),
|
|
|
|
common_(common),
|
2016-03-15 06:26:23 +00:00
|
|
|
state_(graph, 3),
|
2016-02-04 09:40:55 +00:00
|
|
|
stack_(zone),
|
2016-03-30 08:13:50 +00:00
|
|
|
replacements_(nullptr),
|
|
|
|
signature_(signature),
|
|
|
|
placeholder_(graph->NewNode(common->Parameter(-2, "placeholder"),
|
|
|
|
graph->start())) {
|
|
|
|
replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
|
2016-02-04 09:40:55 +00:00
|
|
|
memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount());
|
|
|
|
}
|
|
|
|
|
2016-02-18 15:18:41 +00:00
|
|
|
void Int64Lowering::LowerGraph() {
|
2016-03-08 12:41:25 +00:00
|
|
|
if (!machine()->Is32()) {
|
2016-02-18 15:18:41 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-03-30 08:13:50 +00:00
|
|
|
stack_.push_back({graph()->end(), 0});
|
2016-02-04 09:40:55 +00:00
|
|
|
state_.Set(graph()->end(), State::kOnStack);
|
|
|
|
|
|
|
|
while (!stack_.empty()) {
|
2016-03-30 08:13:50 +00:00
|
|
|
NodeState& top = stack_.back();
|
2016-03-15 06:26:23 +00:00
|
|
|
if (top.input_index == top.node->InputCount()) {
|
|
|
|
// All inputs of top have already been lowered, now lower top.
|
2016-03-30 08:13:50 +00:00
|
|
|
stack_.pop_back();
|
2016-03-15 06:26:23 +00:00
|
|
|
state_.Set(top.node, State::kVisited);
|
|
|
|
LowerNode(top.node);
|
2016-02-04 09:40:55 +00:00
|
|
|
} else {
|
2016-03-15 06:26:23 +00:00
|
|
|
// Push the next input onto the stack.
|
|
|
|
Node* input = top.node->InputAt(top.input_index++);
|
|
|
|
if (state_.Get(input) == State::kUnvisited) {
|
2016-03-30 08:13:50 +00:00
|
|
|
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.
|
|
|
|
PreparePhiReplacement(input);
|
|
|
|
stack_.push_front({input, 0});
|
|
|
|
} else {
|
|
|
|
stack_.push_back({input, 0});
|
|
|
|
}
|
2016-03-15 06:26:23 +00:00
|
|
|
state_.Set(input, State::kOnStack);
|
2016-02-04 09:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 15:18:41 +00:00
|
|
|
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) {
|
2016-02-04 09:40:55 +00:00
|
|
|
switch (node->opcode()) {
|
|
|
|
case IrOpcode::kInt64Constant: {
|
|
|
|
int64_t value = OpParameter<int64_t>(node);
|
|
|
|
Node* low_node = graph()->NewNode(
|
|
|
|
common()->Int32Constant(static_cast<int32_t>(value & 0xFFFFFFFF)));
|
|
|
|
Node* high_node = graph()->NewNode(
|
|
|
|
common()->Int32Constant(static_cast<int32_t>(value >> 32)));
|
2016-02-18 15:18:41 +00:00
|
|
|
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);
|
2016-03-15 12:45:43 +00:00
|
|
|
} else {
|
|
|
|
DefaultLowering(node);
|
2016-02-18 15:18:41 +00:00
|
|
|
}
|
|
|
|
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);
|
2016-03-15 12:45:43 +00:00
|
|
|
} else {
|
|
|
|
DefaultLowering(node);
|
2016-02-18 15:18:41 +00:00
|
|
|
}
|
2016-02-04 09:40:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-02-18 15:18:41 +00:00
|
|
|
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);
|
2016-02-23 15:33:06 +00:00
|
|
|
NodeProperties::ChangeOp(node, common()->Parameter(new_index));
|
2016-02-18 15:18:41 +00:00
|
|
|
|
|
|
|
Node* high_node = nullptr;
|
|
|
|
if (signature()->GetParam(old_index) ==
|
|
|
|
MachineRepresentation::kWord64) {
|
|
|
|
high_node = graph()->NewNode(common()->Parameter(new_index + 1),
|
|
|
|
graph()->start());
|
2016-02-04 09:40:55 +00:00
|
|
|
}
|
2016-02-23 15:33:06 +00:00
|
|
|
ReplaceNode(node, node, high_node);
|
2016-02-18 15:18:41 +00:00
|
|
|
}
|
|
|
|
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));
|
2016-02-04 09:40:55 +00:00
|
|
|
}
|
2016-02-18 15:18:41 +00:00
|
|
|
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;
|
2016-02-04 09:40:55 +00:00
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
case IrOpcode::kWord64And: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
|
|
|
|
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);
|
|
|
|
ReplaceNode(node, GetReplacementLow(input), nullptr);
|
|
|
|
node->NullAllInputs();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// todo(ahaas): I added a list of missing instructions here to make merging
|
|
|
|
// easier when I do them one by one.
|
|
|
|
// kExprI64Add:
|
2016-03-14 15:33:15 +00:00
|
|
|
case IrOpcode::kInt64Add: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(right));
|
|
|
|
node->AppendInput(zone(), GetReplacementHigh(right));
|
|
|
|
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(left));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(left));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Sub:
|
2016-03-16 10:56:29 +00:00
|
|
|
case IrOpcode::kInt64Sub: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(right));
|
|
|
|
node->AppendInput(zone(), GetReplacementHigh(right));
|
|
|
|
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(left));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(left));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Int32PairSub());
|
|
|
|
// 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;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Mul:
|
2016-03-30 10:39:04 +00:00
|
|
|
case IrOpcode::kInt64Mul: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(right));
|
|
|
|
node->AppendInput(zone(), GetReplacementHigh(right));
|
|
|
|
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(left));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(left));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Int32PairMul());
|
|
|
|
// 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;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64DivS:
|
|
|
|
// kExprI64DivU:
|
|
|
|
// kExprI64RemS:
|
|
|
|
// kExprI64RemU:
|
|
|
|
// kExprI64Ior:
|
|
|
|
case IrOpcode::kWord64Or: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
|
|
|
|
Node* low_node =
|
|
|
|
graph()->NewNode(machine()->Word32Or(), GetReplacementLow(left),
|
|
|
|
GetReplacementLow(right));
|
|
|
|
Node* high_node =
|
|
|
|
graph()->NewNode(machine()->Word32Or(), GetReplacementHigh(left),
|
|
|
|
GetReplacementHigh(right));
|
|
|
|
ReplaceNode(node, low_node, high_node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// kExprI64Xor:
|
2016-02-24 09:51:30 +00:00
|
|
|
case IrOpcode::kWord64Xor: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
|
|
|
|
Node* low_node =
|
|
|
|
graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
|
|
|
|
GetReplacementLow(right));
|
|
|
|
Node* high_node =
|
|
|
|
graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
|
|
|
|
GetReplacementHigh(right));
|
|
|
|
ReplaceNode(node, low_node, high_node);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Shl:
|
2016-03-07 15:17:54 +00:00
|
|
|
case IrOpcode::kWord64Shl: {
|
|
|
|
// TODO(turbofan): if the shift count >= 32, then we can set the low word
|
|
|
|
// of the output to 0 and just calculate the high word.
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* shift = node->InputAt(1);
|
|
|
|
if (HasReplacementLow(shift)) {
|
|
|
|
// We do not have to care about the high word replacement, because
|
|
|
|
// the shift can only be between 0 and 63 anyways.
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(shift));
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* value = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(value));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(value));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Word32PairShl());
|
|
|
|
// 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;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64ShrU:
|
2016-03-09 16:37:29 +00:00
|
|
|
case IrOpcode::kWord64Shr: {
|
|
|
|
// TODO(turbofan): if the shift count >= 32, then we can set the low word
|
|
|
|
// of the output to 0 and just calculate the high word.
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* shift = node->InputAt(1);
|
|
|
|
if (HasReplacementLow(shift)) {
|
|
|
|
// We do not have to care about the high word replacement, because
|
|
|
|
// the shift can only be between 0 and 63 anyways.
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(shift));
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* value = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(value));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(value));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Word32PairShr());
|
|
|
|
// 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;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64ShrS:
|
2016-03-09 16:37:29 +00:00
|
|
|
case IrOpcode::kWord64Sar: {
|
|
|
|
// TODO(turbofan): if the shift count >= 32, then we can set the low word
|
|
|
|
// of the output to 0 and just calculate the high word.
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* shift = node->InputAt(1);
|
|
|
|
if (HasReplacementLow(shift)) {
|
|
|
|
// We do not have to care about the high word replacement, because
|
|
|
|
// the shift can only be between 0 and 63 anyways.
|
|
|
|
node->ReplaceInput(1, GetReplacementLow(shift));
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* value = node->InputAt(0);
|
|
|
|
node->ReplaceInput(0, GetReplacementLow(value));
|
|
|
|
node->InsertInput(zone(), 1, GetReplacementHigh(value));
|
|
|
|
|
|
|
|
NodeProperties::ChangeOp(node, machine()->Word32PairSar());
|
|
|
|
// 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;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Eq:
|
2016-02-24 12:09:19 +00:00
|
|
|
case IrOpcode::kWord64Equal: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
|
|
|
|
// TODO(wasm): Use explicit comparisons and && here?
|
|
|
|
Node* replacement = graph()->NewNode(
|
|
|
|
machine()->Word32Equal(),
|
|
|
|
graph()->NewNode(
|
|
|
|
machine()->Word32Or(),
|
|
|
|
graph()->NewNode(machine()->Word32Xor(), GetReplacementLow(left),
|
|
|
|
GetReplacementLow(right)),
|
|
|
|
graph()->NewNode(machine()->Word32Xor(), GetReplacementHigh(left),
|
|
|
|
GetReplacementHigh(right))),
|
|
|
|
graph()->NewNode(common()->Int32Constant(0)));
|
|
|
|
|
|
|
|
ReplaceNode(node, replacement, nullptr);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64LtS:
|
2016-02-25 12:14:35 +00:00
|
|
|
case IrOpcode::kInt64LessThan: {
|
|
|
|
LowerComparison(node, machine()->Int32LessThan(),
|
|
|
|
machine()->Uint32LessThan());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IrOpcode::kInt64LessThanOrEqual: {
|
|
|
|
LowerComparison(node, machine()->Int32LessThan(),
|
|
|
|
machine()->Uint32LessThanOrEqual());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IrOpcode::kUint64LessThan: {
|
|
|
|
LowerComparison(node, machine()->Uint32LessThan(),
|
|
|
|
machine()->Uint32LessThan());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IrOpcode::kUint64LessThanOrEqual: {
|
|
|
|
LowerComparison(node, machine()->Uint32LessThan(),
|
|
|
|
machine()->Uint32LessThanOrEqual());
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
|
|
|
|
// kExprI64SConvertI32:
|
2016-03-09 16:20:59 +00:00
|
|
|
case IrOpcode::kChangeInt32ToInt64: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
if (HasReplacementLow(input)) {
|
|
|
|
input = GetReplacementLow(input);
|
|
|
|
}
|
|
|
|
// We use SAR to preserve the sign in the high word.
|
|
|
|
ReplaceNode(
|
|
|
|
node, input,
|
|
|
|
graph()->NewNode(machine()->Word32Sar(), input,
|
|
|
|
graph()->NewNode(common()->Int32Constant(31))));
|
|
|
|
node->NullAllInputs();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// kExprI64UConvertI32: {
|
|
|
|
case IrOpcode::kChangeUint32ToUint64: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
if (HasReplacementLow(input)) {
|
|
|
|
input = GetReplacementLow(input);
|
|
|
|
}
|
|
|
|
ReplaceNode(node, input, graph()->NewNode(common()->Int32Constant(0)));
|
|
|
|
node->NullAllInputs();
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprF64ReinterpretI64:
|
2016-03-15 12:45:43 +00:00
|
|
|
case IrOpcode::kBitcastInt64ToFloat64: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
Node* stack_slot = graph()->NewNode(
|
|
|
|
machine()->StackSlot(MachineRepresentation::kWord64));
|
|
|
|
|
|
|
|
Node* store_high_word = graph()->NewNode(
|
|
|
|
machine()->Store(
|
|
|
|
StoreRepresentation(MachineRepresentation::kWord32,
|
|
|
|
WriteBarrierKind::kNoWriteBarrier)),
|
|
|
|
stack_slot, graph()->NewNode(common()->Int32Constant(4)),
|
|
|
|
GetReplacementHigh(input), graph()->start(), graph()->start());
|
|
|
|
|
|
|
|
Node* store_low_word = graph()->NewNode(
|
|
|
|
machine()->Store(
|
|
|
|
StoreRepresentation(MachineRepresentation::kWord32,
|
|
|
|
WriteBarrierKind::kNoWriteBarrier)),
|
|
|
|
stack_slot, graph()->NewNode(common()->Int32Constant(0)),
|
|
|
|
GetReplacementLow(input), store_high_word, graph()->start());
|
|
|
|
|
|
|
|
Node* load =
|
|
|
|
graph()->NewNode(machine()->Load(MachineType::Float64()), stack_slot,
|
|
|
|
graph()->NewNode(common()->Int32Constant(0)),
|
|
|
|
store_low_word, graph()->start());
|
|
|
|
|
|
|
|
ReplaceNode(node, load, nullptr);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64ReinterpretF64:
|
2016-03-15 12:17:09 +00:00
|
|
|
case IrOpcode::kBitcastFloat64ToInt64: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
2016-03-15 12:45:43 +00:00
|
|
|
if (HasReplacementLow(input)) {
|
|
|
|
input = GetReplacementLow(input);
|
|
|
|
}
|
2016-03-15 12:17:09 +00:00
|
|
|
Node* stack_slot = graph()->NewNode(
|
|
|
|
machine()->StackSlot(MachineRepresentation::kWord64));
|
|
|
|
Node* store = graph()->NewNode(
|
|
|
|
machine()->Store(
|
|
|
|
StoreRepresentation(MachineRepresentation::kFloat64,
|
|
|
|
WriteBarrierKind::kNoWriteBarrier)),
|
|
|
|
stack_slot, graph()->NewNode(common()->Int32Constant(0)), input,
|
|
|
|
graph()->start(), graph()->start());
|
|
|
|
|
|
|
|
Node* high_node =
|
|
|
|
graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
|
|
|
|
graph()->NewNode(common()->Int32Constant(4)), store,
|
|
|
|
graph()->start());
|
2016-02-23 16:30:27 +00:00
|
|
|
|
2016-03-15 12:17:09 +00:00
|
|
|
Node* low_node =
|
|
|
|
graph()->NewNode(machine()->Load(MachineType::Int32()), stack_slot,
|
|
|
|
graph()->NewNode(common()->Int32Constant(0)), store,
|
|
|
|
graph()->start());
|
|
|
|
ReplaceNode(node, low_node, high_node);
|
|
|
|
break;
|
|
|
|
}
|
2016-03-31 17:04:51 +00:00
|
|
|
case IrOpcode::kWord64Ror: {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
Node* shift = HasReplacementLow(node->InputAt(1))
|
|
|
|
? GetReplacementLow(node->InputAt(1))
|
|
|
|
: node->InputAt(1);
|
|
|
|
Int32Matcher m(shift);
|
|
|
|
if (m.HasValue()) {
|
|
|
|
// Precondition: 0 <= shift < 64.
|
|
|
|
int32_t shift_value = m.Value() & 0x3f;
|
|
|
|
if (shift_value == 0) {
|
|
|
|
ReplaceNode(node, GetReplacementLow(input),
|
|
|
|
GetReplacementHigh(input));
|
|
|
|
} else if (shift_value == 32) {
|
|
|
|
ReplaceNode(node, GetReplacementHigh(input),
|
|
|
|
GetReplacementLow(input));
|
|
|
|
} else {
|
|
|
|
Node* low_input;
|
|
|
|
Node* high_input;
|
|
|
|
if (shift_value < 32) {
|
|
|
|
low_input = GetReplacementLow(input);
|
|
|
|
high_input = GetReplacementHigh(input);
|
|
|
|
} else {
|
|
|
|
low_input = GetReplacementHigh(input);
|
|
|
|
high_input = GetReplacementLow(input);
|
|
|
|
}
|
|
|
|
int32_t masked_shift_value = shift_value & 0x1f;
|
|
|
|
Node* masked_shift =
|
|
|
|
graph()->NewNode(common()->Int32Constant(masked_shift_value));
|
|
|
|
Node* inv_shift = graph()->NewNode(
|
|
|
|
common()->Int32Constant(32 - masked_shift_value));
|
|
|
|
|
|
|
|
Node* low_node = graph()->NewNode(
|
|
|
|
machine()->Word32Or(),
|
|
|
|
graph()->NewNode(machine()->Word32Shr(), low_input, masked_shift),
|
|
|
|
graph()->NewNode(machine()->Word32Shl(), high_input, inv_shift));
|
|
|
|
Node* high_node = graph()->NewNode(
|
|
|
|
machine()->Word32Or(), graph()->NewNode(machine()->Word32Shr(),
|
|
|
|
high_input, masked_shift),
|
|
|
|
graph()->NewNode(machine()->Word32Shl(), low_input, inv_shift));
|
|
|
|
ReplaceNode(node, low_node, high_node);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Node* safe_shift = shift;
|
|
|
|
if (!machine()->Word32ShiftIsSafe()) {
|
|
|
|
safe_shift =
|
|
|
|
graph()->NewNode(machine()->Word32And(), shift,
|
|
|
|
graph()->NewNode(common()->Int32Constant(0x1f)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// By creating this bit-mask with SAR and SHL we do not have to deal
|
|
|
|
// with shift == 0 as a special case.
|
|
|
|
Node* inv_mask = graph()->NewNode(
|
|
|
|
machine()->Word32Shl(),
|
|
|
|
graph()->NewNode(machine()->Word32Sar(),
|
|
|
|
graph()->NewNode(common()->Int32Constant(
|
|
|
|
std::numeric_limits<int32_t>::min())),
|
|
|
|
safe_shift),
|
|
|
|
graph()->NewNode(common()->Int32Constant(1)));
|
|
|
|
|
|
|
|
Node* bit_mask =
|
|
|
|
graph()->NewNode(machine()->Word32Xor(), inv_mask,
|
|
|
|
graph()->NewNode(common()->Int32Constant(-1)));
|
|
|
|
|
|
|
|
// We have to mask the shift value for this comparison. If
|
|
|
|
// !machine()->Word32ShiftIsSafe() then the masking should already be
|
|
|
|
// part of the graph.
|
|
|
|
Node* masked_shift6 = shift;
|
|
|
|
if (machine()->Word32ShiftIsSafe()) {
|
|
|
|
masked_shift6 =
|
|
|
|
graph()->NewNode(machine()->Word32And(), shift,
|
|
|
|
graph()->NewNode(common()->Int32Constant(0x3f)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Diamond lt32(
|
|
|
|
graph(), common(),
|
|
|
|
graph()->NewNode(machine()->Int32LessThan(), masked_shift6,
|
|
|
|
graph()->NewNode(common()->Int32Constant(32))));
|
|
|
|
|
|
|
|
// The low word and the high word can be swapped either at the input or
|
|
|
|
// at the output. We swap the inputs so that shift does not have to be
|
|
|
|
// kept for so long in a register.
|
|
|
|
Node* input_low =
|
|
|
|
lt32.Phi(MachineRepresentation::kWord32, GetReplacementLow(input),
|
|
|
|
GetReplacementHigh(input));
|
|
|
|
Node* input_high =
|
|
|
|
lt32.Phi(MachineRepresentation::kWord32, GetReplacementHigh(input),
|
|
|
|
GetReplacementLow(input));
|
|
|
|
|
|
|
|
Node* rotate_low =
|
|
|
|
graph()->NewNode(machine()->Word32Ror(), input_low, safe_shift);
|
|
|
|
Node* rotate_high =
|
|
|
|
graph()->NewNode(machine()->Word32Ror(), input_high, safe_shift);
|
|
|
|
|
|
|
|
Node* low_node = graph()->NewNode(
|
|
|
|
machine()->Word32Or(),
|
|
|
|
graph()->NewNode(machine()->Word32And(), rotate_low, bit_mask),
|
|
|
|
graph()->NewNode(machine()->Word32And(), rotate_high, inv_mask));
|
|
|
|
|
|
|
|
Node* high_node = graph()->NewNode(
|
|
|
|
machine()->Word32Or(),
|
|
|
|
graph()->NewNode(machine()->Word32And(), rotate_high, bit_mask),
|
|
|
|
graph()->NewNode(machine()->Word32And(), rotate_low, inv_mask));
|
|
|
|
|
|
|
|
ReplaceNode(node, low_node, high_node);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Clz:
|
2016-03-16 11:02:28 +00:00
|
|
|
case IrOpcode::kWord64Clz: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
Diamond d(
|
|
|
|
graph(), common(),
|
|
|
|
graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(input),
|
|
|
|
graph()->NewNode(common()->Int32Constant(0))));
|
|
|
|
|
|
|
|
Node* low_node = d.Phi(
|
|
|
|
MachineRepresentation::kWord32,
|
|
|
|
graph()->NewNode(machine()->Int32Add(),
|
|
|
|
graph()->NewNode(machine()->Word32Clz(),
|
|
|
|
GetReplacementLow(input)),
|
|
|
|
graph()->NewNode(common()->Int32Constant(32))),
|
|
|
|
graph()->NewNode(machine()->Word32Clz(), GetReplacementHigh(input)));
|
|
|
|
ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
// kExprI64Ctz:
|
2016-03-16 12:14:44 +00:00
|
|
|
case IrOpcode::kWord64Ctz: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
DCHECK(machine()->Word32Ctz().IsSupported());
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
Diamond d(
|
|
|
|
graph(), common(),
|
|
|
|
graph()->NewNode(machine()->Word32Equal(), GetReplacementLow(input),
|
|
|
|
graph()->NewNode(common()->Int32Constant(0))));
|
|
|
|
Node* low_node =
|
|
|
|
d.Phi(MachineRepresentation::kWord32,
|
|
|
|
graph()->NewNode(machine()->Int32Add(),
|
|
|
|
graph()->NewNode(machine()->Word32Ctz().op(),
|
|
|
|
GetReplacementHigh(input)),
|
|
|
|
graph()->NewNode(common()->Int32Constant(32))),
|
|
|
|
graph()->NewNode(machine()->Word32Ctz().op(),
|
|
|
|
GetReplacementLow(input)));
|
|
|
|
ReplaceNode(node, low_node, graph()->NewNode(common()->Int32Constant(0)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// kExprI64Popcnt:
|
2016-03-15 10:41:55 +00:00
|
|
|
case IrOpcode::kWord64Popcnt: {
|
|
|
|
DCHECK(node->InputCount() == 1);
|
|
|
|
Node* input = node->InputAt(0);
|
|
|
|
// We assume that a Word64Popcnt node only has been created if
|
|
|
|
// Word32Popcnt is actually supported.
|
|
|
|
DCHECK(machine()->Word32Popcnt().IsSupported());
|
|
|
|
ReplaceNode(node, graph()->NewNode(
|
|
|
|
machine()->Int32Add(),
|
|
|
|
graph()->NewNode(machine()->Word32Popcnt().op(),
|
|
|
|
GetReplacementLow(input)),
|
|
|
|
graph()->NewNode(machine()->Word32Popcnt().op(),
|
|
|
|
GetReplacementHigh(input))),
|
|
|
|
graph()->NewNode(common()->Int32Constant(0)));
|
|
|
|
break;
|
|
|
|
}
|
2016-03-30 08:13:50 +00:00
|
|
|
case IrOpcode::kPhi: {
|
|
|
|
MachineRepresentation rep = PhiRepresentationOf(node->op());
|
|
|
|
if (rep == MachineRepresentation::kWord64) {
|
|
|
|
// The replacement nodes have already been created, we only have to
|
|
|
|
// replace placeholder nodes.
|
|
|
|
Node* low_node = GetReplacementLow(node);
|
|
|
|
Node* high_node = GetReplacementHigh(node);
|
|
|
|
for (int i = 0; i < node->op()->ValueInputCount(); i++) {
|
|
|
|
low_node->ReplaceInput(i, GetReplacementLow(node->InputAt(i)));
|
|
|
|
high_node->ReplaceInput(i, GetReplacementHigh(node->InputAt(i)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DefaultLowering(node);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-02-23 16:30:27 +00:00
|
|
|
|
2016-02-18 15:18:41 +00:00
|
|
|
default: { DefaultLowering(node); }
|
2016-02-04 09:40:55 +00:00
|
|
|
}
|
2016-03-31 17:04:51 +00:00
|
|
|
} // NOLINT(readability/fn_size)
|
2016-02-04 09:40:55 +00:00
|
|
|
|
2016-02-25 12:14:35 +00:00
|
|
|
void Int64Lowering::LowerComparison(Node* node, const Operator* high_word_op,
|
|
|
|
const Operator* low_word_op) {
|
|
|
|
DCHECK(node->InputCount() == 2);
|
|
|
|
Node* left = node->InputAt(0);
|
|
|
|
Node* right = node->InputAt(1);
|
|
|
|
Node* replacement = graph()->NewNode(
|
|
|
|
machine()->Word32Or(),
|
|
|
|
graph()->NewNode(high_word_op, GetReplacementHigh(left),
|
|
|
|
GetReplacementHigh(right)),
|
|
|
|
graph()->NewNode(
|
|
|
|
machine()->Word32And(),
|
|
|
|
graph()->NewNode(machine()->Word32Equal(), GetReplacementHigh(left),
|
|
|
|
GetReplacementHigh(right)),
|
|
|
|
graph()->NewNode(low_word_op, GetReplacementLow(left),
|
|
|
|
GetReplacementLow(right))));
|
|
|
|
|
|
|
|
ReplaceNode(node, replacement, nullptr);
|
|
|
|
}
|
|
|
|
|
2016-02-18 15:18:41 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-03-30 08:13:50 +00:00
|
|
|
|
|
|
|
void Int64Lowering::PreparePhiReplacement(Node* phi) {
|
|
|
|
MachineRepresentation rep = PhiRepresentationOf(phi->op());
|
|
|
|
if (rep == MachineRepresentation::kWord64) {
|
|
|
|
// We have to create the replacements for a phi node before we actually
|
|
|
|
// lower the phi to break potential cycles in the graph. The replacements of
|
|
|
|
// input nodes do not exist yet, so we use a placeholder node to pass the
|
|
|
|
// graph verifier.
|
|
|
|
int value_count = phi->op()->ValueInputCount();
|
|
|
|
Node** inputs_low = zone()->NewArray<Node*>(value_count + 1);
|
|
|
|
Node** inputs_high = zone()->NewArray<Node*>(value_count + 1);
|
|
|
|
for (int i = 0; i < value_count; i++) {
|
|
|
|
inputs_low[i] = placeholder_;
|
|
|
|
inputs_high[i] = placeholder_;
|
|
|
|
}
|
|
|
|
inputs_low[value_count] = NodeProperties::GetControlInput(phi, 0);
|
|
|
|
inputs_high[value_count] = NodeProperties::GetControlInput(phi, 0);
|
|
|
|
ReplaceNode(phi,
|
|
|
|
graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kWord32, value_count),
|
|
|
|
value_count + 1, inputs_low, false),
|
|
|
|
graph()->NewNode(
|
|
|
|
common()->Phi(MachineRepresentation::kWord32, value_count),
|
|
|
|
value_count + 1, inputs_high, false));
|
|
|
|
}
|
|
|
|
}
|
2016-02-04 09:40:55 +00:00
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|