v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
instruction-selector-adapter.h
Go to the documentation of this file.
1// Copyright 2023 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_COMPILER_BACKEND_INSTRUCTION_SELECTOR_ADAPTER_H_
6#define V8_COMPILER_BACKEND_INSTRUCTION_SELECTOR_ADAPTER_H_
7
8#include <optional>
9
18
19namespace v8::internal::compiler {
20
22 static constexpr bool IsTurbofan = false;
23 static constexpr bool IsTurboshaft = true;
24 static constexpr bool AllowsImplicitWord64ToWord32Truncation = true;
25
27 : turboshaft::OperationMatcher(*graph), graph_(graph) {}
28
29 class LoadView {
30 public:
32 switch (graph->Get(node_).opcode) {
33 case turboshaft::Opcode::kLoad:
34 load_ = &graph->Get(node_).Cast<turboshaft::LoadOp>();
35 break;
36#if V8_ENABLE_WEBASSEMBLY
37 case turboshaft::Opcode::kSimd128LoadTransform:
38 load_transform_ =
39 &graph->Get(node_).Cast<turboshaft::Simd128LoadTransformOp>();
40 break;
41#if V8_ENABLE_WASM_SIMD256_REVEC
42 case turboshaft::Opcode::kSimd256LoadTransform:
43 load_transform256_ =
44 &graph->Get(node_).Cast<turboshaft::Simd256LoadTransformOp>();
45 break;
46#endif // V8_ENABLE_WASM_SIMD256_REVEC
47#endif // V8_ENABLE_WEBASSEMBLY
48 default:
49 UNREACHABLE();
50 }
51 }
54 return load_->machine_type();
55 }
58 return load_->loaded_rep;
59 }
64 bool is_protected(bool* traps_on_null) const {
65 if (kind().with_trap_handler) {
66 if (load_) {
67 *traps_on_null = load_->kind.trap_on_null;
68#if V8_ENABLE_WEBASSEMBLY
69 } else {
70#if V8_ENABLE_WASM_SIMD256_REVEC
71 DCHECK(
72 (load_transform_ && !load_transform_->load_kind.trap_on_null) ||
73 (load_transform256_ &&
74 !load_transform256_->load_kind.trap_on_null));
75#else
76 DCHECK(load_transform_);
77 DCHECK(!load_transform_->load_kind.trap_on_null);
78#endif // V8_ENABLE_WASM_SIMD256_REVEC
79 *traps_on_null = false;
80#endif // V8_ENABLE_WEBASSEMBLY
81 }
82 return true;
83 }
84 return false;
85 }
86 bool is_atomic() const { return kind().is_atomic; }
87
89 if (load_) return load_->base();
90#if V8_ENABLE_WEBASSEMBLY
91 if (load_transform_) return load_transform_->base();
92#if V8_ENABLE_WASM_SIMD256_REVEC
93 if (load_transform256_) return load_transform256_->base();
94#endif // V8_ENABLE_WASM_SIMD256_REVEC
95#endif
97 }
99 if (load_) return load_->index().value_or_invalid();
100#if V8_ENABLE_WEBASSEMBLY
101 if (load_transform_) return load_transform_->index();
102#if V8_ENABLE_WASM_SIMD256_REVEC
103 if (load_transform256_) return load_transform256_->index();
104#endif // V8_ENABLE_WASM_SIMD256_REVEC
105#endif
106 UNREACHABLE();
107 }
108 int32_t displacement() const {
109 static_assert(
110 std::is_same_v<decltype(turboshaft::StoreOp::offset), int32_t>);
111 if (load_) {
112 int32_t offset = load_->offset;
113 if (load_->kind.tagged_base) {
115 std::numeric_limits<int32_t>::min() + kHeapObjectTag);
117 }
118 return offset;
119#if V8_ENABLE_WEBASSEMBLY
120 } else if (load_transform_) {
121 int32_t offset = load_transform_->offset;
122 DCHECK(!load_transform_->load_kind.tagged_base);
123 return offset;
124#if V8_ENABLE_WASM_SIMD256_REVEC
125 } else if (load_transform256_) {
126 int32_t offset = load_transform256_->offset;
127 DCHECK(!load_transform256_->load_kind.tagged_base);
128 return offset;
129#endif // V8_ENABLE_WASM_SIMD256_REVEC
130#endif
131 }
132 UNREACHABLE();
133 }
134 uint8_t element_size_log2() const {
135 static_assert(
136 std::is_same_v<decltype(turboshaft::StoreOp::element_size_log2),
137 uint8_t>);
138 if (load_) return load_->element_size_log2;
139#if V8_ENABLE_WEBASSEMBLY
140 if (load_transform_) return 0;
141#if V8_ENABLE_WASM_SIMD256_REVEC
142 if (load_transform256_) return 0;
143#endif // V8_ENABLE_WASM_SIMD256_REVEC
144#endif
145 UNREACHABLE();
146 }
147
148 operator turboshaft::OpIndex() const { return node_; }
149
150 private:
152 if (load_) return load_->kind;
153#if V8_ENABLE_WEBASSEMBLY
154 if (load_transform_) return load_transform_->load_kind;
155#if V8_ENABLE_WASM_SIMD256_REVEC
156 if (load_transform256_) return load_transform256_->load_kind;
157#endif // V8_ENABLE_WASM_SIMD256_REVEC
158#endif
159 UNREACHABLE();
160 }
161
163 const turboshaft::LoadOp* load_ = nullptr;
164#if V8_ENABLE_WEBASSEMBLY
165 const turboshaft::Simd128LoadTransformOp* load_transform_ = nullptr;
166#if V8_ENABLE_WASM_SIMD256_REVEC
167 const turboshaft::Simd256LoadTransformOp* load_transform256_ = nullptr;
168#endif // V8_ENABLE_WASM_SIMD256_REVEC
169#endif
170 };
171
172 class StoreView {
173 public:
175 : node_(node) {
176 op_ = &graph->Get(node_).Cast<turboshaft::StoreOp>();
177 }
178
180 return {op_->stored_rep.ToMachineType().representation(),
181 op_->write_barrier};
182 }
184 return op_->stored_rep;
185 }
186 std::optional<AtomicMemoryOrder> memory_order() const {
187 // TODO(nicohartmann@): Currently we don't support memory orders.
188 if (op_->kind.is_atomic) return AtomicMemoryOrder::kSeqCst;
189 return std::nullopt;
190 }
192 return op_->kind.with_trap_handler
195 }
196 bool is_atomic() const { return op_->kind.is_atomic; }
197
198 turboshaft::OpIndex base() const { return op_->base(); }
199 turboshaft::OptionalOpIndex index() const { return op_->index(); }
200 turboshaft::OpIndex value() const { return op_->value(); }
202 return static_cast<IndirectPointerTag>(op_->indirect_pointer_tag());
203 }
204 int32_t displacement() const {
205 static_assert(
206 std::is_same_v<decltype(turboshaft::StoreOp::offset), int32_t>);
207 int32_t offset = op_->offset;
208 if (op_->kind.tagged_base) {
209 CHECK_GE(offset, std::numeric_limits<int32_t>::min() + kHeapObjectTag);
211 }
212 return offset;
213 }
214 uint8_t element_size_log2() const {
215 static_assert(
216 std::is_same_v<decltype(turboshaft::StoreOp::element_size_log2),
217 uint8_t>);
218 return op_->element_size_log2;
219 }
220
222 return op_->kind.with_trap_handler && op_->kind.trap_on_null;
223 }
224
225 operator turboshaft::OpIndex() const { return node_; }
226
227 private:
230 };
231
232#if V8_ENABLE_WEBASSEMBLY
233 // TODO(391750831): Inline this.
234 class SimdShuffleView {
235 public:
236 explicit SimdShuffleView(const turboshaft::Graph* graph,
238 : node_(node) {
239 op128_ = &graph->Get(node).Cast<turboshaft::Simd128ShuffleOp>();
240 // Initialize input mapping.
241 for (int i = 0; i < op128_->input_count; ++i) {
242 input_mapping_.push_back(i);
243 }
244 }
245
246 bool isSimd128() const {
247 // TODO(nicohartmann@): Extend when we add support for Simd256.
248 return true;
249 }
250
251 const uint8_t* data() const { return op128_->shuffle; }
252
253 turboshaft::OpIndex input(int index) const {
254 DCHECK_LT(index, op128_->input_count);
255 return op128_->input(input_mapping_[index]);
256 }
257
258 void SwapInputs() { std::swap(input_mapping_[0], input_mapping_[1]); }
259
260 void DuplicateFirstInput() {
261 DCHECK_LE(2, input_mapping_.size());
262 input_mapping_[1] = input_mapping_[0];
263 }
264
265 operator turboshaft::OpIndex() const { return node_; }
266
267 private:
268 turboshaft::OpIndex node_;
269 base::SmallVector<int, 2> input_mapping_;
270 const turboshaft::Simd128ShuffleOp* op128_;
271 };
272#endif
273
274 bool is_load(turboshaft::OpIndex node) const {
275 return graph_->Get(node).Is<turboshaft::LoadOp>()
276#if V8_ENABLE_WEBASSEMBLY
277 || graph_->Get(node).Is<turboshaft::Simd128LoadTransformOp>()
278#if V8_ENABLE_WASM_SIMD256_REVEC
279 || graph_->Get(node).Is<turboshaft::Simd256LoadTransformOp>()
280#endif // V8_ENABLE_WASM_SIMD256_REVEC
281#endif
282 ;
283 }
285 return graph_->Get(node).Is<turboshaft::LoadRootRegisterOp>();
286 }
288 DCHECK(is_load(node));
289 return LoadView(graph_, node);
290 }
292 return StoreView(graph_, node);
293 }
294
295#if V8_ENABLE_WEBASSEMBLY
296 SimdShuffleView simd_shuffle_view(turboshaft::OpIndex node) {
297 return SimdShuffleView(graph_, node);
298 }
299#endif
300
302
304 turboshaft::OpIndex node) const {
305 // TODO(nicohartmann@): This might be too slow and we should consider
306 // precomputing.
307 return &schedule->Get(schedule->BlockOf(node));
308 }
309
311 return RpoNumber::FromInt(block->index().id());
312 }
313
315 return schedule->blocks_vector();
316 }
317
318 bool IsLoopHeader(const turboshaft::Block* block) const {
319 return block->IsLoop();
320 }
321
322 size_t PredecessorCount(const turboshaft::Block* block) const {
323 return block->PredecessorCount();
324 }
326 size_t index) const {
327 return block->Predecessors()[index];
328 }
329
334
335 bool IsRetain(turboshaft::OpIndex node) const {
336 return graph_->Get(node).Is<turboshaft::RetainOp>();
337 }
339 turboshaft::ConstantOp* constant =
340 graph_->Get(node).TryCast<turboshaft::ConstantOp>();
341 if (constant == nullptr) return false;
343 }
345 turboshaft::ConstantOp* constant =
346 graph_->Get(node).TryCast<turboshaft::ConstantOp>();
347 if (constant == nullptr) return false;
349 }
351 turboshaft::ConstantOp* constant =
352 graph_->Get(node).TryCast<turboshaft::ConstantOp>();
353 if (constant == nullptr) return false;
354 return constant->kind ==
358 }
360 return graph_->Get(node).opcode == turboshaft::Opcode::kLoad;
361 }
363#if V8_ENABLE_WEBASSEMBLY
364 if (graph_->Get(node).opcode == turboshaft::Opcode::kSimd128LoadTransform) {
365 return true;
366 }
367#if V8_ENABLE_WASM_SIMD256_REVEC
368 if (graph_->Get(node).opcode == turboshaft::Opcode::kSimd256LoadTransform) {
369 return true;
370 }
371#endif // V8_ENABLE_WASM_SIMD256_REVEC
372#endif // V8_ENABLE_WEBASSEMBLY
373
374 if (!IsLoadOrLoadImmutable(node)) return false;
375
376 bool traps_on_null;
377 return LoadView(graph_, node).is_protected(&traps_on_null);
378 }
379
380#ifndef V8_TARGET_ARCH_X64
382 return graph_->Get(node).input_count;
383 }
385 return graph_->Get(node).input(index);
386 }
388 turboshaft::OpIndex node) const {
389 return graph_->Get(node).inputs();
390 }
392 return graph_->Get(node).opcode;
393 }
394#endif
395
396 uint32_t id(turboshaft::OpIndex node) const { return node.id(); }
398 DCHECK(node.valid());
399 return node.value();
400 }
401
402 private:
404};
405
406} // namespace v8::internal::compiler
407
408#endif // V8_COMPILER_BACKEND_INSTRUCTION_SELECTOR_ADAPTER_H_
Schedule * schedule
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static RpoNumber FromInt(int index)
LoadView(turboshaft::Graph *graph, turboshaft::OpIndex node)
turboshaft::RegisterRepresentation ts_result_rep() const
StoreView(turboshaft::Graph *graph, turboshaft::OpIndex node)
base::SmallVector< Block *, 8 > Predecessors() const
Definition graph.h:328
base::iterator_range< OpIndexIterator > OperationIndices(const Block &block) const
Definition graph.h:957
V8_INLINE const Operation & Get(OpIndex i) const
Definition graph.h:618
const underlying_operation_t< Op > & Cast(V< AnyOrNone > op_idx) const
int32_t offset
any_of(const Args &...) -> any_of< Args... >
const int kHeapObjectTag
Definition v8-internal.h:72
Node * node_
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_GE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
bool is_load_root_register(turboshaft::OpIndex node) const
bool IsRelocatableWasmConstant(turboshaft::OpIndex node) const
bool IsExternalConstant(turboshaft::OpIndex node) const
RpoNumber rpo_number(const turboshaft::Block *block) const
const ZoneVector< turboshaft::Block * > & rpo_order(turboshaft::Graph *schedule)
turboshaft::OpIndex input_at(turboshaft::OpIndex node, size_t index) const
base::Vector< const turboshaft::OpIndex > inputs(turboshaft::OpIndex node) const
uint32_t id(turboshaft::OpIndex node) const
bool IsLoadOrLoadImmutable(turboshaft::OpIndex node) const
turboshaft::Opcode opcode(turboshaft::OpIndex node) const
bool IsProtectedLoad(turboshaft::OpIndex node) const
base::iterator_range< turboshaft::Graph::OpIndexIterator > nodes(const turboshaft::Block *block)
static turboshaft::OpIndex value(turboshaft::OptionalOpIndex node)
turboshaft::Block * PredecessorAt(const turboshaft::Block *block, size_t index) const
turboshaft::Block * block(turboshaft::Graph *schedule, turboshaft::OpIndex node) const
bool IsHeapConstant(turboshaft::OpIndex node) const
size_t PredecessorCount(const turboshaft::Block *block) const
int value_input_count(turboshaft::OpIndex node) const
bool IsLoopHeader(const turboshaft::Block *block) const