1 // AsmJit - Machine code generation for C++ 2 // 3 // * Official AsmJit Home Page: https://asmjit.com 4 // * Official Github Repository: https://github.com/asmjit/asmjit 5 // 6 // Copyright (c) 2008-2020 The AsmJit Authors 7 // 8 // This software is provided 'as-is', without any express or implied 9 // warranty. In no event will the authors be held liable for any damages 10 // arising from the use of this software. 11 // 12 // Permission is granted to anyone to use this software for any purpose, 13 // including commercial applications, and to alter it and redistribute it 14 // freely, subject to the following restrictions: 15 // 16 // 1. The origin of this software must not be misrepresented; you must not 17 // claim that you wrote the original software. If you use this software 18 // in a product, an acknowledgment in the product documentation would be 19 // appreciated but is not required. 20 // 2. Altered source versions must be plainly marked as such, and must not be 21 // misrepresented as being the original software. 22 // 3. This notice may not be removed or altered from any source distribution. 23 24 #ifndef ASMJIT_CORE_COMPILER_H_INCLUDED 25 #define ASMJIT_CORE_COMPILER_H_INCLUDED 26 27 #include "../core/api-config.h" 28 #ifndef ASMJIT_NO_COMPILER 29 30 #include "../core/assembler.h" 31 #include "../core/builder.h" 32 #include "../core/constpool.h" 33 #include "../core/compilerdefs.h" 34 #include "../core/func.h" 35 #include "../core/inst.h" 36 #include "../core/operand.h" 37 #include "../core/support.h" 38 #include "../core/zone.h" 39 #include "../core/zonevector.h" 40 41 ASMJIT_BEGIN_NAMESPACE 42 43 // ============================================================================ 44 // [Forward Declarations] 45 // ============================================================================ 46 47 class JumpAnnotation; 48 class JumpNode; 49 class FuncNode; 50 class FuncRetNode; 51 class InvokeNode; 52 53 //! \addtogroup asmjit_compiler 54 //! \{ 55 56 // ============================================================================ 57 // [asmjit::BaseCompiler] 58 // ============================================================================ 59 60 //! Code emitter that uses virtual registers and performs register allocation. 61 //! 62 //! Compiler is a high-level code-generation tool that provides register 63 //! allocation and automatic handling of function calling conventions. It was 64 //! primarily designed for merging multiple parts of code into a function 65 //! without worrying about registers and function calling conventions. 66 //! 67 //! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 68 //! 64-bit code generation within a single code base. 69 //! 70 //! BaseCompiler is based on BaseBuilder and contains all the features it 71 //! provides. It means that the code it stores can be modified (removed, added, 72 //! injected) and analyzed. When the code is finalized the compiler can emit 73 //! the code into an Assembler to translate the abstract representation into a 74 //! machine code. 75 //! 76 //! Check out architecture specific compilers for more details and examples: 77 //! 78 //! - \ref x86::Compiler - X86/X64 compiler implementation. 79 class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder { 80 public: 81 ASMJIT_NONCOPYABLE(BaseCompiler) 82 typedef BaseBuilder Base; 83 84 //! Current function. 85 FuncNode* _func; 86 //! Allocates `VirtReg` objects. 87 Zone _vRegZone; 88 //! Stores array of `VirtReg` pointers. 89 ZoneVector<VirtReg*> _vRegArray; 90 //! Stores jump annotations. 91 ZoneVector<JumpAnnotation*> _jumpAnnotations; 92 93 //! Local constant pool, flushed at the end of each function. 94 ConstPoolNode* _localConstPool; 95 //! Global constant pool, flushed by `finalize()`. 96 ConstPoolNode* _globalConstPool; 97 98 //! \name Construction & Destruction 99 //! \{ 100 101 //! Creates a new `BaseCompiler` instance. 102 ASMJIT_API BaseCompiler() noexcept; 103 //! Destroys the `BaseCompiler` instance. 104 ASMJIT_API virtual ~BaseCompiler() noexcept; 105 106 //! \} 107 108 //! \name Function Management 109 //! \{ 110 111 //! Returns the current function. func()112 inline FuncNode* func() const noexcept { return _func; } 113 114 //! Creates a new \ref FuncNode. 115 ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature); 116 //! Creates a new \ref FuncNode adds it to the compiler. 117 ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature); 118 119 //! Creates a new \ref FuncRetNode. 120 ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); 121 //! Creates a new \ref FuncRetNode and adds it to the compiler. 122 ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); 123 124 //! Creates a new \ref FuncNode with the given `signature` and returns it. newFunc(const FuncSignature & signature)125 inline FuncNode* newFunc(const FuncSignature& signature) { 126 FuncNode* node; 127 _newFuncNode(&node, signature); 128 return node; 129 } 130 131 //! Creates a new \ref FuncNode with the given `signature`, adds it to the 132 //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it. addFunc(const FuncSignature & signature)133 inline FuncNode* addFunc(const FuncSignature& signature) { 134 FuncNode* node; 135 _addFuncNode(&node, signature); 136 return node; 137 } 138 139 //! Adds a function `node` to the instruction stream. 140 ASMJIT_API FuncNode* addFunc(FuncNode* func); 141 //! Emits a sentinel that marks the end of the current function. 142 ASMJIT_API Error endFunc(); 143 144 ASMJIT_API Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg); 145 146 //! Sets a function argument at `argIndex` to `reg`. setArg(size_t argIndex,const BaseReg & reg)147 inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); } 148 //! Sets a function argument at `argIndex` at `valueIndex` to `reg`. setArg(size_t argIndex,size_t valueIndex,const BaseReg & reg)149 inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); } 150 newRet(const Operand_ & o0,const Operand_ & o1)151 inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) { 152 FuncRetNode* node; 153 _newRetNode(&node, o0, o1); 154 return node; 155 } 156 addRet(const Operand_ & o0,const Operand_ & o1)157 inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) { 158 FuncRetNode* node; 159 _addRetNode(&node, o0, o1); 160 return node; 161 } 162 163 //! \} 164 165 //! \name Function Invocation 166 //! \{ 167 168 //! Creates a new \ref InvokeNode. 169 ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); 170 //! Creates a new \ref InvokeNode and adds it to Compiler. 171 ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); 172 173 //! Creates a new `InvokeNode`. newCall(uint32_t instId,const Operand_ & o0,const FuncSignature & signature)174 inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { 175 InvokeNode* node; 176 _newInvokeNode(&node, instId, o0, signature); 177 return node; 178 } 179 180 //! Adds a new `InvokeNode`. addCall(uint32_t instId,const Operand_ & o0,const FuncSignature & signature)181 inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { 182 InvokeNode* node; 183 _addInvokeNode(&node, instId, o0, signature); 184 return node; 185 } 186 187 //! \} 188 189 //! \name Virtual Registers 190 //! \{ 191 192 //! Creates a new virtual register representing the given `typeId` and `signature`. 193 //! 194 //! \note This function is public, but it's not generally recommended to be used 195 //! by AsmJit users, use architecture-specific `newReg()` functionality instead 196 //! or functions like \ref _newReg() and \ref _newRegFmt(). 197 ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name); 198 199 //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. 200 ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr); 201 202 //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. 203 //! 204 //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. 205 ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...); 206 207 //! Creates a new virtual register compatible with the provided reference register `ref`. 208 ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr); 209 210 //! Creates a new virtual register compatible with the provided reference register `ref`. 211 //! 212 //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. 213 ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...); 214 215 //! Tests whether the given `id` is a valid virtual register id. isVirtIdValid(uint32_t id)216 inline bool isVirtIdValid(uint32_t id) const noexcept { 217 uint32_t index = Operand::virtIdToIndex(id); 218 return index < _vRegArray.size(); 219 } 220 //! Tests whether the given `reg` is a virtual register having a valid id. isVirtRegValid(const BaseReg & reg)221 inline bool isVirtRegValid(const BaseReg& reg) const noexcept { 222 return isVirtIdValid(reg.id()); 223 } 224 225 //! Returns \ref VirtReg associated with the given `id`. virtRegById(uint32_t id)226 inline VirtReg* virtRegById(uint32_t id) const noexcept { 227 ASMJIT_ASSERT(isVirtIdValid(id)); 228 return _vRegArray[Operand::virtIdToIndex(id)]; 229 } 230 231 //! Returns \ref VirtReg associated with the given `reg`. virtRegByReg(const BaseReg & reg)232 inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); } 233 234 //! Returns \ref VirtReg associated with the given virtual register `index`. 235 //! 236 //! \note This is not the same as virtual register id. The conversion between 237 //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref 238 //! Operand_::indexToVirtId() functions. virtRegByIndex(uint32_t index)239 inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; } 240 241 //! Returns an array of all virtual registers managed by the Compiler. virtRegs()242 inline const ZoneVector<VirtReg*>& virtRegs() const noexcept { return _vRegArray; } 243 244 //! \name Stack 245 //! \{ 246 247 //! Creates a new stack of the given `size` and `alignment` and stores it to `out`. 248 //! 249 //! \note `name` can be used to give the stack a name, for debugging purposes. 250 ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr); 251 252 //! Updates the stack size of a stack created by `_newStack()` by its `virtId`. 253 ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0); 254 255 //! Updates the stack size of a stack created by `_newStack()`. 256 inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) { 257 return setStackSize(mem.id(), newSize, newAlignment); 258 } 259 260 //! \} 261 262 //! \name Constants 263 //! \{ 264 265 //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope). 266 //! 267 //! This function adds a constant of the given `size` to the built-in \ref 268 //! ConstPool and stores the reference to that constant to the `out` operand. 269 ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size); 270 271 //! \} 272 273 //! \name Miscellaneous 274 //! \{ 275 276 //! Rename the given virtual register `reg` to a formatted string `fmt`. 277 ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...); 278 279 //! \} 280 281 //! \name Jump Annotations 282 //! \{ 283 jumpAnnotations()284 inline const ZoneVector<JumpAnnotation*>& jumpAnnotations() const noexcept { 285 return _jumpAnnotations; 286 } 287 288 ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation); 289 ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation); 290 291 //! Returns a new `JumpAnnotation` instance, which can be used to aggregate 292 //! possible targets of a jump where the target is not a label, for example 293 //! to implement jump tables. 294 ASMJIT_API JumpAnnotation* newJumpAnnotation(); 295 296 //! \} 297 298 #ifndef ASMJIT_NO_DEPRECATED 299 ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future") alloc(BaseReg &)300 inline void alloc(BaseReg&) {} 301 ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future") spill(BaseReg &)302 inline void spill(BaseReg&) {} 303 #endif // !ASMJIT_NO_DEPRECATED 304 305 //! \name Events 306 //! \{ 307 308 ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; 309 ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; 310 311 //! \} 312 }; 313 314 // ============================================================================ 315 // [asmjit::JumpAnnotation] 316 // ============================================================================ 317 318 //! Jump annotation used to annotate jumps. 319 //! 320 //! \ref BaseCompiler allows to emit jumps where the target is either register 321 //! or memory operand. Such jumps cannot be trivially inspected, so instead of 322 //! doing heuristics AsmJit allows to annotate such jumps with possible targets. 323 //! Register allocator then use the annotation to construct control-flow, which 324 //! is then used by liveness analysis and other tools to prepare ground for 325 //! register allocation. 326 class JumpAnnotation { 327 public: 328 ASMJIT_NONCOPYABLE(JumpAnnotation) 329 330 //! Compiler that owns this JumpAnnotation. 331 BaseCompiler* _compiler; 332 //! Annotation identifier. 333 uint32_t _annotationId; 334 //! Vector of label identifiers, see \ref labelIds(). 335 ZoneVector<uint32_t> _labelIds; 336 JumpAnnotation(BaseCompiler * compiler,uint32_t annotationId)337 inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept 338 : _compiler(compiler), 339 _annotationId(annotationId) {} 340 341 //! Returns the compiler that owns this JumpAnnotation. compiler()342 inline BaseCompiler* compiler() const noexcept { return _compiler; } 343 //! Returns the annotation id. annotationId()344 inline uint32_t annotationId() const noexcept { return _annotationId; } 345 //! Returns a vector of label identifiers that lists all targets of the jump. labelIds()346 const ZoneVector<uint32_t>& labelIds() const noexcept { return _labelIds; } 347 348 //! Tests whether the given `label` is a target of this JumpAnnotation. hasLabel(const Label & label)349 inline bool hasLabel(const Label& label) const noexcept { return hasLabelId(label.id()); } 350 //! Tests whether the given `labelId` is a target of this JumpAnnotation. hasLabelId(uint32_t labelId)351 inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); } 352 353 //! Adds the `label` to the list of targets of this JumpAnnotation. addLabel(const Label & label)354 inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); } 355 //! Adds the `labelId` to the list of targets of this JumpAnnotation. addLabelId(uint32_t labelId)356 inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); } 357 }; 358 359 // ============================================================================ 360 // [asmjit::JumpNode] 361 // ============================================================================ 362 363 //! Jump instruction with \ref JumpAnnotation. 364 //! 365 //! \note This node should be only used to represent jump where the jump target 366 //! cannot be deduced by examining instruction operands. For example if the jump 367 //! target is register or memory location. This pattern is often used to perform 368 //! indirect jumps that use jump table, e.g. to implement `switch{}` statement. 369 class JumpNode : public InstNode { 370 public: ASMJIT_NONCOPYABLE(JumpNode)371 ASMJIT_NONCOPYABLE(JumpNode) 372 373 JumpAnnotation* _annotation; 374 375 //! \name Construction & Destruction 376 //! \{ 377 378 ASMJIT_INLINE JumpNode(BaseCompiler* cc, uint32_t instId, uint32_t options, uint32_t opCount, JumpAnnotation* annotation) noexcept 379 : InstNode(cc, instId, options, opCount, kBaseOpCapacity), 380 _annotation(annotation) { 381 setType(kNodeJump); 382 } 383 384 //! \} 385 386 //! \name Accessors 387 //! \{ 388 389 //! Tests whether this JumpNode has associated a \ref JumpAnnotation. hasAnnotation()390 inline bool hasAnnotation() const noexcept { return _annotation != nullptr; } 391 //! Returns the \ref JumpAnnotation associated with this jump, or `nullptr`. annotation()392 inline JumpAnnotation* annotation() const noexcept { return _annotation; } 393 //! Sets the \ref JumpAnnotation associated with this jump to `annotation`. setAnnotation(JumpAnnotation * annotation)394 inline void setAnnotation(JumpAnnotation* annotation) noexcept { _annotation = annotation; } 395 396 //! \} 397 }; 398 399 // ============================================================================ 400 // [asmjit::FuncNode] 401 // ============================================================================ 402 403 //! Function node represents a function used by \ref BaseCompiler. 404 //! 405 //! A function is composed of the following: 406 //! 407 //! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. 408 //! To get the entry, simply use \ref FuncNode::label(), which is the same 409 //! as \ref LabelNode::label(). 410 //! 411 //! - Function exit, which is represented by \ref FuncNode::exitNode(). A 412 //! helper function \ref FuncNode::exitLabel() exists and returns an exit 413 //! label instead of node. 414 //! 415 //! - Function \ref FuncNode::endNode() sentinel. This node marks the end of 416 //! a function - there should be no code that belongs to the function after 417 //! this node, but the Compiler doesn't enforce that at the moment. 418 //! 419 //! - Function detail, see \ref FuncNode::detail(). 420 //! 421 //! - Function frame, see \ref FuncNode::frame(). 422 //! 423 //! - Function arguments mapped to virtual registers, see \ref FuncNode::args(). 424 //! 425 //! In a node list, the function and its body looks like the following: 426 //! 427 //! \code{.unparsed} 428 //! [...] - Anything before the function. 429 //! 430 //! [FuncNode] - Entry point of the function, acts as a label as well. 431 //! <Prolog> - Prolog inserted by the register allocator. 432 //! {...} - Function body - user code basically. 433 //! [ExitLabel] - Exit label 434 //! <Epilog> - Epilog inserted by the register allocator. 435 //! <Return> - Return inserted by the register allocator. 436 //! {...} - Can contain data or user code (error handling, special cases, ...). 437 //! [FuncEnd] - End sentinel 438 //! 439 //! [...] - Anything after the function. 440 //! \endcode 441 //! 442 //! When a function is added to the compiler by \ref BaseCompiler::addFunc() it 443 //! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the 444 //! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called 445 //! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel 446 //! as a marker after additional code or data can be placed, and it's a common 447 //! practice. 448 class FuncNode : public LabelNode { 449 public: 450 ASMJIT_NONCOPYABLE(FuncNode) 451 452 //! Arguments pack. 453 struct ArgPack { 454 VirtReg* _data[Globals::kMaxValuePack]; 455 resetArgPack456 inline void reset() noexcept { 457 for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) 458 _data[valueIndex] = nullptr; 459 } 460 461 inline VirtReg*& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; } 462 inline VirtReg* const& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; } 463 }; 464 465 //! Function detail. 466 FuncDetail _funcDetail; 467 //! Function frame. 468 FuncFrame _frame; 469 //! Function exit label. 470 LabelNode* _exitNode; 471 //! Function end (sentinel). 472 SentinelNode* _end; 473 474 //! Argument packs. 475 ArgPack* _args; 476 477 //! \name Construction & Destruction 478 //! \{ 479 480 //! Creates a new `FuncNode` instance. 481 //! 482 //! Always use `BaseCompiler::addFunc()` to create `FuncNode`. FuncNode(BaseBuilder * cb)483 ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept 484 : LabelNode(cb), 485 _funcDetail(), 486 _frame(), 487 _exitNode(nullptr), 488 _end(nullptr), 489 _args(nullptr) { 490 setType(kNodeFunc); 491 } 492 493 //! \} 494 495 //! \{ 496 //! \name Accessors 497 498 //! Returns function exit `LabelNode`. exitNode()499 inline LabelNode* exitNode() const noexcept { return _exitNode; } 500 //! Returns function exit label. exitLabel()501 inline Label exitLabel() const noexcept { return _exitNode->label(); } 502 503 //! Returns "End of Func" sentinel. endNode()504 inline SentinelNode* endNode() const noexcept { return _end; } 505 506 //! Returns function declaration. detail()507 inline FuncDetail& detail() noexcept { return _funcDetail; } 508 //! Returns function declaration. detail()509 inline const FuncDetail& detail() const noexcept { return _funcDetail; } 510 511 //! Returns function frame. frame()512 inline FuncFrame& frame() noexcept { return _frame; } 513 //! Returns function frame. frame()514 inline const FuncFrame& frame() const noexcept { return _frame; } 515 516 //! Tests whether the function has a return value. hasRet()517 inline bool hasRet() const noexcept { return _funcDetail.hasRet(); } 518 //! Returns arguments count. argCount()519 inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } 520 521 //! Returns argument packs. argPacks()522 inline ArgPack* argPacks() const noexcept { return _args; } 523 524 //! Returns argument pack at `argIndex`. argPack(size_t argIndex)525 inline ArgPack& argPack(size_t argIndex) const noexcept { 526 ASMJIT_ASSERT(argIndex < argCount()); 527 return _args[argIndex]; 528 } 529 530 //! Sets argument at `argIndex`. setArg(size_t argIndex,VirtReg * vReg)531 inline void setArg(size_t argIndex, VirtReg* vReg) noexcept { 532 ASMJIT_ASSERT(argIndex < argCount()); 533 _args[argIndex][0] = vReg; 534 } 535 536 //! Sets argument at `argIndex` and `valueIndex`. setArg(size_t argIndex,size_t valueIndex,VirtReg * vReg)537 inline void setArg(size_t argIndex, size_t valueIndex, VirtReg* vReg) noexcept { 538 ASMJIT_ASSERT(argIndex < argCount()); 539 _args[argIndex][valueIndex] = vReg; 540 } 541 542 //! Resets argument pack at `argIndex`. resetArg(size_t argIndex)543 inline void resetArg(size_t argIndex) noexcept { 544 ASMJIT_ASSERT(argIndex < argCount()); 545 _args[argIndex].reset(); 546 } 547 548 //! Resets argument pack at `argIndex`. resetArg(size_t argIndex,size_t valueIndex)549 inline void resetArg(size_t argIndex, size_t valueIndex) noexcept { 550 ASMJIT_ASSERT(argIndex < argCount()); 551 _args[argIndex][valueIndex] = nullptr; 552 } 553 554 //! Returns function attributes. attributes()555 inline uint32_t attributes() const noexcept { return _frame.attributes(); } 556 //! Adds `attrs` to the function attributes. addAttributes(uint32_t attrs)557 inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); } 558 559 //! \} 560 }; 561 562 // ============================================================================ 563 // [asmjit::FuncRetNode] 564 // ============================================================================ 565 566 //! Function return, used by \ref BaseCompiler. 567 class FuncRetNode : public InstNode { 568 public: ASMJIT_NONCOPYABLE(FuncRetNode)569 ASMJIT_NONCOPYABLE(FuncRetNode) 570 571 //! \name Construction & Destruction 572 //! \{ 573 574 //! Creates a new `FuncRetNode` instance. 575 inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) { 576 _any._nodeType = kNodeFuncRet; 577 } 578 579 //! \} 580 }; 581 582 // ============================================================================ 583 // [asmjit::InvokeNode] 584 // ============================================================================ 585 586 //! Function invocation, used by \ref BaseCompiler. 587 class InvokeNode : public InstNode { 588 public: 589 ASMJIT_NONCOPYABLE(InvokeNode) 590 591 //! Operand pack provides multiple operands that can be associated with a 592 //! single return value of function argument. Sometims this is necessary to 593 //! express an argument or return value that requires multiple registers, for 594 //! example 64-bit value in 32-bit mode or passing / returning homogenous data 595 //! structures. 596 struct OperandPack { 597 //! Operands. 598 Operand_ _data[Globals::kMaxValuePack]; 599 600 //! Reset the pack by resetting all operands in the pack. resetOperandPack601 inline void reset() noexcept { 602 for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) 603 _data[valueIndex].reset(); 604 } 605 606 //! Returns an operand at the given `valueIndex`. 607 inline Operand& operator[](size_t valueIndex) noexcept { 608 ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack); 609 return _data[valueIndex].as<Operand>(); 610 } 611 612 //! Returns an operand at the given `valueIndex` (const). 613 const inline Operand& operator[](size_t valueIndex) const noexcept { 614 ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack); 615 return _data[valueIndex].as<Operand>(); 616 } 617 }; 618 619 //! Function detail. 620 FuncDetail _funcDetail; 621 //! Function return value(s). 622 OperandPack _rets; 623 //! Function arguments. 624 OperandPack* _args; 625 626 //! \name Construction & Destruction 627 //! \{ 628 629 //! Creates a new `InvokeNode` instance. InvokeNode(BaseBuilder * cb,uint32_t instId,uint32_t options)630 inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept 631 : InstNode(cb, instId, options, kBaseOpCapacity), 632 _funcDetail(), 633 _args(nullptr) { 634 setType(kNodeInvoke); 635 _resetOps(); 636 _rets.reset(); 637 addFlags(kFlagIsRemovable); 638 } 639 640 //! \} 641 642 //! \name Accessors 643 //! \{ 644 645 //! Sets the function signature. init(const FuncSignature & signature,const Environment & environment)646 inline Error init(const FuncSignature& signature, const Environment& environment) noexcept { 647 return _funcDetail.init(signature, environment); 648 } 649 650 //! Returns the function detail. detail()651 inline FuncDetail& detail() noexcept { return _funcDetail; } 652 //! Returns the function detail. detail()653 inline const FuncDetail& detail() const noexcept { return _funcDetail; } 654 655 //! Returns the target operand. target()656 inline Operand& target() noexcept { return _opArray[0].as<Operand>(); } 657 //! \overload target()658 inline const Operand& target() const noexcept { return _opArray[0].as<Operand>(); } 659 660 //! Returns the number of function return values. hasRet()661 inline bool hasRet() const noexcept { return _funcDetail.hasRet(); } 662 //! Returns the number of function arguments. argCount()663 inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } 664 665 //! Returns operand pack representing function return value(s). retPack()666 inline OperandPack& retPack() noexcept { return _rets; } 667 //! Returns operand pack representing function return value(s). retPack()668 inline const OperandPack& retPack() const noexcept { return _rets; } 669 670 //! Returns the return value at the given `valueIndex`. 671 inline Operand& ret(size_t valueIndex = 0) noexcept { return _rets[valueIndex]; } 672 //! \overload 673 inline const Operand& ret(size_t valueIndex = 0) const noexcept { return _rets[valueIndex]; } 674 675 //! Returns operand pack representing function return value(s). argPack(size_t argIndex)676 inline OperandPack& argPack(size_t argIndex) noexcept { 677 ASMJIT_ASSERT(argIndex < argCount()); 678 return _args[argIndex]; 679 } 680 //! \overload argPack(size_t argIndex)681 inline const OperandPack& argPack(size_t argIndex) const noexcept { 682 ASMJIT_ASSERT(argIndex < argCount()); 683 return _args[argIndex]; 684 } 685 686 //! Returns a function argument at the given `argIndex`. arg(size_t argIndex,size_t valueIndex)687 inline Operand& arg(size_t argIndex, size_t valueIndex) noexcept { 688 ASMJIT_ASSERT(argIndex < argCount()); 689 return _args[argIndex][valueIndex]; 690 } 691 //! \overload arg(size_t argIndex,size_t valueIndex)692 inline const Operand& arg(size_t argIndex, size_t valueIndex) const noexcept { 693 ASMJIT_ASSERT(argIndex < argCount()); 694 return _args[argIndex][valueIndex]; 695 } 696 697 //! Sets the function return value at `i` to `op`. _setRet(size_t valueIndex,const Operand_ & op)698 inline void _setRet(size_t valueIndex, const Operand_& op) noexcept { _rets[valueIndex] = op; } 699 //! Sets the function argument at `i` to `op`. _setArg(size_t argIndex,size_t valueIndex,const Operand_ & op)700 inline void _setArg(size_t argIndex, size_t valueIndex, const Operand_& op) noexcept { 701 ASMJIT_ASSERT(argIndex < argCount()); 702 _args[argIndex][valueIndex] = op; 703 } 704 705 //! Sets the function return value at `valueIndex` to `reg`. setRet(size_t valueIndex,const BaseReg & reg)706 inline void setRet(size_t valueIndex, const BaseReg& reg) noexcept { _setRet(valueIndex, reg); } 707 708 //! Sets the first function argument in a value-pack at `argIndex` to `reg`. setArg(size_t argIndex,const BaseReg & reg)709 inline void setArg(size_t argIndex, const BaseReg& reg) noexcept { _setArg(argIndex, 0, reg); } 710 //! Sets the first function argument in a value-pack at `argIndex` to `imm`. setArg(size_t argIndex,const Imm & imm)711 inline void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); } 712 713 //! Sets the function argument at `argIndex` and `valueIndex` to `reg`. setArg(size_t argIndex,size_t valueIndex,const BaseReg & reg)714 inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) noexcept { _setArg(argIndex, valueIndex, reg); } 715 //! Sets the function argument at `argIndex` and `valueIndex` to `imm`. setArg(size_t argIndex,size_t valueIndex,const Imm & imm)716 inline void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); } 717 718 //! \} 719 }; 720 721 // ============================================================================ 722 // [asmjit::FuncPass] 723 // ============================================================================ 724 725 //! Function pass extends \ref Pass with \ref FuncPass::runOnFunction(). 726 class ASMJIT_VIRTAPI FuncPass : public Pass { 727 public: 728 ASMJIT_NONCOPYABLE(FuncPass) 729 typedef Pass Base; 730 731 //! \name Construction & Destruction 732 //! \{ 733 734 ASMJIT_API FuncPass(const char* name) noexcept; 735 736 //! \} 737 738 //! \name Accessors 739 //! \{ 740 741 //! Returns the associated `BaseCompiler`. cc()742 inline BaseCompiler* cc() const noexcept { return static_cast<BaseCompiler*>(_cb); } 743 744 //! \} 745 746 //! \name Run 747 //! \{ 748 749 //! Calls `runOnFunction()` on each `FuncNode` node found. 750 ASMJIT_API Error run(Zone* zone, Logger* logger) override; 751 752 //! Called once per `FuncNode`. 753 virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; 754 755 //! \} 756 }; 757 758 //! \} 759 760 ASMJIT_END_NAMESPACE 761 762 #endif // !ASMJIT_NO_COMPILER 763 #endif // ASMJIT_CORE_COMPILER_H_INCLUDED 764