mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
Added basic abstractions to CondCode, Gp, and Vec
* Each architecture now provides r32() and r64() functions for
register casting
* Each architecture now provides v128() function for register
casting, returning just Vec to make writing cross platform
code easier
* Added some basic condition code abstractions so it can be used
interchangeably across architectures
* Added back unlicense to asmjit database (now it's dual licensed)
This commit is contained in:
@@ -4,17 +4,17 @@
|
||||
|
||||
* Please use [Issues](https://github.com/asmjit/asmjit/issues) page to report bugs or create a [pull request](https://github.com/asmjit/asmjit/pulls) if you have already fixed it.
|
||||
|
||||
* Make sure that when a bug is reported it provides as much information as possible to make it easy to either reproduce it locally or to at least guess where the problem could be. AsmJit is a low-level tool, which makes it very easy to emit code that would crash or not work as intended. Always use AsmJit's [Logging](https://asmjit.com/doc/group__asmjit__logging.html) and [Error Handling](https://asmjit.com/doc/group__asmjit__error__handling.html) features first to analyze whether there is not a simple to catch bug in your own code.
|
||||
* Make sure that when a bug is reported it provides as much information as possible to make it easy to either reproduce it locally or to at least guess where the problem could be. AsmJit is a low-level tool, which makes it very easy to emit code that would crash or not work as intended when executed. Always use AsmJit's [Logging](https://asmjit.com/doc/group__asmjit__logging.html) and [Error Handling](https://asmjit.com/doc/group__asmjit__error__handling.html) features first to analyze whether there is not a simple to catch bug in your own code.
|
||||
|
||||
* Don't be afraid to ask for help if you don't know how to solve a particular problem or in case it's unclear how to do it. The community would help if the problem is well described and has a solution. In general we always try to at least improve the documentation in case it doesn't provide enough information and users must ask for help.
|
||||
|
||||
### Asking questions
|
||||
|
||||
* We prefer GitHub issues to be used for reporting bugs or feature requests, but it's still okay to do that. Consider joining our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) to ask questions; it has an active community that can quickly.
|
||||
* We prefer GitHub issues to be used for reporting bugs or feature requests, but it's still okay to ask questions there as well. However, please consider joining our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) to ask questions; it has an active community that can quickly respond.
|
||||
|
||||
### Suggesting feature requests
|
||||
|
||||
* It's very likely that when using AsmJit you have found something that AsmJit doesn't provide and it would be handy to have it built-in. The [Issues](https://github.com/asmjit/asmjit/issues) page can be used to submit feature requests, but please keep in mind that AsmJit is a relatively small project and not all requested features will be accepted, especially if they are non-trivial, time consuming to implement, or the scope of the feature doesn't match AsmJit goals.
|
||||
* It's very likely that when using AsmJit you have found something that AsmJit doesn't provide, which would be handy to have as a built-in. The [Issues](https://github.com/asmjit/asmjit/issues) page can be used to submit feature requests, but please keep in mind that AsmJit is a relatively small project and not all requested features will be accepted, especially if they are non-trivial, time consuming to implement, or the scope of the feature doesn't match AsmJit goals.
|
||||
|
||||
* If you have already implemented the feature you are suggesting, please open a [pull request](https://github.com/asmjit/asmjit/pulls).
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
### Suggesting a documentation enhancement
|
||||
|
||||
* [AsmJit's documentation](https://asmjit.com/doc/index.html) is auto-generated from source code, so if you would like to improve it just open a [pull request](https://github.com/asmjit/asmjit/pulls) with your changes. The documentation uses [Doxygen](https://www.doxygen.nl/) as a front-end, so please use `\ref`, etc... to create links in documentation when necessary.
|
||||
* [AsmJit's documentation](https://asmjit.com/doc/index.html) is auto-generated from source code, so if you would like to improve it just open a [pull request](https://github.com/asmjit/asmjit/pulls) with your changes. The documentation uses [Doxygen](https://www.doxygen.nl/) as a front-end, so you can use `\ref` keyword to create links and other Doxygen keywords to enhance the documentation.
|
||||
|
||||
### Suggesting a website content enhancement
|
||||
|
||||
* [AsmJit's website](https://asmjit.com) is also generated, but not from public sources at the moment. If you did find an issue on the website you can either use contact on the [support page](https://asmjit.com/support.html) or just discuss the change in our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im). Alternatively, opening a regular issue is also okay.
|
||||
* [AsmJit's website](https://asmjit.com) is also generated, but not from public sources at the moment. If you did find an issue on the website you can either use contact information on the [support page](https://asmjit.com/support.html) or to discuss the change on our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im). Alternatively, opening a regular issue is also okay.
|
||||
|
||||
|
||||
## Coding Style & Consistency
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
* The code uses a soft limit of 120 characters per line (including documentation), but it's not enforced and it's okay to use more when it makes sense (for example defining tables, etc...).
|
||||
|
||||
* Since AsmJit doesn't use Exceptions nor RTTI the code cannot use containers provided by the C++ standard library as they use exception handling by design. In general, we try to only use a bare minimum from the C++ standard library to make it viable to use AsmJit even in C code bases where JIT complier is implemented in C++ ([Erlang](https://www.erlang.org/) can be seen as a great example).
|
||||
* Since AsmJit doesn't use Exceptions nor RTTI the code cannot use containers provided by the C++ standard library. In general, we try to only use a bare minimum from the C++ standard library to make it viable to use AsmJit even in C code bases where JIT complier is implemented in C++ ([Erlang](https://www.erlang.org/) can be seen as a great example).
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
* ABI changes happen, but they are usually accumulated and committed within a short time window to not break it often. In general we prefer to break ABI once a year, or once 6 months if there is something that has a high priority. There are no hard rules though.
|
||||
|
||||
* AsmJit uses an `inline namespace`, which should make it impossible to link to AsmJit library that is ABI incompatible. When ABI break happens AsmJit version and ABI namespace is changed, see [asmjit/core/api-config.h](./src/asmjit/core/api-config.h) for more details.
|
||||
* AsmJit uses an `inline namespace`, which should make it impossible to link to AsmJit library that is ABI incompatible. When ABI break happens both AsmJit version and ABI namespace are changed, see [asmjit/core/api-config.h](./src/asmjit/core/api-config.h) for more details.
|
||||
|
||||
* What is an ABI break?
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
|
||||
* Adding/removing virtual functions to/from classes, respectively
|
||||
|
||||
* Changing a signature of a public function or a class member function.
|
||||
* Changing a signature of a public function or a class member function (for example adding a parameter).
|
||||
|
||||
* Changing the value of an enum or global constant (for example instructions are now sorted by name, so adding a new instruction is an ABI break)
|
||||
* Changing the value of an enum or global constant (for example instructions are now sorted by name, so adding a new instruction breaks ABI)
|
||||
|
||||
* Possibly more, but these were the most common...
|
||||
|
||||
@@ -97,4 +97,6 @@
|
||||
|
||||
* Extending the functionality by using reserved members of a struct/class
|
||||
|
||||
* Adding new API including new structs and classes
|
||||
|
||||
* Changing anything that is internal and that doesn't leak to public headers
|
||||
|
||||
26
db/LICENSE.md
Normal file
26
db/LICENSE.md
Normal file
@@ -0,0 +1,26 @@
|
||||
AsmJit database is dual licensed under Zlib and Unlicense (public domain)
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
@@ -14,3 +14,8 @@ To Be Documented
|
||||
----------------
|
||||
|
||||
This project will be refactored and documented in the future.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
AsmJit database is dual licensed under Zlib (AsmJit license) or public domain. The database can be used for any purpose, not just by AsmJit.
|
||||
@@ -1,8 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
// SPDX-License-Identifier: (Zlib or Unlicense)
|
||||
|
||||
(function($scope, $as) {
|
||||
"use strict";
|
||||
|
||||
@@ -31,7 +31,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
|
||||
|
||||
// Format instruction options and instruction mnemonic.
|
||||
InstId instId = inst.realId();
|
||||
if (instId < Inst::_kIdCount)
|
||||
if (instId != Inst::kIdNone && instId < Inst::_kIdCount)
|
||||
ASMJIT_PROPAGATE(InstInternal::instIdToString(instId, sb));
|
||||
else
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
|
||||
|
||||
@@ -47,7 +47,7 @@ ASMJIT_FAVOR_SIZE Error initCallConv(CallConv& cc, CallConvId ccId, const Enviro
|
||||
cc.setSaveRestoreRegSize(RegGroup::kVec, 8);
|
||||
cc.setSaveRestoreAlignment(RegGroup::kGp, 16);
|
||||
cc.setSaveRestoreAlignment(RegGroup::kVec, 16);
|
||||
cc.setSaveRestoreAlignment(RegGroup::kExtraVirt2, 1);
|
||||
cc.setSaveRestoreAlignment(RegGroup::kMask, 1);
|
||||
cc.setSaveRestoreAlignment(RegGroup::kExtraVirt3, 1);
|
||||
cc.setPassedOrder(RegGroup::kGp, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||
cc.setPassedOrder(RegGroup::kVec, 0, 1, 2, 3, 4, 5, 6, 7);
|
||||
|
||||
@@ -55,8 +55,12 @@ public:
|
||||
|
||||
//! Cast this register to a 32-bit W register (returns a new operand).
|
||||
ASMJIT_INLINE_NODEBUG GpW w() const noexcept;
|
||||
//! \overload
|
||||
ASMJIT_INLINE_NODEBUG GpW r32() const noexcept;
|
||||
//! Cast this register to a 64-bit X register (returns a new operand).
|
||||
ASMJIT_INLINE_NODEBUG GpX x() const noexcept;
|
||||
//! \overload
|
||||
ASMJIT_INLINE_NODEBUG GpX r64() const noexcept;
|
||||
};
|
||||
|
||||
//! 32-bit general purpose W register (AArch64).
|
||||
@@ -67,6 +71,8 @@ class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM
|
||||
#ifndef _DOXYGEN
|
||||
ASMJIT_INLINE_NODEBUG GpW Gp::w() const noexcept { return GpW(id()); }
|
||||
ASMJIT_INLINE_NODEBUG GpX Gp::x() const noexcept { return GpX(id()); }
|
||||
ASMJIT_INLINE_NODEBUG GpW Gp::r32() const noexcept { return GpW(id()); }
|
||||
ASMJIT_INLINE_NODEBUG GpX Gp::r64() const noexcept { return GpX(id()); }
|
||||
#endif
|
||||
|
||||
//! Vector element type (AArch64).
|
||||
@@ -153,6 +159,17 @@ public:
|
||||
//! Cast this register to a 128-bit V register.
|
||||
ASMJIT_INLINE_NODEBUG VecV v() const noexcept;
|
||||
|
||||
//! Casts this register to b (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v8() const noexcept;
|
||||
//! Casts this register to h (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v16() const noexcept;
|
||||
//! Casts this register to s (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v32() const noexcept;
|
||||
//! Casts this register to d (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v64() const noexcept;
|
||||
//! Casts this register to q (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v128() const noexcept;
|
||||
|
||||
//! Cast this register to a 128-bit V.B[elementIndex] register.
|
||||
ASMJIT_INLINE_NODEBUG VecV b(uint32_t elementIndex) const noexcept;
|
||||
//! Cast this register to a 128-bit V.H[elementIndex] register.
|
||||
@@ -229,6 +246,12 @@ ASMJIT_INLINE_NODEBUG VecD Vec::d() const noexcept { return VecD(id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecV Vec::q() const noexcept { return VecV(id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecV Vec::v() const noexcept { return VecV(id()); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v8() const noexcept { return VecB(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v16() const noexcept { return VecH(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v32() const noexcept { return VecS(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v64() const noexcept { return VecD(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v128() const noexcept { return VecV(id()); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kB, elementIndex), id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kH, elementIndex), id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kS, elementIndex), id()); }
|
||||
|
||||
@@ -595,14 +595,14 @@ void ARMRAPass::onInit() noexcept {
|
||||
_archTraits = &ArchTraits::byArch(arch);
|
||||
_physRegCount.set(RegGroup::kGp, 32);
|
||||
_physRegCount.set(RegGroup::kVec, 32);
|
||||
_physRegCount.set(RegGroup::kExtraVirt2, 0);
|
||||
_physRegCount.set(RegGroup::kMask, 0);
|
||||
_physRegCount.set(RegGroup::kExtraVirt3, 0);
|
||||
_buildPhysIndex();
|
||||
|
||||
_availableRegCount = _physRegCount;
|
||||
_availableRegs[RegGroup::kGp] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kGp));
|
||||
_availableRegs[RegGroup::kVec] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kVec));
|
||||
_availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt2));
|
||||
_availableRegs[RegGroup::kMask] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kMask));
|
||||
_availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<uint32_t>(_physRegCount.get(RegGroup::kExtraVirt3));
|
||||
|
||||
_scratchRegIndexes[0] = uint8_t(27);
|
||||
|
||||
@@ -555,6 +555,12 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
||||
if (op.isImm()) {
|
||||
const Imm& i = op.as<Imm>();
|
||||
int64_t val = i.value();
|
||||
uint32_t predicate = i.predicate();
|
||||
|
||||
if (predicate) {
|
||||
ASMJIT_PROPAGATE(formatShiftOp(sb, ShiftOp(predicate)));
|
||||
ASMJIT_PROPAGATE(sb.append(' '));
|
||||
}
|
||||
|
||||
if (Support::test(flags, FormatFlags::kHexImms) && uint64_t(val) > 9) {
|
||||
ASMJIT_PROPAGATE(sb.append("0x"));
|
||||
|
||||
@@ -68,6 +68,17 @@ public:
|
||||
//! Gets whether the register is a VEC-V register (128-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
||||
|
||||
//! Gets whether the register is an 8-bit vector register or view, alias if \ref isVecB().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec8() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
||||
//! Gets whether the register is a 16-bit vector register or view, alias if \ref isVecH().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec16() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
|
||||
//! Gets whether the register is a 32-bit vector register or view, alias if \ref isVecS().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec32() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
|
||||
//! Gets whether the register is a 64-bit vector register or view, alias if \ref isVecD().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec64() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
||||
//! Gets whether the register is a 128-bit vector register or view, alias if \ref isVecQ().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec128() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
||||
|
||||
template<RegType kRegType>
|
||||
ASMJIT_INLINE_NODEBUG void setRegT(uint32_t id) noexcept {
|
||||
setSignature(RegTraits<kRegType>::kSignature);
|
||||
@@ -212,7 +223,7 @@ public:
|
||||
Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
|
||||
signature, base.id(), index.id(), 0) {}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG constexpr Mem(uint64_t base, Signature signature = Signature{0}) noexcept
|
||||
ASMJIT_INLINE_NODEBUG constexpr explicit Mem(uint64_t base, Signature signature = Signature{0}) noexcept
|
||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
||||
signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
|
||||
|
||||
|
||||
@@ -127,6 +127,13 @@ static ASMJIT_INLINE_NODEBUG bool isLogicalImm(uint64_t imm, uint32_t width) noe
|
||||
return encodeLogicalImm(imm, width, &dummy);
|
||||
}
|
||||
|
||||
//! Returns true if the given `imm` value is encodable as an immediate with `add` and `sub` instructions on AArch64.
|
||||
//! These two instructions can encode 12-bit immediate value optionally shifted left by 12 bits.
|
||||
ASMJIT_MAYBE_UNUSED
|
||||
static ASMJIT_INLINE_NODEBUG bool isAddSubImm(uint64_t imm) noexcept {
|
||||
return imm <= 0xFFFu || (imm & ~uint64_t(0xFFFu << 12)) == 0;
|
||||
}
|
||||
|
||||
//! Returns true if the given `imm` value is a byte mask. Byte mask has each byte part of the value set to either
|
||||
//! 0x00 or 0xFF. Some ARM instructions accept immediates that form a byte-mask and this function can be used to
|
||||
//! verify that the immediate is encodable before using the value.
|
||||
|
||||
@@ -42,21 +42,24 @@ enum class CondCode : uint8_t {
|
||||
kGT = 0x0Eu, //!< Z==0 & N==V (signed > )
|
||||
kLE = 0x0Fu, //!< Z==1 | N!=V (signed <=)
|
||||
|
||||
kSign = kMI, //!< Sign.
|
||||
kNotSign = kPL, //!< Not sign.
|
||||
|
||||
kOverflow = kVS, //!< Signed overflow.
|
||||
kNotOverflow = kVC, //!< Not signed overflow.
|
||||
kZero = kEQ, //!< Zero flag (alias to equal).
|
||||
kNotZero = kNE, //!< Not zero (alias to Not Equal).
|
||||
|
||||
kEqual = kEQ, //!< Equal `a == b`.
|
||||
kNotEqual = kNE, //!< Not Equal `a != b`.
|
||||
|
||||
kZero = kEQ, //!< Zero (alias to equal).
|
||||
kNotZero = kNE, //!< Not Zero (alias to Not Equal).
|
||||
kCarry = kCS, //!< Carry flag.
|
||||
kNotCarry = kCC, //!< Not carry.
|
||||
|
||||
kSign = kMI, //!< Sign flag.
|
||||
kNotSign = kPL, //!< Not sign.
|
||||
|
||||
kNegative = kMI, //!< Negative.
|
||||
kPositive = kPL, //!< Positive or zero.
|
||||
|
||||
kOverflow = kVS, //!< Signed overflow.
|
||||
kNotOverflow = kVC, //!< Not signed overflow.
|
||||
|
||||
kSignedLT = kLT, //!< Signed `a < b`.
|
||||
kSignedLE = kLE, //!< Signed `a <= b`.
|
||||
kSignedGT = kGT, //!< Signed `a > b`.
|
||||
@@ -67,11 +70,38 @@ enum class CondCode : uint8_t {
|
||||
kUnsignedGT = kHI, //!< Unsigned `a > b`.
|
||||
kUnsignedGE = kHS, //!< Unsigned `a >= b`.
|
||||
|
||||
kBTZero = kZero, //!< Tested bit is zero.
|
||||
kBTNotZero = kNotZero, //!< Tested bit is not zero.
|
||||
|
||||
kAlways = kAL, //!< No condition code (always).
|
||||
|
||||
kMaxValue = 0x0Fu //!< Maximum value of `CondCode`.
|
||||
};
|
||||
|
||||
|
||||
//! \cond
|
||||
static constexpr CondCode _reverseCondTable[] = {
|
||||
CondCode::kAL, // AL <- AL
|
||||
CondCode::kNA, // NA <- NA
|
||||
CondCode::kEQ, // EQ <- EQ
|
||||
CondCode::kNE, // NE <- NE
|
||||
CondCode::kLS, // LS <- CS
|
||||
CondCode::kHI, // HI <- LO
|
||||
CondCode::kMI, // MI <- MI
|
||||
CondCode::kPL, // PL <- PL
|
||||
CondCode::kVS, // VS <- VS
|
||||
CondCode::kVC, // VC <- VC
|
||||
CondCode::kLO, // LO <- HI
|
||||
CondCode::kCS, // CS <- LS
|
||||
CondCode::kLE, // LE <- GE
|
||||
CondCode::kGT, // GT <- LT
|
||||
CondCode::kLT, // LT <- GT
|
||||
CondCode::kGE // GE <- LE
|
||||
};
|
||||
//! \endcond
|
||||
|
||||
//! Reverses a condition code (reverses the corresponding operands of a comparison).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr CondCode reverseCond(CondCode cond) noexcept { return _reverseCondTable[uint8_t(cond)]; }
|
||||
//! Negates a condition code.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr CondCode negateCond(CondCode cond) noexcept { return CondCode(uint8_t(cond) ^ uint8_t(1)); }
|
||||
|
||||
|
||||
@@ -163,6 +163,8 @@ public:
|
||||
//!
|
||||
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
|
||||
ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* fmt, ...);
|
||||
//! \overload
|
||||
inline Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId) { return _newRegFmt(out, typeId, nullptr); }
|
||||
|
||||
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
||||
ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* name = nullptr);
|
||||
|
||||
@@ -173,8 +173,8 @@ enum class RegGroup : uint8_t {
|
||||
//! Describes X86 XMM|YMM|ZMM registers ARM/AArch64 V registers.
|
||||
kVec = 1,
|
||||
|
||||
//! Extra virtual group #2 that can be used by Compiler for register allocation.
|
||||
kExtraVirt2 = 2,
|
||||
//! Mask register group compatible with all backends that can use masking.
|
||||
kMask = 2,
|
||||
//! Extra virtual group #3 that can be used by Compiler for register allocation.
|
||||
kExtraVirt3 = 3,
|
||||
|
||||
@@ -187,8 +187,8 @@ enum class RegGroup : uint8_t {
|
||||
// X86 Specific Register Groups
|
||||
// ----------------------------
|
||||
|
||||
//! K register group (KReg) - maps to \ref RegGroup::kExtraVirt2 (X86, X86_64).
|
||||
kX86_K = kExtraVirt2,
|
||||
//! K register group (KReg) - maps to \ref RegGroup::kMask (X86, X86_64).
|
||||
kX86_K = kMask,
|
||||
//! MMX register group (MM) - maps to \ref RegGroup::kExtraVirt3 (X86, X86_64).
|
||||
kX86_MM = kExtraVirt3,
|
||||
|
||||
@@ -591,6 +591,22 @@ struct Operand_ {
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Equality
|
||||
//! \{
|
||||
|
||||
//! Tests whether the operand is 100% equal to `other` operand.
|
||||
//!
|
||||
//! \note This basically performs a binary comparison, if aby bit is
|
||||
//! different the operands are not equal.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool equals(const Operand_& other) const noexcept {
|
||||
return bool(unsigned(_signature == other._signature) &
|
||||
unsigned(_baseId == other._baseId ) &
|
||||
unsigned(_data[0] == other._data[0] ) &
|
||||
unsigned(_data[1] == other._data[1] ));
|
||||
}
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Accessors
|
||||
//! \{
|
||||
|
||||
@@ -609,6 +625,8 @@ struct Operand_ {
|
||||
//!
|
||||
//! \note Improper use of `setSignature()` can lead to hard-to-debug errors.
|
||||
ASMJIT_INLINE_NODEBUG void setSignature(const Signature& signature) noexcept { _signature = signature; }
|
||||
//! \overload
|
||||
ASMJIT_INLINE_NODEBUG void setSignature(uint32_t signature) noexcept { _signature._bits = signature; }
|
||||
|
||||
//! Returns the type of the operand, see `OpType`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr OperandType opType() const noexcept { return _signature.opType(); }
|
||||
@@ -643,32 +661,53 @@ struct Operand_ {
|
||||
//! not initialized.
|
||||
ASMJIT_INLINE_NODEBUG constexpr uint32_t id() const noexcept { return _baseId; }
|
||||
|
||||
//! Tests whether the operand is 100% equal to `other` operand.
|
||||
//!
|
||||
//! \note This basically performs a binary comparison, if aby bit is
|
||||
//! different the operands are not equal.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool equals(const Operand_& other) const noexcept {
|
||||
return bool(unsigned(_signature == other._signature) &
|
||||
unsigned(_baseId == other._baseId ) &
|
||||
unsigned(_data[0] == other._data[0] ) &
|
||||
unsigned(_data[1] == other._data[1] ));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register matching the given register `type`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegType type) const noexcept {
|
||||
return _signature.subset(Signature::kOpTypeMask | Signature::kRegTypeMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegType(type));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register of the provided register group `regGroup`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegGroup regGroup) const noexcept {
|
||||
return _signature.subset(Signature::kOpTypeMask | Signature::kRegGroupMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegGroup(regGroup));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is register and of register type `regType` and `regId`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegType regType, uint32_t regId) const noexcept { return isReg(regType) && _baseId == regId; }
|
||||
//! Tests whether the operand is register and of register group `regGroup` and `regId`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegGroup regGroup, uint32_t regId) const noexcept { return isReg(regGroup) && _baseId == regId; }
|
||||
|
||||
//! Tests whether the register is a general purpose register (any size).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp() const noexcept { return isReg(RegGroup::kGp); }
|
||||
//! Tests whether the register is a 32-bit general purpose register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp32() const noexcept { return isReg(RegType::kGp32); }
|
||||
//! Tests whether the register is a 64-bit general purpose register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp64() const noexcept { return isReg(RegType::kGp64); }
|
||||
|
||||
//! Tests whether the register is a vector register of any size.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec() const noexcept { return isReg(RegGroup::kVec); }
|
||||
//! Tests whether the register is an 8-bit vector register or view (AArch64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec8() const noexcept { return isReg(RegType::kVec8); }
|
||||
//! Tests whether the register is a 16-bit vector register or view (AArch64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec16() const noexcept { return isReg(RegType::kVec16); }
|
||||
//! Tests whether the register is a 32-bit vector register or view (AArch32, AArch64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec32() const noexcept { return isReg(RegType::kVec32); }
|
||||
//! Tests whether the register is a 64-bit vector register or view (AArch32, AArch64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec64() const noexcept { return isReg(RegType::kVec64); }
|
||||
//! Tests whether the register is a 128-bit vector register or view (AArch32, AArch64, X86, X86_64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec128() const noexcept { return isReg(RegType::kVec128); }
|
||||
//! Tests whether the register is a 256-bit vector register or view (X86, X86_64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec256() const noexcept { return isReg(RegType::kVec256); }
|
||||
//! Tests whether the register is a 512-bit vector register or view (X86, X86_64).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec512() const noexcept { return isReg(RegType::kVec512); }
|
||||
|
||||
//! Tests whether the register is a mask register of any size.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isMask() const noexcept { return isReg(RegGroup::kMask); }
|
||||
|
||||
//! Tests whether the operand is a register matching the given register `type`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isRegList(RegType type) const noexcept {
|
||||
return _signature.subset(Signature::kOpTypeMask | Signature::kRegTypeMask) == (Signature::fromOpType(OperandType::kRegList) | Signature::fromRegType(type));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is register and of register `type` and `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegType type, uint32_t regId) const noexcept {
|
||||
return isReg(type) && _baseId == regId;
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register or memory.
|
||||
//!
|
||||
//! \note This is useful on X86 and X86_64 architectures as many instructions support Reg/Mem operand combination.
|
||||
@@ -951,8 +990,10 @@ public:
|
||||
|
||||
//! Tests whether the register is a general purpose register (any size).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp() const noexcept { return isGroup(RegGroup::kGp); }
|
||||
//! Tests whether the register is a vector register.
|
||||
//! Tests whether the register is a vector register of any size.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec() const noexcept { return isGroup(RegGroup::kVec); }
|
||||
//! Tests whether the register is a mask register of any size.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isMask() const noexcept { return isGroup(RegGroup::kMask); }
|
||||
|
||||
using Operand_::isReg;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
uint32_t registerCount = arch == Arch::kX86 ? 8 : 16;
|
||||
_availableRegs[RegGroup::kGp] = Support::lsbMask<RegMask>(registerCount) & ~Support::bitMask(4u);
|
||||
_availableRegs[RegGroup::kVec] = Support::lsbMask<RegMask>(registerCount);
|
||||
_availableRegs[RegGroup::kExtraVirt2] = Support::lsbMask<RegMask>(8);
|
||||
_availableRegs[RegGroup::kMask] = Support::lsbMask<RegMask>(8);
|
||||
_availableRegs[RegGroup::kExtraVirt3] = Support::lsbMask<RegMask>(8);
|
||||
return kErrorOk;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
case Arch::kAArch64: {
|
||||
_availableRegs[RegGroup::kGp] = 0xFFFFFFFFu & ~Support::bitMask(18, 31u);
|
||||
_availableRegs[RegGroup::kVec] = 0xFFFFFFFFu;
|
||||
_availableRegs[RegGroup::kExtraVirt2] = 0;
|
||||
_availableRegs[RegGroup::kMask] = 0;
|
||||
_availableRegs[RegGroup::kExtraVirt3] = 0;
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
@@ -542,7 +542,7 @@ public:
|
||||
template<typename RegT>
|
||||
ASMJIT_INLINE_NODEBUG RegT newSimilarReg(const RegT& ref) {
|
||||
RegT reg(Globals::NoInit);
|
||||
_newReg(reg, ref);
|
||||
_newReg(®, ref);
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,20 +53,23 @@ enum class CondCode : uint8_t {
|
||||
kNLE = 0x0Fu, //!< ZF==0 & SF==OF (signed > )
|
||||
|
||||
kZero = kZ, //!< Zero flag.
|
||||
kNotZero = kNZ, //!< Non-zero flag.
|
||||
|
||||
kSign = kS, //!< Sign flag.
|
||||
kNotSign = kNS, //!< No sign flag.
|
||||
|
||||
kNegative = kS, //!< Sign flag.
|
||||
kPositive = kNS, //!< No sign flag.
|
||||
|
||||
kOverflow = kO, //!< Overflow (signed).
|
||||
kNotOverflow = kNO, //!< Not overflow (signed).
|
||||
kNotZero = kNZ, //!< Not zero.
|
||||
|
||||
kEqual = kE, //!< `a == b` (equal).
|
||||
kNotEqual = kNE, //!< `a != b` (not equal).
|
||||
|
||||
kCarry = kC, //!< Carry flag.
|
||||
kNotCarry = kNC, //!< Not carry.
|
||||
|
||||
kSign = kS, //!< Sign flag.
|
||||
kNotSign = kNS, //!< Not sign.
|
||||
|
||||
kNegative = kS, //!< Sign flag.
|
||||
kPositive = kNS, //!< Not sign.
|
||||
|
||||
kOverflow = kO, //!< Overflow (signed).
|
||||
kNotOverflow = kNO, //!< Not overflow (signed).
|
||||
|
||||
kSignedLT = kL, //!< `a < b` (signed).
|
||||
kSignedLE = kLE, //!< `a <= b` (signed).
|
||||
kSignedGT = kG, //!< `a > b` (signed).
|
||||
@@ -77,6 +80,9 @@ enum class CondCode : uint8_t {
|
||||
kUnsignedGT = kA, //!< `a > b` (unsigned).
|
||||
kUnsignedGE = kAE, //!< `a >= b` (unsigned).
|
||||
|
||||
kBTZero = kNC, //!< Tested bit is zero.
|
||||
kBTNotZero = kC, //!< Tested bit is non-zero.
|
||||
|
||||
kParityEven = kP, //!< Even parity flag.
|
||||
kParityOdd = kPO, //!< Odd parity flag.
|
||||
|
||||
|
||||
@@ -1315,6 +1315,10 @@ Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, siz
|
||||
|
||||
out->_operands[0].reset(W, size0);
|
||||
out->_operands[1].reset(R | MibRead, size1);
|
||||
|
||||
if (BaseReg::isVec(operands[0]))
|
||||
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
@@ -1366,6 +1370,9 @@ Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, siz
|
||||
out->_operands[0].reset(W, size0);
|
||||
out->_operands[1].reset(R, size1);
|
||||
|
||||
if (BaseReg::isVec(operands[0]))
|
||||
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
||||
|
||||
if (operands[0].isReg() && operands[1].isReg()) {
|
||||
if (instRmInfo.rmOpsMask & 0x1) {
|
||||
out->_operands[0].addOpFlags(RegM);
|
||||
|
||||
@@ -88,12 +88,26 @@ public:
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGpd() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpd>::kSignature); }
|
||||
//! Tests whether the register is a GPQ register (64-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGpq() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpq>::kSignature); }
|
||||
|
||||
//! Tests whether the register is a 32-bit general purpose register, alias of \ref isGpd().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp32() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpd>::kSignature); }
|
||||
//! Tests whether the register is a 64-bit general purpose register, alias of \ref isGpq()
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp64() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpq>::kSignature); }
|
||||
|
||||
//! Tests whether the register is an XMM register (128-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isXmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Xmm>::kSignature); }
|
||||
//! Tests whether the register is a YMM register (256-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isYmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Ymm>::kSignature); }
|
||||
//! Tests whether the register is a ZMM register (512-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isZmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Zmm>::kSignature); }
|
||||
|
||||
//! Tests whether the register is a 128-bit vector register, alias of \ref isXmm().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec128() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Xmm>::kSignature); }
|
||||
//! Tests whether the register is a 256-bit vector register, alias of \ref isYmm().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec256() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Ymm>::kSignature); }
|
||||
//! Tests whether the register is a 512-bit vector register, alias of \ref isZmm().
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec512() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Zmm>::kSignature); }
|
||||
|
||||
//! Tests whether the register is an MMX register (64-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isMm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Mm>::kSignature); }
|
||||
//! Tests whether the register is a K register (64-bit).
|
||||
@@ -242,11 +256,18 @@ class Vec : public Reg {
|
||||
|
||||
//! Casts this register to XMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Xmm xmm() const noexcept;
|
||||
//! Casts this register to YMM.
|
||||
//! Casts this register to YMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Ymm ymm() const noexcept;
|
||||
//! Casts this register to ZMM.
|
||||
//! Casts this register to ZMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Zmm zmm() const noexcept;
|
||||
|
||||
//! Casts this register to XMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v128() const noexcept;
|
||||
//! Casts this register to YMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v256() const noexcept;
|
||||
//! Casts this register to ZMM (clone).
|
||||
ASMJIT_INLINE_NODEBUG Vec v512() const noexcept;
|
||||
|
||||
//! Casts this register to a register that has half the size (or XMM if it's already XMM).
|
||||
ASMJIT_INLINE_NODEBUG Vec half() const noexcept {
|
||||
return Vec(type() == RegType::kX86_Zmm ? signatureOfT<RegType::kX86_Ymm>() : signatureOfT<RegType::kX86_Xmm>(), id());
|
||||
@@ -344,6 +365,9 @@ ASMJIT_INLINE_NODEBUG Gpq Gp::r64() const noexcept { return Gpq(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Xmm Vec::xmm() const noexcept { return Xmm(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Ymm Vec::ymm() const noexcept { return Ymm(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Zmm Vec::zmm() const noexcept { return Zmm(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v128() const noexcept { return Xmm(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v256() const noexcept { return Ymm(id()); }
|
||||
ASMJIT_INLINE_NODEBUG Vec Vec::v512() const noexcept { return Zmm(id()); }
|
||||
//! \endcond
|
||||
|
||||
//! \namespace asmjit::x86::regs
|
||||
|
||||
Reference in New Issue
Block a user