v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
define-assembler-macros.inc
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// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD
6
7// This file defines Turboshaft's assembler macros. Include this file before
8// your reducers and don't forget to include 'undef-assembler-macros.inc'
9// afterwards.
10
11#ifdef V8_COMPILER_TURBOSHAFT_ASSEMBLER_MACROS_DEFINED
12#error \
13 "Assembler macros already defined. Did you forget to #include \"undef-assembler-macros.inc\" in a previous file?"
14#endif
15
16#define V8_COMPILER_TURBOSHAFT_ASSEMBLER_MACROS_DEFINED 1
17
18#define TSA_DCHECK(assembler, condition) \
19 (assembler)->Asm().Dcheck(condition, #condition, __FILE__, __LINE__ )
20#ifdef ENABLE_SLOW_DCHECKS
21#define TSA_SLOW_DCHECK(assembler, ...) \
22 do { \
23 if (v8_flags.enable_slow_asserts) { \
24 TSA_DCHECK(assembler, __VA_ARGS__); \
25 } \
26 } while(false)
27#else
28#define TSA_SLOW_DCHECK(assembler, ...) ((void)0)
29#endif
30
31#define LIKELY(...) ConditionWithHint(__VA_ARGS__, BranchHint::kTrue)
32#define UNLIKELY(...) ConditionWithHint(__VA_ARGS__, BranchHint::kFalse)
33
34#define BIND(label, ...) \
35 auto [CONCAT(is_bound_, __LINE__), ##__VA_ARGS__] = \
36 Asm().ControlFlowHelper_Bind(label); \
37 (::v8::internal::compiler::turboshaft::detail::SuppressUnusedWarning( \
38 CONCAT(is_bound_, __LINE__)))
39#define BIND_LOOP(loop_label, ...) \
40 for(auto [CONCAT(run_loop_, __LINE__), ##__VA_ARGS__] = \
41 Asm().ControlFlowHelper_BindLoop(loop_label); CONCAT(run_loop_, __LINE__); \
42 Asm().ControlFlowHelper_EndLoop(loop_label), \
43 CONCAT(run_loop_, __LINE__) = false)
44
45#define WHILE(...) \
46 for (auto [CONCAT(run_loop_, __LINE__), loop_header_xx, loop_exit_xx] \
47 = Asm().ControlFlowHelper_While([&]() { \
48 return Asm().resolve(ConstOrV<Word32>(__VA_ARGS__)); \
49 }); \
50 CONCAT(run_loop_, __LINE__); \
51 Asm().ControlFlowHelper_EndWhileLoop(loop_header_xx, loop_exit_xx), \
52 CONCAT(run_loop_, __LINE__) = false)
53#define FOREACH_IMPL_2(arg, iterable) \
54 for (auto [CONCAT(run_loop_, __LINE__), iterable_xx, loop_header_yy, \
55 loop_exit_xx, current_iterator_xx, arg] = \
56 Asm().ControlFlowHelper_Foreach(iterable); \
57 CONCAT(run_loop_, __LINE__); \
58 Asm().ControlFlowHelper_EndForeachLoop( \
59 std::move(iterable_xx), loop_header_yy, loop_exit_xx, \
60 current_iterator_xx), \
61 CONCAT(run_loop_, __LINE__) = false)
62#define FOREACH_IMPL_3(arg0, arg1, iterable) \
63 for (auto [CONCAT(run_loop_, __LINE__), iterable_xx, loop_header_yy, \
64 loop_exit_xx, current_iterator_xx, arg0, arg1] = \
65 Asm().ControlFlowHelper_Foreach(iterable); \
66 CONCAT(run_loop_, __LINE__); \
67 Asm().ControlFlowHelper_EndForeachLoop( \
68 std::move(iterable_xx), loop_header_yy, loop_exit_xx, \
69 current_iterator_xx), \
70 CONCAT(run_loop_, __LINE__) = false)
71// TODO(nicohartmann): Add more `FOREACH_IMPL_N` versions when we see need.
72#define FOREACH(...) \
73 CONCAT(FOREACH_IMPL_, COUNT_MACRO_ARGS(__VA_ARGS__))(__VA_ARGS__)
74
75#define BREAK Asm().ControlFlowHelper_Goto(loop_exit_xx, {})
76// TODO(nicohartmann): CONTINUE currently doesn't work for FOREACH.
77#define CONTINUE Asm().ControlFlowHelper_Goto(loop_header_xx, {})
78
79#define GOTO(label, ...) \
80 Asm().ControlFlowHelper_Goto(label, {__VA_ARGS__})
81#define GOTO_IF(cond, label, ...) \
82 Asm().ControlFlowHelper_GotoIf(cond, label, {__VA_ARGS__})
83#define GOTO_IF_NOT(cond, label, ...) \
84 Asm().ControlFlowHelper_GotoIfNot(cond, label, {__VA_ARGS__})
85
86// Clang/GCC helpfully warn us about dangling else in nested if statements. This
87// dangling is intentional for the way these macros work, so suppress the
88// warning with Pragmas. Clang and GCC helpfully disagree on where the warning
89// is (on the if or the else), so they need separate macros.
90#if defined(__clang__)
91// TODO(chromium:377144577): re-enable force-unrolling once this has been fixed
92// in LLVM.
93#define FORCE_UNROLL_LOOP
94#define SUPPRESSED_DANGLING_ELSE_WARNING_IF(...) if (__VA_ARGS__)
95#define SUPPRESSED_DANGLING_ELSE_WARNING_ELSE \
96 _Pragma("GCC diagnostic push") \
97 _Pragma("GCC diagnostic ignored \"-Wdangling-else\"") else _Pragma( \
98 "GCC diagnostic pop")
99#elif defined(__GNUC__)
100#define FORCE_UNROLL_LOOP
101#define SUPPRESSED_DANGLING_ELSE_WARNING_IF(...) \
102 _Pragma("GCC diagnostic push") \
103 _Pragma("GCC diagnostic ignored \"-Wdangling-else\"") if (__VA_ARGS__) \
104 _Pragma("GCC diagnostic pop")
105#define SUPPRESSED_DANGLING_ELSE_WARNING_ELSE else
106#else
107#define FORCE_UNROLL_LOOP
108#define SUPPRESSED_DANGLING_ELSE_WARNING_IF(...) if (__VA_ARGS__)
109#define SUPPRESSED_DANGLING_ELSE_WARNING_ELSE else
110#endif
111
112#define NO_SHADOW \
113 _Pragma("GCC diagnostic push") \
114 _Pragma("GCC diagnostic ignored \"-Wshadow\"")
115#define RE_SHADOW _Pragma("GCC diagnostic pop")
116
117// IF/ELSE macros. These expand to a real C++ if-else, so that we can get
118// similar block syntax behaviour (with an optional `ELSE`). Since C++ will only
119// evaluate one side of the if-else, wrap it in a for loop that executes the
120// if-else three times: once for each side of the branch, and once to close the
121// if. Each iteration also emits a goto-end if the corresponding branch target
122// was bound. An if around the for loop encapsulates the state -- this is
123// outside the for loop to make it easier for the compiler to unroll the three
124// loop iterations.
125#define IF(...) \
126 NO_SHADOW \
127 SUPPRESSED_DANGLING_ELSE_WARNING_IF( \
128 typename std::decay_t<decltype(Asm())>::ControlFlowHelper_IfState state; \
129 true) \
130 FORCE_UNROLL_LOOP \
131 for (int iteration = 0, bound = false; iteration < 3; \
132 (bound ? Asm().ControlFlowHelper_FinishIfBlock(&state) : (void)0), \
133 bound = false, iteration++) \
134 RE_SHADOW \
135 SUPPRESSED_DANGLING_ELSE_WARNING_IF(iteration == 2) { \
136 Asm().ControlFlowHelper_EndIf(&state); \
137 } \
138 SUPPRESSED_DANGLING_ELSE_WARNING_ELSE if ( \
139 iteration == 0 && \
140 (bound = Asm().ControlFlowHelper_BindIf(__VA_ARGS__, &state)))
141
142#define IF_NOT(...) \
143 NO_SHADOW \
144 SUPPRESSED_DANGLING_ELSE_WARNING_IF( \
145 typename std::decay_t<decltype(Asm())>::ControlFlowHelper_IfState state; \
146 true) \
147 FORCE_UNROLL_LOOP \
148 for (int iteration = 0, bound = false; iteration < 3; \
149 (bound ? Asm().ControlFlowHelper_FinishIfBlock(&state) : (void)0), \
150 bound = false, iteration++) \
151 RE_SHADOW \
152 SUPPRESSED_DANGLING_ELSE_WARNING_IF(iteration == 2) { \
153 Asm().ControlFlowHelper_EndIf(&state); \
154 } \
155 SUPPRESSED_DANGLING_ELSE_WARNING_ELSE if ( \
156 iteration == 0 && \
157 (bound = Asm().ControlFlowHelper_BindIfNot(__VA_ARGS__, &state)))
158
159#define ELSE \
160 SUPPRESSED_DANGLING_ELSE_WARNING_ELSE if ( \
161 iteration == 1 && (bound = Asm().ControlFlowHelper_BindElse(&state)))
162
163#define Assert(condition) AssertImpl(condition, #condition, __FILE__, __LINE__)
164
165#ifdef DEBUG
166// In debug builds, `REDUCE(operation)` makes sure that `operation##Op` exists
167// by using this name in an expression. This will detect typos in the name which
168// would otherwise stay unnoticed potentially.
169#define REDUCE(operation) \
170 CONCAT(CHECK_Reduce, operation) = \
171 (::v8::internal::compiler::turboshaft::detail::SuppressUnusedWarning( \
172 std::is_same_v<operation##Op, operation##Op>), \
173 decltype(CONCAT(CHECK_Reduce, operation)){}); \
174 template <class... Args> \
175 decltype(CONCAT(CHECK_Reduce, operation)) Reduce##operation(Args... args) { \
176 if (v8_flags.turboshaft_trace_intermediate_reductions) { \
177 base::SmallVector<OperationStorageSlot, 32> storage; \
178 operation##Op* op = CreateOperation<operation##Op>(storage, args...); \
179 PrintF("%*s", Asm().intermediate_tracing_depth(), ""); \
180 std::cout << "[" << ReducerName() << "]: reducing " << *op << "\n"; \
181 } \
182 Asm().intermediate_tracing_depth()++; \
183 decltype(CONCAT(CHECK_Reduce, operation)) result = \
184 Reduce##operation##Helper(args...); \
185 Asm().intermediate_tracing_depth()--; \
186 return result; \
187 } \
188 decltype(CONCAT(CHECK_Reduce, operation)) Reduce##operation##Helper
189
190#define REDUCE_INPUT_GRAPH(operation) \
191 CONCAT(CHECK_ReduceInputGraph, operation) = \
192 (::v8::internal::compiler::turboshaft::detail::SuppressUnusedWarning( \
193 std::is_same_v<operation##Op, operation##Op>), \
194 decltype(CONCAT(CHECK_ReduceInputGraph, operation)){}); \
195 decltype(CONCAT( \
196 CHECK_ReduceInputGraph, \
197 operation)) ReduceInputGraph##operation(OpIndex ig_index, \
198 const operation##Op& op) { \
199 if (v8_flags.turboshaft_trace_intermediate_reductions) { \
200 PrintF("%*s", Asm().intermediate_tracing_depth(), ""); \
201 std::cout << "[" << ReducerName() << "]: @input-reducing " << op << "\n";\
202 } \
203 Asm().intermediate_tracing_depth()++; \
204 decltype(CONCAT(CHECK_ReduceInputGraph, operation)) result = \
205 ReduceInputGraph##operation##Helper(ig_index, op); \
206 Asm().intermediate_tracing_depth()--; \
207 return result; \
208 } \
209 decltype(CONCAT(CHECK_ReduceInputGraph, \
210 operation)) ReduceInputGraph##operation##Helper
211#else
212#define REDUCE(operation) Reduce##operation
213#define REDUCE_INPUT_GRAPH(operation) ReduceInputGraph##operation
214#endif // DEBUG
215
216#define __ Asm().