You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Theodosius/dependencies/asmjit/core/emitter.cpp

417 lines
13 KiB

// AsmJit - Machine code generation for C++
//
// * Official AsmJit Home Page: https://asmjit.com
// * Official Github Repository: https://github.com/asmjit/asmjit
//
// Copyright (c) 2008-2020 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
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#include "../core/api-build_p.h"
#include "../core/emitterutils_p.h"
#include "../core/errorhandler.h"
#include "../core/logger.h"
#include "../core/support.h"
#ifdef ASMJIT_BUILD_X86
#include "../x86/x86emithelper_p.h"
#include "../x86/x86instdb_p.h"
#endif // ASMJIT_BUILD_X86
#ifdef ASMJIT_BUILD_ARM
#include "../arm/a64emithelper_p.h"
#include "../arm/a64instdb.h"
#endif // ASMJIT_BUILD_ARM
ASMJIT_BEGIN_NAMESPACE
// ============================================================================
// [asmjit::BaseEmitter - Construction / Destruction]
// ============================================================================
BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept
: _emitterType(uint8_t(emitterType)) {}
BaseEmitter::~BaseEmitter() noexcept {
if (_code) {
_addEmitterFlags(kFlagDestroyed);
_code->detach(this);
}
}
// ============================================================================
// [asmjit::BaseEmitter - Finalize]
// ============================================================================
Error BaseEmitter::finalize() {
// Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`.
return kErrorOk;
}
// ============================================================================
// [asmjit::BaseEmitter - Internals]
// ============================================================================
static constexpr uint32_t kEmitterPreservedFlags = BaseEmitter::kFlagOwnLogger | BaseEmitter::kFlagOwnErrorHandler;
static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept {
bool emitComments = false;
bool hasValidationOptions = false;
if (self->emitterType() == BaseEmitter::kTypeAssembler) {
// Assembler: Don't emit comments if logger is not attached.
emitComments = self->_code != nullptr && self->_logger != nullptr;
hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler);
}
else {
// Builder/Compiler: Always emit comments, we cannot assume they won't be used.
emitComments = self->_code != nullptr;
hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate);
}
if (emitComments)
self->_addEmitterFlags(BaseEmitter::kFlagLogComments);
else
self->_clearEmitterFlags(BaseEmitter::kFlagLogComments);
// The reserved option tells emitter (Assembler/Builder/Compiler) that there
// may be either a border case (CodeHolder not attached, for example) or that
// logging or validation is required.
if (self->_code == nullptr || self->_logger || hasValidationOptions)
self->_forcedInstOptions |= BaseInst::kOptionReserved;
else
self->_forcedInstOptions &= ~BaseInst::kOptionReserved;
}
// ============================================================================
// [asmjit::BaseEmitter - Validation Options]
// ============================================================================
void BaseEmitter::addValidationOptions(uint32_t options) noexcept {
_validationOptions = uint8_t(_validationOptions | options);
BaseEmitter_updateForcedOptions(this);
}
void BaseEmitter::clearValidationOptions(uint32_t options) noexcept {
_validationOptions = uint8_t(_validationOptions | options);
BaseEmitter_updateForcedOptions(this);
}
// ============================================================================
// [asmjit::BaseEmitter - Logging]
// ============================================================================
void BaseEmitter::setLogger(Logger* logger) noexcept {
#ifndef ASMJIT_NO_LOGGING
if (logger) {
_logger = logger;
_addEmitterFlags(kFlagOwnLogger);
}
else {
_logger = nullptr;
_clearEmitterFlags(kFlagOwnLogger);
if (_code)
_logger = _code->logger();
}
BaseEmitter_updateForcedOptions(this);
#else
DebugUtils::unused(logger);
#endif
}
// ============================================================================
// [asmjit::BaseEmitter - Error Handling]
// ============================================================================
void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept {
if (errorHandler) {
_errorHandler = errorHandler;
_addEmitterFlags(kFlagOwnErrorHandler);
}
else {
_errorHandler = nullptr;
_clearEmitterFlags(kFlagOwnErrorHandler);
if (_code)
_errorHandler = _code->errorHandler();
}
}
Error BaseEmitter::reportError(Error err, const char* message) {
ErrorHandler* eh = _errorHandler;
if (eh) {
if (!message)
message = DebugUtils::errorAsString(err);
eh->handleError(err, message, this);
}
return err;
}
// ============================================================================
// [asmjit::BaseEmitter - Labels]
// ============================================================================
Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept {
return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId));
}
bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept {
return _code && labelId < _code->labelCount();
}
// ============================================================================
// [asmjit::BaseEmitter - Emit (Low-Level)]
// ============================================================================
using EmitterUtils::noExt;
Error BaseEmitter::_emitI(uint32_t instId) {
return _emit(instId, noExt[0], noExt[1], noExt[2], noExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) {
return _emit(instId, o0, noExt[1], noExt[2], noExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) {
return _emit(instId, o0, o1, noExt[2], noExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) {
return _emit(instId, o0, o1, o2, noExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
Operand_ opExt[3] = { o3 };
return _emit(instId, o0, o1, o2, opExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) {
Operand_ opExt[3] = { o3, o4 };
return _emit(instId, o0, o1, o2, opExt);
}
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
Operand_ opExt[3] = { o3, o4, o5 };
return _emit(instId, o0, o1, o2, opExt);
}
Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) {
const Operand_* op = operands;
Operand_ opExt[3];
switch (opCount) {
case 0:
return _emit(instId, noExt[0], noExt[1], noExt[2], noExt);
case 1:
return _emit(instId, op[0], noExt[1], noExt[2], noExt);
case 2:
return _emit(instId, op[0], op[1], noExt[2], noExt);
case 3:
return _emit(instId, op[0], op[1], op[2], noExt);
case 4:
opExt[0] = op[3];
opExt[1].reset();
opExt[2].reset();
return _emit(instId, op[0], op[1], op[2], opExt);
case 5:
opExt[0] = op[3];
opExt[1] = op[4];
opExt[2].reset();
return _emit(instId, op[0], op[1], op[2], opExt);
case 6:
return _emit(instId, op[0], op[1], op[2], op + 3);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================
// [asmjit::BaseEmitter - Emit (High-Level)]
// ============================================================================
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
#ifdef ASMJIT_BUILD_X86
if (environment().isFamilyX86()) {
x86::EmitHelper emitHelper(this, frame.isAvxEnabled());
return emitHelper.emitProlog(frame);
}
#endif
#ifdef ASMJIT_BUILD_ARM
if (environment().isArchAArch64()) {
a64::EmitHelper emitHelper(this);
return emitHelper.emitProlog(frame);
}
#endif
return DebugUtils::errored(kErrorInvalidArch);
}
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitEpilog(const FuncFrame& frame) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
#ifdef ASMJIT_BUILD_X86
if (environment().isFamilyX86()) {
x86::EmitHelper emitHelper(this, frame.isAvxEnabled());
return emitHelper.emitEpilog(frame);
}
#endif
#ifdef ASMJIT_BUILD_ARM
if (environment().isArchAArch64()) {
a64::EmitHelper emitHelper(this);
return emitHelper.emitEpilog(frame);
}
#endif
return DebugUtils::errored(kErrorInvalidArch);
}
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
#ifdef ASMJIT_BUILD_X86
if (environment().isFamilyX86()) {
x86::EmitHelper emitHelper(this, frame.isAvxEnabled());
return emitHelper.emitArgsAssignment(frame, args);
}
#endif
#ifdef ASMJIT_BUILD_ARM
if (environment().isArchAArch64()) {
a64::EmitHelper emitHelper(this);
return emitHelper.emitArgsAssignment(frame, args);
}
#endif
return DebugUtils::errored(kErrorInvalidArch);
}
// ============================================================================
// [asmjit::BaseEmitter - Comment]
// ============================================================================
Error BaseEmitter::commentf(const char* fmt, ...) {
if (!hasEmitterFlag(kFlagLogComments)) {
if (!hasEmitterFlag(kFlagAttached))
return reportError(DebugUtils::errored(kErrorNotInitialized));
return kErrorOk;
}
#ifndef ASMJIT_NO_LOGGING
StringTmp<1024> sb;
va_list ap;
va_start(ap, fmt);
Error err = sb.appendVFormat(fmt, ap);
va_end(ap);
ASMJIT_PROPAGATE(err);
return comment(sb.data(), sb.size());
#else
DebugUtils::unused(fmt);
return kErrorOk;
#endif
}
Error BaseEmitter::commentv(const char* fmt, va_list ap) {
if (!hasEmitterFlag(kFlagLogComments)) {
if (!hasEmitterFlag(kFlagAttached))
return reportError(DebugUtils::errored(kErrorNotInitialized));
return kErrorOk;
}
#ifndef ASMJIT_NO_LOGGING
StringTmp<1024> sb;
Error err = sb.appendVFormat(fmt, ap);
ASMJIT_PROPAGATE(err);
return comment(sb.data(), sb.size());
#else
DebugUtils::unused(fmt, ap);
return kErrorOk;
#endif
}
// ============================================================================
// [asmjit::BaseEmitter - Events]
// ============================================================================
Error BaseEmitter::onAttach(CodeHolder* code) noexcept {
_code = code;
_environment = code->environment();
_addEmitterFlags(kFlagAttached);
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
_gpRegInfo.setSignature(archTraits._regInfo[nativeRegType].signature());
onSettingsUpdated();
return kErrorOk;
}
Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
DebugUtils::unused(code);
if (!hasOwnLogger())
_logger = nullptr;
if (!hasOwnErrorHandler())
_errorHandler = nullptr;
_clearEmitterFlags(~kEmitterPreservedFlags);
_forcedInstOptions = BaseInst::kOptionReserved;
_privateData = 0;
_environment.reset();
_gpRegInfo.reset();
_instOptions = 0;
_extraReg.reset();
_inlineComment = nullptr;
return kErrorOk;
}
void BaseEmitter::onSettingsUpdated() noexcept {
// Only called when attached to CodeHolder by CodeHolder.
ASMJIT_ASSERT(_code != nullptr);
if (!hasOwnLogger())
_logger = _code->logger();
if (!hasOwnErrorHandler())
_errorHandler = _code->errorHandler();
BaseEmitter_updateForcedOptions(this);
}
ASMJIT_END_NAMESPACE