From 2cfa686ebdc19e181caed766a4772813c898b5af Mon Sep 17 00:00:00 2001 From: kobalicek Date: Mon, 13 Dec 2021 23:58:02 +0100 Subject: [API] Fixed most static analysis issues reported by clang [Bug] Workarounded GCC 11 issue affecting unaligned loads/stores (most likely a compiler bug) --- .github/workflows/build.yml | 14 +++++++++- src/asmjit/core.h | 6 +++-- src/asmjit/core/api-config.h | 27 ++++++++++++++++++++ src/asmjit/core/archtraits.cpp | 2 +- src/asmjit/core/builder.cpp | 13 +++++----- src/asmjit/core/builder.h | 40 +++++++++++++---------------- src/asmjit/core/codeholder.cpp | 2 ++ src/asmjit/core/compiler.cpp | 10 ++++++-- src/asmjit/core/compiler.h | 40 ++++++++++++++--------------- src/asmjit/core/compilerdefs.h | 2 +- src/asmjit/core/emitter.h | 4 +-- src/asmjit/core/funcargscontext.cpp | 1 + src/asmjit/core/funcargscontext_p.h | 2 +- src/asmjit/core/operand.h | 51 +++++++++++++++---------------------- src/asmjit/core/rapass.cpp | 4 ++- src/asmjit/core/string.cpp | 20 +++++++-------- src/asmjit/core/string.h | 12 ++++----- src/asmjit/core/support.h | 12 ++++++--- src/asmjit/core/zonetree.h | 27 +++++++++++++++----- src/asmjit/x86/x86archtraits_p.h | 4 +-- src/asmjit/x86/x86emithelper.cpp | 4 ++- src/asmjit/x86/x86operand.h | 26 +++++++++---------- src/asmjit/x86/x86rapass.cpp | 8 +++--- 23 files changed, 195 insertions(+), 136 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d7877f1..94d6796 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: - { title: "diag-asan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "address" } - { title: "diag-ubsan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "undefined" } - { title: "diag-valgrind" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "valgrind" } - - { title: "diag-scan-build", os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON", diagnostics: "scan-build" } + - { title: "diag-scan-build", os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , diagnostics: "scan-build" } - { title: "no-deprecated" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_DEPRECATED=1" } - { title: "no-intrinsics" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_INTRINSICS=1" } @@ -67,6 +67,10 @@ jobs: - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-11" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-11" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-11" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-11" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } @@ -79,6 +83,14 @@ jobs: - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-11", arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-11", arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-11", arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-11", arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-12", arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-12", arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-12", arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } + - { title: "linux" , os: "ubuntu-20.04" , cc: "clang-12", arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } - { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" } - { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" } diff --git a/src/asmjit/core.h b/src/asmjit/core.h index 58a380d..32f208f 100644 --- a/src/asmjit/core.h +++ b/src/asmjit/core.h @@ -7,7 +7,7 @@ #define ASMJIT_CORE_H_INCLUDED //! Root namespace used by AsmJit. -namespace asmjit {} +namespace asmjit { //! \mainpage API Reference //! @@ -240,7 +240,7 @@ namespace asmjit {} //! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED` //! it's not using anything, which was deprecated. //! -//! ### Changes committed at XXXX-XX-XX +//! ### Changes committed at 2021-12-13 //! //! Core changes: //! @@ -1812,6 +1812,8 @@ namespace asmjit {} //! \brief Register allocator internals. //! \endcond +} // {asmjit} + #include "asmjit-scope-begin.h" #include "core/archtraits.h" #include "core/assembler.h" diff --git a/src/asmjit/core/api-config.h b/src/asmjit/core/api-config.h index 7407c57..3c4f8b2 100644 --- a/src/asmjit/core/api-config.h +++ b/src/asmjit/core/api-config.h @@ -374,6 +374,33 @@ namespace asmjit { #define ASMJIT_MAYBE_UNUSED #endif +#if defined(__clang_major__) && __clang_major__ >= 4 && !defined(_DOXYGEN) + // NOTE: Clang allows to apply this attribute to function arguments, which is what we want. Once GCC decides to + // support this use, we will enable it for GCC as well. However, until that, it will be clang only, which is + // what we need for static analysis. + #define ASMJIT_NONNULL(FUNCTION_ARGUMENT) FUNCTION_ARGUMENT __attribute__((__nonnull__)) +#else + #define ASMJIT_NONNULL(FUNCTION_ARGUMENT) FUNCTION_ARGUMENT +#endif + +//! \def ASMJIT_ASSUME(...) +//! +//! Macro that tells the C/C++ compiler that the expression `...` evaluates to true. +//! +//! This macro has two purposes: +//! +//! 1. Enable optimizations that would not be possible without the assumption. +//! 2. Hint static analysis tools that a certain condition is true to prevent false positives. +#if defined(__clang__) + #define ASMJIT_ASSUME(...) __builtin_assume(__VA_ARGS__) +#elif defined(__GNUC__) + #define ASMJIT_ASSUME(...) do { if (!(__VA_ARGS__)) __builtin_unreachable(); } while (0) +#elif defined(_MSC_VER) + #define ASMJIT_ASSUME(...) __assume(__VA_ARGS__) +#else + #define ASMJIT_ASSUME(...) (void)0 +#endif + //! \def ASMJIT_LIKELY(...) //! //! Condition is likely to be taken (mostly error handling and edge cases). diff --git a/src/asmjit/core/archtraits.cpp b/src/asmjit/core/archtraits.cpp index 8b79ee2..b83d930 100644 --- a/src/asmjit/core/archtraits.cpp +++ b/src/asmjit/core/archtraits.cpp @@ -39,7 +39,7 @@ static const constexpr ArchTraits noArchTraits = { }}, // RegTypeToSignature. - #define V(index) { OperandSignature(0) } + #define V(index) OperandSignature{0} {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, #undef V diff --git a/src/asmjit/core/builder.cpp b/src/asmjit/core/builder.cpp index 108a8b0..e3767a1 100644 --- a/src/asmjit/core/builder.cpp +++ b/src/asmjit/core/builder.cpp @@ -146,7 +146,6 @@ Error BaseBuilder::newCommentNode(CommentNode** out, const char* data, size_t si } BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept { - ASMJIT_ASSERT(node); ASMJIT_ASSERT(!node->_prev); ASMJIT_ASSERT(!node->_next); ASMJIT_ASSERT(!node->isActive()); @@ -185,9 +184,6 @@ BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept { } BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept { - ASMJIT_ASSERT(node); - ASMJIT_ASSERT(ref); - ASMJIT_ASSERT(!node->_prev); ASMJIT_ASSERT(!node->_next); @@ -211,11 +207,9 @@ BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept { } BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept { - ASMJIT_ASSERT(node != nullptr); ASMJIT_ASSERT(!node->_prev); ASMJIT_ASSERT(!node->_next); ASMJIT_ASSERT(!node->isActive()); - ASMJIT_ASSERT(ref != nullptr); ASMJIT_ASSERT(ref->isActive()); BaseNode* prev = ref->prev(); @@ -357,6 +351,7 @@ Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) { Error BaseBuilder::section(Section* section) { SectionNode* node; ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id())); + ASMJIT_ASSUME(node != nullptr); if (!node->isActive()) { // Insert the section at the end if it was not part of the code. @@ -649,6 +644,7 @@ Error BaseBuilder::align(AlignMode alignMode, uint32_t alignment) { AlignNode* node; ASMJIT_PROPAGATE(newAlignNode(&node, alignMode, alignment)); + ASMJIT_ASSUME(node != nullptr); addNode(node); return kErrorOk; @@ -663,6 +659,7 @@ Error BaseBuilder::embed(const void* data, size_t dataSize) { EmbedDataNode* node; ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, data, dataSize)); + ASMJIT_ASSUME(node != nullptr); addNode(node); return kErrorOk; @@ -674,6 +671,7 @@ Error BaseBuilder::embedDataArray(TypeId typeId, const void* data, size_t itemCo EmbedDataNode* node; ASMJIT_PROPAGATE(newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat)); + ASMJIT_ASSUME(node != nullptr); addNode(node); return kErrorOk; @@ -691,6 +689,7 @@ Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { EmbedDataNode* node; ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, nullptr, pool.size())); + ASMJIT_ASSUME(node != nullptr); pool.fill(node->data()); addNode(node); @@ -744,6 +743,7 @@ Error BaseBuilder::comment(const char* data, size_t size) { CommentNode* node; ASMJIT_PROPAGATE(newCommentNode(&node, data, size)); + ASMJIT_ASSUME(node != nullptr); addNode(node); return kErrorOk; @@ -848,6 +848,7 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept { return err; } + ASMJIT_ASSUME(initialSection != nullptr); _cursor = initialSection; _firstNode = initialSection; _lastNode = initialSection; diff --git a/src/asmjit/core/builder.h b/src/asmjit/core/builder.h index 545471d..8376986 100644 --- a/src/asmjit/core/builder.h +++ b/src/asmjit/core/builder.h @@ -191,7 +191,7 @@ public: //! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler //! is destroyed it destroys all nodes it created so no manual memory management is required. template - inline Error _newNodeT(T** out, Args&&... args) { + inline Error _newNodeT(T** ASMJIT_NONNULL(out), Args&&... args) { *out = _allocator.newT(this, std::forward(args)...); if (ASMJIT_UNLIKELY(!*out)) return reportError(DebugUtils::errored(kErrorOutOfMemory)); @@ -199,26 +199,26 @@ public: } //! Creates a new \ref InstNode. - ASMJIT_API Error newInstNode(InstNode** out, InstId instId, InstOptions instOptions, uint32_t opCount); + ASMJIT_API Error newInstNode(InstNode** ASMJIT_NONNULL(out), InstId instId, InstOptions instOptions, uint32_t opCount); //! Creates a new \ref LabelNode. - ASMJIT_API Error newLabelNode(LabelNode** out); + ASMJIT_API Error newLabelNode(LabelNode** ASMJIT_NONNULL(out)); //! Creates a new \ref AlignNode. - ASMJIT_API Error newAlignNode(AlignNode** out, AlignMode alignMode, uint32_t alignment); + ASMJIT_API Error newAlignNode(AlignNode** ASMJIT_NONNULL(out), AlignMode alignMode, uint32_t alignment); //! Creates a new \ref EmbedDataNode. - ASMJIT_API Error newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1); + ASMJIT_API Error newEmbedDataNode(EmbedDataNode** ASMJIT_NONNULL(out), TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1); //! Creates a new \ref ConstPoolNode. - ASMJIT_API Error newConstPoolNode(ConstPoolNode** out); + ASMJIT_API Error newConstPoolNode(ConstPoolNode** ASMJIT_NONNULL(out)); //! Creates a new \ref CommentNode. - ASMJIT_API Error newCommentNode(CommentNode** out, const char* data, size_t size); + ASMJIT_API Error newCommentNode(CommentNode** ASMJIT_NONNULL(out), const char* data, size_t size); //! Adds `node` after the current and sets the current node to the given `node`. - ASMJIT_API BaseNode* addNode(BaseNode* node) noexcept; + ASMJIT_API BaseNode* addNode(BaseNode* ASMJIT_NONNULL(node)) noexcept; //! Inserts the given `node` after `ref`. - ASMJIT_API BaseNode* addAfter(BaseNode* node, BaseNode* ref) noexcept; + ASMJIT_API BaseNode* addAfter(BaseNode* ASMJIT_NONNULL(node), BaseNode* ASMJIT_NONNULL(ref)) noexcept; //! Inserts the given `node` before `ref`. - ASMJIT_API BaseNode* addBefore(BaseNode* node, BaseNode* ref) noexcept; + ASMJIT_API BaseNode* addBefore(BaseNode* ASMJIT_NONNULL(node), BaseNode* ASMJIT_NONNULL(ref)) noexcept; //! Removes the given `node`. - ASMJIT_API BaseNode* removeNode(BaseNode* node) noexcept; + ASMJIT_API BaseNode* removeNode(BaseNode* ASMJIT_NONNULL(node)) noexcept; //! Removes multiple nodes. ASMJIT_API void removeNodes(BaseNode* first, BaseNode* last) noexcept; @@ -227,9 +227,7 @@ public: //! When the Builder/Compiler is created it automatically creates a '.text' \ref SectionNode, which will be the //! initial one. When instructions are added they are always added after the cursor and the cursor is changed //! to be that newly added node. Use `setCursor()` to change where new nodes are inserted. - inline BaseNode* cursor() const noexcept { - return _cursor; - } + inline BaseNode* cursor() const noexcept { return _cursor; } //! Sets the current node to `node` and return the previous one. ASMJIT_API BaseNode* setCursor(BaseNode* node) noexcept; @@ -238,9 +236,7 @@ public: //! //! Only use this function if you are concerned about performance and want this inlined (for example if you set //! the cursor in a loop, etc...). - inline void _setCursor(BaseNode* node) noexcept { - _cursor = node; - } + inline void _setCursor(BaseNode* node) noexcept { _cursor = node; } //! \} @@ -264,9 +260,9 @@ public: //! //! \remarks This function will either get the existing `SectionNode` or create it in case it wasn't created before. //! You can check whether a section has a registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`. - ASMJIT_API Error sectionNodeOf(SectionNode** out, uint32_t sectionId); + ASMJIT_API Error sectionNodeOf(SectionNode** ASMJIT_NONNULL(out), uint32_t sectionId); - ASMJIT_API Error section(Section* section) override; + ASMJIT_API Error section(Section* ASMJIT_NONNULL(section)) override; //! Returns whether the section links of active section nodes are dirty. You can update these links by calling //! `updateSectionLinks()` in such case. @@ -300,10 +296,10 @@ public: //! //! \remarks This function will either get the existing `LabelNode` or create it in case it wasn't created before. //! You can check whether a label has a registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode(). - ASMJIT_API Error labelNodeOf(LabelNode** out, uint32_t labelId); + ASMJIT_API Error labelNodeOf(LabelNode** ASMJIT_NONNULL(out), uint32_t labelId); //! \overload - inline Error labelNodeOf(LabelNode** out, const Label& label) { + inline Error labelNodeOf(LabelNode** ASMJIT_NONNULL(out), const Label& label) { return labelNodeOf(out, label.id()); } @@ -311,7 +307,7 @@ public: //! //! This function is used internally to register a newly created `LabelNode` with this instance of Builder/Compiler. //! Use \ref labelNodeOf() functions to get back \ref LabelNode from a label or its identifier. - ASMJIT_API Error registerLabelNode(LabelNode* node); + ASMJIT_API Error registerLabelNode(LabelNode* ASMJIT_NONNULL(node)); ASMJIT_API Label newLabel() override; ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) override; diff --git a/src/asmjit/core/codeholder.cpp b/src/asmjit/core/codeholder.cpp index f446801..2beebff 100644 --- a/src/asmjit/core/codeholder.cpp +++ b/src/asmjit/core/codeholder.cpp @@ -1054,6 +1054,8 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { // Fixup the virtual size of the address table if it's the last section. if (_sectionsByOrder.last() == addressTableSection) { + ASMJIT_ASSERT(addressTableSection != nullptr); + size_t addressTableSize = addressTableEntryCount * addressSize; addressTableSection->_buffer._size = addressTableSize; addressTableSection->_virtualSize = addressTableSize; diff --git a/src/asmjit/core/compiler.cpp b/src/asmjit/core/compiler.cpp index bfa84f3..b1c6b80 100644 --- a/src/asmjit/core/compiler.cpp +++ b/src/asmjit/core/compiler.cpp @@ -104,6 +104,8 @@ Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature) Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature) { ASMJIT_PROPAGATE(newFuncNode(out, signature)); + ASMJIT_ASSUME(*out != nullptr); + addFunc(*out); return kErrorOk; } @@ -113,6 +115,8 @@ Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const FuncRetNode* node; ASMJIT_PROPAGATE(_newNodeT(&node)); + ASMJIT_ASSUME(node != nullptr); + node->setOpCount(opCount); node->setOp(0, o0); node->setOp(1, o1); @@ -129,7 +133,6 @@ Error BaseCompiler::addFuncRetNode(FuncRetNode** out, const Operand_& o0, const } FuncNode* BaseCompiler::addFunc(FuncNode* func) { - ASMJIT_ASSERT(_func == nullptr); _func = func; addNode(func); // Function node. @@ -255,6 +258,7 @@ Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) { VirtReg* vReg; ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name)); + ASMJIT_ASSUME(vReg != nullptr); out->_initReg(regSignature, vReg->id()); return kErrorOk; @@ -338,6 +342,7 @@ Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) VirtReg* vReg; ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name)); + ASMJIT_ASSUME(vReg != nullptr); out->_initReg(regSignature, vReg->id()); return kErrorOk; @@ -370,7 +375,8 @@ Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, c alignment = 64; VirtReg* vReg; - ASMJIT_PROPAGATE(newVirtReg(&vReg, TypeId::kVoid, OperandSignature(0), name)); + ASMJIT_PROPAGATE(newVirtReg(&vReg, TypeId::kVoid, OperandSignature{0}, name)); + ASMJIT_ASSUME(vReg != nullptr); vReg->_virtSize = size; vReg->_isStack = true; diff --git a/src/asmjit/core/compiler.h b/src/asmjit/core/compiler.h index 1331e62..709fd95 100644 --- a/src/asmjit/core/compiler.h +++ b/src/asmjit/core/compiler.h @@ -85,14 +85,14 @@ public: //! \{ //! Creates a new \ref FuncNode. - ASMJIT_API Error newFuncNode(FuncNode** out, const FuncSignature& signature); + ASMJIT_API Error newFuncNode(FuncNode** ASMJIT_NONNULL(out), const FuncSignature& signature); //! Creates a new \ref FuncNode adds it to the instruction stream. - ASMJIT_API Error addFuncNode(FuncNode** out, const FuncSignature& signature); + ASMJIT_API Error addFuncNode(FuncNode** ASMJIT_NONNULL(out), const FuncSignature& signature); //! Creates a new \ref FuncRetNode. - ASMJIT_API Error newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + ASMJIT_API Error newFuncRetNode(FuncRetNode** ASMJIT_NONNULL(out), const Operand_& o0, const Operand_& o1); //! Creates a new \ref FuncRetNode and adds it to the instruction stream. - ASMJIT_API Error addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + ASMJIT_API Error addFuncRetNode(FuncRetNode** ASMJIT_NONNULL(out), const Operand_& o0, const Operand_& o1); //! Returns the current function. inline FuncNode* func() const noexcept { return _func; } @@ -113,7 +113,7 @@ public: } //! Adds a function `node` to the instruction stream. - ASMJIT_API FuncNode* addFunc(FuncNode* func); + ASMJIT_API FuncNode* addFunc(FuncNode* ASMJIT_NONNULL(func)); //! Emits a sentinel that marks the end of the current function. ASMJIT_API Error endFunc(); @@ -140,9 +140,9 @@ public: //! \{ //! Creates a new \ref InvokeNode. - ASMJIT_API Error newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature); + ASMJIT_API Error newInvokeNode(InvokeNode** ASMJIT_NONNULL(out), InstId instId, const Operand_& o0, const FuncSignature& signature); //! Creates a new \ref InvokeNode and adds it to the instruction stream. - ASMJIT_API Error addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature); + ASMJIT_API Error addInvokeNode(InvokeNode** ASMJIT_NONNULL(out), InstId instId, const Operand_& o0, const FuncSignature& signature); //! \} @@ -153,23 +153,23 @@ public: //! //! \note This function is public, but it's not generally recommended to be used by AsmJit users, use architecture //! specific `newReg()` functionality instead or functions like \ref _newReg() and \ref _newRegFmt(). - ASMJIT_API Error newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name); + ASMJIT_API Error newVirtReg(VirtReg** ASMJIT_NONNULL(out), TypeId typeId, OperandSignature signature, const char* name); //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. - ASMJIT_API Error _newReg(BaseReg* out, TypeId typeId, const char* name = nullptr); + ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* name = nullptr); //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. //! //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. - ASMJIT_API Error _newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...); + ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* fmt, ...); //! Creates a new virtual register compatible with the provided reference register `ref`. - ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr); + ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* name = nullptr); //! Creates a new virtual register compatible with the provided reference register `ref`. //! //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. - ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...); + ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* fmt, ...); //! Tests whether the given `id` is a valid virtual register id. inline bool isVirtIdValid(uint32_t id) const noexcept { @@ -205,7 +205,7 @@ public: //! Creates a new stack of the given `size` and `alignment` and stores it to `out`. //! //! \note `name` can be used to give the stack a name, for debugging purposes. - ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr); + ASMJIT_API Error _newStack(BaseMem* ASMJIT_NONNULL(out), uint32_t size, uint32_t alignment, const char* name = nullptr); //! Updates the stack size of a stack created by `_newStack()` by its `virtId`. ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0); @@ -224,7 +224,7 @@ public: //! //! This function adds a constant of the given `size` to the built-in \ref ConstPool and stores the reference to that //! constant to the `out` operand. - ASMJIT_API Error _newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size); + ASMJIT_API Error _newConst(BaseMem* ASMJIT_NONNULL(out), ConstPoolScope scope, const void* data, size_t size); //! \} @@ -243,7 +243,7 @@ public: return _jumpAnnotations; } - ASMJIT_API Error newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation); + ASMJIT_API Error newJumpNode(JumpNode** ASMJIT_NONNULL(out), InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation); ASMJIT_API Error emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation); //! Returns a new `JumpAnnotation` instance, which can be used to aggregate possible targets of a jump where the @@ -286,7 +286,7 @@ public: //! \name Construction & Destruction //! \{ - inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept + inline JumpAnnotation(BaseCompiler* ASMJIT_NONNULL(compiler), uint32_t annotationId) noexcept : _compiler(compiler), _annotationId(annotationId) {} @@ -339,7 +339,7 @@ public: //! \name Construction & Destruction //! \{ - inline JumpNode(BaseCompiler* cc, InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept + inline JumpNode(BaseCompiler* ASMJIT_NONNULL(cc), InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept : InstNode(cc, instId, options, opCount, kBaseOpCapacity), _annotation(annotation) { setType(NodeType::kJump); @@ -439,7 +439,7 @@ public: //! Creates a new `FuncNode` instance. //! //! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`. - inline FuncNode(BaseBuilder* cb) noexcept + inline FuncNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept : LabelNode(cb), _funcDetail(), _frame(), @@ -539,7 +539,7 @@ public: //! \{ //! Creates a new `FuncRetNode` instance. - inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) { + inline FuncRetNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept : InstNode(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) { _any._nodeType = NodeType::kFuncRet; } @@ -593,7 +593,7 @@ public: //! \{ //! Creates a new `InvokeNode` instance. - inline InvokeNode(BaseBuilder* cb, InstId instId, InstOptions options) noexcept + inline InvokeNode(BaseBuilder* ASMJIT_NONNULL(cb), InstId instId, InstOptions options) noexcept : InstNode(cb, instId, options, kBaseOpCapacity), _funcDetail(), _args(nullptr) { diff --git a/src/asmjit/core/compilerdefs.h b/src/asmjit/core/compilerdefs.h index f2e7a4e..2f60c7f 100644 --- a/src/asmjit/core/compilerdefs.h +++ b/src/asmjit/core/compilerdefs.h @@ -58,7 +58,7 @@ public: //! \name Construction & Destruction //! \{ - inline VirtReg(const OperandSignature& signature, uint32_t id, uint32_t virtSize, uint32_t alignment, TypeId typeId) noexcept + inline VirtReg(OperandSignature signature, uint32_t id, uint32_t virtSize, uint32_t alignment, TypeId typeId) noexcept : _signature(signature), _id(id), _virtSize(virtSize), diff --git a/src/asmjit/core/emitter.h b/src/asmjit/core/emitter.h index 17a98ba..2aca695 100644 --- a/src/asmjit/core/emitter.h +++ b/src/asmjit/core/emitter.h @@ -671,9 +671,9 @@ public: //! \{ //! Called after the emitter was attached to `CodeHolder`. - virtual Error onAttach(CodeHolder* code) noexcept = 0; + virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0; //! Called after the emitter was detached from `CodeHolder`. - virtual Error onDetach(CodeHolder* code) noexcept = 0; + virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0; //! Called when \ref CodeHolder has updated an important setting, which involves the following: //! diff --git a/src/asmjit/core/funcargscontext.cpp b/src/asmjit/core/funcargscontext.cpp index 8ce806f..1db50a7 100644 --- a/src/asmjit/core/funcargscontext.cpp +++ b/src/asmjit/core/funcargscontext.cpp @@ -99,6 +99,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co RegGroup srcGroup = archTraits().regTypeToGroup(src.regType()); if (dstGroup == srcGroup) { + ASMJIT_ASSERT(dstWd != nullptr); dstWd->assign(varId, srcId); // The best case, register is allocated where it is expected to be. diff --git a/src/asmjit/core/funcargscontext_p.h b/src/asmjit/core/funcargscontext_p.h index 1c928eb..72ee105 100644 --- a/src/asmjit/core/funcargscontext_p.h +++ b/src/asmjit/core/funcargscontext_p.h @@ -27,7 +27,7 @@ static inline OperandSignature getSuitableRegForMemToMemMove(Arch arch, TypeId d uint32_t maxSize = Support::max(dstSize, srcSize); uint32_t regSize = Environment::registerSizeFromArch(arch); - OperandSignature signature(0); + OperandSignature signature{0}; if (maxSize <= regSize || (TypeUtils::isInt(dstTypeId) && TypeUtils::isInt(srcTypeId))) signature = maxSize <= 4 ? archTraits.regTypeToSignature(RegType::kGp32) : archTraits.regTypeToSignature(RegType::kGp64); diff --git a/src/asmjit/core/operand.h b/src/asmjit/core/operand.h index 96ef3ba..0bf098a 100644 --- a/src/asmjit/core/operand.h +++ b/src/asmjit/core/operand.h @@ -265,15 +265,6 @@ struct OperandSignature { //! \} - //! \name Construction & Destruction - //! \{ - - inline OperandSignature() noexcept = default; - inline constexpr OperandSignature(const OperandSignature& other) noexcept = default; - inline constexpr explicit OperandSignature(uint32_t bits) noexcept : _bits(bits) {} - - //! \{ - //! \name Overloaded Operators //! //! Overloaded operators make `OperandSignature` behave like regular integer. @@ -283,25 +274,23 @@ struct OperandSignature { inline constexpr bool operator!() const noexcept { return _bits != 0; } inline constexpr explicit operator bool() const noexcept { return _bits != 0; } - inline OperandSignature& operator=(uint32_t x) noexcept { _bits = x; return *this; } inline OperandSignature& operator|=(uint32_t x) noexcept { _bits |= x; return *this; } inline OperandSignature& operator&=(uint32_t x) noexcept { _bits &= x; return *this; } inline OperandSignature& operator^=(uint32_t x) noexcept { _bits ^= x; return *this; } - inline OperandSignature& operator=(const OperandSignature& other) noexcept { return operator=(other._bits); } inline OperandSignature& operator|=(const OperandSignature& other) noexcept { return operator|=(other._bits); } inline OperandSignature& operator&=(const OperandSignature& other) noexcept { return operator&=(other._bits); } inline OperandSignature& operator^=(const OperandSignature& other) noexcept { return operator^=(other._bits); } - inline constexpr OperandSignature operator~() const noexcept { return OperandSignature(~_bits); } + inline constexpr OperandSignature operator~() const noexcept { return OperandSignature{~_bits}; } - inline constexpr OperandSignature operator|(uint32_t x) const noexcept { return OperandSignature(_bits | x); } - inline constexpr OperandSignature operator&(uint32_t x) const noexcept { return OperandSignature(_bits & x); } - inline constexpr OperandSignature operator^(uint32_t x) const noexcept { return OperandSignature(_bits ^ x); } + inline constexpr OperandSignature operator|(uint32_t x) const noexcept { return OperandSignature{_bits | x}; } + inline constexpr OperandSignature operator&(uint32_t x) const noexcept { return OperandSignature{_bits & x}; } + inline constexpr OperandSignature operator^(uint32_t x) const noexcept { return OperandSignature{_bits ^ x}; } - inline constexpr OperandSignature operator|(const OperandSignature& other) const noexcept { return OperandSignature(_bits | other._bits); } - inline constexpr OperandSignature operator&(const OperandSignature& other) const noexcept { return OperandSignature(_bits & other._bits); } - inline constexpr OperandSignature operator^(const OperandSignature& other) const noexcept { return OperandSignature(_bits ^ other._bits); } + inline constexpr OperandSignature operator|(const OperandSignature& other) const noexcept { return OperandSignature{_bits | other._bits}; } + inline constexpr OperandSignature operator&(const OperandSignature& other) const noexcept { return OperandSignature{_bits & other._bits}; } + inline constexpr OperandSignature operator^(const OperandSignature& other) const noexcept { return OperandSignature{_bits ^ other._bits}; } inline constexpr bool operator==(uint32_t x) const noexcept { return _bits == x; } inline constexpr bool operator!=(uint32_t x) const noexcept { return _bits != x; } @@ -340,7 +329,7 @@ struct OperandSignature { _bits = (_bits & ~kFieldMask) | (value << kFieldShift); } - inline constexpr OperandSignature subset(uint32_t mask) const noexcept { return OperandSignature(_bits & mask); } + inline constexpr OperandSignature subset(uint32_t mask) const noexcept { return OperandSignature{_bits & mask}; } template inline constexpr bool matchesSignature(const OperandSignature& signature) const noexcept { @@ -386,24 +375,24 @@ struct OperandSignature { //! \{ static inline constexpr OperandSignature fromBits(uint32_t bits) noexcept { - return OperandSignature(bits); + return OperandSignature{bits}; } template static inline constexpr OperandSignature fromValue(const T& value) noexcept { - return OperandSignature(uint32_t(value) << Support::ConstCTZ::value); + return OperandSignature{uint32_t(value) << Support::ConstCTZ::value}; } static inline constexpr OperandSignature fromOpType(OperandType opType) noexcept { - return OperandSignature(uint32_t(opType) << kOpTypeShift); + return OperandSignature{uint32_t(opType) << kOpTypeShift}; } static inline constexpr OperandSignature fromRegType(RegType regType) noexcept { - return OperandSignature(uint32_t(regType) << kRegTypeShift); + return OperandSignature{uint32_t(regType) << kRegTypeShift}; } static inline constexpr OperandSignature fromRegGroup(RegGroup regGroup) noexcept { - return OperandSignature(uint32_t(regGroup) << kRegGroupShift); + return OperandSignature{uint32_t(regGroup) << kRegGroupShift}; } static inline constexpr OperandSignature fromRegTypeAndGroup(RegType regType, RegGroup regGroup) noexcept { @@ -411,19 +400,19 @@ struct OperandSignature { } static inline constexpr OperandSignature fromMemBaseType(RegType baseType) noexcept { - return OperandSignature(uint32_t(baseType) << kMemBaseTypeShift); + return OperandSignature{uint32_t(baseType) << kMemBaseTypeShift}; } static inline constexpr OperandSignature fromMemIndexType(RegType indexType) noexcept { - return OperandSignature(uint32_t(indexType) << kMemIndexTypeShift); + return OperandSignature{uint32_t(indexType) << kMemIndexTypeShift}; } static inline constexpr OperandSignature fromPredicate(uint32_t predicate) noexcept { - return OperandSignature(predicate << kPredicateShift); + return OperandSignature{predicate << kPredicateShift}; } static inline constexpr OperandSignature fromSize(uint32_t size) noexcept { - return OperandSignature(size << kSizeShift); + return OperandSignature{size << kSizeShift}; } //! \} @@ -544,7 +533,7 @@ struct Operand_ { //! assert(a == b); //! ``` inline void reset() noexcept { - _signature = 0; + _signature.reset(); _baseId = 0; _data[0] = 0; _data[1] = 0; @@ -1091,7 +1080,7 @@ struct RegTraits { \ public: \ /*! Default constructor that only setups basics. */ \ inline constexpr REG() noexcept \ - : BASE(Signature(kSignature), kIdBad) {} \ + : BASE(Signature{kSignature}, kIdBad) {} \ \ /*! Makes a copy of the `other` register operand. */ \ inline constexpr REG(const REG& other) noexcept \ @@ -1134,7 +1123,7 @@ public: \ \ /*! Creates a register operand having its id set to `id`. */ \ inline constexpr explicit REG(uint32_t id) noexcept \ - : BASE(Signature(kSignature), id) {} + : BASE(Signature{kSignature}, id) {} //! \endcond //! Base class for all memory operands. diff --git a/src/asmjit/core/rapass.cpp b/src/asmjit/core/rapass.cpp index 9d714cd..d953338 100644 --- a/src/asmjit/core/rapass.cpp +++ b/src/asmjit/core/rapass.cpp @@ -471,11 +471,13 @@ Error BaseRAPass::buildCFGDominators() noexcept { uint32_t j = preds.size(); while (j) { RABlock* p = preds[--j]; - if (!p->iDom()) continue; + if (!p->iDom()) + continue; iDom = !iDom ? p : intersectBlocks(iDom, p); } if (block->iDom() != iDom) { + ASMJIT_ASSUME(iDom != nullptr); ASMJIT_RA_LOG_FORMAT(" IDom of #%u -> #%u\n", block->blockId(), iDom->blockId()); block->setIDom(iDom); changed = true; diff --git a/src/asmjit/core/string.cpp b/src/asmjit/core/string.cpp index 19d1e18..83dc6ef 100644 --- a/src/asmjit/core/string.cpp +++ b/src/asmjit/core/string.cpp @@ -29,7 +29,7 @@ Error String::reset() noexcept { } Error String::clear() noexcept { - if (isLarge()) { + if (isLargeOrExternal()) { _large.size = 0; _large.data[0] = '\0'; } @@ -48,7 +48,7 @@ char* String::prepare(ModifyOp op, size_t size) noexcept { size_t curSize; size_t curCapacity; - if (isLarge()) { + if (isLargeOrExternal()) { curData = this->_large.data; curSize = this->_large.size; curCapacity = this->_large.capacity; @@ -143,7 +143,7 @@ Error String::assign(const char* data, size_t size) noexcept { if (size == SIZE_MAX) size = data ? strlen(data) : size_t(0); - if (isLarge()) { + if (isLargeOrExternal()) { if (size <= _large.capacity) { dst = _large.data; _large.size = size; @@ -157,7 +157,7 @@ Error String::assign(const char* data, size_t size) noexcept { if (ASMJIT_UNLIKELY(!dst)) return DebugUtils::errored(kErrorOutOfMemory); - if (!isExternal()) + if (_type == kTypeLarge) ::free(_large.data); _large.type = kTypeLarge; @@ -447,7 +447,7 @@ Error String::_opVFormat(ModifyOp op, const char* fmt, va_list ap) noexcept { } Error String::truncate(size_t newSize) noexcept { - if (isLarge()) { + if (isLargeOrExternal()) { if (newSize < _large.size) { _large.data[newSize] = '\0'; _large.size = newSize; @@ -491,7 +491,7 @@ bool String::eq(const char* other, size_t size) const noexcept { UNIT(core_string) { String s; - EXPECT(s.isLarge() == false); + EXPECT(s.isLargeOrExternal() == false); EXPECT(s.isExternal() == false); EXPECT(s.assign('a') == kErrorOk); @@ -525,14 +525,14 @@ UNIT(core_string) { const char* large = "Large string that will not fit into SSO buffer"; EXPECT(s.assign(large) == kErrorOk); - EXPECT(s.isLarge() == true); + EXPECT(s.isLargeOrExternal() == true); EXPECT(s.size() == strlen(large)); EXPECT(s.capacity() > String::kSSOCapacity); EXPECT(s.eq(large) == true); EXPECT(s.eq(large, strlen(large)) == true); const char* additional = " (additional content)"; - EXPECT(s.isLarge() == true); + EXPECT(s.isLargeOrExternal() == true); EXPECT(s.append(additional) == kErrorOk); EXPECT(s.size() == strlen(large) + strlen(additional)); @@ -540,7 +540,7 @@ UNIT(core_string) { EXPECT(s.size() == 0); EXPECT(s.empty() == true); EXPECT(s.data()[0] == '\0'); - EXPECT(s.isLarge() == true); // Clear should never release the memory. + EXPECT(s.isLargeOrExternal() == true); // Clear should never release the memory. EXPECT(s.appendUInt(1234) == kErrorOk); EXPECT(s.eq("1234") == true); @@ -549,7 +549,7 @@ UNIT(core_string) { EXPECT(s.eq("0xFFFF")); StringTmp<64> sTmp; - EXPECT(sTmp.isLarge()); + EXPECT(sTmp.isLargeOrExternal()); EXPECT(sTmp.isExternal()); EXPECT(sTmp.appendChars(' ', 1000) == kErrorOk); EXPECT(!sTmp.isExternal()); diff --git a/src/asmjit/core/string.h b/src/asmjit/core/string.h index d309b82..2562e66 100644 --- a/src/asmjit/core/string.h +++ b/src/asmjit/core/string.h @@ -169,20 +169,20 @@ public: //! \name Accessors //! \{ - inline bool isLarge() const noexcept { return _type >= kTypeLarge; } inline bool isExternal() const noexcept { return _type == kTypeExternal; } + inline bool isLargeOrExternal() const noexcept { return _type >= kTypeLarge; } //! Tests whether the string is empty. inline bool empty() const noexcept { return size() == 0; } //! Returns the size of the string. - inline size_t size() const noexcept { return isLarge() ? size_t(_large.size) : size_t(_type); } + inline size_t size() const noexcept { return isLargeOrExternal() ? size_t(_large.size) : size_t(_type); } //! Returns the capacity of the string. - inline size_t capacity() const noexcept { return isLarge() ? _large.capacity : size_t(kSSOCapacity); } + inline size_t capacity() const noexcept { return isLargeOrExternal() ? _large.capacity : size_t(kSSOCapacity); } //! Returns the data of the string. - inline char* data() noexcept { return isLarge() ? _large.data : _small.data; } + inline char* data() noexcept { return isLargeOrExternal() ? _large.data : _small.data; } //! \overload - inline const char* data() const noexcept { return isLarge() ? _large.data : _small.data; } + inline const char* data() const noexcept { return isLargeOrExternal() ? _large.data : _small.data; } inline char* start() noexcept { return data(); } inline const char* start() const noexcept { return data(); } @@ -330,7 +330,7 @@ public: } inline void _setSize(size_t newSize) noexcept { - if (isLarge()) + if (isLargeOrExternal()) _large.size = newSize; else _small.type = uint8_t(newSize); diff --git a/src/asmjit/core/support.h b/src/asmjit/core/support.h index ebf0354..5b142d4 100644 --- a/src/asmjit/core/support.h +++ b/src/asmjit/core/support.h @@ -17,18 +17,24 @@ ASMJIT_BEGIN_NAMESPACE //! \addtogroup asmjit_utilities //! \{ -//! Contains support classes and functions that may be used by AsmJit source -//! and header files. Anything defined here is considered internal and should -//! not be used outside of AsmJit and related projects like AsmTK. +//! Contains support classes and functions that may be used by AsmJit source and header files. Anything defined +//! here is considered internal and should not be used outside of AsmJit and related projects like AsmTK. namespace Support { // Support - Architecture Features & Constraints // ============================================= //! \cond INTERNAL +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 11 +// There is a bug in GCC11+ that makes it unusable to use annotated unaligned loads/stores. +static constexpr bool kUnalignedAccess16 = false; +static constexpr bool kUnalignedAccess32 = false; +static constexpr bool kUnalignedAccess64 = false; +#else static constexpr bool kUnalignedAccess16 = ASMJIT_ARCH_X86 != 0; static constexpr bool kUnalignedAccess32 = ASMJIT_ARCH_X86 != 0; static constexpr bool kUnalignedAccess64 = ASMJIT_ARCH_X86 != 0; +#endif //! \endcond // Support - Basic Traits diff --git a/src/asmjit/core/zonetree.h b/src/asmjit/core/zonetree.h index 41c4e0e..64ccdc8 100644 --- a/src/asmjit/core/zonetree.h +++ b/src/asmjit/core/zonetree.h @@ -149,7 +149,7 @@ public: } template> - void insert(NodeT* node, const CompareT& cmp = CompareT()) noexcept { + void insert(NodeT* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept { // Node to insert must not contain garbage. ASMJIT_ASSERT(!node->hasLeft()); ASMJIT_ASSERT(!node->hasRight()); @@ -188,9 +188,12 @@ public: } // Fix red violation. - if (_isValidRed(q) && _isValidRed(p)) + if (_isValidRed(q) && _isValidRed(p)) { + ASMJIT_ASSUME(g != nullptr); + ASMJIT_ASSUME(p != nullptr); t->_setChild(t->_getRight() == g, q == p->_getChild(last) ? _singleRotate(g, !last) : _doubleRotate(g, !last)); + } // Stop if found. if (q == node) @@ -214,7 +217,7 @@ public: //! Remove node from RBTree. template> - void remove(ZoneTreeNode* node, const CompareT& cmp = CompareT()) noexcept { + void remove(ZoneTreeNode* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept { ZoneTreeNode head; // False root node, head._setRight(_root); // having root on the right. @@ -258,6 +261,9 @@ public: q->_makeRed(); } else { + ASMJIT_ASSUME(g != nullptr); + ASMJIT_ASSUME(s != nullptr); + size_t dir2 = g->_getRight() == p; ZoneTreeNode* child = g->_getChild(dir2); @@ -342,9 +348,14 @@ public: static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return ZoneTreeNode::_isValidRed(node); } //! Single rotation. - static inline ZoneTreeNode* _singleRotate(ZoneTreeNode* root, size_t dir) noexcept { + static inline ZoneTreeNode* _singleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept { ZoneTreeNode* save = root->_getChild(!dir); - root->_setChild(!dir, save->_getChild(dir)); + ASMJIT_ASSUME(save != nullptr); + + ZoneTreeNode* saveChild = save->_getChild(dir); + ASMJIT_ASSUME(saveChild != nullptr); + + root->_setChild(!dir, saveChild); save->_setChild( dir, root); root->_makeRed(); save->_makeBlack(); @@ -352,8 +363,10 @@ public: } //! Double rotation. - static inline ZoneTreeNode* _doubleRotate(ZoneTreeNode* root, size_t dir) noexcept { - root->_setChild(!dir, _singleRotate(root->_getChild(!dir), !dir)); + static inline ZoneTreeNode* _doubleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept { + ZoneTreeNode* child = root->_getChild(!dir); + ASMJIT_ASSUME(child != nullptr); + root->_setChild(!dir, _singleRotate(child, !dir)); return _singleRotate(root, dir); } diff --git a/src/asmjit/x86/x86archtraits_p.h b/src/asmjit/x86/x86archtraits_p.h index 7c43651..90ae5d5 100644 --- a/src/asmjit/x86/x86archtraits_p.h +++ b/src/asmjit/x86/x86archtraits_p.h @@ -39,7 +39,7 @@ static const constexpr ArchTraits x86ArchTraits = { }}, // Register signatures. - #define V(index) OperandSignature(x86::RegTraits::kSignature) + #define V(index) OperandSignature{x86::RegTraits::kSignature} {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, #undef V @@ -100,7 +100,7 @@ static const constexpr ArchTraits x64ArchTraits = { }}, // Register signatures. - #define V(index) OperandSignature(x86::RegTraits::kSignature) + #define V(index) OperandSignature{x86::RegTraits::kSignature} {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }}, #undef V diff --git a/src/asmjit/x86/x86emithelper.cpp b/src/asmjit/x86/x86emithelper.cpp index 4a85a16..d2d90c7 100644 --- a/src/asmjit/x86/x86emithelper.cpp +++ b/src/asmjit/x86/x86emithelper.cpp @@ -80,8 +80,10 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove( if (memFlags & kSrcMem) { instId = Inst::kIdMovzx; dst.setSignature(Reg::signatureOfT()); + break; } - else if (!memFlags) { + + if (!memFlags) { // Change both destination and source registers to GPD (safer, no dependencies). dst.setSignature(Reg::signatureOfT()); src.setSignature(Reg::signatureOfT()); diff --git a/src/asmjit/x86/x86operand.h b/src/asmjit/x86/x86operand.h index bfd09bd..037d4af 100644 --- a/src/asmjit/x86/x86operand.h +++ b/src/asmjit/x86/x86operand.h @@ -115,7 +115,7 @@ public: template inline void setRegT(uint32_t rId) noexcept { - setSignature(OperandSignature(RegTraits::kSignature)); + setSignature(OperandSignature{RegTraits::kSignature}); setId(rId); } @@ -135,18 +135,18 @@ public: static inline TypeId typeIdOfT() noexcept { return TypeId(RegTraits::kTypeId); } template - static inline OperandSignature signatureOfT() noexcept { return OperandSignature(RegTraits::kSignature); } + static inline OperandSignature signatureOfT() noexcept { return OperandSignature{RegTraits::kSignature}; } static inline OperandSignature signatureOfVecByType(TypeId typeId) noexcept { - return OperandSignature(typeId <= TypeId::_kVec128End ? uint32_t(RegTraits::kSignature) : + return OperandSignature{typeId <= TypeId::_kVec128End ? uint32_t(RegTraits::kSignature) : typeId <= TypeId::_kVec256End ? uint32_t(RegTraits::kSignature) : - uint32_t(RegTraits::kSignature)); + uint32_t(RegTraits::kSignature)}; } static inline OperandSignature signatureOfVecBySize(uint32_t size) noexcept { - return OperandSignature(size <= 16 ? uint32_t(RegTraits::kSignature) : + return OperandSignature{size <= 16 ? uint32_t(RegTraits::kSignature) : size <= 32 ? uint32_t(RegTraits::kSignature) : - uint32_t(RegTraits::kSignature)); + uint32_t(RegTraits::kSignature)}; } //! Tests whether the `op` operand is either a low or high 8-bit GPB register. @@ -735,13 +735,13 @@ public: inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept : BaseMem(signature, baseId, indexId, offset) {} - inline constexpr Mem(const Label& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr Mem(const Label& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromMemBaseType(RegType::kLabelTag) | Signature::fromSize(size) | signature, base.id(), 0, off) {} - inline constexpr Mem(const Label& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr Mem(const Label& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromMemBaseType(RegType::kLabelTag) | Signature::fromMemIndexType(index.type()) | @@ -749,13 +749,13 @@ public: Signature::fromSize(size) | signature, base.id(), index.id(), off) {} - inline constexpr Mem(const BaseReg& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr Mem(const BaseReg& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromMemBaseType(base.type()) | Signature::fromSize(size) | signature, base.id(), 0, off) {} - inline constexpr Mem(const BaseReg& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr Mem(const BaseReg& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromMemBaseType(base.type()) | Signature::fromMemIndexType(index.type()) | @@ -763,12 +763,12 @@ public: Signature::fromSize(size) | signature, base.id(), index.id(), off) {} - inline constexpr explicit Mem(uint64_t base, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr explicit Mem(uint64_t base, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromSize(size) | signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {} - inline constexpr Mem(uint64_t base, const BaseReg& index, uint32_t shift = 0, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + inline constexpr Mem(uint64_t base, const BaseReg& index, uint32_t shift = 0, uint32_t size = 0, Signature signature = OperandSignature{0}) noexcept : BaseMem(Signature::fromOpType(OperandType::kMem) | Signature::fromMemIndexType(index.type()) | Signature::fromValue(shift) | @@ -798,7 +798,7 @@ public: } inline constexpr Mem cloneBroadcasted(Broadcast b) const noexcept { - return Mem((_signature & ~Signature(kSignatureMemBroadcastMask)) | Signature::fromValue(b), _baseId, _data[0], int32_t(_data[1])); + return Mem((_signature & ~Signature{kSignatureMemBroadcastMask}) | Signature::fromValue(b), _baseId, _data[0], int32_t(_data[1])); } //! \} diff --git a/src/asmjit/x86/x86rapass.cpp b/src/asmjit/x86/x86rapass.cpp index 3a63c08..4f0325a 100644 --- a/src/asmjit/x86/x86rapass.cpp +++ b/src/asmjit/x86/x86rapass.cpp @@ -695,8 +695,8 @@ Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept // ================================ static inline OperandSignature x86VecRegSignatureBySize(uint32_t size) noexcept { - return OperandSignature(size >= 64 ? uint32_t(Zmm::kSignature) : - size >= 32 ? uint32_t(Ymm::kSignature) : uint32_t(Xmm::kSignature)); + return OperandSignature{size >= 64 ? uint32_t(Zmm::kSignature) : + size >= 32 ? uint32_t(Ymm::kSignature) : uint32_t(Xmm::kSignature)}; } Error RACFGBuilder::moveVecToPtr(InvokeNode* invokeNode, const FuncValue& arg, const Vec& src, BaseReg* out) noexcept { @@ -1358,8 +1358,8 @@ Error X86RAPass::emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, RAWorkReg* wbReg = workRegById(bWorkId); bool is64Bit = Support::max(waReg->typeId(), wbReg->typeId()) >= TypeId::kInt64; - OperandSignature sign = is64Bit ? OperandSignature(RegTraits::kSignature) - : OperandSignature(RegTraits::kSignature); + OperandSignature sign = is64Bit ? OperandSignature{RegTraits::kSignature} + : OperandSignature{RegTraits::kSignature}; #ifndef ASMJIT_NO_LOGGING if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) { -- cgit v1.2.3