1 // [AsmJit] 2 // Machine Code Generation for C++. 3 // 4 // [License] 5 // Zlib - See LICENSE.md file in the package. 6 7 #ifndef _ASMJIT_CORE_COMPILER_H 8 #define _ASMJIT_CORE_COMPILER_H 9 10 #include "../core/build.h" 11 #ifndef ASMJIT_NO_COMPILER 12 13 #include "../core/assembler.h" 14 #include "../core/builder.h" 15 #include "../core/constpool.h" 16 #include "../core/func.h" 17 #include "../core/inst.h" 18 #include "../core/operand.h" 19 #include "../core/support.h" 20 #include "../core/zone.h" 21 #include "../core/zonevector.h" 22 23 ASMJIT_BEGIN_NAMESPACE 24 25 // ============================================================================ 26 // [Forward Declarations] 27 // ============================================================================ 28 29 struct RATiedReg; 30 class RAWorkReg; 31 32 class FuncNode; 33 class FuncRetNode; 34 class FuncCallNode; 35 36 //! \addtogroup asmjit_compiler 37 //! \{ 38 39 // ============================================================================ 40 // [asmjit::VirtReg] 41 // ============================================================================ 42 43 //! Virtual register data (BaseCompiler). 44 class VirtReg { 45 public: 46 ASMJIT_NONCOPYABLE(VirtReg) 47 48 //! Virtual register id. 49 uint32_t _id; 50 //! Virtual register info (signature). 51 RegInfo _info; 52 //! Virtual register size (can be smaller than `regInfo._size`). 53 uint32_t _virtSize; 54 //! Virtual register alignment (for spilling). 55 uint8_t _alignment; 56 //! Type-id. 57 uint8_t _typeId; 58 //! Virtual register weight for alloc/spill decisions. 59 uint8_t _weight; 60 //! True if this is a fixed register, never reallocated. 61 uint8_t _isFixed : 1; 62 //! True if the virtual register is only used as a stack (never accessed as register). 63 uint8_t _isStack : 1; 64 uint8_t _reserved : 6; 65 66 //! Virtual register name (user provided or automatically generated). 67 ZoneString<16> _name; 68 69 // ------------------------------------------------------------------------- 70 // The following members are used exclusively by RAPass. They are initialized 71 // when the VirtReg is created to NULL pointers and then changed during RAPass 72 // execution. RAPass sets them back to NULL before it returns. 73 // ------------------------------------------------------------------------- 74 75 //! Reference to `RAWorkReg`, used during register allocation. 76 RAWorkReg* _workReg; 77 78 //! \name Construction & Destruction 79 //! \{ 80 VirtReg(uint32_t id,uint32_t signature,uint32_t virtSize,uint32_t alignment,uint32_t typeId)81 inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept 82 : _id(id), 83 _virtSize(virtSize), 84 _alignment(uint8_t(alignment)), 85 _typeId(uint8_t(typeId)), 86 _weight(1), 87 _isFixed(false), 88 _isStack(false), 89 _reserved(0), 90 _name(), 91 _workReg(nullptr) { _info._signature = signature; } 92 93 //! \} 94 95 //! \name Accessors 96 //! \{ 97 98 //! Returns the virtual register id. id()99 inline uint32_t id() const noexcept { return _id; } 100 101 //! Returns the virtual register name. name()102 inline const char* name() const noexcept { return _name.data(); } 103 //! Returns the size of the virtual register name. nameSize()104 inline uint32_t nameSize() const noexcept { return _name.size(); } 105 106 //! Returns a register information that wraps the register signature. info()107 inline const RegInfo& info() const noexcept { return _info; } 108 //! Returns a virtual register type (maps to the physical register type as well). type()109 inline uint32_t type() const noexcept { return _info.type(); } 110 //! Returns a virtual register group (maps to the physical register group as well). group()111 inline uint32_t group() const noexcept { return _info.group(); } 112 113 //! Returns a real size of the register this virtual register maps to. 114 //! 115 //! For example if this is a 128-bit SIMD register used for a scalar single 116 //! precision floating point value then its virtSize would be 4, however, the 117 //! `regSize` would still say 16 (128-bits), because it's the smallest size 118 //! of that register type. regSize()119 inline uint32_t regSize() const noexcept { return _info.size(); } 120 121 //! Returns a register signature of this virtual register. signature()122 inline uint32_t signature() const noexcept { return _info.signature(); } 123 124 //! Returns the virtual register size. 125 //! 126 //! The virtual register size describes how many bytes the virtual register 127 //! needs to store its content. It can be smaller than the physical register 128 //! size, see `regSize()`. virtSize()129 inline uint32_t virtSize() const noexcept { return _virtSize; } 130 131 //! Returns the virtual register alignment. alignment()132 inline uint32_t alignment() const noexcept { return _alignment; } 133 134 //! Returns the virtual register type id, see `Type::Id`. typeId()135 inline uint32_t typeId() const noexcept { return _typeId; } 136 137 //! Returns the virtual register weight - the register allocator can use it 138 //! as explicit hint for alloc/spill decisions. weight()139 inline uint32_t weight() const noexcept { return _weight; } 140 //! Sets the virtual register weight (0 to 255) - the register allocator can 141 //! use it as explicit hint for alloc/spill decisions and initial bin-packing. setWeight(uint32_t weight)142 inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); } 143 144 //! Returns whether the virtual register is always allocated to a fixed 145 //! physical register (and never reallocated). 146 //! 147 //! \note This is only used for special purposes and it's mostly internal. isFixed()148 inline bool isFixed() const noexcept { return bool(_isFixed); } 149 150 //! Returns whether the virtual register is indeed a stack that only uses 151 //! the virtual register id for making it accessible. 152 //! 153 //! \note It's an error if a stack is accessed as a register. isStack()154 inline bool isStack() const noexcept { return bool(_isStack); } 155 hasWorkReg()156 inline bool hasWorkReg() const noexcept { return _workReg != nullptr; } workReg()157 inline RAWorkReg* workReg() const noexcept { return _workReg; } setWorkReg(RAWorkReg * workReg)158 inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; } resetWorkReg()159 inline void resetWorkReg() noexcept { _workReg = nullptr; } 160 161 //! \} 162 }; 163 164 // ============================================================================ 165 // [asmjit::BaseCompiler] 166 // ============================================================================ 167 168 //! Code emitter that uses virtual registers and performs register allocation. 169 //! 170 //! Compiler is a high-level code-generation tool that provides register 171 //! allocation and automatic handling of function calling conventions. It was 172 //! primarily designed for merging multiple parts of code into a function 173 //! without worrying about registers and function calling conventions. 174 //! 175 //! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit 176 //! code at the same time. 177 //! 178 //! BaseCompiler is based on BaseBuilder and contains all the features it 179 //! provides. It means that the code it stores can be modified (removed, added, 180 //! injected) and analyzed. When the code is finalized the compiler can emit 181 //! the code into an Assembler to translate the abstract representation into a 182 //! machine code. 183 class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder { 184 public: 185 ASMJIT_NONCOPYABLE(BaseCompiler) 186 typedef BaseBuilder Base; 187 188 //! Current function. 189 FuncNode* _func; 190 //! Allocates `VirtReg` objects. 191 Zone _vRegZone; 192 //! Stores array of `VirtReg` pointers. 193 ZoneVector<VirtReg*> _vRegArray; 194 195 //! Local constant pool, flushed at the end of each function. 196 ConstPoolNode* _localConstPool; 197 //! Global constant pool, flushed by `finalize()`. 198 ConstPoolNode* _globalConstPool; 199 200 //! \name Construction & Destruction 201 //! \{ 202 203 //! Creates a new `BaseCompiler` instance. 204 ASMJIT_API BaseCompiler() noexcept; 205 //! Destroys the `BaseCompiler` instance. 206 ASMJIT_API virtual ~BaseCompiler() noexcept; 207 208 //! \} 209 210 //! \name Function API 211 //! \{ 212 213 //! Returns the current function. func()214 inline FuncNode* func() const noexcept { return _func; } 215 216 //! Creates a new `FuncNode`. 217 ASMJIT_API FuncNode* newFunc(const FuncSignature& sign) noexcept; 218 //! Adds a function `node` to the stream. 219 ASMJIT_API FuncNode* addFunc(FuncNode* func); 220 //! Adds a new function. 221 ASMJIT_API FuncNode* addFunc(const FuncSignature& sign); 222 //! Emits a sentinel that marks the end of the current function. 223 ASMJIT_API Error endFunc(); 224 225 //! Sets a function argument at `argIndex` to `reg`. 226 ASMJIT_API Error setArg(uint32_t argIndex, const BaseReg& reg); 227 228 //! Creates a new `FuncRetNode`. 229 ASMJIT_API FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) noexcept; 230 //! Adds a new `FuncRetNode`. 231 ASMJIT_API FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) noexcept; 232 233 //! \} 234 235 //! \name Function Calls 236 //! \{ 237 238 //! Creates a new `FuncCallNode`. 239 ASMJIT_API FuncCallNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; 240 //! Adds a new `FuncCallNode`. 241 ASMJIT_API FuncCallNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; 242 243 //! \} 244 245 //! \name Virtual Registers 246 //! \{ 247 248 //! Creates a new virtual register representing the given `typeId` and `signature`. 249 ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept; 250 251 ASMJIT_API Error _newReg(BaseReg& out, uint32_t typeId, const char* name = nullptr); 252 ASMJIT_API Error _newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...); 253 254 ASMJIT_API Error _newReg(BaseReg& out, const BaseReg& ref, const char* name = nullptr); 255 ASMJIT_API Error _newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...); 256 257 //! Tests whether the given `id` is a valid virtual register id. isVirtIdValid(uint32_t id)258 inline bool isVirtIdValid(uint32_t id) const noexcept { 259 uint32_t index = Operand::virtIdToIndex(id); 260 return index < _vRegArray.size(); 261 } 262 //! Tests whether the given `reg` is a virtual register having a valid id. isVirtRegValid(const BaseReg & reg)263 inline bool isVirtRegValid(const BaseReg& reg) const noexcept { 264 return isVirtIdValid(reg.id()); 265 } 266 267 //! Returns `VirtReg` associated with the given `id`. virtRegById(uint32_t id)268 inline VirtReg* virtRegById(uint32_t id) const noexcept { 269 ASMJIT_ASSERT(isVirtIdValid(id)); 270 return _vRegArray[Operand::virtIdToIndex(id)]; 271 } 272 //! Returns `VirtReg` associated with the given `reg`. virtRegByReg(const BaseReg & reg)273 inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); } 274 //! Returns `VirtReg` associated with the given `index`. virtRegByIndex(uint32_t index)275 inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; } 276 277 //! Returns an array of all virtual registers managed by the Compiler. virtRegs()278 inline const ZoneVector<VirtReg*>& virtRegs() const noexcept { return _vRegArray; } 279 280 //! \name Stack 281 //! \{ 282 283 ASMJIT_API Error _newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name = nullptr); 284 285 //! \} 286 287 //! \name Constants 288 //! \{ 289 290 ASMJIT_API Error _newConst(BaseMem& out, uint32_t scope, const void* data, size_t size); 291 292 //! \} 293 294 //! \name Miscellaneous 295 //! \{ 296 297 //! Rename the given virtual register `reg` to a formatted string `fmt`. 298 //! 299 //! \note Only new name will appear in the logger. 300 ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...); 301 302 //! \} 303 304 // TODO: These should be removed alloc(BaseReg & reg)305 inline void alloc(BaseReg& reg) { ASMJIT_UNUSED(reg); } spill(BaseReg & reg)306 inline void spill(BaseReg& reg) { ASMJIT_UNUSED(reg); } 307 308 //! \name Events 309 //! \{ 310 311 ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; 312 ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; 313 314 //! \} 315 }; 316 317 // ============================================================================ 318 // [asmjit::FuncNode] 319 // ============================================================================ 320 321 //! Function entry (BaseCompiler). 322 class FuncNode : public LabelNode { 323 public: 324 ASMJIT_NONCOPYABLE(FuncNode) 325 326 //! Function detail. 327 FuncDetail _funcDetail; 328 //! Function frame. 329 FuncFrame _frame; 330 //! Function exit (label). 331 LabelNode* _exitNode; 332 //! Function end (sentinel). 333 SentinelNode* _end; 334 //! Arguments array as `VirtReg`. 335 VirtReg** _args; 336 337 //! \name Construction & Destruction 338 //! \{ 339 340 //! Creates a new `FuncNode` instance. 341 //! 342 //! Always use `BaseCompiler::addFunc()` to create `FuncNode`. FuncNode(BaseBuilder * cb)343 ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept 344 : LabelNode(cb), 345 _funcDetail(), 346 _frame(), 347 _exitNode(nullptr), 348 _end(nullptr), 349 _args(nullptr) { 350 setType(kNodeFunc); 351 } 352 353 //! \} 354 355 //! \{ 356 //! \name Accessors 357 358 //! Returns function exit `LabelNode`. exitNode()359 inline LabelNode* exitNode() const noexcept { return _exitNode; } 360 //! Returns function exit label. exitLabel()361 inline Label exitLabel() const noexcept { return _exitNode->label(); } 362 363 //! Returns "End of Func" sentinel. endNode()364 inline SentinelNode* endNode() const noexcept { return _end; } 365 366 //! Returns function declaration. detail()367 inline FuncDetail& detail() noexcept { return _funcDetail; } 368 //! Returns function declaration. detail()369 inline const FuncDetail& detail() const noexcept { return _funcDetail; } 370 371 //! Returns function frame. frame()372 inline FuncFrame& frame() noexcept { return _frame; } 373 //! Returns function frame. frame()374 inline const FuncFrame& frame() const noexcept { return _frame; } 375 376 //! Returns arguments count. argCount()377 inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } 378 //! Returns returns count. retCount()379 inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); } 380 381 //! Returns arguments list. args()382 inline VirtReg** args() const noexcept { return _args; } 383 384 //! Returns argument at `i`. arg(uint32_t i)385 inline VirtReg* arg(uint32_t i) const noexcept { 386 ASMJIT_ASSERT(i < argCount()); 387 return _args[i]; 388 } 389 390 //! Sets argument at `i`. setArg(uint32_t i,VirtReg * vReg)391 inline void setArg(uint32_t i, VirtReg* vReg) noexcept { 392 ASMJIT_ASSERT(i < argCount()); 393 _args[i] = vReg; 394 } 395 396 //! Resets argument at `i`. resetArg(uint32_t i)397 inline void resetArg(uint32_t i) noexcept { 398 ASMJIT_ASSERT(i < argCount()); 399 _args[i] = nullptr; 400 } 401 attributes()402 inline uint32_t attributes() const noexcept { return _frame.attributes(); } addAttributes(uint32_t attrs)403 inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); } 404 405 //! \} 406 }; 407 408 // ============================================================================ 409 // [asmjit::FuncRetNode] 410 // ============================================================================ 411 412 //! Function return (BaseCompiler). 413 class FuncRetNode : public InstNode { 414 public: ASMJIT_NONCOPYABLE(FuncRetNode)415 ASMJIT_NONCOPYABLE(FuncRetNode) 416 417 //! \name Construction & Destruction 418 //! \{ 419 420 //! Creates a new `FuncRetNode` instance. 421 inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) { 422 _any._nodeType = kNodeFuncRet; 423 } 424 425 //! \} 426 }; 427 428 // ============================================================================ 429 // [asmjit::FuncCallNode] 430 // ============================================================================ 431 432 //! Function call (BaseCompiler). 433 class FuncCallNode : public InstNode { 434 public: 435 ASMJIT_NONCOPYABLE(FuncCallNode) 436 437 //! Function detail. 438 FuncDetail _funcDetail; 439 //! Returns. 440 Operand_ _rets[2]; 441 //! Arguments. 442 Operand_* _args; 443 444 //! \name Construction & Destruction 445 //! \{ 446 447 //! Creates a new `FuncCallNode` instance. FuncCallNode(BaseBuilder * cb,uint32_t instId,uint32_t options)448 inline FuncCallNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept 449 : InstNode(cb, instId, options, kBaseOpCapacity), 450 _funcDetail(), 451 _args(nullptr) { 452 setType(kNodeFuncCall); 453 _resetOps(); 454 _rets[0].reset(); 455 _rets[1].reset(); 456 addFlags(kFlagIsRemovable); 457 } 458 459 //! \} 460 461 //! \name Accessors 462 //! \{ 463 464 //! Sets the function signature. setSignature(const FuncSignature & sign)465 inline Error setSignature(const FuncSignature& sign) noexcept { 466 return _funcDetail.init(sign); 467 } 468 469 //! Returns the function detail. detail()470 inline FuncDetail& detail() noexcept { return _funcDetail; } 471 //! Returns the function detail. detail()472 inline const FuncDetail& detail() const noexcept { return _funcDetail; } 473 474 //! Returns the target operand. target()475 inline Operand& target() noexcept { return _opArray[0].as<Operand>(); } 476 //! \overload target()477 inline const Operand& target() const noexcept { return _opArray[0].as<Operand>(); } 478 479 //! Returns the number of function arguments. argCount()480 inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); } 481 //! Returns the number of function return values. retCount()482 inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); } 483 484 //! Returns the return value at `i`. 485 inline Operand& ret(uint32_t i = 0) noexcept { 486 ASMJIT_ASSERT(i < 2); 487 return _rets[i].as<Operand>(); 488 } 489 //! \overload 490 inline const Operand& ret(uint32_t i = 0) const noexcept { 491 ASMJIT_ASSERT(i < 2); 492 return _rets[i].as<Operand>(); 493 } 494 495 //! Returns the function argument at `i`. arg(uint32_t i)496 inline Operand& arg(uint32_t i) noexcept { 497 ASMJIT_ASSERT(i < kFuncArgCountLoHi); 498 return _args[i].as<Operand>(); 499 } 500 //! \overload arg(uint32_t i)501 inline const Operand& arg(uint32_t i) const noexcept { 502 ASMJIT_ASSERT(i < kFuncArgCountLoHi); 503 return _args[i].as<Operand>(); 504 } 505 506 //! Sets the function argument at `i` to `op`. 507 ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept; 508 //! Sets the function return value at `i` to `op`. 509 ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept; 510 511 //! Sets the function argument at `i` to `reg`. setArg(uint32_t i,const BaseReg & reg)512 inline bool setArg(uint32_t i, const BaseReg& reg) noexcept { return _setArg(i, reg); } 513 //! Sets the function argument at `i` to `imm`. setArg(uint32_t i,const Imm & imm)514 inline bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); } 515 516 //! Sets the function return value at `i` to `var`. setRet(uint32_t i,const BaseReg & reg)517 inline bool setRet(uint32_t i, const BaseReg& reg) noexcept { return _setRet(i, reg); } 518 519 //! \} 520 }; 521 522 // ============================================================================ 523 // [asmjit::FuncPass] 524 // ============================================================================ 525 526 class ASMJIT_VIRTAPI FuncPass : public Pass { 527 public: 528 ASMJIT_NONCOPYABLE(FuncPass) 529 typedef Pass Base; 530 531 //! \name Construction & Destruction 532 //! \{ 533 534 ASMJIT_API FuncPass(const char* name) noexcept; 535 536 //! \} 537 538 //! \name Accessors 539 //! \{ 540 541 //! Returns the associated `BaseCompiler`. cc()542 inline BaseCompiler* cc() const noexcept { return static_cast<BaseCompiler*>(_cb); } 543 544 //! \} 545 546 //! \name Run 547 //! \{ 548 549 //! Calls `runOnFunction()` on each `FuncNode` node found. 550 ASMJIT_API Error run(Zone* zone, Logger* logger) noexcept override; 551 552 //! Called once per `FuncNode`. 553 virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept = 0; 554 555 //! \} 556 }; 557 558 //! \} 559 560 ASMJIT_END_NAMESPACE 561 562 #endif // !ASMJIT_NO_COMPILER 563 #endif // _ASMJIT_CORE_COMPILER_H 564