Commit 7a61dad0 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by V8 LUCI CQ

[turboshaft] some IR refactorings

- Remove TruncateInt64ToInt32 instead of translating to Turboshaft, since it has no effect. Removing it simplifies pattern-matching in optimizations.
- Change how exception handling is done in Turboshaft: The exception value is obtained as the result of `CatchExceptionOp` instead of a special projection. This simplifies projections.
- Add `TupleOp` as the counterpart to `ProjectionOp`, which is useful
  for lowerings of operations that have multiple outputs.

- Split BinopOp into WordBinopOp and FloatBinopOp because they have quite different semantics and many kinds only exist for one of them.
- rename IntegerUnary to WordUnary and other occurences of
  Integer/Integral
- rename ChangeOp::Kind::kUnsignedFloatTruncate` to `kJSFloatTruncate`
  because it actually has JS wrap-around semantics.
- move/add representation DCHECKs to operation constructors.
- add some convinience helpers to `AssemblerInterface`.

- Add a mechanism to check which operations are supported by the machine.

Drive-by fix: Abort current block in OptimizationPhase::VisitBlock if
  we lower to a block-terminator.

Bug: v8:12783
Change-Id: Ib738accccd22fb1606d9dab86f57ac1e739fcec2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3857449
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarDarius Mercadier <dmercadier@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82857}
parent 156c302f
......@@ -2876,6 +2876,7 @@ filegroup(
"src/compiler/turboshaft/recreate-schedule.cc",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/utils.h",
"src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.cc",
"src/compiler/type-cache.h",
......
......@@ -2995,6 +2995,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/optimization-phase.h",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/utils.h",
"src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.h",
"src/compiler/type-narrowing-reducer.h",
......
......@@ -2013,6 +2013,8 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
immediate_mode = kLoadStoreImm16;
break;
case MachineRepresentation::kWord32:
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTagged:
opcode = kArm64Ldrsw;
immediate_mode = kLoadStoreImm32;
break;
......
......@@ -1657,6 +1657,8 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
opcode = load_rep.IsSigned() ? kX64Movsxwq : kX64Movzxwq;
break;
case MachineRepresentation::kWord32:
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTagged:
// ChangeInt32ToInt64 must interpret its input as a _signed_ 32-bit
// integer, so here we must sign-extend the loaded value in any case.
opcode = kX64Movsxlq;
......
......@@ -112,7 +112,7 @@ class V8_EXPORT_PRIVATE JSGraph : public MachineGraph {
// Cached global node accessor methods.
#define DECLARE_GETTER(name) Node* name();
CACHED_GLOBAL_LIST(DECLARE_GETTER)
#undef DECLARE_FIELD
#undef DECLARE_GETTER
private:
Isolate* isolate_;
......
This diff is collapsed.
......@@ -121,8 +121,8 @@ void DecompressionAnalyzer::ProcessOperation(const Operation& op) {
}
break;
}
case Opcode::kBinop: {
auto& binary_op = op.Cast<BinopOp>();
case Opcode::kWordBinop: {
auto& binary_op = op.Cast<WordBinopOp>();
if (binary_op.rep == MachineRepresentation::kWord64) {
MarkAsNeedsDecompression(binary_op.left());
MarkAsNeedsDecompression(binary_op.right());
......
This diff is collapsed.
......@@ -7,10 +7,14 @@
#include <atomic>
#include <sstream>
#include "src/base/platform/mutex.h"
#include "src/base/platform/platform.h"
#include "src/codegen/machine-type.h"
#include "src/common/assert-scope.h"
#include "src/common/globals.h"
#include "src/compiler/backend/instruction-selector.h"
#include "src/compiler/frame-states.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/turboshaft/deopt-data.h"
#include "src/compiler/turboshaft/graph.h"
#include "src/handles/handles-inl.h"
......@@ -39,11 +43,11 @@ std::ostream& operator<<(std::ostream& os, OperationPrintStyle styled_op) {
return os;
}
std::ostream& operator<<(std::ostream& os, IntegerUnaryOp::Kind kind) {
std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind) {
switch (kind) {
case IntegerUnaryOp::Kind::kReverseBytes:
case WordUnaryOp::Kind::kReverseBytes:
return os << "ReverseBytes";
case IntegerUnaryOp::Kind::kCountLeadingZeros:
case WordUnaryOp::Kind::kCountLeadingZeros:
return os << "CountLeadingZeros";
}
}
......@@ -95,6 +99,30 @@ std::ostream& operator<<(std::ostream& os, FloatUnaryOp::Kind kind) {
}
}
// static
bool FloatUnaryOp::IsSupported(Kind kind, MachineRepresentation rep) {
switch (kind) {
case Kind::kRoundDown:
return rep == MachineRepresentation::kFloat32
? SupportedOperations::float32_round_down()
: SupportedOperations::float64_round_down();
case Kind::kRoundUp:
return rep == MachineRepresentation::kFloat32
? SupportedOperations::float32_round_up()
: SupportedOperations::float64_round_up();
case Kind::kRoundToZero:
return rep == MachineRepresentation::kFloat32
? SupportedOperations::float32_round_to_zero()
: SupportedOperations::float64_round_to_zero();
case Kind::kRoundTiesEven:
return rep == MachineRepresentation::kFloat32
? SupportedOperations::float32_round_ties_even()
: SupportedOperations::float64_round_ties_even();
default:
return true;
}
}
std::ostream& operator<<(std::ostream& os, ShiftOp::Kind kind) {
switch (kind) {
case ShiftOp::Kind::kShiftRightArithmeticShiftOutZeros:
......@@ -131,14 +159,12 @@ std::ostream& operator<<(std::ostream& os, ChangeOp::Kind kind) {
return os << "SignedNarrowing";
case ChangeOp::Kind::kUnsignedNarrowing:
return os << "UnsignedNarrowing";
case ChangeOp::Kind::kIntegerTruncate:
return os << "IntegerTruncate";
case ChangeOp::Kind::kFloatConversion:
return os << "FloatConversion";
case ChangeOp::Kind::kSignedFloatTruncate:
return os << "SignedFloatTruncate";
case ChangeOp::Kind::kUnsignedFloatTruncate:
return os << "UnsignedFloatTruncate";
case ChangeOp::Kind::kJSFloatTruncate:
return os << "JSFloatTruncate";
case ChangeOp::Kind::kSignedFloatTruncateOverflowToMin:
return os << "SignedFloatTruncateOverflowToMin";
case ChangeOp::Kind::kSignedToFloat:
......@@ -167,15 +193,6 @@ std::ostream& operator<<(std::ostream& os, Float64InsertWord32Op::Kind kind) {
}
}
std::ostream& operator<<(std::ostream& os, ProjectionOp::Kind kind) {
switch (kind) {
case ProjectionOp::Kind::kTuple:
return os << "tuple";
case ProjectionOp::Kind::kExceptionValue:
return os << "exception value";
}
}
std::ostream& operator<<(std::ostream& os, FrameConstantOp::Kind kind) {
switch (kind) {
case FrameConstantOp::Kind::kStackCheckOffset:
......@@ -334,7 +351,7 @@ void FrameStateOp::PrintOptions(std::ostream& os) const {
os << "]";
}
void BinopOp::PrintOptions(std::ostream& os) const {
void WordBinopOp::PrintOptions(std::ostream& os) const {
os << "[";
switch (kind) {
case Kind::kAdd:
......@@ -373,6 +390,29 @@ void BinopOp::PrintOptions(std::ostream& os) const {
case Kind::kBitwiseXor:
os << "BitwiseXor, ";
break;
}
os << rep;
os << "]";
}
void FloatBinopOp::PrintOptions(std::ostream& os) const {
os << "[";
switch (kind) {
case Kind::kAdd:
os << "Add, ";
break;
case Kind::kSub:
os << "Sub, ";
break;
case Kind::kMul:
os << "Mul, ";
break;
case Kind::kDiv:
os << "Div, ";
break;
case Kind::kMod:
os << "Mod, ";
break;
case Kind::kMin:
os << "Min, ";
break;
......@@ -419,7 +459,7 @@ std::ostream& operator<<(std::ostream& os, const Block* b) {
}
std::ostream& operator<<(std::ostream& os, OpProperties opProperties) {
if(opProperties == OpProperties::Pure()) {
if (opProperties == OpProperties::Pure()) {
os << "Pure";
} else if (opProperties == OpProperties::Reading()) {
os << "Reading";
......@@ -451,4 +491,22 @@ std::string Operation::ToString() const {
return ss.str();
}
base::LazyMutex SupportedOperations::mutex_;
SupportedOperations SupportedOperations::instance_;
bool SupportedOperations::initialized_;
void SupportedOperations::Initialize() {
base::MutexGuard lock(mutex_.Pointer());
if (initialized_) return;
initialized_ = true;
MachineOperatorBuilder::Flags supported =
InstructionSelector::SupportedMachineOperatorFlags();
#define SET_SUPPORTED(name, machine_name) \
instance_.name##_ = supported & MachineOperatorBuilder::Flag::k##machine_name;
SUPPORTED_OPERATIONS_LIST(SET_SUPPORTED)
#undef SET_SUPPORTED
}
} // namespace v8::internal::compiler::turboshaft
This diff is collapsed.
......@@ -209,6 +209,7 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
}
assembler.current_block()->SetDeferred(input_block.IsDeferred());
for (OpIndex index : input_graph.OperationIndices(input_block)) {
if (!assembler.current_block()) break;
assembler.SetCurrentOrigin(index);
OpIndex first_output_index = assembler.graph().next_operation_index();
USE(first_output_index);
......@@ -327,7 +328,7 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
// predecessors did not change. In kDominator order, the order of control
// predecessor might or might not change.
for (OpIndex input : base::Reversed(old_inputs)) {
if (new_pred->Origin() == old_pred) {
if (new_pred && new_pred->Origin() == old_pred) {
new_inputs.push_back(MapToNewGraph(input));
new_pred = new_pred->NeighboringPredecessor();
}
......@@ -398,6 +399,7 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
return assembler.Call(callee, base::VectorOf(arguments), op.descriptor);
}
OpIndex ReduceReturn(const ReturnOp& op) {
// We very rarely have tuples longer than 4.
auto return_values = MapToNewGraph<4>(op.return_values());
return assembler.Return(MapToNewGraph(op.pop_count()),
base::VectorOf(return_values));
......@@ -406,8 +408,8 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
return assembler.OverflowCheckedBinop(
MapToNewGraph(op.left()), MapToNewGraph(op.right()), op.kind, op.rep);
}
OpIndex ReduceIntegerUnary(const IntegerUnaryOp& op) {
return assembler.IntegerUnary(MapToNewGraph(op.input()), op.kind, op.rep);
OpIndex ReduceWordUnary(const WordUnaryOp& op) {
return assembler.WordUnary(MapToNewGraph(op.input()), op.kind, op.rep);
}
OpIndex ReduceFloatUnary(const FloatUnaryOp& op) {
return assembler.FloatUnary(MapToNewGraph(op.input()), op.kind, op.rep);
......@@ -487,12 +489,19 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
MapToNewGraph(op.frame_state()), op.negated,
op.parameters);
}
OpIndex ReduceTuple(const TupleOp& op) {
return assembler.Tuple(base::VectorOf(MapToNewGraph<4>(op.inputs())));
}
OpIndex ReduceProjection(const ProjectionOp& op) {
return assembler.Projection(MapToNewGraph(op.input()), op.kind, op.index);
return assembler.Projection(MapToNewGraph(op.input()), op.index);
}
OpIndex ReduceBinop(const BinopOp& op) {
return assembler.Binop(MapToNewGraph(op.left()), MapToNewGraph(op.right()),
op.kind, op.rep);
OpIndex ReduceWordBinop(const WordBinopOp& op) {
return assembler.WordBinop(MapToNewGraph(op.left()),
MapToNewGraph(op.right()), op.kind, op.rep);
}
OpIndex ReduceFloatBinop(const FloatBinopOp& op) {
return assembler.FloatBinop(MapToNewGraph(op.left()),
MapToNewGraph(op.right()), op.kind, op.rep);
}
OpIndex ReduceUnreachable(const UnreachableOp& op) {
return assembler.Unreachable();
......
// Copyright 2022 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.
#ifndef V8_COMPILER_TURBOSHAFT_UTILS_H_
#define V8_COMPILER_TURBOSHAFT_UTILS_H_
#include <iostream>
#include <tuple>
#include "src/base/logging.h"
namespace v8::internal::compiler::turboshaft {
template <class... Ts>
struct any_of : std::tuple<const Ts&...> {
explicit any_of(const Ts&... args) : std::tuple<const Ts&...>(args...) {}
template <class T, size_t... indices>
bool Contains(const T& value, std::index_sequence<indices...>) {
return ((value == std::get<indices>(*this)) || ...);
}
template <size_t... indices>
std::ostream& PrintTo(std::ostream& os, std::index_sequence<indices...>) {
bool first = true;
os << "any_of(";
(((first ? (first = false, os) : os << ", "),
os << base::PrintCheckOperand(std::get<indices>(*this))),
...);
return os << ")";
}
};
template <class... Args>
any_of(const Args&...) -> any_of<Args...>;
template <class T, class... Ts>
bool operator==(const T& value, any_of<Ts...> options) {
return options.Contains(value, std::index_sequence_for<Ts...>{});
}
template <class... Ts>
std::ostream& operator<<(std::ostream& os, any_of<Ts...> any) {
return any.PrintTo(os, std::index_sequence_for<Ts...>{});
}
template <class... Ts>
struct all_of : std::tuple<const Ts&...> {
explicit all_of(const Ts&... args) : std::tuple<const Ts&...>(args...) {}
template <class T, size_t... indices>
bool AllEqualTo(const T& value, std::index_sequence<indices...>) {
return ((value == std::get<indices>(*this)) && ...);
}
template <class T, size_t... indices>
bool AllNotEqualTo(const T& value, std::index_sequence<indices...>) {
return ((value != std::get<indices>(*this)) && ...);
}
template <size_t... indices>
std::ostream& PrintTo(std::ostream& os, std::index_sequence<indices...>) {
bool first = true;
os << "all_of(";
(((first ? (first = false, os) : os << ", "),
os << base::PrintCheckOperand(std::get<indices>(*this))),
...);
return os << ")";
}
};
template <class... Args>
all_of(const Args&...) -> all_of<Args...>;
template <class T, class... Ts>
bool operator==(all_of<Ts...> values, const T& target) {
return values.AllEqualTo(target, std::index_sequence_for<Ts...>{});
}
template <class T, class... Ts>
bool operator!=(const T& target, all_of<Ts...> values) {
return values.AllNotEqualTo(target, std::index_sequence_for<Ts...>{});
}
template <class... Ts>
std::ostream& operator<<(std::ostream& os, all_of<Ts...> all) {
return all.PrintTo(os, std::index_sequence_for<Ts...>{});
}
} // namespace v8::internal::compiler::turboshaft
#endif // V8_COMPILER_TURBOSHAFT_UTILS_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment