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 <gsps@google.com>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61251}
This commit is contained in:
Georg Schmid 2019-05-06 17:49:31 +02:00 committed by Commit Bot
parent 9b7347665e
commit a542b735b4
16 changed files with 76 additions and 4 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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) \

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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.

View File

@ -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.",

View File

@ -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) {

View File

@ -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)

View File

@ -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

View File

@ -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) \

View File

@ -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);
})();