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:
parent
9b7347665e
commit
a542b735b4
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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.",
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
16
test/mjsunit/compiler/constant-fold-add-static.js
Normal file
16
test/mjsunit/compiler/constant-fold-add-static.js
Normal 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);
|
||||
})();
|
Loading…
Reference in New Issue
Block a user