Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Unified Diff: src/compiler/wasm-compiler.cc

Issue 1901063002: [wasm] Copy the tagged-to-int32/float64 and int32/float64-to-tagged code to the wasm compiler. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/wasm-compiler.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/wasm-compiler.cc
diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
index c8b8c85a8949f93f0b6c663f529a3830a621ab63..fd697f717cc38e2e6a24d6fa199578d97f63460c 100644
--- a/src/compiler/wasm-compiler.cc
+++ b/src/compiler/wasm-compiler.cc
@@ -10,7 +10,6 @@
#include "src/base/platform/platform.h"
#include "src/compiler/access-builder.h"
-#include "src/compiler/change-lowering.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/diamond.h"
#include "src/compiler/graph.h"
@@ -24,10 +23,7 @@
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/pipeline.h"
-#include "src/compiler/simplified-lowering.h"
-#include "src/compiler/simplified-operator.h"
#include "src/compiler/source-position.h"
-#include "src/compiler/typer.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
@@ -2074,24 +2070,148 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t index, Node** args) {
return BuildWasmCall(sig, args);
}
+Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
+ // Implement Rol by Ror since TurboFan does not have Rol opcode.
+ // TODO(weiliang): support Word32Rol opcode in TurboFan.
+ Int32Matcher m(right);
+ if (m.HasValue()) {
+ return Binop(wasm::kExprI32Ror, left,
+ jsgraph()->Int32Constant(32 - m.Value()));
+ } else {
+ return Binop(wasm::kExprI32Ror, left,
+ Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
+ }
+}
+
+Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
+ // Implement Rol by Ror since TurboFan does not have Rol opcode.
+ // TODO(weiliang): support Word64Rol opcode in TurboFan.
+ Int64Matcher m(right);
+ if (m.HasValue()) {
+ return Binop(wasm::kExprI64Ror, left,
+ jsgraph()->Int64Constant(64 - m.Value()));
+ } else {
+ return Binop(wasm::kExprI64Ror, left,
+ Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
+ }
+}
+
+Node* WasmGraphBuilder::Invert(Node* node) {
+ return Unop(wasm::kExprI32Eqz, node);
+}
+
+Node* WasmGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (machine->Is64()) {
+ return BuildChangeInt32ToSmi(value);
+ }
+
+ Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value);
+
+ Node* ovf = graph()->NewNode(common->Projection(1), add);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
+ graph()->start());
+
+ Node* if_true = graph()->NewNode(common->IfTrue(), branch);
+ Node* vtrue = BuildAllocateHeapNumberWithValue(
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
+
+ Node* if_false = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfalse = graph()->NewNode(common->Projection(0), add);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
+ vtrue, vfalse, merge);
+ return phi;
+}
+
+Node* WasmGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ Node* const value32 = graph()->NewNode(
+ machine->TruncateFloat64ToInt32(TruncationMode::kRoundToZero), value);
+ Node* check_same = graph()->NewNode(
+ machine->Float64Equal(), value,
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
+ Node* branch_same =
+ graph()->NewNode(common->Branch(), check_same, graph()->start());
+
+ Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
+ Node* vsmi;
+ Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
+ Node* vbox;
+
+ // We only need to check for -0 if the {value} can potentially contain -0.
+ Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
+ jsgraph()->Int32Constant(0));
+ Node* branch_zero =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
+
+ Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
+ Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
+
+ // In case of 0, we need to check the high bits for the IEEE -0 pattern.
+ Node* check_negative = graph()->NewNode(
+ machine->Int32LessThan(),
+ graph()->NewNode(machine->Float64ExtractHighWord32(), value),
+ jsgraph()->Int32Constant(0));
+ Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_negative, if_zero);
+
+ Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
+ Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
+
+ // We need to create a box for negative 0.
+ if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
+ if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
+
+ // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
+ // machines we need to deal with potential overflow and fallback to boxing.
+ if (machine->Is64()) {
+ vsmi = BuildChangeInt32ToSmi(value32);
+ } else {
+ Node* smi_tag =
+ graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32);
+
+ Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag);
+ Node* branch_ovf =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
+
+ Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
+ if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
+
+ if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
+ vsmi = graph()->NewNode(common->Projection(0), smi_tag);
+ }
+
+ // Allocate the box for the {value}.
+ vbox = BuildAllocateHeapNumberWithValue(value, if_box);
+
+ Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
+ value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
+ vbox, control);
+ return value;
+}
Node* WasmGraphBuilder::ToJS(Node* node, Node* context, wasm::LocalType type) {
- SimplifiedOperatorBuilder simplified(jsgraph()->zone());
switch (type) {
case wasm::kAstI32:
- return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
+ return BuildChangeInt32ToTagged(node);
case wasm::kAstI64:
// TODO(titzer): i64->JS has no good solution right now. Using lower 32
// bits.
node =
graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), node);
- return graph()->NewNode(simplified.ChangeInt32ToTagged(), node);
+ return BuildChangeInt32ToTagged(node);
case wasm::kAstF32:
node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
node);
- return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
+ return BuildChangeFloat64ToTagged(node);
case wasm::kAstF64:
- return graph()->NewNode(simplified.ChangeFloat64ToTagged(), node);
+ return BuildChangeFloat64ToTagged(node);
case wasm::kAstStmt:
return jsgraph()->UndefinedConstant();
default:
@@ -2117,6 +2237,117 @@ Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
return result;
}
+bool CanCover(Node* value, IrOpcode::Value opcode) {
+ if (value->opcode() != opcode) return false;
+ bool first = true;
+ for (Edge const edge : value->use_edges()) {
+ if (NodeProperties::IsControlEdge(edge)) continue;
+ if (NodeProperties::IsEffectEdge(edge)) continue;
+ DCHECK(NodeProperties::IsValueEdge(edge));
+ if (!first) return false;
+ first = false;
+ }
+ return true;
+}
+
+Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (CanCover(value, IrOpcode::kJSToNumber)) {
+ // ChangeTaggedToFloat64(JSToNumber(x)) =>
+ // if IsSmi(x) then ChangeSmiToFloat64(x)
+ // else let y = JSToNumber(x) in
+ // if IsSmi(y) then ChangeSmiToFloat64(y)
+ // else BuildLoadHeapNumberValue(y)
+ Node* object = NodeProperties::GetValueInput(value, 0);
+ Node* context = NodeProperties::GetContextInput(value);
+ Node* frame_state = NodeProperties::GetFrameStateInput(value, 0);
+ Node* effect = NodeProperties::GetEffectInput(value);
+ Node* control = NodeProperties::GetControlInput(value);
+
+ const Operator* merge_op = common->Merge(2);
+ const Operator* ephi_op = common->EffectPhi(2);
+ const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
+
+ Node* check1 = BuildTestNotSmi(object);
+ Node* branch1 =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
+
+ Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
+ Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
+ effect, if_true1);
+ Node* etrue1 = vtrue1;
+
+ Node* check2 = BuildTestNotSmi(vtrue1);
+ Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
+
+ Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
+ Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
+
+ Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
+ Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
+
+ if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
+ vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
+ Node* vfalse1 = BuildChangeSmiToFloat64(object);
+ Node* efalse1 = effect;
+
+ Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
+ Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
+ Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
+
+ // Wire the new diamond into the graph, {JSToNumber} can still throw.
+ NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
+
+ // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
+ // the node and places it inside the diamond. Come up with a helper method!
+ for (Node* use : etrue1->uses()) {
+ if (use->opcode() == IrOpcode::kIfSuccess) {
+ use->ReplaceUses(merge1);
+ NodeProperties::ReplaceControlInput(branch2, use);
+ }
+ }
+ return phi1;
+ }
+
+ Node* check = BuildTestNotSmi(value);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
+ graph()->start());
+
+ Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
+
+ Node* vnot_smi;
+ Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
+ jsgraph()->UndefinedConstant());
+ Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_undefined, if_not_smi);
+
+ Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
+ Node* vundefined =
+ jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+
+ Node* if_not_undefined =
+ graph()->NewNode(common->IfFalse(), branch_undefined);
+ Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
+
+ if_not_smi =
+ graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
+ vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vundefined, vheap_number, if_not_smi);
+
+ Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfrom_smi = BuildChangeSmiToFloat64(value);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vnot_smi, vfrom_smi, merge);
+
+ return phi;
+}
+
Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
wasm::LocalType type) {
// Do a JavaScript ToNumber.
@@ -2124,7 +2355,7 @@ Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
// Change representation.
SimplifiedOperatorBuilder simplified(jsgraph()->zone());
- num = graph()->NewNode(simplified.ChangeTaggedToFloat64(), num);
+ num = BuildChangeTaggedToFloat64(num);
switch (type) {
case wasm::kAstI32: {
@@ -2156,36 +2387,75 @@ Node* WasmGraphBuilder::FromJS(Node* node, Node* context,
return num;
}
-Node* WasmGraphBuilder::BuildI32Rol(Node* left, Node* right) {
- // Implement Rol by Ror since TurboFan does not have Rol opcode.
- // TODO(weiliang): support Word32Rol opcode in TurboFan.
- Int32Matcher m(right);
- if (m.HasValue()) {
- return Binop(wasm::kExprI32Ror, left,
- jsgraph()->Int32Constant(32 - m.Value()));
- } else {
- return Binop(wasm::kExprI32Ror, left,
- Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(32), right));
+Node* WasmGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
+ if (jsgraph()->machine()->Is64()) {
+ value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
}
+ return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
+ BuildSmiShiftBitsConstant());
}
-Node* WasmGraphBuilder::BuildI64Rol(Node* left, Node* right) {
- // Implement Rol by Ror since TurboFan does not have Rol opcode.
- // TODO(weiliang): support Word64Rol opcode in TurboFan.
- Int64Matcher m(right);
- if (m.HasValue()) {
- return Binop(wasm::kExprI64Ror, left,
- jsgraph()->Int64Constant(64 - m.Value()));
- } else {
- return Binop(wasm::kExprI64Ror, left,
- Binop(wasm::kExprI64Sub, jsgraph()->Int64Constant(64), right));
+Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
+ value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
+ BuildSmiShiftBitsConstant());
+ if (jsgraph()->machine()->Is64()) {
+ value =
+ graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
}
+ return value;
}
-Node* WasmGraphBuilder::Invert(Node* node) {
- return Unop(wasm::kExprI32Eqz, node);
+Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
+ return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
+ BuildChangeSmiToInt32(value));
+}
+
+Node* WasmGraphBuilder::BuildTestNotSmi(Node* value) {
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagMask == 1);
+ return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
+ jsgraph()->IntPtrConstant(kSmiTagMask));
}
+Node* WasmGraphBuilder::BuildSmiShiftBitsConstant() {
+ return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
+}
+
+Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
+ Node* control) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+ // The AllocateHeapNumberStub does not use the context, so we can safely pass
+ // in Smi zero here.
+ Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
+ Node* target = jsgraph()->HeapConstant(callable.code());
+ Node* context = jsgraph()->NoContextConstant();
+ Node* effect = graph()->NewNode(common->BeginRegion(), graph()->start());
+ if (!allocate_heap_number_operator_.is_set()) {
+ CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
+ jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNoFlags, Operator::kNoThrow);
+ allocate_heap_number_operator_.set(common->Call(descriptor));
+ }
+ Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
+ target, context, effect, control);
+ Node* store =
+ graph()->NewNode(machine->Store(StoreRepresentation(
+ MachineRepresentation::kFloat64, kNoWriteBarrier)),
+ heap_number, BuildHeapNumberValueIndexConstant(), value,
+ heap_number, control);
+ return graph()->NewNode(common->FinishRegion(), heap_number, store);
+}
+
+Node* WasmGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
+ return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
+ value, BuildHeapNumberValueIndexConstant(),
+ graph()->start(), control);
+}
+
+Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
+ return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
+}
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code,
wasm::FunctionSig* sig) {
@@ -2536,18 +2806,6 @@ Handle<JSFunction> CompileJSToWasmWrapper(
// Run the compilation pipeline.
//----------------------------------------------------------------------------
{
- // Changes lowering requires types.
- Typer typer(isolate, &graph);
- NodeVector roots(&zone);
- jsgraph.GetCachedNodes(&roots);
- typer.Run(roots);
-
- // Run generic and change lowering.
- ChangeLowering changes(&jsgraph);
- GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
- graph_reducer.AddReducer(&changes);
- graph_reducer.ReduceGraph();
-
if (FLAG_trace_turbo_graph) { // Simple textual RPO.
OFStream os(stdout);
os << "-- Graph after change lowering -- " << std::endl;
@@ -2623,18 +2881,6 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> code = Handle<Code>::null();
{
- // Changes lowering requires types.
- Typer typer(isolate, &graph);
- NodeVector roots(&zone);
- jsgraph.GetCachedNodes(&roots);
- typer.Run(roots);
-
- // Run generic and change lowering.
- ChangeLowering changes(&jsgraph);
- GraphReducer graph_reducer(&zone, &graph, jsgraph.Dead());
- graph_reducer.AddReducer(&changes);
- graph_reducer.ReduceGraph();
-
if (FLAG_trace_turbo_graph) { // Simple textual RPO.
OFStream os(stdout);
os << "-- Graph after change lowering -- " << std::endl;
« no previous file with comments | « src/compiler/wasm-compiler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698