Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

erts: Update asmjit #9495

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion erts/emulator/asmjit.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a465fe71ab3d0e224b2b4bd0fac69ae68ab9239d
029075b84bf0161a761beb63e6eda519a29020db
112 changes: 112 additions & 0 deletions erts/emulator/asmjit/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<!--
%CopyrightBegin%

SPDX-FileCopyrightText: Copyright (c) 2024 The AsmJit Authors

SPDX-License-Identifier: Zlib

%CopyrightEnd%
-->

## How to Contribute to AsmJit

### Did you find a bug or something isn't working as expected?

* 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 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 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, 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).

* Ports (requesting new AsmJit backends) can be reported as feature requests, but only by people that are willing to work on them as creating new ports takes a lot of time.

### 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 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 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

* If you decide to open a pull request, make sure that the code you submit uses the same convention as the rest of the code. We prefer keeping the code consistent.

* [.editorconfig](./.editorconfig) should help with basic settings.

* Initially, AsmJit coding style was based on Google C++ Style Guide, but it has diverged from it.

* Include guards use `<PATH_TO_SRC>_H_INCLUDED` format.

* `asmjit` namespace must be open by `ASMJIT_BEGIN_NAMESPACE` and closed by `ASMJIT_END_NAMESPACE`

* `asmjit::xxx` (backend specific) nested namespace must be open by `ASMJIT_BEGIN_SUB_NAMESPACE(xxx)` and closed by `ASMJIT_END_SUB_NAMESPACE`.

* Opening bracket is on the same line, like `struct Something {`, `if (condition) {`, etc...

* 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. 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

* AsmJit uses a minimalist unit testing framework to write unit tests to avoid third-party dependencies.

* At the moment tests are in the same file as the implementation and are only compiled when `ASMJIT_TEST` macro is defined.

* Use `-DASMJIT_TEST=1` when invoking [CMake](https://cmake.org/) to compile AsmJit tests.

* Unit tests are compiled to a single `asmjit_test_unit[.exe]` executable.

* Other tests have their own executables based on what is tested.

* Always add assembler tests when adding new instructions, see [asmjit_test_assembler_x64.cpp](./test/asmjit_test_assembler_x64.cpp) and [asmjit_test_assembler_a64.cpp](./test/asmjit_test_assembler_a64.cpp) for more details.

## Pull Request Messages

* If a change fixes a bug the message should should start with `[bug]`.

* If a change fixes or enhances documentation it should start with `[doc]`.

* If a change fixes or enhances our CI it should start with `[ci]`.

* If a change breaks ABI it must start with `[abi]`.

* Otherwise there is no suggested prefix.

## ABI Changes

* 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 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?

* Modifying a public struct/class in a way that its functionality is altered and/or its size is changed

* Adding/removing virtual functions to/from classes, respectively

* 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 breaks ABI)

* Possibly more, but these were the most common...

* What is not ABI break?

* 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
2 changes: 1 addition & 1 deletion erts/emulator/asmjit/LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2008-2020 The AsmJit Authors
Copyright (c) 2008-2024 The AsmJit Authors

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
Expand Down
48 changes: 26 additions & 22 deletions erts/emulator/asmjit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ AsmJit is a lightweight library for machine code generation written in C++ langu

* [Official Home Page (asmjit.com)](https://asmjit.com)
* [Official Repository (asmjit/asmjit)](https://github.com/asmjit/asmjit)
* [Public Chat Channel](https://gitter.im/asmjit/asmjit)
* [Public Chat Channel](https://app.gitter.im/#/room/#asmjit:gitter.im)
* [Zlib License](./LICENSE.md)

See [asmjit.com](https://asmjit.com) page for more details, examples, and documentation.
Expand All @@ -16,38 +16,42 @@ Documentation
* [Documentation Index](https://asmjit.com/doc/index.html)
* [Build Instructions](https://asmjit.com/doc/group__asmjit__build.html)

Contributing
------------

* See [CONTRIBUTING](./CONTRIBUTING.md) page for more details

Breaking Changes
----------------

Breaking the API is sometimes inevitable, what to do?

* See [Breaking Changes Guide](https://asmjit.com/doc/group__asmjit__breaking__changes.html), which is now part of AsmJit documentation.
* See [Breaking Changes Guide](https://asmjit.com/doc/group__asmjit__breaking__changes.html), which is now part of AsmJit documentation
* See asmjit tests, they always compile and provide implementation of many use-cases:
* [asmjit_test_emitters.cpp](./test/asmjit_test_emitters.cpp) - Tests that demonstrate the purpose of emitters.
* [asmjit_test_assembler_x86.cpp](./test/asmjit_test_assembler_x86.cpp) - Tests targeting AsmJit's Assembler (x86/x64).
* [asmjit_test_compiler_x86.cpp](./test/asmjit_test_compiler_x86.cpp) - Tests targeting AsmJit's Compiler (x86/x64).
* [asmjit_test_instinfo.cpp](./test/asmjit_test_instinfo.cpp) - Tests that query instruction information.
* [asmjit_test_emitters.cpp](./test/asmjit_test_emitters.cpp) - Tests that demonstrate the purpose of emitters
* [asmjit_test_assembler_x86.cpp](./test/asmjit_test_assembler_x86.cpp) - Tests targeting AsmJit's Assembler (x86/x64)
* [asmjit_test_compiler_x86.cpp](./test/asmjit_test_compiler_x86.cpp) - Tests targeting AsmJit's Compiler (x86/x64)
* [asmjit_test_instinfo.cpp](./test/asmjit_test_instinfo.cpp) - Tests that query instruction information
* [asmjit_test_x86_sections.cpp](./test/asmjit_test_x86_sections.cpp) - Multiple sections test.
* Visit our [Official Chat](https://gitter.im/asmjit/asmjit) if you need a quick help.
* Visit our [Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) if you need a quick help

Project Organization
--------------------

* **`/`** - Project root.
* **src** - Source code.
* **asmjit** - Source code and headers (always point include path in here).
* **core** - Core API, backend independent except relocations.
* **arm** - ARM specific API, used only by ARM and AArch64 backends.
* **x86** - X86 specific API, used only by X86 and X64 backends.
* **test** - Unit and integration tests (don't embed in your project).
* **tools** - Tools used for configuring, documenting, and generating files.

TODO
----

* [ ] Ports:
* [ ] 32-bit ARM/Thumb port.
* [ ] RISC-V port.
* **`/`** - Project root
* **src** - Source code
* **asmjit** - Source code and headers (always point include path in here)
* **core** - Core API, backend independent except relocations
* **arm** - ARM specific API, used only by ARM and AArch64 backends
* **x86** - X86 specific API, used only by X86 and X64 backends
* **test** - Unit and integration tests (don't embed in your project)
* **tools** - Tools used for configuring, documenting, and generating files

Ports
-----

* [ ] 32-bit ARM/Thumb port (work in progress)
* [ ] RISC-V port (not in progress, help welcome)

Support
-------
Expand Down
60 changes: 47 additions & 13 deletions erts/emulator/asmjit/arm/a64assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ static constexpr uint32_t kWX = InstDB::kWX;
static const uint8_t armShiftOpToLdStOptMap[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
#undef VALUE

// a64::Assembler - ExtendOpToRegType
// ==================================

static inline RegType extendOptionToRegType(uint32_t option) noexcept {
uint32_t pred = (uint32_t(RegType::kARM_GpW) << (0x0 * 4)) | // 0b000 - UXTB.
(uint32_t(RegType::kARM_GpW) << (0x1 * 4)) | // 0b001 - UXTH.
(uint32_t(RegType::kARM_GpW) << (0x2 * 4)) | // 0b010 - UXTW.
(uint32_t(RegType::kARM_GpX) << (0x3 * 4)) | // 0b011 - UXTX|LSL.
(uint32_t(RegType::kARM_GpW) << (0x4 * 4)) | // 0b100 - SXTB.
(uint32_t(RegType::kARM_GpW) << (0x5 * 4)) | // 0b101 - SXTH.
(uint32_t(RegType::kARM_GpW) << (0x6 * 4)) | // 0b110 - SXTW.
(uint32_t(RegType::kARM_GpX) << (0x7 * 4)) ; // 0b111 - SXTX.
return RegType((pred >> (option * 4u)) & 0xFu);
}

// asmjit::a64::Assembler - SizeOp
// ===============================

Expand Down Expand Up @@ -467,7 +482,7 @@ static inline bool matchSignature(const Operand_& o0, const Operand_& o1, const
}

static inline bool matchSignature(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint32_t instFlags) noexcept {
return matchSignature(o0, o1, instFlags) && o1.signature() == o2.signature() && o2.signature() == o3.signature();;
return matchSignature(o0, o1, instFlags) && o1.signature() == o2.signature() && o2.signature() == o3.signature();
}

// Memory must be either:
Expand Down Expand Up @@ -1228,9 +1243,6 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
}

if (isign4 == ENC_OPS3(Reg, Reg, Reg) || isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
if (!checkSignature(o1, o2))
goto InvalidInstruction;

uint32_t opSize = x ? 64 : 32;
uint64_t shift = 0;
uint32_t sType = uint32_t(ShiftOp::kLSL);
Expand All @@ -1247,11 +1259,17 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
if (sType <= uint32_t(ShiftOp::kASR)) {
bool hasSP = o0.as<Gp>().isSP() || o1.as<Gp>().isSP();
if (!hasSP) {
if (!checkGpId(o0, o1, kZR))
if (!checkSignature(o1, o2)) {
goto InvalidInstruction;
}

if (!checkGpId(o0, o1, kZR)) {
goto InvalidPhysId;
}

if (shift >= opSize)
if (shift >= opSize) {
goto InvalidImmediate;
}

opcode.reset(uint32_t(opData.shiftedOp) << 21);
opcode.addImm(x, 31);
Expand All @@ -1264,17 +1282,20 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
}

// SP register can only be used with LSL or Extend.
if (sType != uint32_t(ShiftOp::kLSL))
if (sType != uint32_t(ShiftOp::kLSL)) {
goto InvalidImmediate;
}

sType = x ? uint32_t(ShiftOp::kUXTX) : uint32_t(ShiftOp::kUXTW);
}

// Extend operation - UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX.
opcode.reset(uint32_t(opData.extendedOp) << 21);
sType -= uint32_t(ShiftOp::kUXTB);

if (sType > 7 || shift > 4)
if (sType > 7 || shift > 4) {
goto InvalidImmediate;
}

if (!(opcode.get() & B(29))) {
// ADD|SUB (extend) - ZR is not allowed.
Expand All @@ -1287,6 +1308,11 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
goto InvalidPhysId;
}

// Validate whether the register operands match extend option.
if (o2.as<Reg>().type() != extendOptionToRegType(sType) || o1.as<Reg>().type() < o2.as<Reg>().type()) {
goto InvalidInstruction;
}

opcode.addImm(x, 31);
opcode.addReg(o2, 16);
opcode.addImm(sType, 13);
Expand Down Expand Up @@ -1412,9 +1438,6 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
}

if (isign4 == ENC_OPS2(Reg, Reg) || isign4 == ENC_OPS3(Reg, Reg, Imm)) {
if (!checkSignature(o0, o1))
goto InvalidInstruction;

uint32_t opSize = x ? 64 : 32;
uint32_t sType = 0;
uint64_t shift = 0;
Expand All @@ -1429,8 +1452,13 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
// Shift operation - LSL, LSR, ASR.
if (sType <= uint32_t(ShiftOp::kASR)) {
if (!hasSP) {
if (shift >= opSize)
if (!checkSignature(o0, o1)) {
goto InvalidInstruction;
}

if (shift >= opSize) {
goto InvalidImmediate;
}

opcode.reset(uint32_t(opData.shiftedOp) << 21);
opcode.addImm(x, 31);
Expand All @@ -1451,8 +1479,14 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co

// Extend operation - UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX.
sType -= uint32_t(ShiftOp::kUXTB);
if (sType > 7 || shift > 4)
if (sType > 7 || shift > 4) {
goto InvalidImmediate;
}

// Validate whether the register operands match extend option.
if (o1.as<Reg>().type() != extendOptionToRegType(sType) || o0.as<Reg>().type() < o1.as<Reg>().type()) {
goto InvalidInstruction;
}

opcode.reset(uint32_t(opData.extendedOp) << 21);
opcode.addImm(x, 31);
Expand Down
2 changes: 2 additions & 0 deletions erts/emulator/asmjit/arm/a64emithelper_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class EmitHelper : public BaseEmitHelper {
ASMJIT_INLINE_NODEBUG explicit EmitHelper(BaseEmitter* emitter = nullptr) noexcept
: BaseEmitHelper(emitter) {}

ASMJIT_INLINE_NODEBUG virtual ~EmitHelper() noexcept = default;

Error emitRegMove(
const Operand_& dst_,
const Operand_& src_, TypeId typeId, const char* comment = nullptr) override;
Expand Down
11 changes: 11 additions & 0 deletions erts/emulator/asmjit/arm/a64emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ struct EmitterExplicitT {

//! \endcond


//! \name Native Registers
//! \{

//! Returns either 32-bit or 64-bit GP register of the given `id` depending on the emitter's architecture.
inline Gp gpz(uint32_t id) const noexcept { return Gp(_emitter()->_gpSignature, id); }
//! Clones the given `reg` to either 32-bit or 64-bit GP register depending on the emitter's architecture.
inline Gp gpz(const Gp& reg) const noexcept { return Gp(_emitter()->_gpSignature, reg.id()); }

//! \}

//! \name General Purpose Instructions
//! \{

Expand Down
2 changes: 1 addition & 1 deletion erts/emulator/asmjit/arm/a64formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
Loading
Loading