Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
8 : #define ASMJIT_CORE_EMITTER_H_INCLUDED
9 :
10 : #include "archtraits.h"
11 : #include "codeholder.h"
12 : #include "formatter.h"
13 : #include "inst.h"
14 : #include "operand.h"
15 : #include "type.h"
16 :
17 : ASMJIT_BEGIN_NAMESPACE
18 :
19 : //! \addtogroup asmjit_core
20 : //! \{
21 :
22 : class ConstPool;
23 : class FuncFrame;
24 : class FuncArgsAssignment;
25 :
26 : //! Align mode, used by \ref BaseEmitter::align().
27 : enum class AlignMode : uint8_t {
28 : //! Align executable code.
29 : kCode = 0,
30 : //! Align non-executable code.
31 : kData = 1,
32 : //! Align by a sequence of zeros.
33 : kZero = 2,
34 :
35 : //! Maximum value of `AlignMode`.
36 : kMaxValue = kZero
37 : };
38 :
39 : //! Emitter type used by \ref BaseEmitter.
40 : enum class EmitterType : uint8_t {
41 : //! Unknown or uninitialized.
42 : kNone = 0,
43 : //! Emitter inherits from \ref BaseAssembler.
44 : kAssembler = 1,
45 : //! Emitter inherits from \ref BaseBuilder.
46 : kBuilder = 2,
47 : //! Emitter inherits from \ref BaseCompiler.
48 : kCompiler = 3,
49 :
50 : //! Maximum value of `EmitterType`.
51 : kMaxValue = kCompiler
52 : };
53 :
54 : //! Emitter flags, used by \ref BaseEmitter.
55 : enum class EmitterFlags : uint8_t {
56 : //! No flags.
57 : kNone = 0u,
58 : //! Emitter is attached to CodeHolder.
59 : kAttached = 0x01u,
60 : //! The emitter must emit comments.
61 : kLogComments = 0x08u,
62 : //! The emitter has its own \ref Logger (not propagated from \ref CodeHolder).
63 : kOwnLogger = 0x10u,
64 : //! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder).
65 : kOwnErrorHandler = 0x20u,
66 : //! The emitter was finalized.
67 : kFinalized = 0x40u,
68 : //! The emitter was destroyed.
69 : //!
70 : //! This flag is used for a very short time when an emitter is being destroyed by
71 : //! CodeHolder.
72 : kDestroyed = 0x80u
73 : };
74 109968 : ASMJIT_DEFINE_ENUM_FLAGS(EmitterFlags)
75 :
76 : //! Encoding options.
77 : enum class EncodingOptions : uint32_t {
78 : //! No encoding options.
79 : kNone = 0,
80 :
81 : //! Emit instructions that are optimized for size, if possible.
82 : //!
83 : //! Default: false.
84 : //!
85 : //! X86 Specific
86 : //! ------------
87 : //!
88 : //! When this option is set it the assembler will try to fix instructions if possible into operation equivalent
89 : //! instructions that take less bytes by taking advantage of implicit zero extension. For example instruction
90 : //! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` and `and r32, imm` when the
91 : //! immediate constant is lesser than `2^31`.
92 : kOptimizeForSize = 0x00000001u,
93 :
94 : //! Emit optimized code-alignment sequences.
95 : //!
96 : //! Default: false.
97 : //!
98 : //! X86 Specific
99 : //! ------------
100 : //!
101 : //! Default align sequence used by X86 architecture is one-byte (0x90) opcode that is often shown by disassemblers
102 : //! as NOP. However there are more optimized align sequences for 2-11 bytes that may execute faster on certain CPUs.
103 : //! If this feature is enabled AsmJit will generate specialized sequences for alignment between 2 to 11 bytes.
104 : kOptimizedAlign = 0x00000002u,
105 :
106 : //! Emit jump-prediction hints.
107 : //!
108 : //! Default: false.
109 : //!
110 : //! X86 Specific
111 : //! ------------
112 : //!
113 : //! Jump prediction is usually based on the direction of the jump. If the jump is backward it is usually predicted as
114 : //! taken; and if the jump is forward it is usually predicted as not-taken. The reason is that loops generally use
115 : //! backward jumps and conditions usually use forward jumps. However this behavior can be overridden by using
116 : //! instruction prefixes. If this option is enabled these hints will be emitted.
117 : //!
118 : //! This feature is disabled by default, because the only processor that used to take into consideration prediction
119 : //! hints was P4. Newer processors implement heuristics for branch prediction and ignore static hints. This means
120 : //! that this feature can be only used for annotation purposes.
121 : kPredictedJumps = 0x00000010u
122 : };
123 27492 : ASMJIT_DEFINE_ENUM_FLAGS(EncodingOptions)
124 :
125 : //! Diagnostic options are used to tell emitters and their passes to perform diagnostics when emitting or processing
126 : //! user code. These options control validation and extra diagnostics that can be performed by higher level emitters.
127 : //!
128 : //! Instruction Validation
129 : //! ----------------------
130 : //!
131 : //! \ref BaseAssembler implementation perform by default only basic checks that are necessary to identify all
132 : //! variations of an instruction so the correct encoding can be selected. This is fine for production-ready code
133 : //! as the assembler doesn't have to perform checks that would slow it down. However, sometimes these checks are
134 : //! beneficial especially when the project that uses AsmJit is in a development phase, in which mistakes happen
135 : //! often. To make the experience of using AsmJit seamless it offers validation features that can be controlled
136 : //! by \ref DiagnosticOptions.
137 : //!
138 : //! Compiler Diagnostics
139 : //! --------------------
140 : //!
141 : //! Diagnostic options work with \ref BaseCompiler passes (precisely with its register allocation pass). These options
142 : //! can be used to enable logging of all operations that the Compiler does.
143 : enum class DiagnosticOptions : uint32_t {
144 : //! No validation options.
145 : kNone = 0,
146 :
147 : //! Perform strict validation in \ref BaseAssembler::emit() implementations.
148 : //!
149 : //! This flag ensures that each instruction is checked before it's encoded into a binary representation. This flag
150 : //! is only relevant for \ref BaseAssembler implementations, but can be set in any other emitter type, in that case
151 : //! if that emitter needs to create an assembler on its own, for the purpose of \ref BaseEmitter::finalize() it
152 : //! would propagate this flag to such assembler so all instructions passed to it are explicitly validated.
153 : //!
154 : //! Default: false.
155 : kValidateAssembler = 0x00000001u,
156 :
157 : //! Perform strict validation in \ref BaseBuilder::emit() and \ref BaseCompiler::emit() implementations.
158 : //!
159 : //! This flag ensures that each instruction is checked before an \ref InstNode representing the instruction is
160 : //! created by \ref BaseBuilder or \ref BaseCompiler. This option could be more useful than \ref kValidateAssembler
161 : //! in cases in which there is an invalid instruction passed to an assembler, which was invalid much earlier, most
162 : //! likely when such instruction was passed to Builder/Compiler.
163 : //!
164 : //! This is a separate option that was introduced, because it's possible to manipulate the instruction stream
165 : //! emitted by \ref BaseBuilder and \ref BaseCompiler - this means that it's allowed to emit invalid instructions
166 : //! (for example with missing operands) that will be fixed later before finalizing it.
167 : //!
168 : //! Default: false.
169 : kValidateIntermediate = 0x00000002u,
170 :
171 : //! Annotate all nodes processed by register allocator (Compiler/RA).
172 : //!
173 : //! \note Annotations don't need debug options, however, some debug options like `kRADebugLiveness` may influence
174 : //! their output (for example the mentioned option would add liveness information to per-instruction annotation).
175 : kRAAnnotate = 0x00000080u,
176 :
177 : //! Debug CFG generation and other related algorithms / operations (Compiler/RA).
178 : kRADebugCFG = 0x00000100u,
179 :
180 : //! Debug liveness analysis (Compiler/RA).
181 : kRADebugLiveness = 0x00000200u,
182 :
183 : //! Debug register allocation assignment (Compiler/RA).
184 : kRADebugAssignment = 0x00000400u,
185 :
186 : //! Debug the removal of code part of unreachable blocks.
187 : kRADebugUnreachable = 0x00000800u,
188 :
189 : //! Enable all debug options (Compiler/RA).
190 : kRADebugAll = 0x0000FF00u,
191 : };
192 27492 : ASMJIT_DEFINE_ENUM_FLAGS(DiagnosticOptions)
193 :
194 : //! Provides a base foundation to emitting code - specialized by \ref BaseAssembler and \ref BaseBuilder.
195 : class ASMJIT_VIRTAPI BaseEmitter {
196 : public:
197 : ASMJIT_BASE_CLASS(BaseEmitter)
198 :
199 : //! \name Members
200 : //! \{
201 :
202 : //! See \ref EmitterType.
203 : EmitterType _emitterType = EmitterType::kNone;
204 : //! See \ref EmitterFlags.
205 : EmitterFlags _emitterFlags = EmitterFlags::kNone;
206 : //! Validation flags in case validation is used.
207 : //!
208 : //! \note Validation flags are specific to the emitter and they are setup at construction time and then never
209 : //! changed.
210 : ValidationFlags _validationFlags = ValidationFlags::kNone;
211 : //! Validation options.
212 : DiagnosticOptions _diagnosticOptions = DiagnosticOptions::kNone;
213 :
214 : //! All supported architectures in a bit-mask, where LSB is the bit with a zero index.
215 : uint64_t _archMask = 0;
216 :
217 : //! Encoding options.
218 : EncodingOptions _encodingOptions = EncodingOptions::kNone;
219 :
220 : //! Forced instruction options, combined with \ref _instOptions by \ref emit().
221 : InstOptions _forcedInstOptions = InstOptions::kReserved;
222 : //! Internal private data used freely by any emitter.
223 : uint32_t _privateData = 0;
224 :
225 : //! CodeHolder the emitter is attached to.
226 : CodeHolder* _code = nullptr;
227 : //! Attached \ref Logger.
228 : Logger* _logger = nullptr;
229 : //! Attached \ref ErrorHandler.
230 : ErrorHandler* _errorHandler = nullptr;
231 :
232 : //! Describes the target environment, matches \ref CodeHolder::environment().
233 : Environment _environment {};
234 : //! Native GP register signature and signature related information.
235 : OperandSignature _gpSignature {};
236 :
237 : //! Next instruction options (affects the next instruction).
238 : InstOptions _instOptions = InstOptions::kNone;
239 : //! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
240 : RegOnly _extraReg {};
241 : //! Inline comment of the next instruction (affects the next instruction).
242 : const char* _inlineComment = nullptr;
243 :
244 : //! Function callbacks used by emitter implementation.
245 : //!
246 : //! These are typically shared between Assembler/Builder/Compiler of a single backend.
247 : struct Funcs {
248 : typedef Error (ASMJIT_CDECL* EmitProlog)(BaseEmitter* emitter, const FuncFrame& frame);
249 : typedef Error (ASMJIT_CDECL* EmitEpilog)(BaseEmitter* emitter, const FuncFrame& frame);
250 : typedef Error (ASMJIT_CDECL* EmitArgsAssignment)(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args);
251 :
252 : typedef Error (ASMJIT_CDECL* FormatInstruction)(
253 : String& sb,
254 : FormatFlags formatFlags,
255 : const BaseEmitter* emitter,
256 : Arch arch,
257 : const BaseInst& inst, const Operand_* operands, size_t opCount) ASMJIT_NOEXCEPT_TYPE;
258 :
259 : typedef Error (ASMJIT_CDECL* ValidateFunc)(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) ASMJIT_NOEXCEPT_TYPE;
260 :
261 : //! Emit prolog implementation.
262 : EmitProlog emitProlog;
263 : //! Emit epilog implementation.
264 : EmitEpilog emitEpilog;
265 : //! Emit arguments assignment implementation.
266 : EmitArgsAssignment emitArgsAssignment;
267 : //! Instruction formatter implementation.
268 : FormatInstruction formatInstruction;
269 : //! Instruction validation implementation.
270 : ValidateFunc validate;
271 :
272 : //! Resets all functions to nullptr.
273 : inline void reset() noexcept {
274 : emitProlog = nullptr;
275 : emitEpilog = nullptr;
276 : emitArgsAssignment = nullptr;
277 : validate = nullptr;
278 : }
279 : };
280 :
281 : Funcs _funcs {};
282 :
283 : //! \}
284 :
285 : //! \name Construction & Destruction
286 : //! \{
287 :
288 : ASMJIT_API explicit BaseEmitter(EmitterType emitterType) noexcept;
289 : ASMJIT_API virtual ~BaseEmitter() noexcept;
290 :
291 : //! \}
292 :
293 : //! \name Cast
294 : //! \{
295 :
296 : template<typename T>
297 : inline T* as() noexcept { return reinterpret_cast<T*>(this); }
298 :
299 : template<typename T>
300 : inline const T* as() const noexcept { return reinterpret_cast<const T*>(this); }
301 :
302 : //! \}
303 :
304 : //! \name Emitter Type & Flags
305 : //! \{
306 :
307 : //! Returns the type of this emitter, see `EmitterType`.
308 137460 : inline EmitterType emitterType() const noexcept { return _emitterType; }
309 : //! Returns emitter flags , see `Flags`.
310 : inline EmitterFlags emitterFlags() const noexcept { return _emitterFlags; }
311 :
312 : //! Tests whether the emitter inherits from `BaseAssembler`.
313 54984 : inline bool isAssembler() const noexcept { return _emitterType == EmitterType::kAssembler; }
314 : //! Tests whether the emitter inherits from `BaseBuilder`.
315 : //!
316 : //! \note Both Builder and Compiler emitters would return `true`.
317 : inline bool isBuilder() const noexcept { return uint32_t(_emitterType) >= uint32_t(EmitterType::kBuilder); }
318 : //! Tests whether the emitter inherits from `BaseCompiler`.
319 0 : inline bool isCompiler() const noexcept { return _emitterType == EmitterType::kCompiler; }
320 :
321 : //! Tests whether the emitter has the given `flag` enabled.
322 109968 : inline bool hasEmitterFlag(EmitterFlags flag) const noexcept { return Support::test(_emitterFlags, flag); }
323 : //! Tests whether the emitter is finalized.
324 : inline bool isFinalized() const noexcept { return hasEmitterFlag(EmitterFlags::kFinalized); }
325 : //! Tests whether the emitter is destroyed (only used during destruction).
326 : inline bool isDestroyed() const noexcept { return hasEmitterFlag(EmitterFlags::kDestroyed); }
327 :
328 54984 : inline void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
329 82476 : inline void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
330 :
331 : //! \}
332 :
333 : //! \name Target Information
334 : //! \{
335 :
336 : //! Returns the CodeHolder this emitter is attached to.
337 0 : inline CodeHolder* code() const noexcept { return _code; }
338 :
339 : //! Returns the target environment.
340 : //!
341 : //! The returned \ref Environment reference matches \ref CodeHolder::environment().
342 37131 : inline const Environment& environment() const noexcept { return _environment; }
343 :
344 : //! Tests whether the target architecture is 32-bit.
345 : inline bool is32Bit() const noexcept { return environment().is32Bit(); }
346 : //! Tests whether the target architecture is 64-bit.
347 : inline bool is64Bit() const noexcept { return environment().is64Bit(); }
348 :
349 : //! Returns the target architecture type.
350 : inline Arch arch() const noexcept { return environment().arch(); }
351 : //! Returns the target architecture sub-type.
352 : inline SubArch subArch() const noexcept { return environment().subArch(); }
353 :
354 : //! Returns the target architecture's GP register size (4 or 8 bytes).
355 27492 : inline uint32_t registerSize() const noexcept { return environment().registerSize(); }
356 :
357 : //! \}
358 :
359 : //! \name Initialization & Finalization
360 : //! \{
361 :
362 : //! Tests whether the emitter is initialized (i.e. attached to \ref CodeHolder).
363 : inline bool isInitialized() const noexcept { return _code != nullptr; }
364 :
365 : //! Finalizes this emitter.
366 : //!
367 : //! Materializes the content of the emitter by serializing it to the attached \ref CodeHolder through an architecture
368 : //! specific \ref BaseAssembler. This function won't do anything if the emitter inherits from \ref BaseAssembler as
369 : //! assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. However, if this is an emitter that
370 : //! inherits from \ref BaseBuilder or \ref BaseCompiler then these emitters need the materialization phase as they
371 : //! store their content in a representation not visible to \ref CodeHolder.
372 : ASMJIT_API virtual Error finalize();
373 :
374 : //! \}
375 :
376 : //! \name Logging
377 : //! \{
378 :
379 : //! Tests whether the emitter has a logger.
380 : inline bool hasLogger() const noexcept { return _logger != nullptr; }
381 :
382 : //! Tests whether the emitter has its own logger.
383 : //!
384 : //! Own logger means that it overrides the possible logger that may be used by \ref CodeHolder this emitter is
385 : //! attached to.
386 : inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnLogger); }
387 :
388 : //! Returns the logger this emitter uses.
389 : //!
390 : //! The returned logger is either the emitter's own logger or it's logger used by \ref CodeHolder this emitter
391 : //! is attached to.
392 0 : inline Logger* logger() const noexcept { return _logger; }
393 :
394 : //! Sets or resets the logger of the emitter.
395 : //!
396 : //! If the `logger` argument is non-null then the logger will be considered emitter's own logger, see \ref
397 : //! hasOwnLogger() for more details. If the given `logger` is null then the emitter will automatically use logger
398 : //! that is attached to the \ref CodeHolder this emitter is attached to.
399 : ASMJIT_API void setLogger(Logger* logger) noexcept;
400 :
401 : //! Resets the logger of this emitter.
402 : //!
403 : //! The emitter will bail to using a logger attached to \ref CodeHolder this emitter is attached to, or no logger
404 : //! at all if \ref CodeHolder doesn't have one.
405 : inline void resetLogger() noexcept { return setLogger(nullptr); }
406 :
407 : //! \}
408 :
409 : //! \name Error Handling
410 : //! \{
411 :
412 : //! Tests whether the emitter has an error handler attached.
413 : inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
414 :
415 : //! Tests whether the emitter has its own error handler.
416 : //!
417 : //! Own error handler means that it overrides the possible error handler that may be used by \ref CodeHolder this
418 : //! emitter is attached to.
419 : inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnErrorHandler); }
420 :
421 : //! Returns the error handler this emitter uses.
422 : //!
423 : //! The returned error handler is either the emitter's own error handler or it's error handler used by
424 : //! \ref CodeHolder this emitter is attached to.
425 27492 : inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
426 :
427 : //! Sets or resets the error handler of the emitter.
428 : ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept;
429 :
430 : //! Resets the error handler.
431 : inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
432 :
433 : //! Handles the given error in the following way:
434 : //! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
435 : //! first, and then returns the error. The `handleError()` function may throw.
436 : //! 2. if the emitter doesn't have \ref ErrorHandler, the error is simply returned.
437 : ASMJIT_API Error reportError(Error err, const char* message = nullptr);
438 :
439 : //! \}
440 :
441 : //! \name Encoding Options
442 : //! \{
443 :
444 : //! Returns encoding options.
445 27492 : inline EncodingOptions encodingOptions() const noexcept { return _encodingOptions; }
446 : //! Tests whether the encoding `option` is set.
447 0 : inline bool hasEncodingOption(EncodingOptions option) const noexcept { return Support::test(_encodingOptions, option); }
448 :
449 : //! Enables the given encoding `options`.
450 : inline void addEncodingOptions(EncodingOptions options) noexcept { _encodingOptions |= options; }
451 : //! Disables the given encoding `options`.
452 : inline void clearEncodingOptions(EncodingOptions options) noexcept { _encodingOptions &= ~options; }
453 :
454 : //! \}
455 :
456 : //! \name Diagnostic Options
457 : //! \{
458 :
459 : //! Returns the emitter's diagnostic options.
460 27492 : inline DiagnosticOptions diagnosticOptions() const noexcept { return _diagnosticOptions; }
461 :
462 : //! Tests whether the given `option` is present in the emitter's diagnostic options.
463 109968 : inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
464 :
465 : //! Activates the given diagnostic `options`.
466 : //!
467 : //! This function is used to activate explicit validation options that will be then used by all emitter
468 : //! implementations. There are in general two possibilities:
469 : //!
470 : //! - Architecture specific assembler is used. In this case a \ref DiagnosticOptions::kValidateAssembler can be
471 : //! used to turn on explicit validation that will be used before an instruction is emitted. This means that
472 : //! internally an extra step will be performed to make sure that the instruction is correct. This is needed,
473 : //! because by default assemblers prefer speed over strictness.
474 : //!
475 : //! This option should be used in debug builds as it's pretty expensive.
476 : //!
477 : //! - Architecture specific builder or compiler is used. In this case the user can turn on
478 : //! \ref DiagnosticOptions::kValidateIntermediate option that adds explicit validation step before the Builder
479 : //! or Compiler creates an \ref InstNode to represent an emitted instruction. Error will be returned if the
480 : //! instruction is ill-formed. In addition, also \ref DiagnosticOptions::kValidateAssembler can be used, which
481 : //! would not be consumed by Builder / Compiler directly, but it would be propagated to an architecture specific
482 : //! \ref BaseAssembler implementation it creates during \ref BaseEmitter::finalize().
483 : ASMJIT_API void addDiagnosticOptions(DiagnosticOptions options) noexcept;
484 :
485 : //! Deactivates the given validation `options`.
486 : //!
487 : //! See \ref addDiagnosticOptions() and \ref DiagnosticOptions for more details.
488 : ASMJIT_API void clearDiagnosticOptions(DiagnosticOptions options) noexcept;
489 :
490 : //! \}
491 :
492 : //! \name Instruction Options
493 : //! \{
494 :
495 : //! Returns forced instruction options.
496 : //!
497 : //! Forced instruction options are merged with next instruction options before the instruction is encoded. These
498 : //! options have some bits reserved that are used by error handling, logging, and instruction validation purposes.
499 : //! Other options are globals that affect each instruction.
500 774379 : inline InstOptions forcedInstOptions() const noexcept { return _forcedInstOptions; }
501 :
502 : //! Returns options of the next instruction.
503 774379 : inline InstOptions instOptions() const noexcept { return _instOptions; }
504 : //! Returns options of the next instruction.
505 392009 : inline void setInstOptions(InstOptions options) noexcept { _instOptions = options; }
506 : //! Adds options of the next instruction.
507 : inline void addInstOptions(InstOptions options) noexcept { _instOptions |= options; }
508 : //! Resets options of the next instruction.
509 392009 : inline void resetInstOptions() noexcept { _instOptions = InstOptions::kNone; }
510 :
511 : //! Tests whether the extra register operand is valid.
512 : inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
513 : //! Returns an extra operand that will be used by the next instruction (architecture specific).
514 : inline const RegOnly& extraReg() const noexcept { return _extraReg; }
515 : //! Sets an extra operand that will be used by the next instruction (architecture specific).
516 : inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
517 : //! Sets an extra operand that will be used by the next instruction (architecture specific).
518 : inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
519 : //! Resets an extra operand that will be used by the next instruction (architecture specific).
520 : inline void resetExtraReg() noexcept { _extraReg.reset(); }
521 :
522 : //! Returns comment/annotation of the next instruction.
523 382370 : inline const char* inlineComment() const noexcept { return _inlineComment; }
524 : //! Sets comment/annotation of the next instruction.
525 : //!
526 : //! \note This string is set back to null by `_emit()`, but until that it has to remain valid as the Emitter is not
527 : //! required to make a copy of it (and it would be slow to do that for each instruction).
528 552198 : inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
529 : //! Resets the comment/annotation to nullptr.
530 829363 : inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
531 :
532 : //! \}
533 :
534 : //! \name Sections
535 : //! \{
536 :
537 : virtual Error section(Section* section) = 0;
538 :
539 : //! \}
540 :
541 : //! \name Labels
542 : //! \{
543 :
544 : //! Creates a new label.
545 : virtual Label newLabel() = 0;
546 : //! Creates a new named label.
547 : virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) = 0;
548 :
549 : //! Creates a new anonymous label with a name, which can only be used for debugging purposes.
550 : inline Label newAnonymousLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kAnonymous); }
551 : //! Creates a new external label.
552 : inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kExternal); }
553 :
554 : //! Returns `Label` by `name`.
555 : //!
556 : //! Returns invalid Label in case that the name is invalid or label was not found.
557 : //!
558 : //! \note This function doesn't trigger ErrorHandler in case the name is invalid or no such label exist. You must
559 : //! always check the validity of the `Label` returned.
560 : ASMJIT_API Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
561 :
562 : //! Binds the `label` to the current position of the current section.
563 : //!
564 : //! \note Attempt to bind the same label multiple times will return an error.
565 : virtual Error bind(const Label& label) = 0;
566 :
567 : //! Tests whether the label `id` is valid (i.e. registered).
568 : ASMJIT_API bool isLabelValid(uint32_t labelId) const noexcept;
569 : //! Tests whether the `label` is valid (i.e. registered).
570 0 : inline bool isLabelValid(const Label& label) const noexcept { return isLabelValid(label.id()); }
571 :
572 : //! \}
573 :
574 : //! \name Emit
575 : //! \{
576 :
577 : // NOTE: These `emit()` helpers are designed to address a code-bloat generated by C++ compilers to call a function
578 : // having many arguments. Each parameter to `_emit()` requires some code to pass it, which means that if we default
579 : // to 5 arguments in `_emit()` and instId the C++ compiler would have to generate a virtual function call having 5
580 : // parameters and additional `this` argument, which is quite a lot. Since by default most instructions have 2 to 3
581 : // operands it's better to introduce helpers that pass from 0 to 6 operands that help to reduce the size of emit(...)
582 : // function call.
583 :
584 : //! Emits an instruction (internal).
585 : ASMJIT_API Error _emitI(InstId instId);
586 : //! \overload
587 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0);
588 : //! \overload
589 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1);
590 : //! \overload
591 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
592 : //! \overload
593 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
594 : //! \overload
595 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
596 : //! \overload
597 : ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
598 :
599 : //! Emits an instruction `instId` with the given `operands`.
600 : template<typename... Args>
601 : ASMJIT_FORCE_INLINE Error emit(InstId instId, Args&&... operands) {
602 77713 : return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
603 : }
604 :
605 : ASMJIT_FORCE_INLINE Error emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
606 : return _emitOpArray(instId, operands, opCount);
607 : }
608 :
609 : ASMJIT_FORCE_INLINE Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
610 : setInstOptions(inst.options());
611 : setExtraReg(inst.extraReg());
612 : return _emitOpArray(inst.id(), operands, opCount);
613 : }
614 :
615 : //! \cond INTERNAL
616 : //! Emits an instruction - all 6 operands must be defined.
617 : virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0;
618 : //! Emits instruction having operands stored in array.
619 : ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount);
620 : //! \endcond
621 :
622 : //! \}
623 :
624 : //! \name Emit Utilities
625 : //! \{
626 :
627 : ASMJIT_API Error emitProlog(const FuncFrame& frame);
628 : ASMJIT_API Error emitEpilog(const FuncFrame& frame);
629 : ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
630 :
631 : //! \}
632 :
633 : //! \name Align
634 : //! \{
635 :
636 : //! Aligns the current CodeBuffer position to the `alignment` specified.
637 : //!
638 : //! The sequence that is used to fill the gap between the aligned location and the current location depends on the
639 : //! align `mode`, see \ref AlignMode. The `alignment` argument specifies alignment in bytes, so for example when
640 : //! it's `32` it means that the code buffer will be aligned to `32` bytes.
641 : virtual Error align(AlignMode alignMode, uint32_t alignment) = 0;
642 :
643 : //! \}
644 :
645 : //! \name Embed
646 : //! \{
647 :
648 : //! Embeds raw data into the \ref CodeBuffer.
649 : virtual Error embed(const void* data, size_t dataSize) = 0;
650 :
651 : //! Embeds a typed data array.
652 : //!
653 : //! This is the most flexible function for embedding data as it allows to:
654 : //!
655 : //! - Assign a `typeId` to the data, so the emitter knows the type of items stored in `data`. Binary data should
656 : //! use \ref TypeId::kUInt8.
657 : //!
658 : //! - Repeat the given data `repeatCount` times, so the data can be used as a fill pattern for example, or as a
659 : //! pattern used by SIMD instructions.
660 : virtual Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0;
661 :
662 : //! Embeds int8_t `value` repeated by `repeatCount`.
663 : inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt8, &value, 1, repeatCount); }
664 : //! Embeds uint8_t `value` repeated by `repeatCount`.
665 : inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt8, &value, 1, repeatCount); }
666 : //! Embeds int16_t `value` repeated by `repeatCount`.
667 : inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt16, &value, 1, repeatCount); }
668 : //! Embeds uint16_t `value` repeated by `repeatCount`.
669 : inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt16, &value, 1, repeatCount); }
670 : //! Embeds int32_t `value` repeated by `repeatCount`.
671 : inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt32, &value, 1, repeatCount); }
672 : //! Embeds uint32_t `value` repeated by `repeatCount`.
673 : inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt32, &value, 1, repeatCount); }
674 : //! Embeds int64_t `value` repeated by `repeatCount`.
675 : inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt64, &value, 1, repeatCount); }
676 : //! Embeds uint64_t `value` repeated by `repeatCount`.
677 : inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt64, &value, 1, repeatCount); }
678 : //! Embeds a floating point `value` repeated by `repeatCount`.
679 : inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<float>::kTypeId), &value, 1, repeatCount); }
680 : //! Embeds a floating point `value` repeated by `repeatCount`.
681 : inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<double>::kTypeId), &value, 1, repeatCount); }
682 :
683 : //! Embeds a constant pool at the current offset by performing the following:
684 : //! 1. Aligns by using AlignMode::kData to the minimum `pool` alignment.
685 : //! 2. Binds the ConstPool label so it's bound to an aligned location.
686 : //! 3. Emits ConstPool content.
687 : virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
688 :
689 : //! Embeds an absolute `label` address as data.
690 : //!
691 : //! The `dataSize` is an optional argument that can be used to specify the size of the address data. If it's zero
692 : //! (default) the address size is deduced from the target architecture (either 4 or 8 bytes).
693 : virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0;
694 :
695 : //! Embeds a delta (distance) between the `label` and `base` calculating it as `label - base`. This function was
696 : //! designed to make it easier to embed lookup tables where each index is a relative distance of two labels.
697 : virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0;
698 :
699 : //! \}
700 :
701 : //! \name Comment
702 : //! \{
703 :
704 : //! Emits a comment stored in `data` with an optional `size` parameter.
705 : virtual Error comment(const char* data, size_t size = SIZE_MAX) = 0;
706 :
707 : //! Emits a formatted comment specified by `fmt` and variable number of arguments.
708 : ASMJIT_API Error commentf(const char* fmt, ...);
709 : //! Emits a formatted comment specified by `fmt` and `ap`.
710 : ASMJIT_API Error commentv(const char* fmt, va_list ap);
711 :
712 : //! \}
713 :
714 : //! \name Events
715 : //! \{
716 :
717 : //! Called after the emitter was attached to `CodeHolder`.
718 : virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0;
719 : //! Called after the emitter was detached from `CodeHolder`.
720 : virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0;
721 :
722 : //! Called when \ref CodeHolder has updated an important setting, which involves the following:
723 : //!
724 : //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been called).
725 : //!
726 : //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() has been called).
727 : //!
728 : //! This function ensures that the settings are properly propagated from \ref CodeHolder to the emitter.
729 : //!
730 : //! \note This function is virtual and can be overridden, however, if you do so, always call \ref
731 : //! BaseEmitter::onSettingsUpdated() within your own implementation to ensure that the emitter is
732 : //! in a consistent state.
733 : ASMJIT_API virtual void onSettingsUpdated() noexcept;
734 :
735 : //! \}
736 : };
737 :
738 : //! \}
739 :
740 : ASMJIT_END_NAMESPACE
741 :
742 : #endif // ASMJIT_CORE_EMITTER_H_INCLUDED
743 :
744 : #endif // __PLUMED_HAS_ASMJIT
|