Commit 197471fa authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[turboshaft][wasm] Implement some wasm requirements

- Add Turboshaft to the wasm pipeline (behind a flag).
- Add a few operators.
- Implement SimplifyLoopsPhase, which ensures each loop has at most
  two inputs.
- Remove the unneeded effect argument from
  {FlagContinuation::FromTrap}.

Bug: v8:12783
Change-Id: I03a3f8cf3af40fc75bf57cfbad973b754b13dd8c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3899126
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83365}
parent 5dfa2195
...@@ -2881,6 +2881,8 @@ filegroup( ...@@ -2881,6 +2881,8 @@ filegroup(
"src/compiler/turboshaft/representations.cc", "src/compiler/turboshaft/representations.cc",
"src/compiler/turboshaft/representations.h", "src/compiler/turboshaft/representations.h",
"src/compiler/turboshaft/sidetable.h", "src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/simplify-tf-loops.cc",
"src/compiler/turboshaft/simplify-tf-loops.h",
"src/compiler/turboshaft/utils.h", "src/compiler/turboshaft/utils.h",
"src/compiler/turboshaft/value-numbering-assembler.h", "src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.cc", "src/compiler/type-cache.cc",
......
...@@ -2935,6 +2935,7 @@ v8_header_set("v8_internal_headers") { ...@@ -2935,6 +2935,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/recreate-schedule.h", "src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/representations.h", "src/compiler/turboshaft/representations.h",
"src/compiler/turboshaft/sidetable.h", "src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/simplify-tf-loops.h",
"src/compiler/turboshaft/utils.h", "src/compiler/turboshaft/utils.h",
"src/compiler/turboshaft/value-numbering-assembler.h", "src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.h", "src/compiler/type-cache.h",
...@@ -4231,6 +4232,7 @@ v8_source_set("v8_turboshaft") { ...@@ -4231,6 +4232,7 @@ v8_source_set("v8_turboshaft") {
"src/compiler/turboshaft/optimization-phase.cc", "src/compiler/turboshaft/optimization-phase.cc",
"src/compiler/turboshaft/recreate-schedule.cc", "src/compiler/turboshaft/recreate-schedule.cc",
"src/compiler/turboshaft/representations.cc", "src/compiler/turboshaft/representations.cc",
"src/compiler/turboshaft/simplify-tf-loops.cc",
] ]
public_deps = [ public_deps = [
......
...@@ -14,12 +14,9 @@ ...@@ -14,12 +14,9 @@
#include "src/compiler/backend/instruction-selector-impl.h" #include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/compiler-source-position-table.h" #include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/js-heap-broker.h" #include "src/compiler/js-heap-broker.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
#include "src/compiler/state-values-utils.h" #include "src/compiler/state-values-utils.h"
#include "src/deoptimizer/deoptimizer.h"
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/simd-shuffle.h" #include "src/wasm/simd-shuffle.h"
...@@ -3137,14 +3134,12 @@ void InstructionSelector::VisitSelect(Node* node) { ...@@ -3137,14 +3134,12 @@ void InstructionSelector::VisitSelect(Node* node) {
} }
void InstructionSelector::VisitTrapIf(Node* node, TrapId trap_id) { void InstructionSelector::VisitTrapIf(Node* node, TrapId trap_id) {
FlagsContinuation cont = FlagsContinuation cont = FlagsContinuation::ForTrap(kNotEqual, trap_id);
FlagsContinuation::ForTrap(kNotEqual, trap_id, node->InputAt(1));
VisitWordCompareZero(node, node->InputAt(0), &cont); VisitWordCompareZero(node, node->InputAt(0), &cont);
} }
void InstructionSelector::VisitTrapUnless(Node* node, TrapId trap_id) { void InstructionSelector::VisitTrapUnless(Node* node, TrapId trap_id) {
FlagsContinuation cont = FlagsContinuation cont = FlagsContinuation::ForTrap(kEqual, trap_id);
FlagsContinuation::ForTrap(kEqual, trap_id, node->InputAt(1));
VisitWordCompareZero(node, node->InputAt(0), &cont); VisitWordCompareZero(node, node->InputAt(0), &cont);
} }
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <map> #include <map>
#include "src/codegen/cpu-features.h" #include "src/codegen/cpu-features.h"
#include "src/common/globals.h"
#include "src/compiler/backend/instruction-scheduler.h" #include "src/compiler/backend/instruction-scheduler.h"
#include "src/compiler/backend/instruction.h" #include "src/compiler/backend/instruction.h"
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
...@@ -78,9 +77,8 @@ class FlagsContinuation final { ...@@ -78,9 +77,8 @@ class FlagsContinuation final {
} }
// Creates a new flags continuation for a wasm trap. // Creates a new flags continuation for a wasm trap.
static FlagsContinuation ForTrap(FlagsCondition condition, TrapId trap_id, static FlagsContinuation ForTrap(FlagsCondition condition, TrapId trap_id) {
Node* result) { return FlagsContinuation(condition, trap_id);
return FlagsContinuation(condition, trap_id, result);
} }
static FlagsContinuation ForSelect(FlagsCondition condition, Node* result, static FlagsContinuation ForSelect(FlagsCondition condition, Node* result,
...@@ -218,13 +216,8 @@ class FlagsContinuation final { ...@@ -218,13 +216,8 @@ class FlagsContinuation final {
DCHECK_NOT_NULL(result); DCHECK_NOT_NULL(result);
} }
FlagsContinuation(FlagsCondition condition, TrapId trap_id, Node* result) FlagsContinuation(FlagsCondition condition, TrapId trap_id)
: mode_(kFlags_trap), : mode_(kFlags_trap), condition_(condition), trap_id_(trap_id) {}
condition_(condition),
frame_state_or_result_(result),
trap_id_(trap_id) {
DCHECK_NOT_NULL(result);
}
FlagsContinuation(FlagsCondition condition, Node* result, Node* true_value, FlagsContinuation(FlagsCondition condition, Node* result, Node* true_value,
Node* false_value) Node* false_value)
......
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
#include "src/compiler/turboshaft/graph.h" #include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/optimization-phase.h" #include "src/compiler/turboshaft/optimization-phase.h"
#include "src/compiler/turboshaft/recreate-schedule.h" #include "src/compiler/turboshaft/recreate-schedule.h"
#include "src/compiler/turboshaft/simplify-tf-loops.h"
#include "src/compiler/turboshaft/value-numbering-assembler.h" #include "src/compiler/turboshaft/value-numbering-assembler.h"
#include "src/compiler/type-narrowing-reducer.h" #include "src/compiler/type-narrowing-reducer.h"
#include "src/compiler/typed-optimization.h" #include "src/compiler/typed-optimization.h"
...@@ -2104,6 +2105,19 @@ struct WasmGCOptimizationPhase { ...@@ -2104,6 +2105,19 @@ struct WasmGCOptimizationPhase {
} }
}; };
struct SimplifyLoopsPhase {
DECL_PIPELINE_PHASE_CONSTANTS(SimplifyLoops)
void Run(PipelineData* data, Zone* temp_zone) {
GraphReducer graph_reducer(
temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(),
data->jsgraph()->Dead(), data->observe_node_manager());
SimplifyTFLoops simplify_loops(&graph_reducer, data->mcgraph());
AddReducer(data, &graph_reducer, &simplify_loops);
graph_reducer.ReduceGraph();
}
};
struct WasmGCLoweringPhase { struct WasmGCLoweringPhase {
DECL_PIPELINE_PHASE_CONSTANTS(WasmGCLowering) DECL_PIPELINE_PHASE_CONSTANTS(WasmGCLowering)
...@@ -3384,9 +3398,11 @@ void Pipeline::GenerateCodeForWasmFunction( ...@@ -3384,9 +3398,11 @@ void Pipeline::GenerateCodeForWasmFunction(
pipeline.Run<MachineOperatorOptimizationPhase>(); pipeline.Run<MachineOperatorOptimizationPhase>();
pipeline.RunPrintAndVerify(MachineOperatorOptimizationPhase::phase_name(), pipeline.RunPrintAndVerify(MachineOperatorOptimizationPhase::phase_name(),
true); true);
pipeline.Run<DecompressionOptimizationPhase>(); if (!v8_flags.turboshaft_wasm) {
pipeline.RunPrintAndVerify(DecompressionOptimizationPhase::phase_name(), pipeline.Run<DecompressionOptimizationPhase>();
true); pipeline.RunPrintAndVerify(DecompressionOptimizationPhase::phase_name(),
true);
}
} }
if (v8_flags.wasm_opt) { if (v8_flags.wasm_opt) {
...@@ -3395,6 +3411,11 @@ void Pipeline::GenerateCodeForWasmFunction( ...@@ -3395,6 +3411,11 @@ void Pipeline::GenerateCodeForWasmFunction(
true); true);
} }
if (v8_flags.turboshaft_wasm) {
pipeline.Run<SimplifyLoopsPhase>();
pipeline.RunPrintAndVerify(SimplifyLoopsPhase::phase_name(), true);
}
if (v8_flags.turbo_splitting && !is_asm_js) { if (v8_flags.turbo_splitting && !is_asm_js) {
data.info()->set_splitting(); data.info()->set_splitting();
} }
...@@ -3407,6 +3428,30 @@ void Pipeline::GenerateCodeForWasmFunction( ...@@ -3407,6 +3428,30 @@ void Pipeline::GenerateCodeForWasmFunction(
pipeline.ComputeScheduledGraph(); pipeline.ComputeScheduledGraph();
Linkage linkage(call_descriptor); Linkage linkage(call_descriptor);
if (v8_flags.turboshaft_wasm) {
if (base::Optional<BailoutReason> bailout =
pipeline.Run<BuildTurboshaftPhase>()) {
pipeline.info()->AbortOptimization(*bailout);
data.EndPhaseKind();
info->SetWasmCompilationResult({});
return;
}
pipeline.Run<PrintTurboshaftGraphPhase>(BuildTurboshaftPhase::phase_name());
pipeline.Run<OptimizeTurboshaftPhase>();
pipeline.Run<PrintTurboshaftGraphPhase>(
OptimizeTurboshaftPhase::phase_name());
pipeline.Run<DecompressionOptimizationPhase>();
pipeline.Run<PrintTurboshaftGraphPhase>(
DecompressionOptimizationPhase::phase_name());
pipeline.Run<TurboshaftRecreateSchedulePhase>(&linkage);
TraceSchedule(data.info(), &data, data.schedule(),
TurboshaftRecreateSchedulePhase::phase_name());
}
if (!pipeline.SelectInstructions(&linkage)) return; if (!pipeline.SelectInstructions(&linkage)) return;
pipeline.AssembleCode(&linkage); pipeline.AssembleCode(&linkage);
......
...@@ -11,16 +11,13 @@ ...@@ -11,16 +11,13 @@
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include "src/base/iterator.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/base/small-vector.h" #include "src/base/small-vector.h"
#include "src/base/template-utils.h" #include "src/base/template-utils.h"
#include "src/codegen/machine-type.h" #include "src/codegen/reloc-info.h"
#include "src/codegen/source-position.h"
#include "src/compiler/turboshaft/graph.h" #include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/operations.h" #include "src/compiler/turboshaft/operations.h"
#include "src/zone/zone-containers.h"
namespace v8::internal::compiler::turboshaft { namespace v8::internal::compiler::turboshaft {
...@@ -359,9 +356,29 @@ class AssemblerInterface : public Superclass { ...@@ -359,9 +356,29 @@ class AssemblerInterface : public Superclass {
WordRepresentation::Word32()) WordRepresentation::Word32())
DECL_SINGLE_REP_UNARY(Word64CountLeadingZeros, WordUnary, CountLeadingZeros, DECL_SINGLE_REP_UNARY(Word64CountLeadingZeros, WordUnary, CountLeadingZeros,
WordRepresentation::Word64()) WordRepresentation::Word64())
DECL_MULTI_REP_UNARY(WordCountTrailingZeros, WordUnary, WordRepresentation,
CountTrailingZeros)
DECL_SINGLE_REP_UNARY(Word32CountTrailingZeros, WordUnary, CountTrailingZeros,
WordRepresentation::Word32())
DECL_SINGLE_REP_UNARY(Word64CountTrailingZeros, WordUnary, CountTrailingZeros,
WordRepresentation::Word64())
DECL_MULTI_REP_UNARY(WordPopCount, WordUnary, WordRepresentation, PopCount)
DECL_SINGLE_REP_UNARY(Word32PopCount, WordUnary, PopCount,
WordRepresentation::Word32())
DECL_SINGLE_REP_UNARY(Word64PopCount, WordUnary, PopCount,
WordRepresentation::Word64())
#undef DECL_SINGLE_REP_UNARY #undef DECL_SINGLE_REP_UNARY
#undef DECL_MULTI_REP_UNARY #undef DECL_MULTI_REP_UNARY
OpIndex Word32Select(OpIndex condition, OpIndex left, OpIndex right) {
return subclass().Select(condition, left, right,
WordRepresentation::Word32());
}
OpIndex Word64Select(OpIndex condition, OpIndex left, OpIndex right) {
return subclass().Select(condition, left, right,
WordRepresentation::Word64());
}
OpIndex Word32Constant(uint32_t value) { OpIndex Word32Constant(uint32_t value) {
return subclass().Constant(ConstantOp::Kind::kWord32, uint64_t{value}); return subclass().Constant(ConstantOp::Kind::kWord32, uint64_t{value});
} }
...@@ -413,6 +430,13 @@ class AssemblerInterface : public Superclass { ...@@ -413,6 +430,13 @@ class AssemblerInterface : public Superclass {
OpIndex ExternalConstant(ExternalReference value) { OpIndex ExternalConstant(ExternalReference value) {
return subclass().Constant(ConstantOp::Kind::kExternal, value); return subclass().Constant(ConstantOp::Kind::kExternal, value);
} }
OpIndex RelocatableConstant(int64_t value, RelocInfo::Mode mode) {
DCHECK_EQ(mode, any_of(RelocInfo::WASM_CALL, RelocInfo::WASM_STUB_CALL));
return subclass().Constant(mode == RelocInfo::WASM_CALL
? ConstantOp::Kind::kRelocatableWasmCall
: ConstantOp::Kind::kRelocatableWasmStubCall,
static_cast<uint64_t>(value));
}
#define DECL_CHANGE(name, kind, from, to) \ #define DECL_CHANGE(name, kind, from, to) \
OpIndex name(OpIndex input) { \ OpIndex name(OpIndex input) { \
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_TURBOSHAFT_DEOPT_DATA_H_ #ifndef V8_COMPILER_TURBOSHAFT_DEOPT_DATA_H_
#define V8_COMPILER_TURBOSHAFT_DEOPT_DATA_H_ #define V8_COMPILER_TURBOSHAFT_DEOPT_DATA_H_
#include "src/base/small-vector.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/compiler/turboshaft/operations.h" #include "src/compiler/turboshaft/operations.h"
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "src/compiler/machine-operator.h" #include "src/compiler/machine-operator.h"
#include "src/compiler/node-aux-data.h" #include "src/compiler/node-aux-data.h"
#include "src/compiler/node-origin-table.h" #include "src/compiler/node-origin-table.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/opcodes.h" #include "src/compiler/opcodes.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
...@@ -202,6 +201,7 @@ base::Optional<BailoutReason> GraphBuilder::Run() { ...@@ -202,6 +201,7 @@ base::Optional<BailoutReason> GraphBuilder::Run() {
case BasicBlock::kReturn: case BasicBlock::kReturn:
case BasicBlock::kDeoptimize: case BasicBlock::kDeoptimize:
case BasicBlock::kThrow: case BasicBlock::kThrow:
case BasicBlock::kTailCall:
break; break;
case BasicBlock::kCall: { case BasicBlock::kCall: {
Node* call = block->control_input(); Node* call = block->control_input();
...@@ -216,8 +216,6 @@ base::Optional<BailoutReason> GraphBuilder::Run() { ...@@ -216,8 +216,6 @@ base::Optional<BailoutReason> GraphBuilder::Run() {
op_mapping.Set(if_exception_node, catch_exception); op_mapping.Set(if_exception_node, catch_exception);
break; break;
} }
case BasicBlock::kTailCall:
UNIMPLEMENTED();
case BasicBlock::kNone: case BasicBlock::kNone:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -323,7 +321,10 @@ OpIndex GraphBuilder::Process( ...@@ -323,7 +321,10 @@ OpIndex GraphBuilder::Process(
return assembler.CompressedHeapConstant(HeapConstantOf(op)); return assembler.CompressedHeapConstant(HeapConstantOf(op));
case IrOpcode::kExternalConstant: case IrOpcode::kExternalConstant:
return assembler.ExternalConstant(OpParameter<ExternalReference>(op)); return assembler.ExternalConstant(OpParameter<ExternalReference>(op));
case IrOpcode::kRelocatableInt64Constant:
return assembler.RelocatableConstant(
OpParameter<RelocatablePtrConstantInfo>(op).value(),
OpParameter<RelocatablePtrConstantInfo>(op).rmode());
#define BINOP_CASE(opcode, assembler_op) \ #define BINOP_CASE(opcode, assembler_op) \
case IrOpcode::k##opcode: \ case IrOpcode::k##opcode: \
return assembler.assembler_op(Map(node->InputAt(0)), Map(node->InputAt(1))); return assembler.assembler_op(Map(node->InputAt(0)), Map(node->InputAt(1)));
...@@ -431,6 +432,10 @@ OpIndex GraphBuilder::Process( ...@@ -431,6 +432,10 @@ OpIndex GraphBuilder::Process(
UNARY_CASE(Word64ReverseBytes, Word64ReverseBytes) UNARY_CASE(Word64ReverseBytes, Word64ReverseBytes)
UNARY_CASE(Word32Clz, Word32CountLeadingZeros) UNARY_CASE(Word32Clz, Word32CountLeadingZeros)
UNARY_CASE(Word64Clz, Word64CountLeadingZeros) UNARY_CASE(Word64Clz, Word64CountLeadingZeros)
UNARY_CASE(Word32Ctz, Word32CountTrailingZeros)
UNARY_CASE(Word64Ctz, Word64CountTrailingZeros)
UNARY_CASE(Word32Popcnt, Word32PopCount)
UNARY_CASE(Word64Popcnt, Word64PopCount)
UNARY_CASE(Float32Abs, Float32Abs) UNARY_CASE(Float32Abs, Float32Abs)
UNARY_CASE(Float64Abs, Float64Abs) UNARY_CASE(Float64Abs, Float64Abs)
...@@ -481,9 +486,17 @@ OpIndex GraphBuilder::Process( ...@@ -481,9 +486,17 @@ OpIndex GraphBuilder::Process(
CHANGE_CASE(BitcastInt64ToFloat64, Bitcast, Word64, Float64) CHANGE_CASE(BitcastInt64ToFloat64, Bitcast, Word64, Float64)
CHANGE_CASE(ChangeUint32ToUint64, ZeroExtend, Word32, Word64) CHANGE_CASE(ChangeUint32ToUint64, ZeroExtend, Word32, Word64)
CHANGE_CASE(ChangeInt32ToInt64, SignExtend, Word32, Word64) CHANGE_CASE(ChangeInt32ToInt64, SignExtend, Word32, Word64)
CHANGE_CASE(ChangeInt32ToFloat64, SignedToFloat, Word32, Float64) CHANGE_CASE(SignExtendWord32ToInt64, SignExtend, Word32, Word64)
CHANGE_CASE(ChangeInt64ToFloat64, SignedToFloat, Word64, Float64) CHANGE_CASE(ChangeInt32ToFloat64, SignedNarrowing, Word32, Float64)
CHANGE_CASE(ChangeInt64ToFloat64, SignedNarrowing, Word64, Float64)
CHANGE_CASE(ChangeUint32ToFloat64, UnsignedToFloat, Word32, Float64) CHANGE_CASE(ChangeUint32ToFloat64, UnsignedToFloat, Word32, Float64)
CHANGE_CASE(RoundInt64ToFloat64, SignedToFloat, Word64, Float64)
CHANGE_CASE(RoundUint64ToFloat64, UnsignedToFloat, Word64, Float64)
CHANGE_CASE(RoundInt32ToFloat32, SignedToFloat, Word32, Float32)
CHANGE_CASE(RoundUint32ToFloat32, UnsignedToFloat, Word32, Float32)
CHANGE_CASE(RoundInt64ToFloat32, SignedToFloat, Word64, Float32)
CHANGE_CASE(RoundUint64ToFloat32, UnsignedToFloat, Word64, Float32)
CHANGE_CASE(TruncateFloat64ToWord32, JSFloatTruncate, Float64, Word32) CHANGE_CASE(TruncateFloat64ToWord32, JSFloatTruncate, Float64, Word32)
CHANGE_CASE(TruncateFloat64ToFloat32, FloatConversion, Float64, Float32) CHANGE_CASE(TruncateFloat64ToFloat32, FloatConversion, Float64, Float32)
CHANGE_CASE(ChangeFloat32ToFloat64, FloatConversion, Float32, Float64) CHANGE_CASE(ChangeFloat32ToFloat64, FloatConversion, Float32, Float64)
...@@ -498,21 +511,36 @@ OpIndex GraphBuilder::Process( ...@@ -498,21 +511,36 @@ OpIndex GraphBuilder::Process(
case IrOpcode::kTruncateInt64ToInt32: case IrOpcode::kTruncateInt64ToInt32:
// 64- to 32-bit truncation is implicit in Turboshaft. // 64- to 32-bit truncation is implicit in Turboshaft.
return Map(node->InputAt(0)); return Map(node->InputAt(0));
case IrOpcode::kTruncateFloat32ToInt32: {
ChangeOp::Kind kind =
OpParameter<TruncateKind>(node->op()) ==
TruncateKind::kArchitectureDefault
? ChangeOp::Kind::kSignedFloatTruncate
: ChangeOp::Kind::kSignedFloatTruncateOverflowToMin;
return assembler.Change(Map(node->InputAt(0)), kind,
RegisterRepresentation::Float32(),
RegisterRepresentation::Word32());
}
case IrOpcode::kTruncateFloat32ToUint32: {
ChangeOp::Kind kind =
OpParameter<TruncateKind>(node->op()) ==
TruncateKind::kArchitectureDefault
? ChangeOp::Kind::kUnsignedFloatTruncate
: ChangeOp::Kind::kUnsignedFloatTruncateOverflowToMin;
return assembler.Change(Map(node->InputAt(0)), kind,
RegisterRepresentation::Float32(),
RegisterRepresentation::Word32());
}
case IrOpcode::kTruncateFloat64ToInt64: { case IrOpcode::kTruncateFloat64ToInt64: {
ChangeOp::Kind kind; ChangeOp::Kind kind =
switch (OpParameter<TruncateKind>(op)) { OpParameter<TruncateKind>(node->op()) ==
case TruncateKind::kArchitectureDefault: TruncateKind::kArchitectureDefault
kind = ChangeOp::Kind::kSignedFloatTruncate; ? ChangeOp::Kind::kSignedFloatTruncate
break; : ChangeOp::Kind::kSignedFloatTruncateOverflowToMin;
case TruncateKind::kSetOverflowToMin:
kind = ChangeOp::Kind::kSignedFloatTruncateOverflowToMin;
break;
}
return assembler.Change(Map(node->InputAt(0)), kind, return assembler.Change(Map(node->InputAt(0)), kind,
RegisterRepresentation::Float64(), RegisterRepresentation::Float64(),
RegisterRepresentation::Word64()); RegisterRepresentation::Word64());
} }
case IrOpcode::kFloat64InsertLowWord32: case IrOpcode::kFloat64InsertLowWord32:
return assembler.Float64InsertWord32( return assembler.Float64InsertWord32(
Map(node->InputAt(0)), Map(node->InputAt(1)), Map(node->InputAt(0)), Map(node->InputAt(1)),
...@@ -531,16 +559,27 @@ OpIndex GraphBuilder::Process( ...@@ -531,16 +559,27 @@ OpIndex GraphBuilder::Process(
RegisterRepresentation::PointerSized(), RegisterRepresentation::PointerSized(),
RegisterRepresentation::Tagged()); RegisterRepresentation::Tagged());
case IrOpcode::kWord32Select:
return assembler.Word32Select(
Map(node->InputAt(0)), Map(node->InputAt(1)), Map(node->InputAt(2)));
case IrOpcode::kWord64Select:
return assembler.Word64Select(
Map(node->InputAt(0)), Map(node->InputAt(1)), Map(node->InputAt(2)));
case IrOpcode::kLoad: case IrOpcode::kLoad:
case IrOpcode::kLoadImmutable:
case IrOpcode::kProtectedLoad:
case IrOpcode::kUnalignedLoad: { case IrOpcode::kUnalignedLoad: {
MemoryRepresentation loaded_rep = MemoryRepresentation loaded_rep =
MemoryRepresentation::FromMachineType(LoadRepresentationOf(op)); MemoryRepresentation::FromMachineType(LoadRepresentationOf(op));
RegisterRepresentation result_rep = loaded_rep.ToRegisterRepresentation(); RegisterRepresentation result_rep = loaded_rep.ToRegisterRepresentation();
Node* base = node->InputAt(0); Node* base = node->InputAt(0);
Node* index = node->InputAt(1); Node* index = node->InputAt(1);
LoadOp::Kind kind = opcode == IrOpcode::kLoad // It's ok to merge LoadImmutable into Load after scheduling.
? LoadOp::Kind::kRawAligned LoadOp::Kind kind =
: LoadOp::Kind::kRawUnaligned; opcode == IrOpcode::kUnalignedLoad ? LoadOp::Kind::kRawUnaligned
: opcode == IrOpcode::kProtectedLoad ? LoadOp::Kind::kProtected
: LoadOp::Kind::kRawAligned;
if (index->opcode() == IrOpcode::kInt32Constant) { if (index->opcode() == IrOpcode::kInt32Constant) {
int32_t offset = OpParameter<int32_t>(index->op()); int32_t offset = OpParameter<int32_t>(index->op());
return assembler.Load(Map(base), kind, loaded_rep, result_rep, offset); return assembler.Load(Map(base), kind, loaded_rep, result_rep, offset);
...@@ -559,14 +598,17 @@ OpIndex GraphBuilder::Process( ...@@ -559,14 +598,17 @@ OpIndex GraphBuilder::Process(
} }
case IrOpcode::kStore: case IrOpcode::kStore:
case IrOpcode::kUnalignedStore: { case IrOpcode::kUnalignedStore:
bool aligned = opcode == IrOpcode::kStore; case IrOpcode::kProtectedStore: {
bool aligned = opcode != IrOpcode::kUnalignedStore;
StoreRepresentation store_rep = StoreRepresentation store_rep =
aligned ? StoreRepresentationOf(op) aligned ? StoreRepresentationOf(op)
: StoreRepresentation(UnalignedStoreRepresentationOf(op), : StoreRepresentation(UnalignedStoreRepresentationOf(op),
WriteBarrierKind::kNoWriteBarrier); WriteBarrierKind::kNoWriteBarrier);
StoreOp::Kind kind = StoreOp::Kind kind =
aligned ? StoreOp::Kind::kRawAligned : StoreOp::Kind::kRawUnaligned; opcode == IrOpcode::kStore ? StoreOp::Kind::kRawAligned
: opcode == IrOpcode::kUnalignedStore ? StoreOp::Kind::kRawAligned
: StoreOp::Kind::kProtected;
Node* base = node->InputAt(0); Node* base = node->InputAt(0);
Node* index = node->InputAt(1); Node* index = node->InputAt(1);
Node* value = node->InputAt(2); Node* value = node->InputAt(2);
...@@ -654,6 +696,21 @@ OpIndex GraphBuilder::Process( ...@@ -654,6 +696,21 @@ OpIndex GraphBuilder::Process(
return call; return call;
} }
case IrOpcode::kTailCall: {
auto call_descriptor = CallDescriptorOf(op);
base::SmallVector<OpIndex, 16> arguments;
// The input `0` is the callee, the following value inputs are the
// arguments. `CallDescriptor::InputCount()` counts the callee and
// arguments.
OpIndex callee = Map(node->InputAt(0));
for (int i = 1; i < static_cast<int>(call_descriptor->InputCount());
++i) {
arguments.emplace_back(Map(node->InputAt(i)));
}
return assembler.TailCall(callee, base::VectorOf(arguments),
call_descriptor);
}
case IrOpcode::kFrameState: { case IrOpcode::kFrameState: {
FrameState frame_state{node}; FrameState frame_state{node};
FrameStateData::Builder builder; FrameStateData::Builder builder;
...@@ -673,6 +730,13 @@ OpIndex GraphBuilder::Process( ...@@ -673,6 +730,13 @@ OpIndex GraphBuilder::Process(
&DeoptimizeParametersOf(op)); &DeoptimizeParametersOf(op));
} }
case IrOpcode::kTrapIf:
case IrOpcode::kTrapUnless: {
OpIndex condition = Map(node->InputAt(0));
bool negated = op->opcode() == IrOpcode::kTrapUnless;
return assembler.TrapIf(condition, negated, TrapIdOf(op));
}
case IrOpcode::kDeoptimize: { case IrOpcode::kDeoptimize: {
OpIndex frame_state = Map(node->InputAt(0)); OpIndex frame_state = Map(node->InputAt(0));
return assembler.Deoptimize(frame_state, &DeoptimizeParametersOf(op)); return assembler.Deoptimize(frame_state, &DeoptimizeParametersOf(op));
......
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
#include <sstream> #include <sstream>
#include "src/base/platform/mutex.h" #include "src/base/platform/mutex.h"
#include "src/base/platform/platform.h"
#include "src/codegen/machine-type.h" #include "src/codegen/machine-type.h"
#include "src/common/assert-scope.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/compiler/backend/instruction-selector.h" #include "src/compiler/backend/instruction-selector.h"
#include "src/compiler/frame-states.h" #include "src/compiler/frame-states.h"
...@@ -49,6 +47,10 @@ std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind) { ...@@ -49,6 +47,10 @@ std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind) {
return os << "ReverseBytes"; return os << "ReverseBytes";
case WordUnaryOp::Kind::kCountLeadingZeros: case WordUnaryOp::Kind::kCountLeadingZeros:
return os << "CountLeadingZeros"; return os << "CountLeadingZeros";
case WordUnaryOp::Kind::kCountTrailingZeros:
return os << "CountTrailingZeros";
case WordUnaryOp::Kind::kPopCount:
return os << "PopCount";
} }
} }
...@@ -143,6 +145,23 @@ bool FloatUnaryOp::IsSupported(Kind kind, FloatRepresentation rep) { ...@@ -143,6 +145,23 @@ bool FloatUnaryOp::IsSupported(Kind kind, FloatRepresentation rep) {
} }
} }
// static
bool WordUnaryOp::IsSupported(Kind kind, WordRepresentation rep) {
switch (kind) {
case Kind::kCountLeadingZeros:
case Kind::kReverseBytes:
return true;
case Kind::kCountTrailingZeros:
return rep == WordRepresentation::Word32()
? SupportedOperations::word32_ctz()
: SupportedOperations::word64_ctz();
case Kind::kPopCount:
return rep == WordRepresentation::Word32()
? SupportedOperations::word32_popcnt()
: SupportedOperations::word64_popcnt();
}
}
std::ostream& operator<<(std::ostream& os, ShiftOp::Kind kind) { std::ostream& operator<<(std::ostream& os, ShiftOp::Kind kind) {
switch (kind) { switch (kind) {
case ShiftOp::Kind::kShiftRightArithmeticShiftOutZeros: case ShiftOp::Kind::kShiftRightArithmeticShiftOutZeros:
...@@ -181,12 +200,16 @@ std::ostream& operator<<(std::ostream& os, ChangeOp::Kind kind) { ...@@ -181,12 +200,16 @@ std::ostream& operator<<(std::ostream& os, ChangeOp::Kind kind) {
return os << "UnsignedNarrowing"; return os << "UnsignedNarrowing";
case ChangeOp::Kind::kFloatConversion: case ChangeOp::Kind::kFloatConversion:
return os << "FloatConversion"; return os << "FloatConversion";
case ChangeOp::Kind::kSignedFloatTruncate:
return os << "SignedFloatTruncate";
case ChangeOp::Kind::kJSFloatTruncate: case ChangeOp::Kind::kJSFloatTruncate:
return os << "JSFloatTruncate"; return os << "JSFloatTruncate";
case ChangeOp::Kind::kSignedFloatTruncate:
return os << "SignedFloatTruncate";
case ChangeOp::Kind::kSignedFloatTruncateOverflowToMin: case ChangeOp::Kind::kSignedFloatTruncateOverflowToMin:
return os << "SignedFloatTruncateOverflowToMin"; return os << "SignedFloatTruncateOverflowToMin";
case ChangeOp::Kind::kUnsignedFloatTruncate:
return os << "UnsignedFloatTruncate";
case ChangeOp::Kind::kUnsignedFloatTruncateOverflowToMin:
return os << "UnsignedFloatTruncateOverflowToMin";
case ChangeOp::Kind::kSignedToFloat: case ChangeOp::Kind::kSignedToFloat:
return os << "SignedToFloat"; return os << "SignedToFloat";
case ChangeOp::Kind::kUnsignedToFloat: case ChangeOp::Kind::kUnsignedToFloat:
...@@ -269,6 +292,14 @@ void ConstantOp::PrintOptions(std::ostream& os) const { ...@@ -269,6 +292,14 @@ void ConstantOp::PrintOptions(std::ostream& os) const {
case Kind::kCompressedHeapObject: case Kind::kCompressedHeapObject:
os << "compressed heap object: " << handle(); os << "compressed heap object: " << handle();
break; break;
case Kind::kRelocatableWasmCall:
os << "relocatable wasm call: 0x"
<< reinterpret_cast<void*>(storage.integral);
break;
case Kind::kRelocatableWasmStubCall:
os << "relocatable wasm stub call: 0x"
<< reinterpret_cast<void*>(storage.integral);
break;
} }
os << "]"; os << "]";
} }
...@@ -485,8 +516,8 @@ std::ostream& operator<<(std::ostream& os, OpProperties opProperties) { ...@@ -485,8 +516,8 @@ std::ostream& operator<<(std::ostream& os, OpProperties opProperties) {
os << "Reading"; os << "Reading";
} else if (opProperties == OpProperties::Writing()) { } else if (opProperties == OpProperties::Writing()) {
os << "Writing"; os << "Writing";
} else if (opProperties == OpProperties::CanDeopt()) { } else if (opProperties == OpProperties::CanAbort()) {
os << "CanDeopt"; os << "CanAbort";
} else if (opProperties == OpProperties::AnySideEffects()) { } else if (opProperties == OpProperties::AnySideEffects()) {
os << "AnySideEffects"; os << "AnySideEffects";
} else if (opProperties == OpProperties::BlockTerminator()) { } else if (opProperties == OpProperties::BlockTerminator()) {
......
...@@ -13,22 +13,18 @@ ...@@ -13,22 +13,18 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "src/base/functional.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/base/platform/mutex.h" #include "src/base/platform/mutex.h"
#include "src/base/small-vector.h"
#include "src/base/template-utils.h" #include "src/base/template-utils.h"
#include "src/base/vector.h" #include "src/base/vector.h"
#include "src/codegen/external-reference.h" #include "src/codegen/external-reference.h"
#include "src/codegen/machine-type.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/compiler/globals.h" #include "src/compiler/globals.h"
#include "src/compiler/turboshaft/fast-hash.h" #include "src/compiler/turboshaft/fast-hash.h"
#include "src/compiler/turboshaft/representations.h" #include "src/compiler/turboshaft/representations.h"
#include "src/compiler/turboshaft/utils.h" #include "src/compiler/turboshaft/utils.h"
#include "src/compiler/write-barrier-kind.h" #include "src/compiler/write-barrier-kind.h"
#include "src/zone/zone.h"
namespace v8::internal { namespace v8::internal {
class HeapObject; class HeapObject;
...@@ -38,6 +34,7 @@ class CallDescriptor; ...@@ -38,6 +34,7 @@ class CallDescriptor;
class DeoptimizeParameters; class DeoptimizeParameters;
class FrameStateInfo; class FrameStateInfo;
class Node; class Node;
enum class TrapId : uint32_t;
} // namespace v8::internal::compiler } // namespace v8::internal::compiler
namespace v8::internal::compiler::turboshaft { namespace v8::internal::compiler::turboshaft {
class Block; class Block;
...@@ -75,6 +72,7 @@ class Graph; ...@@ -75,6 +72,7 @@ class Graph;
V(Change) \ V(Change) \
V(Float64InsertWord32) \ V(Float64InsertWord32) \
V(TaggedBitcast) \ V(TaggedBitcast) \
V(Select) \
V(PendingLoopPhi) \ V(PendingLoopPhi) \
V(Constant) \ V(Constant) \
V(Load) \ V(Load) \
...@@ -91,9 +89,11 @@ class Graph; ...@@ -91,9 +89,11 @@ class Graph;
V(CheckLazyDeopt) \ V(CheckLazyDeopt) \
V(Deoptimize) \ V(Deoptimize) \
V(DeoptimizeIf) \ V(DeoptimizeIf) \
V(TrapIf) \
V(Phi) \ V(Phi) \
V(FrameState) \ V(FrameState) \
V(Call) \ V(Call) \
V(TailCall) \
V(Unreachable) \ V(Unreachable) \
V(Return) \ V(Return) \
V(Branch) \ V(Branch) \
...@@ -252,7 +252,7 @@ struct OpProperties { ...@@ -252,7 +252,7 @@ struct OpProperties {
static constexpr OpProperties Writing() { static constexpr OpProperties Writing() {
return {false, true, false, false}; return {false, true, false, false};
} }
static constexpr OpProperties CanDeopt() { static constexpr OpProperties CanAbort() {
return {false, false, true, false}; return {false, false, true, false};
} }
static constexpr OpProperties AnySideEffects() { static constexpr OpProperties AnySideEffects() {
...@@ -261,6 +261,9 @@ struct OpProperties { ...@@ -261,6 +261,9 @@ struct OpProperties {
static constexpr OpProperties BlockTerminator() { static constexpr OpProperties BlockTerminator() {
return {false, false, false, true}; return {false, false, false, true};
} }
static constexpr OpProperties BlockTerminatorWithAnySideEffect() {
return {true, true, true, true};
}
bool operator==(const OpProperties& other) const { bool operator==(const OpProperties& other) const {
return can_read == other.can_read && can_write == other.can_write && return can_read == other.can_read && can_write == other.can_write &&
can_abort == other.can_abort && can_abort == other.can_abort &&
...@@ -721,6 +724,8 @@ struct WordUnaryOp : FixedArityOperationT<1, WordUnaryOp> { ...@@ -721,6 +724,8 @@ struct WordUnaryOp : FixedArityOperationT<1, WordUnaryOp> {
enum class Kind : uint8_t { enum class Kind : uint8_t {
kReverseBytes, kReverseBytes,
kCountLeadingZeros, kCountLeadingZeros,
kCountTrailingZeros,
kPopCount,
}; };
Kind kind; Kind kind;
WordRepresentation rep; WordRepresentation rep;
...@@ -728,8 +733,12 @@ struct WordUnaryOp : FixedArityOperationT<1, WordUnaryOp> { ...@@ -728,8 +733,12 @@ struct WordUnaryOp : FixedArityOperationT<1, WordUnaryOp> {
OpIndex input() const { return Base::input(0); } OpIndex input() const { return Base::input(0); }
static bool IsSupported(Kind kind, WordRepresentation rep);
explicit WordUnaryOp(OpIndex input, Kind kind, WordRepresentation rep) explicit WordUnaryOp(OpIndex input, Kind kind, WordRepresentation rep)
: Base(input), kind(kind), rep(rep) {} : Base(input), kind(kind), rep(rep) {
DCHECK(IsSupported(kind, rep));
}
auto options() const { return std::tuple{kind, rep}; } auto options() const { return std::tuple{kind, rep}; }
}; };
std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind); std::ostream& operator<<(std::ostream& os, WordUnaryOp::Kind kind);
...@@ -889,6 +898,12 @@ struct ChangeOp : FixedArityOperationT<1, ChangeOp> { ...@@ -889,6 +898,12 @@ struct ChangeOp : FixedArityOperationT<1, ChangeOp> {
// like kSignedFloatTruncate, but overflow guaranteed to result in the // like kSignedFloatTruncate, but overflow guaranteed to result in the
// minimal integer // minimal integer
kSignedFloatTruncateOverflowToMin, kSignedFloatTruncateOverflowToMin,
// conversion to unsigned integer, rounding towards zero,
// overflow behavior system-specific
kUnsignedFloatTruncate,
// like kUnsignedFloatTruncate, but overflow guaranteed to result in the
// minimal integer
kUnsignedFloatTruncateOverflowToMin,
// JS semantics float64 to word32 truncation // JS semantics float64 to word32 truncation
// https://tc39.es/ecma262/#sec-touint32 // https://tc39.es/ecma262/#sec-touint32
kJSFloatTruncate, kJSFloatTruncate,
...@@ -951,6 +966,25 @@ struct TaggedBitcastOp : FixedArityOperationT<1, TaggedBitcastOp> { ...@@ -951,6 +966,25 @@ struct TaggedBitcastOp : FixedArityOperationT<1, TaggedBitcastOp> {
auto options() const { return std::tuple{from, to}; } auto options() const { return std::tuple{from, to}; }
}; };
struct SelectOp : FixedArityOperationT<3, SelectOp> {
// TODO(12783): Support all register reps.
WordRepresentation rep;
static constexpr OpProperties properties = OpProperties::Pure();
OpIndex condition() const { return Base::input(0); }
OpIndex left() const { return Base::input(1); }
OpIndex right() const { return Base::input(2); }
SelectOp(OpIndex condition, OpIndex left, OpIndex right,
WordRepresentation rep)
: Base(condition, left, right), rep(rep) {
DCHECK(rep == WordRepresentation::Word32()
? SupportedOperations::word32_select()
: SupportedOperations::word64_select());
}
auto options() const { return std::tuple{rep}; }
};
struct PhiOp : OperationT<PhiOp> { struct PhiOp : OperationT<PhiOp> {
RegisterRepresentation rep; RegisterRepresentation rep;
...@@ -1001,7 +1035,9 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1001,7 +1035,9 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
kTaggedIndex, kTaggedIndex,
kExternal, kExternal,
kHeapObject, kHeapObject,
kCompressedHeapObject kCompressedHeapObject,
kRelocatableWasmCall,
kRelocatableWasmStubCall
}; };
Kind kind; Kind kind;
...@@ -1033,6 +1069,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1033,6 +1069,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
return RegisterRepresentation::Float64(); return RegisterRepresentation::Float64();
case Kind::kExternal: case Kind::kExternal:
case Kind::kTaggedIndex: case Kind::kTaggedIndex:
case Kind::kRelocatableWasmCall:
case Kind::kRelocatableWasmStubCall:
return RegisterRepresentation::PointerSized(); return RegisterRepresentation::PointerSized();
case Kind::kHeapObject: case Kind::kHeapObject:
case Kind::kNumber: case Kind::kNumber:
...@@ -1050,7 +1088,9 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1050,7 +1088,9 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
} }
uint64_t integral() const { uint64_t integral() const {
DCHECK(kind == Kind::kWord32 || kind == Kind::kWord64); DCHECK(kind == Kind::kWord32 || kind == Kind::kWord64 ||
kind == Kind::kRelocatableWasmCall ||
kind == Kind::kRelocatableWasmStubCall);
return storage.integral; return storage.integral;
} }
...@@ -1119,6 +1159,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1119,6 +1159,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kExternal: case Kind::kExternal:
case Kind::kHeapObject: case Kind::kHeapObject:
case Kind::kCompressedHeapObject: case Kind::kCompressedHeapObject:
case Kind::kRelocatableWasmCall:
case Kind::kRelocatableWasmStubCall:
UNREACHABLE(); UNREACHABLE();
} }
} }
...@@ -1137,6 +1179,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1137,6 +1179,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kExternal: case Kind::kExternal:
case Kind::kHeapObject: case Kind::kHeapObject:
case Kind::kCompressedHeapObject: case Kind::kCompressedHeapObject:
case Kind::kRelocatableWasmCall:
case Kind::kRelocatableWasmStubCall:
UNREACHABLE(); UNREACHABLE();
} }
} }
...@@ -1160,6 +1204,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1160,6 +1204,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kWord32: case Kind::kWord32:
case Kind::kWord64: case Kind::kWord64:
case Kind::kTaggedIndex: case Kind::kTaggedIndex:
case Kind::kRelocatableWasmCall:
case Kind::kRelocatableWasmStubCall:
return fast_hash_combine(opcode, kind, storage.integral); return fast_hash_combine(opcode, kind, storage.integral);
case Kind::kFloat32: case Kind::kFloat32:
return fast_hash_combine(opcode, kind, storage.float32); return fast_hash_combine(opcode, kind, storage.float32);
...@@ -1179,6 +1225,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1179,6 +1225,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kWord32: case Kind::kWord32:
case Kind::kWord64: case Kind::kWord64:
case Kind::kTaggedIndex: case Kind::kTaggedIndex:
case Kind::kRelocatableWasmCall:
case Kind::kRelocatableWasmStubCall:
return storage.integral == other.storage.integral; return storage.integral == other.storage.integral;
case Kind::kFloat32: case Kind::kFloat32:
// Using a bit_cast to uint32_t in order to return false when comparing // Using a bit_cast to uint32_t in order to return false when comparing
...@@ -1211,7 +1259,12 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { ...@@ -1211,7 +1259,12 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
// When result_rep is RegisterRepresentation::Compressed(), then the load does // When result_rep is RegisterRepresentation::Compressed(), then the load does
// not decompress the value. // not decompress the value.
struct LoadOp : FixedArityOperationT<1, LoadOp> { struct LoadOp : FixedArityOperationT<1, LoadOp> {
enum class Kind : uint8_t { kTaggedBase, kRawAligned, kRawUnaligned }; enum class Kind : uint8_t {
kTaggedBase,
kRawAligned,
kRawUnaligned,
kProtected
};
Kind kind; Kind kind;
MemoryRepresentation loaded_rep; MemoryRepresentation loaded_rep;
RegisterRepresentation result_rep; RegisterRepresentation result_rep;
...@@ -1244,6 +1297,7 @@ inline bool IsAlignedAccess(LoadOp::Kind kind) { ...@@ -1244,6 +1297,7 @@ inline bool IsAlignedAccess(LoadOp::Kind kind) {
case LoadOp::Kind::kRawAligned: case LoadOp::Kind::kRawAligned:
return true; return true;
case LoadOp::Kind::kRawUnaligned: case LoadOp::Kind::kRawUnaligned:
case LoadOp::Kind::kProtected:
return false; return false;
} }
} }
...@@ -1430,7 +1484,7 @@ struct FrameStateOp : OperationT<FrameStateOp> { ...@@ -1430,7 +1484,7 @@ struct FrameStateOp : OperationT<FrameStateOp> {
// Semantically, it deopts if the current code object has been // Semantically, it deopts if the current code object has been
// deoptimized. But this might also be implemented differently. // deoptimized. But this might also be implemented differently.
struct CheckLazyDeoptOp : FixedArityOperationT<2, CheckLazyDeoptOp> { struct CheckLazyDeoptOp : FixedArityOperationT<2, CheckLazyDeoptOp> {
static constexpr OpProperties properties = OpProperties::CanDeopt(); static constexpr OpProperties properties = OpProperties::CanAbort();
OpIndex call() const { return input(0); } OpIndex call() const { return input(0); }
OpIndex frame_state() const { return input(1); } OpIndex frame_state() const { return input(1); }
...@@ -1456,7 +1510,7 @@ struct DeoptimizeIfOp : FixedArityOperationT<2, DeoptimizeIfOp> { ...@@ -1456,7 +1510,7 @@ struct DeoptimizeIfOp : FixedArityOperationT<2, DeoptimizeIfOp> {
bool negated; bool negated;
const DeoptimizeParameters* parameters; const DeoptimizeParameters* parameters;
static constexpr OpProperties properties = OpProperties::CanDeopt(); static constexpr OpProperties properties = OpProperties::CanAbort();
OpIndex condition() const { return input(0); } OpIndex condition() const { return input(0); }
OpIndex frame_state() const { return input(1); } OpIndex frame_state() const { return input(1); }
...@@ -1469,6 +1523,19 @@ struct DeoptimizeIfOp : FixedArityOperationT<2, DeoptimizeIfOp> { ...@@ -1469,6 +1523,19 @@ struct DeoptimizeIfOp : FixedArityOperationT<2, DeoptimizeIfOp> {
auto options() const { return std::tuple{negated, parameters}; } auto options() const { return std::tuple{negated, parameters}; }
}; };
struct TrapIfOp : FixedArityOperationT<1, TrapIfOp> {
bool negated;
const TrapId trap_id;
static constexpr OpProperties properties = OpProperties::CanAbort();
OpIndex condition() const { return input(0); }
TrapIfOp(OpIndex condition, bool negated, const TrapId trap_id)
: Base(condition), negated(negated), trap_id(trap_id) {}
auto options() const { return std::tuple{negated, trap_id}; }
};
struct ParameterOp : FixedArityOperationT<0, ParameterOp> { struct ParameterOp : FixedArityOperationT<0, ParameterOp> {
int32_t parameter_index; int32_t parameter_index;
const char* debug_name; const char* debug_name;
...@@ -1516,6 +1583,33 @@ struct CallOp : OperationT<CallOp> { ...@@ -1516,6 +1583,33 @@ struct CallOp : OperationT<CallOp> {
auto options() const { return std::tuple{descriptor}; } auto options() const { return std::tuple{descriptor}; }
}; };
struct TailCallOp : OperationT<TailCallOp> {
const CallDescriptor* descriptor;
static constexpr OpProperties properties =
OpProperties::BlockTerminatorWithAnySideEffect();
OpIndex callee() const { return input(0); }
base::Vector<const OpIndex> arguments() const {
return inputs().SubVector(1, input_count);
}
TailCallOp(OpIndex callee, base::Vector<const OpIndex> arguments,
const CallDescriptor* descriptor)
: Base(1 + arguments.size()), descriptor(descriptor) {
base::Vector<OpIndex> inputs = this->inputs();
inputs[0] = callee;
inputs.SubVector(1, inputs.size()).OverwriteWith(arguments);
}
static TailCallOp& New(Graph* graph, OpIndex callee,
base::Vector<const OpIndex> arguments,
const CallDescriptor* descriptor) {
return Base::New(graph, 1 + arguments.size(), callee, arguments,
descriptor);
}
auto options() const { return std::tuple{descriptor}; }
};
// Control-flow should never reach here. // Control-flow should never reach here.
struct UnreachableOp : FixedArityOperationT<0, UnreachableOp> { struct UnreachableOp : FixedArityOperationT<0, UnreachableOp> {
static constexpr OpProperties properties = OpProperties::BlockTerminator(); static constexpr OpProperties properties = OpProperties::BlockTerminator();
......
...@@ -402,6 +402,11 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl { ...@@ -402,6 +402,11 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
auto arguments = MapToNewGraph<16>(op.arguments()); auto arguments = MapToNewGraph<16>(op.arguments());
return assembler.Call(callee, base::VectorOf(arguments), op.descriptor); return assembler.Call(callee, base::VectorOf(arguments), op.descriptor);
} }
OpIndex ReduceTailCall(const TailCallOp& op) {
OpIndex callee = MapToNewGraph(op.callee());
auto arguments = MapToNewGraph<16>(op.arguments());
return assembler.TailCall(callee, base::VectorOf(arguments), op.descriptor);
}
OpIndex ReduceReturn(const ReturnOp& op) { OpIndex ReduceReturn(const ReturnOp& op) {
// We very rarely have tuples longer than 4. // We very rarely have tuples longer than 4.
auto return_values = MapToNewGraph<4>(op.return_values()); auto return_values = MapToNewGraph<4>(op.return_values());
...@@ -440,6 +445,11 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl { ...@@ -440,6 +445,11 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
OpIndex ReduceTaggedBitcast(const TaggedBitcastOp& op) { OpIndex ReduceTaggedBitcast(const TaggedBitcastOp& op) {
return assembler.TaggedBitcast(MapToNewGraph(op.input()), op.from, op.to); return assembler.TaggedBitcast(MapToNewGraph(op.input()), op.from, op.to);
} }
OpIndex ReduceSelect(const SelectOp& op) {
return assembler.Select(MapToNewGraph(op.condition()),
MapToNewGraph(op.left()), MapToNewGraph(op.right()),
op.rep);
}
OpIndex ReduceConstant(const ConstantOp& op) { OpIndex ReduceConstant(const ConstantOp& op) {
return assembler.Constant(op.kind, op.storage); return assembler.Constant(op.kind, op.storage);
} }
...@@ -493,6 +503,10 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl { ...@@ -493,6 +503,10 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
MapToNewGraph(op.frame_state()), op.negated, MapToNewGraph(op.frame_state()), op.negated,
op.parameters); op.parameters);
} }
OpIndex ReduceTrapIf(const TrapIfOp& op) {
return assembler.TrapIf(MapToNewGraph(op.condition()), op.negated,
op.trap_id);
}
OpIndex ReduceTuple(const TupleOp& op) { OpIndex ReduceTuple(const TupleOp& op) {
return assembler.Tuple(base::VectorOf(MapToNewGraph<4>(op.inputs()))); return assembler.Tuple(base::VectorOf(MapToNewGraph<4>(op.inputs())));
} }
......
...@@ -88,6 +88,13 @@ struct ScheduleBuilder { ...@@ -88,6 +88,13 @@ struct ScheduleBuilder {
return AddNode(machine.Is64() ? machine.Word64Shl() : machine.Word32Shl(), return AddNode(machine.Is64() ? machine.Word64Shl() : machine.Word32Shl(),
{a, b}); {a, b});
} }
Node* RelocatableIntPtrConstant(intptr_t value, RelocInfo::Mode mode) {
return AddNode(machine.Is64()
? common.RelocatableInt64Constant(value, mode)
: common.RelocatableInt32Constant(
base::checked_cast<int32_t>(value), mode),
{});
}
void ProcessOperation(const Operation& op); void ProcessOperation(const Operation& op);
#define DECL_PROCESS_OPERATION(Name) Node* ProcessOperation(const Name##Op& op); #define DECL_PROCESS_OPERATION(Name) Node* ProcessOperation(const Name##Op& op);
TURBOSHAFT_OPERATION_LIST(DECL_PROCESS_OPERATION) TURBOSHAFT_OPERATION_LIST(DECL_PROCESS_OPERATION)
...@@ -363,6 +370,12 @@ Node* ScheduleBuilder::ProcessOperation(const WordUnaryOp& op) { ...@@ -363,6 +370,12 @@ Node* ScheduleBuilder::ProcessOperation(const WordUnaryOp& op) {
case WordUnaryOp::Kind::kCountLeadingZeros: case WordUnaryOp::Kind::kCountLeadingZeros:
o = word64 ? machine.Word64Clz() : machine.Word32Clz(); o = word64 ? machine.Word64Clz() : machine.Word32Clz();
break; break;
case WordUnaryOp::Kind::kCountTrailingZeros:
o = word64 ? machine.Word64Ctz().op() : machine.Word32Ctz().op();
break;
case WordUnaryOp::Kind::kPopCount:
o = word64 ? machine.Word64Popcnt().op() : machine.Word32Popcnt().op();
break;
} }
return AddNode(o, {GetNode(op.input())}); return AddNode(o, {GetNode(op.input())});
} }
...@@ -628,6 +641,22 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { ...@@ -628,6 +641,22 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
break; break;
case Kind::kUnsignedFloatTruncate:
if (op.from == FloatRepresentation::Float32() &&
op.to == WordRepresentation::Word32()) {
o = machine.TruncateFloat32ToUint32(TruncateKind::kArchitectureDefault);
} else {
UNIMPLEMENTED();
}
break;
case Kind::kUnsignedFloatTruncateOverflowToMin:
if (op.from == FloatRepresentation::Float32() &&
op.to == WordRepresentation::Word32()) {
o = machine.TruncateFloat32ToUint32(TruncateKind::kSetOverflowToMin);
} else {
UNIMPLEMENTED();
}
break;
case Kind::kJSFloatTruncate: case Kind::kJSFloatTruncate:
if (op.from == FloatRepresentation::Float64() && if (op.from == FloatRepresentation::Float64() &&
op.to == WordRepresentation::Word32()) { op.to == WordRepresentation::Word32()) {
...@@ -642,7 +671,16 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { ...@@ -642,7 +671,16 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) {
o = machine.ChangeInt32ToFloat64(); o = machine.ChangeInt32ToFloat64();
} else if (op.from == WordRepresentation::Word64() && } else if (op.from == WordRepresentation::Word64() &&
op.to == FloatRepresentation::Float64()) { op.to == FloatRepresentation::Float64()) {
o = machine.ChangeInt64ToFloat64(); o = machine.RoundInt64ToFloat64();
} else if (op.from == WordRepresentation::Word32() &&
op.to == FloatRepresentation::Float32()) {
o = machine.RoundInt32ToFloat32();
} else if (op.from == WordRepresentation::Word64() &&
op.to == FloatRepresentation::Float32()) {
o = machine.RoundInt64ToFloat32();
} else if (op.from == WordRepresentation::Word32() &&
op.to == FloatRepresentation::Float64()) {
o = machine.ChangeInt32ToFloat64();
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -651,6 +689,15 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { ...@@ -651,6 +689,15 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) {
if (op.from == WordRepresentation::Word32() && if (op.from == WordRepresentation::Word32() &&
op.to == FloatRepresentation::Float64()) { op.to == FloatRepresentation::Float64()) {
o = machine.ChangeUint32ToFloat64(); o = machine.ChangeUint32ToFloat64();
} else if (op.from == WordRepresentation::Word32() &&
op.to == FloatRepresentation::Float32()) {
o = machine.RoundUint32ToFloat32();
} else if (op.from == WordRepresentation::Word64() &&
op.to == FloatRepresentation::Float32()) {
o = machine.RoundUint64ToFloat32();
} else if (op.from == WordRepresentation::Word64() &&
op.to == FloatRepresentation::Float64()) {
o = machine.RoundUint64ToFloat64();
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -708,6 +755,12 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) { ...@@ -708,6 +755,12 @@ Node* ScheduleBuilder::ProcessOperation(const ChangeOp& op) {
} else if (op.from == FloatRepresentation::Float64() && } else if (op.from == FloatRepresentation::Float64() &&
op.to == WordRepresentation::Word32()) { op.to == WordRepresentation::Word32()) {
o = machine.ChangeFloat64ToInt32(); o = machine.ChangeFloat64ToInt32();
} else if (op.from == WordRepresentation::Word32() &&
op.to == FloatRepresentation::Float64()) {
o = machine.ChangeInt32ToFloat64();
} else if (op.from == WordRepresentation::Word64() &&
op.to == FloatRepresentation::Float64()) {
o = machine.ChangeInt64ToFloat64();
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -749,6 +802,14 @@ Node* ScheduleBuilder::ProcessOperation(const TaggedBitcastOp& op) { ...@@ -749,6 +802,14 @@ Node* ScheduleBuilder::ProcessOperation(const TaggedBitcastOp& op) {
} }
return AddNode(o, {GetNode(op.input())}); return AddNode(o, {GetNode(op.input())});
} }
Node* ScheduleBuilder::ProcessOperation(const SelectOp& op) {
const Operator* o = op.rep == WordRepresentation::Word32()
? machine.Word32Select().op()
: machine.Word64Select().op();
return AddNode(
o, {GetNode(op.condition()), GetNode(op.left()), GetNode(op.right())});
}
Node* ScheduleBuilder::ProcessOperation(const PendingLoopPhiOp& op) { Node* ScheduleBuilder::ProcessOperation(const PendingLoopPhiOp& op) {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -779,6 +840,11 @@ Node* ScheduleBuilder::ProcessOperation(const ConstantOp& op) { ...@@ -779,6 +840,11 @@ Node* ScheduleBuilder::ProcessOperation(const ConstantOp& op) {
return AddNode(common.Float64Constant(op.float64()), {}); return AddNode(common.Float64Constant(op.float64()), {});
case ConstantOp::Kind::kFloat32: case ConstantOp::Kind::kFloat32:
return AddNode(common.Float32Constant(op.float32()), {}); return AddNode(common.Float32Constant(op.float32()), {});
case ConstantOp::Kind::kRelocatableWasmCall:
return RelocatableIntPtrConstant(op.integral(), RelocInfo::WASM_CALL);
case ConstantOp::Kind::kRelocatableWasmStubCall:
return RelocatableIntPtrConstant(op.integral(),
RelocInfo::WASM_STUB_CALL);
} }
} }
Node* ScheduleBuilder::ProcessOperation(const LoadOp& op) { Node* ScheduleBuilder::ProcessOperation(const LoadOp& op) {
...@@ -788,9 +854,11 @@ Node* ScheduleBuilder::ProcessOperation(const LoadOp& op) { ...@@ -788,9 +854,11 @@ Node* ScheduleBuilder::ProcessOperation(const LoadOp& op) {
offset -= kHeapObjectTag; offset -= kHeapObjectTag;
} }
Node* base = GetNode(op.base()); Node* base = GetNode(op.base());
return AddNode(IsAlignedAccess(op.kind) return AddNode(op.kind == LoadOp::Kind::kRawAligned
? machine.Load(op.loaded_rep.ToMachineType()) ? machine.Load(op.loaded_rep.ToMachineType())
: machine.UnalignedLoad(op.loaded_rep.ToMachineType()), : op.kind == LoadOp::Kind::kRawUnaligned
? machine.UnalignedLoad(op.loaded_rep.ToMachineType())
: machine.ProtectedLoad(op.loaded_rep.ToMachineType()),
{base, IntPtrConstant(offset)}); {base, IntPtrConstant(offset)});
} }
Node* ScheduleBuilder::ProcessOperation(const IndexedLoadOp& op) { Node* ScheduleBuilder::ProcessOperation(const IndexedLoadOp& op) {
...@@ -815,8 +883,10 @@ Node* ScheduleBuilder::ProcessOperation(const IndexedLoadOp& op) { ...@@ -815,8 +883,10 @@ Node* ScheduleBuilder::ProcessOperation(const IndexedLoadOp& op) {
loaded_rep = MachineType::CompressedPointer(); loaded_rep = MachineType::CompressedPointer();
} }
} }
return AddNode(IsAlignedAccess(op.kind) ? machine.Load(loaded_rep) return AddNode(op.kind == LoadOp::Kind::kRawAligned ? machine.Load(loaded_rep)
: machine.UnalignedLoad(loaded_rep), : op.kind == LoadOp::Kind::kRawUnaligned
? machine.UnalignedLoad(loaded_rep)
: machine.ProtectedLoad(loaded_rep),
{base, index}); {base, index});
} }
Node* ScheduleBuilder::ProcessOperation(const StoreOp& op) { Node* ScheduleBuilder::ProcessOperation(const StoreOp& op) {
...@@ -831,6 +901,9 @@ Node* ScheduleBuilder::ProcessOperation(const StoreOp& op) { ...@@ -831,6 +901,9 @@ Node* ScheduleBuilder::ProcessOperation(const StoreOp& op) {
if (IsAlignedAccess(op.kind)) { if (IsAlignedAccess(op.kind)) {
o = machine.Store(StoreRepresentation( o = machine.Store(StoreRepresentation(
op.stored_rep.ToMachineType().representation(), op.write_barrier)); op.stored_rep.ToMachineType().representation(), op.write_barrier));
} else if (op.kind == LoadOp::Kind::kProtected) {
DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier);
o = machine.ProtectedStore(op.stored_rep.ToMachineType().representation());
} else { } else {
DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier); DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier);
o = machine.UnalignedStore(op.stored_rep.ToMachineType().representation()); o = machine.UnalignedStore(op.stored_rep.ToMachineType().representation());
...@@ -856,6 +929,9 @@ Node* ScheduleBuilder::ProcessOperation(const IndexedStoreOp& op) { ...@@ -856,6 +929,9 @@ Node* ScheduleBuilder::ProcessOperation(const IndexedStoreOp& op) {
if (IsAlignedAccess(op.kind)) { if (IsAlignedAccess(op.kind)) {
o = machine.Store(StoreRepresentation( o = machine.Store(StoreRepresentation(
op.stored_rep.ToMachineType().representation(), op.write_barrier)); op.stored_rep.ToMachineType().representation(), op.write_barrier));
} else if (op.kind == LoadOp::Kind::kProtected) {
DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier);
o = machine.ProtectedStore(op.stored_rep.ToMachineType().representation());
} else { } else {
DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier); DCHECK_EQ(op.write_barrier, WriteBarrierKind::kNoWriteBarrier);
o = machine.UnalignedStore(op.stored_rep.ToMachineType().representation()); o = machine.UnalignedStore(op.stored_rep.ToMachineType().representation());
...@@ -927,6 +1003,12 @@ Node* ScheduleBuilder::ProcessOperation(const DeoptimizeIfOp& op) { ...@@ -927,6 +1003,12 @@ Node* ScheduleBuilder::ProcessOperation(const DeoptimizeIfOp& op) {
op.parameters->feedback()); op.parameters->feedback());
return AddNode(o, {condition, frame_state}); return AddNode(o, {condition, frame_state});
} }
Node* ScheduleBuilder::ProcessOperation(const TrapIfOp& op) {
Node* condition = GetNode(op.condition());
const Operator* o =
op.negated ? common.TrapUnless(op.trap_id) : common.TrapIf(op.trap_id);
return AddNode(o, {condition});
}
Node* ScheduleBuilder::ProcessOperation(const DeoptimizeOp& op) { Node* ScheduleBuilder::ProcessOperation(const DeoptimizeOp& op) {
Node* frame_state = GetNode(op.frame_state()); Node* frame_state = GetNode(op.frame_state());
const Operator* o = const Operator* o =
...@@ -1087,6 +1169,17 @@ Node* ScheduleBuilder::ProcessOperation(const CallOp& op) { ...@@ -1087,6 +1169,17 @@ Node* ScheduleBuilder::ProcessOperation(const CallOp& op) {
} }
return AddNode(common.Call(op.descriptor), base::VectorOf(inputs)); return AddNode(common.Call(op.descriptor), base::VectorOf(inputs));
} }
Node* ScheduleBuilder::ProcessOperation(const TailCallOp& op) {
base::SmallVector<Node*, 16> inputs;
inputs.push_back(GetNode(op.callee()));
for (OpIndex i : op.arguments()) {
inputs.push_back(GetNode(i));
}
Node* call = MakeNode(common.TailCall(op.descriptor), base::VectorOf(inputs));
schedule->AddTailCall(current_block, call);
current_block = nullptr;
return nullptr;
}
Node* ScheduleBuilder::ProcessOperation(const UnreachableOp& op) { Node* ScheduleBuilder::ProcessOperation(const UnreachableOp& op) {
Node* node = MakeNode(common.Throw(), {}); Node* node = MakeNode(common.Throw(), {});
schedule->AddThrow(current_block, node); schedule->AddThrow(current_block, node);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "src/compiler/compiler-source-position-table.h" #include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/node-origin-table.h" #include "src/compiler/node-origin-table.h"
#include "src/compiler/node.h"
namespace v8::internal { namespace v8::internal {
class Zone; class Zone;
} }
......
// 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.
#include "src/compiler/turboshaft/simplify-tf-loops.h"
#include "src/base/small-vector.h"
#include "src/compiler/machine-graph.h"
#include "src/compiler/node-properties.h"
namespace v8::internal::compiler {
Reduction SimplifyTFLoops::Reduce(Node* node) {
if (node->opcode() != IrOpcode::kLoop) return NoChange();
if (node->InputCount() <= 2) return NoChange();
Node* new_loop = mcgraph_->graph()->NewNode(mcgraph_->common()->Loop(2),
node->InputAt(0), node);
node->RemoveInput(0);
NodeProperties::ChangeOp(node, mcgraph_->common()->Merge(node->InputCount()));
base::SmallVector<Edge, 4> control_uses;
for (Edge edge : node->use_edges()) {
Node* use = edge.from();
if (!NodeProperties::IsPhi(use)) {
control_uses.emplace_back(edge);
continue;
}
Node* dominating_input = use->InputAt(0);
use->RemoveInput(0);
NodeProperties::ChangeOp(
use, use->opcode() == IrOpcode::kPhi
? mcgraph_->common()->Phi(PhiRepresentationOf(use->op()),
use->InputCount() - 1)
: mcgraph_->common()->EffectPhi(use->InputCount() - 1));
Node* new_phi = mcgraph_->graph()->NewNode(
use->opcode() == IrOpcode::kPhi
? mcgraph_->common()->Phi(PhiRepresentationOf(use->op()), 2)
: mcgraph_->common()->EffectPhi(2),
dominating_input, use, new_loop);
ReplaceWithValue(use, new_phi, new_phi, new_phi);
// Restore the use <- new_phi edge we just broke.
new_phi->ReplaceInput(1, use);
}
for (Edge edge : control_uses) {
if (edge.from() != new_loop) {
edge.from()->ReplaceInput(edge.index(), new_loop);
}
}
return NoChange();
}
} // namespace v8::internal::compiler
// 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_SIMPLIFY_TF_LOOPS_H_
#define V8_COMPILER_TURBOSHAFT_SIMPLIFY_TF_LOOPS_H_
#include "src/compiler/graph-reducer.h"
namespace v8::internal::compiler {
class MachineGraph;
// Constrain loop nodes to have at most two inputs, by introducing additional
// merges as needed.
class SimplifyTFLoops final : public AdvancedReducer {
public:
SimplifyTFLoops(Editor* editor, MachineGraph* mcgraph)
: AdvancedReducer(editor), mcgraph_(mcgraph) {}
const char* reducer_name() const override { return "SimplifyTFLoops"; }
Reduction Reduce(Node* node) final;
private:
MachineGraph* const mcgraph_;
};
} // namespace v8::internal::compiler
#endif // V8_COMPILER_TURBOSHAFT_SIMPLIFY_TF_LOOPS_H_
...@@ -963,10 +963,12 @@ DEFINE_FLOAT(script_delay_fraction, 0.0, ...@@ -963,10 +963,12 @@ DEFINE_FLOAT(script_delay_fraction, 0.0,
"busy wait after each Script::Run by the given fraction of the " "busy wait after each Script::Run by the given fraction of the "
"run's duration") "run's duration")
DEFINE_BOOL(turboshaft, false, "enable TurboFan's Turboshaft phases") DEFINE_BOOL(turboshaft, false, "enable TurboFan's Turboshaft phases for JS")
DEFINE_WEAK_IMPLICATION(future, turboshaft) DEFINE_WEAK_IMPLICATION(future, turboshaft)
DEFINE_BOOL(turboshaft_trace_reduction, false, DEFINE_BOOL(turboshaft_trace_reduction, false,
"trace individual Turboshaft reduction steps") "trace individual Turboshaft reduction steps")
DEFINE_BOOL(turboshaft_wasm, false,
"enable TurboFan's Turboshaft phases for wasm")
// Favor memory over execution speed. // Favor memory over execution speed.
DEFINE_BOOL(optimize_for_size, false, DEFINE_BOOL(optimize_for_size, false,
......
...@@ -366,6 +366,7 @@ class RuntimeCallTimer final { ...@@ -366,6 +366,7 @@ class RuntimeCallTimer final {
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Scheduling) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Scheduling) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SelectInstructions) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SelectInstructions) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifiedLowering) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifiedLowering) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifyLoops) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, StoreStoreElimination) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, StoreStoreElimination) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TraceScheduleAndVerify) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TraceScheduleAndVerify) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildTurboshaft) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildTurboshaft) \
......
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