From a542b735b498be7c6a69bf67ff797dd1c3bf05d4 Mon Sep 17 00:00:00 2001 From: Georg Schmid Date: Mon, 6 May 2019 17:49:31 +0200 Subject: [PATCH] Add StaticAssert node and corresponding intrinsic that allows explicit static asserts in tests R=tebbi@chromium.org Change-Id: I1003a4f4a0e9227618e685a2fb56ead2083709a9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1594731 Commit-Queue: Georg Schmid Reviewed-by: Tobias Tebbi Cr-Commit-Position: refs/heads/master@{#61251} --- src/compiler/backend/instruction-selector.cc | 8 ++++++++ src/compiler/backend/instruction-selector.h | 1 + src/compiler/common-operator-reducer.cc | 14 ++++++++++++++ src/compiler/common-operator-reducer.h | 1 + src/compiler/common-operator.cc | 3 ++- src/compiler/common-operator.h | 1 + src/compiler/js-intrinsic-lowering.cc | 14 ++++++++++++++ src/compiler/js-intrinsic-lowering.h | 1 + src/compiler/memory-optimizer.cc | 1 + src/compiler/opcodes.h | 5 +++-- src/compiler/simplified-lowering.cc | 2 ++ src/compiler/typer.cc | 2 ++ src/compiler/verifier.cc | 1 + src/runtime/runtime-test.cc | 7 +++++++ src/runtime/runtime.h | 3 ++- .../mjsunit/compiler/constant-fold-add-static.js | 16 ++++++++++++++++ 16 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 test/mjsunit/compiler/constant-fold-add-static.js diff --git a/src/compiler/backend/instruction-selector.cc b/src/compiler/backend/instruction-selector.cc index 704dccf7d9..1541d14448 100644 --- a/src/compiler/backend/instruction-selector.cc +++ b/src/compiler/backend/instruction-selector.cc @@ -1329,6 +1329,9 @@ void InstructionSelector::VisitNode(Node* node) { case IrOpcode::kUnreachable: VisitUnreachable(node); return; + case IrOpcode::kStaticAssert: + VisitStaticAssert(node); + return; case IrOpcode::kDeadValue: VisitDeadValue(node); return; @@ -2839,6 +2842,11 @@ void InstructionSelector::VisitUnreachable(Node* node) { Emit(kArchDebugBreak, g.NoOutput()); } +void InstructionSelector::VisitStaticAssert(Node* node) { + node->InputAt(0)->Print(); + FATAL("Expected static assert to hold, but got non-true input!\n"); +} + void InstructionSelector::VisitDeadValue(Node* node) { OperandGenerator g(this); MarkAsRepresentation(DeadValueRepresentationOf(node->op()), node); diff --git a/src/compiler/backend/instruction-selector.h b/src/compiler/backend/instruction-selector.h index ecc3497498..1d01f419fa 100644 --- a/src/compiler/backend/instruction-selector.h +++ b/src/compiler/backend/instruction-selector.h @@ -628,6 +628,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final { void VisitThrow(Node* node); void VisitRetain(Node* node); void VisitUnreachable(Node* node); + void VisitStaticAssert(Node* node); void VisitDeadValue(Node* node); void VisitWordCompareZero(Node* user, Node* value, FlagsContinuation* cont); diff --git a/src/compiler/common-operator-reducer.cc b/src/compiler/common-operator-reducer.cc index 57f1866bdb..fa727748f6 100644 --- a/src/compiler/common-operator-reducer.cc +++ b/src/compiler/common-operator-reducer.cc @@ -72,6 +72,8 @@ Reduction CommonOperatorReducer::Reduce(Node* node) { return ReduceSelect(node); case IrOpcode::kSwitch: return ReduceSwitch(node); + case IrOpcode::kStaticAssert: + return ReduceStaticAssert(node); default: break; } @@ -459,6 +461,18 @@ Reduction CommonOperatorReducer::ReduceSwitch(Node* node) { return NoChange(); } +Reduction CommonOperatorReducer::ReduceStaticAssert(Node* node) { + DCHECK_EQ(IrOpcode::kStaticAssert, node->opcode()); + Node* const cond = node->InputAt(0); + Decision decision = DecideCondition(broker(), cond); + if (decision == Decision::kTrue) { + RelaxEffectsAndControls(node); + return Changed(node); + } else { + return NoChange(); + } +} + Reduction CommonOperatorReducer::Change(Node* node, Operator const* op, Node* a) { node->ReplaceInput(0, a); diff --git a/src/compiler/common-operator-reducer.h b/src/compiler/common-operator-reducer.h index b1d98e0558..0272cbd31d 100644 --- a/src/compiler/common-operator-reducer.h +++ b/src/compiler/common-operator-reducer.h @@ -42,6 +42,7 @@ class V8_EXPORT_PRIVATE CommonOperatorReducer final Reduction ReduceReturn(Node* node); Reduction ReduceSelect(Node* node); Reduction ReduceSwitch(Node* node); + Reduction ReduceStaticAssert(Node* node); Reduction Change(Node* node, Operator const* op, Node* a); Reduction Change(Node* node, Operator const* op, Node* a, Node* b); diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc index f9d05ef851..c8cc98844e 100644 --- a/src/compiler/common-operator.cc +++ b/src/compiler/common-operator.cc @@ -464,7 +464,8 @@ IfValueParameters const& IfValueParametersOf(const Operator* op) { V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \ V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \ V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \ - V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0) + V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0) \ + V(StaticAssert, Operator::kFoldable, 1, 1, 0, 0, 1, 0) #define CACHED_BRANCH_LIST(V) \ V(None, CriticalSafetyCheck) \ diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h index 717b18c1ec..a21e0b0dbc 100644 --- a/src/compiler/common-operator.h +++ b/src/compiler/common-operator.h @@ -454,6 +454,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final const Operator* Dead(); const Operator* DeadValue(MachineRepresentation rep); const Operator* Unreachable(); + const Operator* StaticAssert(); const Operator* End(size_t control_input_count); const Operator* Branch(BranchHint = BranchHint::kNone, IsSafetyCheck = IsSafetyCheck::kSafetyCheck); diff --git a/src/compiler/js-intrinsic-lowering.cc b/src/compiler/js-intrinsic-lowering.cc index e37757fb32..f3b2b3170c 100644 --- a/src/compiler/js-intrinsic-lowering.cc +++ b/src/compiler/js-intrinsic-lowering.cc @@ -28,6 +28,7 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange(); const Runtime::Function* const f = Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id()); + if (f->function_id == Runtime::kStaticAssert) return ReduceStaticAssert(node); if (f->intrinsic_type != Runtime::IntrinsicType::INLINE) return NoChange(); switch (f->function_id) { case Runtime::kInlineCopyDataProperties: @@ -268,6 +269,19 @@ Reduction JSIntrinsicLowering::ReduceIsSmi(Node* node) { return Change(node, simplified()->ObjectIsSmi()); } +Reduction JSIntrinsicLowering::ReduceStaticAssert(Node* node) { + if (FLAG_always_opt) { + // Ignore static asserts, as we most likely won't have enough information + RelaxEffectsAndControls(node); + } else { + Node* value = NodeProperties::GetValueInput(node, 0); + Node* effect = NodeProperties::GetEffectInput(node); + Node* assert = graph()->NewNode(common()->StaticAssert(), value, effect); + ReplaceWithValue(node, node, assert, nullptr); + } + return Changed(jsgraph_->UndefinedConstant()); +} + Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) { // Replace all effect uses of {node} with the effect dependency. RelaxEffectsAndControls(node); diff --git a/src/compiler/js-intrinsic-lowering.h b/src/compiler/js-intrinsic-lowering.h index 358e1f327b..36cc1213bf 100644 --- a/src/compiler/js-intrinsic-lowering.h +++ b/src/compiler/js-intrinsic-lowering.h @@ -58,6 +58,7 @@ class V8_EXPORT_PRIVATE JSIntrinsicLowering final Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type); Reduction ReduceIsJSReceiver(Node* node); Reduction ReduceIsSmi(Node* node); + Reduction ReduceStaticAssert(Node* node); Reduction ReduceToLength(Node* node); Reduction ReduceToObject(Node* node); Reduction ReduceToString(Node* node); diff --git a/src/compiler/memory-optimizer.cc b/src/compiler/memory-optimizer.cc index 7aec86a3a8..d06e8d88fd 100644 --- a/src/compiler/memory-optimizer.cc +++ b/src/compiler/memory-optimizer.cc @@ -101,6 +101,7 @@ bool CanAllocate(const Node* node) { case IrOpcode::kUnalignedStore: case IrOpcode::kUnsafePointerAdd: case IrOpcode::kUnreachable: + case IrOpcode::kStaticAssert: case IrOpcode::kWord32AtomicAdd: case IrOpcode::kWord32AtomicAnd: case IrOpcode::kWord32AtomicCompareExchange: diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 8aa815e240..fd0571357c 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -81,7 +81,8 @@ INNER_OP_LIST(V) \ V(Unreachable) \ V(DeadValue) \ - V(Dead) + V(Dead) \ + V(StaticAssert) // Opcodes for JavaScript operators. #define JS_COMPARE_BINOP_LIST(V) \ @@ -886,7 +887,7 @@ class V8_EXPORT_PRIVATE IrOpcode { // Returns true if opcode for common operator. static bool IsCommonOpcode(Value value) { - return kStart <= value && value <= kDead; + return kStart <= value && value <= kStaticAssert; } // Returns true if opcode for control operator. diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 9d066bdb5c..0595363dde 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -3440,6 +3440,8 @@ class RepresentationSelector { case IrOpcode::kDeadValue: ProcessInput(node, 0, UseInfo::Any()); return SetOutput(node, MachineRepresentation::kNone); + case IrOpcode::kStaticAssert: + return VisitUnop(node, UseInfo::Any(), MachineRepresentation::kTagged); default: FATAL( "Representation inference: unsupported opcode %i (%s), node #%i\n.", diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 134dfad83a..ad1234051b 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -995,6 +995,8 @@ Type Typer::Visitor::TypeDeadValue(Node* node) { return Type::None(); } Type Typer::Visitor::TypeUnreachable(Node* node) { return Type::None(); } +Type Typer::Visitor::TypeStaticAssert(Node* node) { UNREACHABLE(); } + // JS comparison operators. Type Typer::Visitor::JSEqualTyper(Type lhs, Type rhs, Typer* t) { diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index d6ed56e0c5..f1fa1b817d 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -1830,6 +1830,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { case IrOpcode::kSignExtendWord8ToInt64: case IrOpcode::kSignExtendWord16ToInt64: case IrOpcode::kSignExtendWord32ToInt64: + case IrOpcode::kStaticAssert: #define SIMD_MACHINE_OP_CASE(Name) case IrOpcode::k##Name: MACHINE_SIMD_OP_LIST(SIMD_MACHINE_OP_CASE) diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc index 3afa2a9899..c729415931 100644 --- a/src/runtime/runtime-test.cc +++ b/src/runtime/runtime-test.cc @@ -1250,5 +1250,12 @@ RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) { return ReadOnlyRoots(isolate).undefined_value(); } +RUNTIME_FUNCTION(Runtime_StaticAssert) { + SealHandleScope shs(isolate); + // Always lowered to StaticAssert node in Turbofan, so we should never get + // here in compiled code. + return ReadOnlyRoots(isolate).undefined_value(); +} + } // namespace internal } // namespace v8 diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 2ca0dbab12..ed75aa9228 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -517,7 +517,8 @@ namespace internal { F(WasmGetNumberOfInstances, 1, 1) \ F(WasmNumInterpretedCalls, 1, 1) \ F(WasmTraceMemory, 1, 1) \ - F(SetWasmThreadsEnabled, 1, 1) + F(SetWasmThreadsEnabled, 1, 1) \ + F(StaticAssert, 1, 1) #define FOR_EACH_INTRINSIC_TYPEDARRAY(F, I) \ F(ArrayBufferDetach, 1, 1) \ diff --git a/test/mjsunit/compiler/constant-fold-add-static.js b/test/mjsunit/compiler/constant-fold-add-static.js new file mode 100644 index 0000000000..5b148da28c --- /dev/null +++ b/test/mjsunit/compiler/constant-fold-add-static.js @@ -0,0 +1,16 @@ +// Copyright 2019 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. + +// Flags: --allow-natives-syntax + +// Check that constant-folding of arithmetic results in identical nodes. +(function() { + function foo(x) { + %StaticAssert(1 * x == x + 0); + } + foo(121); + foo(122); + %OptimizeFunctionOnNextCall(foo); + foo(123); +})();