v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
turboshaft-builtins-assembler-inl.h
Go to the documentation of this file.
1// Copyright 2024 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_CODEGEN_TURBOSHAFT_BUILTINS_ASSEMBLER_INL_H_
6#define V8_CODEGEN_TURBOSHAFT_BUILTINS_ASSEMBLER_INL_H_
7
8#include <iterator>
9
10#include "src/common/globals.h"
19
20#define DEFINE_TURBOSHAFT_ALIASES() \
21 template <typename T> \
22 using V = compiler::turboshaft::V<T>; \
23 template <typename T> \
24 using ConstOrV = compiler::turboshaft::ConstOrV<T>; \
25 template <typename T> \
26 using OptionalV = compiler::turboshaft::OptionalV<T>; \
27 template <typename... Ts> \
28 using Label = compiler::turboshaft::Label<Ts...>; \
29 template <typename... Ts> \
30 using LoopLabel = compiler::turboshaft::LoopLabel<Ts...>; \
31 using Block = compiler::turboshaft::Block; \
32 using OpIndex = compiler::turboshaft::OpIndex; \
33 using Word32 = compiler::turboshaft::Word32; \
34 using Word64 = compiler::turboshaft::Word64; \
35 using WordPtr = compiler::turboshaft::WordPtr; \
36 using Float32 = compiler::turboshaft::Float32; \
37 using Float64 = compiler::turboshaft::Float64; \
38 using RegisterRepresentation = compiler::turboshaft::RegisterRepresentation; \
39 using MemoryRepresentation = compiler::turboshaft::MemoryRepresentation; \
40 using BuiltinCallDescriptor = compiler::turboshaft::BuiltinCallDescriptor; \
41 using AccessBuilderTS = compiler::turboshaft::AccessBuilderTS;
42
43#define BUILTIN_REDUCER(name) \
44 TURBOSHAFT_REDUCER_BOILERPLATE(name) \
45 DEFINE_TURBOSHAFT_ALIASES()
46
47namespace v8::internal {
48
50
52
53namespace detail {
54
55// TODO(nicohartmann): Rename once CSA is (mostly) gone.
56template <typename Assembler>
58 public:
60
61 auto& Asm() const { return *assembler_; }
62
63 // |argc| specifies the number of arguments passed to the builtin.
64 template <typename T>
66 OptionalV<WordPtr> fp = {})
67 : assembler_(assembler) {
68 if constexpr (std::is_same_v<T, WordPtr>) {
69 argc_ = argc;
70 } else {
71 if constexpr (std::is_same_v<T, Word32>) {
72 DCHECK((std::is_same_v<WordPtr, Word64>));
73 argc_ = assembler_->ChangeInt32ToInt64(argc);
74 } else {
75 static_assert(std::is_same_v<T, Word64>);
76 DCHECK((std::is_same_v<WordPtr, Word32>));
77 argc_ = assembler_->TruncateWord64ToWord32(argc);
78 }
79 }
80 if (fp.has_value()) {
81 fp_ = fp.value();
82 } else {
83 fp_ = __ FramePointer();
84 }
85 const intptr_t offset =
88 // base_ points to the first argument, not the receiver
89 // whether present or not.
90 base_ = __ WordPtrAdd(fp_, offset);
91 }
92
94
96 return __ WordPtrSub(argc_, kJSArgcReceiverSlots);
97 }
98
100 TSA_DCHECK(this, __ UintPtrLessThan(index, GetLengthWithoutReceiver()));
101 return V<Object>::Cast(
102 __ LoadOffHeap(AtIndexPtr(index), MemoryRepresentation::AnyTagged()));
103 }
104
105 class Iterator {
106 public:
109
110 // {end} is the iterator-typical exclusive one past the last element.
112 ConstOrV<WordPtr> end_index)
113 : args_(args), begin_index_(begin_index), end_index_(end_index) {}
114
115 template <typename A>
116 iterator_type Begin(A& assembler) {
118 // Pre-compute the end offset.
119 end_offset_ = args_->AtIndexPtr(assembler.resolve(end_index_));
120 return args_->AtIndexPtr(assembler.resolve(begin_index_));
121 }
122
123 template <typename A>
125 iterator_type current_iterator) const {
126 return assembler.UintPtrLessThanOrEqual(end_offset_, current_iterator);
127 }
128
129 template <typename A>
130 iterator_type Advance(A& assembler, iterator_type current_iterator) const {
131 return assembler.WordPtrAdd(
133 }
134
135 template <typename A>
136 value_type Dereference(A& assembler, iterator_type current_iterator) const {
137 return V<Object>::Cast(assembler.LoadOffHeap(
138 current_iterator, MemoryRepresentation::AnyTagged()));
139 }
140
141 private:
146 };
147
149 return Iterator(this, begin, end);
150 }
151
153 return Iterator(this, begin, GetLengthWithoutReceiver());
154 }
155
156 Iterator Range() const {
157 return Iterator(this, 0, GetLengthWithoutReceiver());
158 }
159
160 private:
163 assembler_->ElementOffsetFromIndex(index, SYSTEM_POINTER_ELEMENTS, 0);
164 return __ WordPtrAdd(base_, offset);
165 }
166
171};
172
173} // namespace detail
174
175template <typename Next>
176class FeedbackCollectorReducer : public Next {
177 public:
178 BUILTIN_REDUCER(FeedbackCollector)
179
181 static constexpr bool HasFeedbackCollector() { return true; }
182
183 void CombineFeedback(int additional_feedback) {
184 __ CodeComment("CombineFeedback");
186 feedback_, __ SmiConstant(Smi::FromInt(additional_feedback)));
187 }
188
189 void OverwriteFeedback(int new_feedback) {
190 __ CodeComment("OverwriteFeedback");
191 feedback_ = __ SmiConstant(Smi::FromInt(new_feedback));
192 }
193
194 void CombineFeedbackOnException(int additional_feedback) {
195 feedback_on_exception_ = __ SmiConstant(Smi::FromInt(additional_feedback));
196 }
197
201
202 V<Word32> FeedbackIs(int checked_feedback) {
203 return __ SmiEqual(feedback_,
204 __ SmiConstant(Smi::FromInt(checked_feedback)));
205 }
206
211
213 V<Word32> length = __ LoadField(feedback_vector,
215 return ChangePositiveInt32ToIntPtr(length);
216 }
217
219 V<WordPtr> slot,
220 int additional_offset = 0) {
221 __ CodeComment("LoadFeedbackVectorSlot");
222 int32_t header_size =
223 FeedbackVector::kRawFeedbackSlotsOffset + additional_offset;
225 __ ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, header_size);
227 offset, LoadFeedbackVectorLength(feedback_vector),
228 FeedbackVector::kHeaderSize));
230 __ Load(feedback_vector, offset,
233 }
234
236 V<FeedbackVector> feedback_vector, V<WordPtr> slot, V<Object> value,
238 int additional_offset = 0) {
239 __ CodeComment("StoreFeedbackVectorSlot");
240 DCHECK(IsAligned(additional_offset, kTaggedSize));
241 int header_size =
242 FeedbackVector::kRawFeedbackSlotsOffset + additional_offset;
244 __ ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, header_size);
246 LoadFeedbackVectorLength(feedback_vector),
247 FeedbackVector::kHeaderSize));
248 switch (barrier_mode) {
249 case SKIP_WRITE_BARRIER: {
250 __ Store(feedback_vector, offset, value,
254 return;
255 }
261 UNREACHABLE();
262 }
263 }
264
265 void SetFeedbackSlot(V<WordPtr> slot_id) { slot_id_ = slot_id; }
266 void SetFeedbackVector(V<FeedbackVector> feedback_vector) {
267 TSA_DCHECK(this, IsFeedbackVector(feedback_vector));
268 maybe_feedback_vector_ = feedback_vector;
269 feedback_ = __ SmiConstant(Smi::FromInt(0));
271 }
272
274#ifndef V8_JITLESS
276#else
277 maybe_feedback_vector_ = __ UndefinedConstant();
278#endif
279 feedback_ = __ SmiConstant(Smi::FromInt(0));
281 }
282
284#ifndef V8_JITLESS
286#else
288#endif // !V8_JITLESS
289 }
290
292 __ CodeComment("UpdateFeedback");
294#ifdef V8_JITLESS
295 TSA_DCHECK(this, __ IsUndefined(maybe_feedback_vector_));
296 return;
297#else
298 UNREACHABLE();
299#endif // !V8_JITLESS
300 }
301
302 Label<> done(this);
304 GOTO_IF(__ IsUndefined(maybe_feedback_vector_), done);
305 } else {
307 }
308
309 V<FeedbackVector> feedback_vector =
311
312 V<MaybeObject> feedback_element =
313 LoadFeedbackVectorSlot(feedback_vector, slot_id_);
314 V<Smi> previous_feedback = V<Smi>::Cast(feedback_element);
315 V<Smi> combined_feedback = __ SmiBitwiseOr(previous_feedback, feedback_);
316 IF_NOT (__ SmiEqual(previous_feedback, combined_feedback)) {
317 StoreFeedbackVectorSlot(feedback_vector, slot_id_, combined_feedback,
319 // TODO(nicohartmann):
320 // ReportFeedbackUpdate(maybe_feedback_vector_, slot_id_,
321 // "UpdateFeedback");
322 }
323 GOTO(done);
324
325 BIND(done);
326 }
327
329 return __ BitcastWord32ToSmi(
330 __ Word32BitwiseOr(__ BitcastSmiToWord32(a), __ BitcastSmiToWord32(b)));
331 }
332
334 return __ Word32Equal(__ BitcastSmiToWord32(a), __ BitcastSmiToWord32(b));
335 }
336
338 TSA_DCHECK(this, __ Int32LessThanOrEqual(0, input));
339 return __ ChangeUint32ToUintPtr(input);
340 }
341
343 V<Map> map = __ LoadMapField(heap_object);
344 return __ IsFeedbackVectorMap(map);
345 }
346
348 int header_size,
350 // Make sure we point to the last field.
351 int element_size = 1 << ElementsKindToShiftSize(kind);
352 int correction = header_size - element_size;
353 V<WordPtr> last_offset =
354 __ ElementOffsetFromIndex(length, kind, correction);
355 return __ IntPtrLessThanOrEqual(offset, last_offset);
356 }
357
358 private:
364};
365
366template <typename Next>
367class NoFeedbackCollectorReducer : public Next {
368 public:
369 BUILTIN_REDUCER(NoFeedbackCollector)
370
371 static constexpr bool HasFeedbackCollector() { return false; }
372
373 void CombineFeedback(int additional_feedback) {}
374
375 void OverwriteFeedback(int new_feedback) {}
376
377 V<Word32> FeedbackIs(int checked_feedback) { UNREACHABLE(); }
378
381};
382
383template <typename Next>
384class BuiltinsReducer : public Next {
385 public:
387
388 using BuiltinArgumentsTS = detail::BuiltinArgumentsTS<assembler_t>;
389
390 void EmitBuiltinProlog(Builtin builtin_id) {
391 // Bind the entry block.
392 __ Bind(__ NewBlock());
393 // Eagerly emit all parameters such that they are guaranteed to be in the
394 // entry block (assembler will cache them).
395 const compiler::CallDescriptor* desc =
396 __ data() -> builtin_call_descriptor();
397 for (int i = 0; i < static_cast<int>(desc->ParameterCount()); ++i) {
399 desc->GetParameterType(i)));
400 }
401 // TODO(nicohartmann): CSA tracks some debug information here.
402 // Emit stack check.
403 if (Builtins::KindOf(builtin_id) == Builtins::TSJ) {
405 }
406 }
407
408 void EmitEpilog(Block* catch_block) {
409 DCHECK_EQ(__ HasFeedbackCollector(), catch_block != nullptr);
410 if (catch_block) {
411 // If the handler can potentially throw, we catch the exception here and
412 // update the feedback vector before we rethrow the exception.
413 if (__ Bind(catch_block)) {
414 V<Object> exception = __ CatchBlockBegin();
415 __ CombineExceptionFeedback();
416 __ UpdateFeedback();
417 __ template CallRuntime<
419 __ data()->isolate(), __ NoContextConstant(), {exception});
420 __ Unreachable();
421 }
422 }
423 }
424
426 return __ template Parameter<Context>(
428 __ data()->builtin_call_descriptor()->JSParameterCount())));
429 }
430
436
438 compiler::turboshaft::V<Object> return_value) {
439 // PopAndReturn is supposed to be using ONLY in CSA/Torque builtins for
440 // dropping ALL JS arguments that are currently located on the stack.
441 // The check below ensures that there are no directly accessible stack
442 // parameters from current builtin, which implies that the builtin with
443 // JS calling convention (TFJ) was created with kDontAdaptArgumentsSentinel.
444 // This simplifies semantics of this instruction because in case of presence
445 // of directly accessible stack parameters it's impossible to distinguish
446 // the following cases:
447 // 1) stack parameter is included in JS arguments (and therefore it will be
448 // dropped as a part of 'pop' number of arguments),
449 // 2) stack parameter is NOT included in JS arguments (and therefore it
450 // should
451 // be dropped in ADDITION to the 'pop' number of arguments).
452 // Additionally, in order to simplify assembly code, PopAndReturn is also
453 // not allowed in builtins with stub linkage and parameters on stack.
454 CHECK_EQ(__ data()->builtin_call_descriptor()->ParameterSlotCount(), 0);
455 V<WordPtr> pop_count = arguments.GetLengthWithReceiver();
456 std::initializer_list<const OpIndex> temp{return_value};
457 __ Return(__ TruncateWordPtrToWord32(pop_count), base::VectorOf(temp));
458 }
459
461 Label<Word32> is_number(this);
463 context, value, IsKnownTaggedPointer::kNo, is_number);
464
465 BIND(is_number, number);
466 return number;
467 }
468
470 return InstanceTypeEqual(instance_type, BIGINT_TYPE);
471 }
474 ConstOrV<Word32> other_instance_type) {
475 return __ Word32Equal(instance_type, other_instance_type);
476 }
477
479 return __ WordPtrBitwiseAnd(__ WordPtrAdd(size, kObjectAlignmentMask),
481 }
482
484 intptr_t base_size) {
485 const int element_size_shift = ElementsKindToShiftSize(kind);
486 if (std::optional<intptr_t> constant_index = TryToIntPtrConstant(index)) {
487 return __ WordPtrConstant(base_size +
488 (1 << element_size_shift) * (*constant_index));
489 }
490 if (element_size_shift == 0) {
491 return __ WordPtrAdd(base_size, index);
492 } else {
493 DCHECK_LT(0, element_size_shift);
494 return __ WordPtrAdd(base_size,
495 __ WordPtrShiftLeft(index, element_size_shift));
496 }
497 }
498
499 std::optional<intptr_t> TryToIntPtrConstant(ConstOrV<WordPtr> index) {
500 if (index.is_constant()) return index.constant_value();
501 intptr_t value;
502 if (matcher_.MatchIntegralWordPtrConstant(index.value(), &value)) {
503 return value;
504 }
505 return std::nullopt;
506 }
507
508 template <Object::Conversion Conversion>
510 IsKnownTaggedPointer is_known_tagged_pointer,
511 Label<Word32>& if_number,
512 Label<BigInt>* if_bigint = nullptr,
513 Label<BigInt>* if_bigint64 = nullptr) {
515 if_bigint != nullptr);
516
517 if (is_known_tagged_pointer == IsKnownTaggedPointer::kNo) {
518 IF (__ IsSmi(value)) {
520 GOTO(if_number, __ UntagSmi(V<Smi>::Cast(value)));
521 }
522 }
523
524 ScopedVar<HeapObject> value_heap_object(this, V<HeapObject>::Cast(value));
525 WHILE(1) {
526 V<Map> map = __ LoadMapField(value_heap_object);
527
528 IF (__ IsHeapNumberMap(map)) {
529 __ CombineFeedback(BinaryOperationFeedback::kNumber);
530 V<Float64> value_float64 =
531 __ LoadHeapNumberValue(V<HeapNumber>::Cast(value_heap_object));
532 GOTO(if_number, __ JSTruncateFloat64ToWord32(value_float64));
533 }
534
535 V<Word32> instance_type = __ LoadInstanceTypeField(map);
536 if (Conversion == Object::Conversion::kToNumeric) {
537 IF (IsBigIntInstanceType(instance_type)) {
538 V<BigInt> value_bigint = V<BigInt>::Cast(value_heap_object);
539 if (Is64() && if_bigint64) {
540 IF (IsSmallBigInt(value_bigint)) {
541 __ CombineFeedback(BinaryOperationFeedback::kBigInt64);
542 GOTO(*if_bigint64, value_bigint);
543 }
544 }
545 __ CombineFeedback(BinaryOperationFeedback::kBigInt);
546 GOTO(*if_bigint, value_bigint);
547 }
548 }
549
550 // Not HeapNumber (or BigInt if conversion == kToNumeric).
551 if (__ HasFeedbackCollector()) {
552 // We do not require an Or with earlier feedback here because once we
553 // convert the value to a Numeric, we cannot reach this path. We can
554 // only reach this path on the first pass when the feedback is kNone.
556 }
557 IF (InstanceTypeEqual(instance_type, ODDBALL_TYPE)) {
559 V<Float64> oddball_value =
560 __ LoadField(V<Oddball>::Cast(value_heap_object),
561 AccessBuilderTS::ForHeapNumberOrOddballOrHoleValue());
562 GOTO(if_number, __ JSTruncateFloat64ToWord32(oddball_value));
563 }
564
565 // Not an oddball either -> convert.
566 V<Object> converted_value;
567 // TODO(nicohartmann): We have to make sure that we store the feedback if
568 // any of those calls throws an exception.
569 __ OverwriteFeedback(BinaryOperationFeedback::kAny);
570
571 using Builtin =
572 std::conditional_t<Conversion == Object::Conversion::kToNumeric,
575 converted_value = __ template CallBuiltin<Builtin>(
576 isolate(), context, {V<JSAnyNotNumber>::Cast(value_heap_object)});
577
578 GOTO_IF(__ IsSmi(converted_value), if_number,
579 __ UntagSmi(V<Smi>::Cast(converted_value)));
580 value_heap_object = V<HeapObject>::Cast(converted_value);
581 }
582
583 __ Unreachable();
584 }
585
586 private:
588 Isolate* isolate() { return __ data() -> isolate(); }
589};
590
591template <template <typename> typename Reducer,
592 template <typename> typename FeedbackReducer>
595 Reducer, BuiltinsReducer, FeedbackReducer,
596 compiler::turboshaft::MachineLoweringReducer,
597 compiler::turboshaft::VariableReducer> {
598 public:
600 Reducer, BuiltinsReducer, FeedbackReducer,
607
608 using Base::Asm;
609};
610
612
613} // namespace v8::internal
614
615#endif // V8_CODEGEN_TURBOSHAFT_BUILTINS_ASSEMBLER_INL_H_
#define BIND(label)
#define GOTO(label,...)
#define TSA_SLOW_DCHECK(assembler,...)
#define IF_NOT(...)
#define TSA_DCHECK(assembler, condition)
#define WHILE(...)
#define IF(...)
#define GOTO_IF(cond, label,...)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Builtins::Kind kind
Definition builtins.cc:40
V< Word32 > TruncateTaggedToWord32(V< Context > context, V< Object > value)
compiler::turboshaft::OperationMatcher matcher_
void TaggedToWord32OrBigIntImpl(V< Context > context, V< Object > value, IsKnownTaggedPointer is_known_tagged_pointer, Label< Word32 > &if_number, Label< BigInt > *if_bigint=nullptr, Label< BigInt > *if_bigint64=nullptr)
std::optional< intptr_t > TryToIntPtrConstant(ConstOrV< WordPtr > index)
V< WordPtr > ElementOffsetFromIndex(ConstOrV< WordPtr > index, ElementsKind kind, intptr_t base_size)
void PopAndReturn(BuiltinArgumentsTS &arguments, compiler::turboshaft::V< Object > return_value)
V< Word32 > InstanceTypeEqual(ConstOrV< Word32 > instance_type, ConstOrV< Word32 > other_instance_type)
V< Word32 > IsBigIntInstanceType(ConstOrV< Word32 > instance_type)
V< WordPtr > AlignTagged(V< WordPtr > size)
static V8_EXPORT_PRIVATE Kind KindOf(Builtin builtin)
Definition builtins.cc:471
static constexpr int kFixedSlotCountAboveFp
static constexpr UpdateFeedbackMode DefaultUpdateFeedbackMode()
compiler::turboshaft::Var< Smi, assembler_t > feedback_
compiler::turboshaft::Var< Smi, assembler_t > feedback_on_exception_
V< MaybeObject > LoadFeedbackVectorSlot(V< FeedbackVector > feedback_vector, V< WordPtr > slot, int additional_offset=0)
void SetFeedbackVector(V< FeedbackVector > feedback_vector)
V< Word32 > IsFeedbackVector(V< HeapObject > heap_object)
void StoreFeedbackVectorSlot(V< FeedbackVector > feedback_vector, V< WordPtr > slot, V< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER, int additional_offset=0)
V< Word32 > IsOffsetInBounds(V< WordPtr > offset, V< WordPtr > length, int header_size, ElementsKind kind=HOLEY_ELEMENTS)
V< WordPtr > LoadFeedbackVectorLength(V< FeedbackVector > feedback_vector)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
TurboshaftBuiltinsAssembler(compiler::turboshaft::PipelineData *data, compiler::turboshaft::Graph &graph, Zone *phase_zone)
static constexpr int GetJSCallContextParamIndex(int parameter_count)
Definition linkage.h:495
static FieldAccessTS< FeedbackVector, Word32 > ForFeedbackVectorLength()
static constexpr MemoryRepresentation AnyTagged()
bool MatchIntegralWordPtrConstant(V< Any > matched, T *constant) const
static constexpr RegisterRepresentation FromMachineType(MachineType type)
static V< T > Cast(V< U > index)
Definition index.h:632
Iterator(const BuiltinArgumentsTS *args, ConstOrV< WordPtr > begin_index, ConstOrV< WordPtr > end_index)
iterator_type Advance(A &assembler, iterator_type current_iterator) const
OptionalV< Word32 > IsEnd(A &assembler, iterator_type current_iterator) const
value_type Dereference(A &assembler, iterator_type current_iterator) const
V< WordPtr > AtIndexPtr(ConstOrV< WordPtr > index) const
Iterator Range(ConstOrV< WordPtr > begin, ConstOrV< WordPtr > end) const
V< Object > AtIndex(ConstOrV< WordPtr > index) const
BuiltinArgumentsTS(Assembler *assembler, V< T > argc, OptionalV< WordPtr > fp={})
Iterator Range(ConstOrV< WordPtr > begin) const
static constexpr Register feedback_vector()
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int32_t offset
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
constexpr int kTaggedSize
Definition globals.h:542
@ SKIP_WRITE_BARRIER
Definition objects.h:52
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
@ UPDATE_EPHEMERON_KEY_WRITE_BARRIER
Definition objects.h:54
@ UNSAFE_SKIP_WRITE_BARRIER
Definition objects.h:53
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
constexpr int kJSArgcReceiverSlots
Definition globals.h:2778
constexpr int kSystemPointerSize
Definition globals.h:410
constexpr int ElementsKindToShiftSize(ElementsKind elements_kind)
constexpr intptr_t kObjectAlignmentMask
Definition globals.h:931
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
constexpr int JSParameterCount(int param_count_without_receiver)
Definition globals.h:2782
return value
Definition map-inl.h:893
constexpr bool Is64()
constexpr int A
constexpr int ElementsKindToByteSize(ElementsKind elements_kind)
i::Address Load(i::Address address)
Definition unwinder.cc:19
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
#define BUILTIN_REDUCER(name)
#define DEFINE_TURBOSHAFT_ALIASES()