mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
Refactored naming of data types in formatted text, which is now part of architecture traits
This commit is contained in:
@@ -40,18 +40,37 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static const constexpr ArchTraits noArchTraits = {
|
static const constexpr ArchTraits noArchTraits = {
|
||||||
0xFF, // SP.
|
// SP/FP/LR/PC.
|
||||||
0xFF, // FP.
|
0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, // LR.
|
|
||||||
0xFF, // PC.
|
// Reserved,
|
||||||
{ 0, 0, 0 }, // Reserved.
|
{ 0, 0, 0 },
|
||||||
0, // HW stack alignment.
|
|
||||||
0, // Min stack offset.
|
// HW stack alignment.
|
||||||
0, // Max stack offset.
|
0,
|
||||||
{ 0, 0, 0, 0}, // ISA features [Gp, Vec, Other0, Other1].
|
|
||||||
{ { 0 } }, // RegTypeToSignature.
|
// Min/Max stack offset.
|
||||||
{ 0 }, // RegTypeToTypeId.
|
0, 0,
|
||||||
{ 0 } // TypeIdToRegType.
|
|
||||||
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
|
{ 0, 0, 0, 0},
|
||||||
|
|
||||||
|
// RegTypeToSignature.
|
||||||
|
{ { 0 } },
|
||||||
|
|
||||||
|
// RegTypeToTypeId.
|
||||||
|
{ 0 },
|
||||||
|
|
||||||
|
// TypeIdToRegType.
|
||||||
|
{ 0 },
|
||||||
|
|
||||||
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
|
{
|
||||||
|
ISAWordNameId::kByte,
|
||||||
|
ISAWordNameId::kHalf,
|
||||||
|
ISAWordNameId::kWord,
|
||||||
|
ISAWordNameId::kQuad
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
|
ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
|
||||||
|
|||||||
@@ -33,6 +33,41 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Identifier used to represent names of different data types across architectures.
|
||||||
|
enum class ISAWordNameId : uint8_t {
|
||||||
|
//! Describes 'db' (X86/X86_64 convention, always 8-bit quantity).
|
||||||
|
kDB = 0,
|
||||||
|
//! Describes 'dw' (X86/X86_64 convention, always 16-bit word).
|
||||||
|
kDW,
|
||||||
|
//! Describes 'dd' (X86/X86_64 convention, always 32-bit word).
|
||||||
|
kDD,
|
||||||
|
//! Describes 'dq' (X86/X86_64 convention, always 64-bit word).
|
||||||
|
kDQ,
|
||||||
|
//! Describes 'byte' (always 8-bit quantity).
|
||||||
|
kByte,
|
||||||
|
//! Describes 'half' (most likely 16-bit word).
|
||||||
|
kHalf,
|
||||||
|
//! Describes 'word' (either 16-bit or 32-bit word).
|
||||||
|
kWord,
|
||||||
|
//! Describes 'hword' (most likely 16-bit word).
|
||||||
|
kHWord,
|
||||||
|
//! Describes 'dword' (either 32-bit or 64-bit word).
|
||||||
|
kDWord,
|
||||||
|
//! Describes 'qword' (64-bit word).
|
||||||
|
kQWord,
|
||||||
|
//! Describes 'xword' (64-bit word).
|
||||||
|
kXWord,
|
||||||
|
//! Describes 'short' (always 16-bit word).
|
||||||
|
kShort,
|
||||||
|
//! Describes 'long' (most likely 32-bit word).
|
||||||
|
kLong,
|
||||||
|
//! Describes 'quad' (64-bit word).
|
||||||
|
kQuad,
|
||||||
|
|
||||||
|
//! Maximum value.
|
||||||
|
kMaxValue = kQuad
|
||||||
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// [asmjit::ArchTraits]
|
// [asmjit::ArchTraits]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -60,6 +95,7 @@ struct ArchTraits {
|
|||||||
uint8_t _reserved[3];
|
uint8_t _reserved[3];
|
||||||
//! Hardware stack alignment requirement.
|
//! Hardware stack alignment requirement.
|
||||||
uint8_t _hwStackAlignment;
|
uint8_t _hwStackAlignment;
|
||||||
|
|
||||||
//! Minimum addressable offset on stack guaranteed for all instructions.
|
//! Minimum addressable offset on stack guaranteed for all instructions.
|
||||||
uint32_t _minStackOffset;
|
uint32_t _minStackOffset;
|
||||||
//! Maximum addressable offset on stack depending on specific instruction.
|
//! Maximum addressable offset on stack depending on specific instruction.
|
||||||
@@ -76,6 +112,9 @@ struct ArchTraits {
|
|||||||
//! Maps base TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref Type::Id.
|
//! Maps base TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref Type::Id.
|
||||||
uint8_t _typeIdToRegType[32];
|
uint8_t _typeIdToRegType[32];
|
||||||
|
|
||||||
|
//! Word name identifiers of 8-bit, 16-bit, 32-biit, and 64-bit quantities that appear in formatted text.
|
||||||
|
ISAWordNameId _isaWordNameIdTable[4];
|
||||||
|
|
||||||
//! Resets all members to zeros.
|
//! Resets all members to zeros.
|
||||||
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
||||||
|
|
||||||
@@ -141,6 +180,18 @@ struct ArchTraits {
|
|||||||
return _regTypeToTypeId[rType];
|
return _regTypeToTypeId[rType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Returns a table of ISA word names that appear in formatted text. Word names are ISA dependent.
|
||||||
|
//!
|
||||||
|
//! The index of this table is log2 of the size:
|
||||||
|
//! - [0] 8-bits
|
||||||
|
//! - [1] 16-bits
|
||||||
|
//! - [2] 32-bits
|
||||||
|
//! - [3] 64-bits
|
||||||
|
inline const ISAWordNameId* isaWordNameIdTable() const noexcept { return _isaWordNameIdTable; }
|
||||||
|
|
||||||
|
//! Returns an ISA word name identifier of the given `index`, see \ref isaWordNameIdTable() for more details.
|
||||||
|
inline ISAWordNameId isaWordNameId(uint32_t index) const noexcept { return _isaWordNameIdTable[index]; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Statics
|
//! \name Statics
|
||||||
|
|||||||
@@ -138,19 +138,6 @@ Error BaseAssembler::bind(const Label& label) {
|
|||||||
// [asmjit::BaseAssembler - Embed]
|
// [asmjit::BaseAssembler - Embed]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
|
||||||
struct DataSizeByPower {
|
|
||||||
char str[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static const DataSizeByPower dataSizeByPowerTable[] = {
|
|
||||||
{ "db" },
|
|
||||||
{ "dw" },
|
|
||||||
{ "dd" },
|
|
||||||
{ "dq" }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
@@ -162,30 +149,34 @@ Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
|||||||
ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize));
|
ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize));
|
||||||
|
|
||||||
writer.emitData(data, dataSize);
|
writer.emitData(data, dataSize);
|
||||||
|
writer.done(this);
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger)
|
if (_logger) {
|
||||||
_logger->logBinary(data, dataSize);
|
StringTmp<512> sb;
|
||||||
|
Formatter::formatData(sb, _logger->flags(), arch(), Type::kIdU8, data, dataSize, 1);
|
||||||
|
sb.append('\n');
|
||||||
|
_logger->log(sb);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
writer.done(this);
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount) {
|
Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) {
|
||||||
uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
|
uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
|
||||||
uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
|
uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
|
if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
|
|
||||||
if (itemCcount == 0 || repeatCount == 0)
|
if (itemCount == 0 || repeatCount == 0)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
uint32_t typeSize = Type::sizeOf(finalTypeId);
|
uint32_t typeSize = Type::sizeOf(finalTypeId);
|
||||||
Support::FastUInt8 of = 0;
|
Support::FastUInt8 of = 0;
|
||||||
|
|
||||||
size_t dataSize = Support::mulOverflow(itemCcount, size_t(typeSize), &of);
|
size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of);
|
||||||
size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of);
|
size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(of))
|
if (ASMJIT_UNLIKELY(of))
|
||||||
@@ -194,23 +185,37 @@ Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t it
|
|||||||
CodeWriter writer(this);
|
CodeWriter writer(this);
|
||||||
ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize));
|
ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize));
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
for (size_t i = 0; i < repeatCount; i++)
|
||||||
const uint8_t* start = writer.cursor();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (size_t i = 0; i < repeatCount; i++) {
|
|
||||||
writer.emitData(data, dataSize);
|
writer.emitData(data, dataSize);
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
|
||||||
if (_logger)
|
|
||||||
_logger->logBinary(start, totalSize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
writer.done(this);
|
writer.done(this);
|
||||||
|
|
||||||
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
if (_logger) {
|
||||||
|
StringTmp<512> sb;
|
||||||
|
Formatter::formatData(sb, _logger->flags(), arch(), typeId, data, itemCount, repeatCount);
|
||||||
|
sb.append('\n');
|
||||||
|
_logger->log(sb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
static const uint8_t dataTypeIdBySize[9] = {
|
||||||
|
Type::kIdVoid, // [0] (invalid)
|
||||||
|
Type::kIdU8, // [1] (uint8_t)
|
||||||
|
Type::kIdU16, // [2] (uint16_t)
|
||||||
|
Type::kIdVoid, // [3] (invalid)
|
||||||
|
Type::kIdU32, // [4] (uint32_t)
|
||||||
|
Type::kIdVoid, // [5] (invalid)
|
||||||
|
Type::kIdVoid, // [6] (invalid)
|
||||||
|
Type::kIdVoid, // [7] (invalid)
|
||||||
|
Type::kIdU64 // [8] (uint64_t)
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
|
Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
@@ -222,19 +227,32 @@ Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
|
|||||||
ASMJIT_PROPAGATE(bind(label));
|
ASMJIT_PROPAGATE(bind(label));
|
||||||
|
|
||||||
size_t size = pool.size();
|
size_t size = pool.size();
|
||||||
|
if (!size)
|
||||||
|
return kErrorOk;
|
||||||
|
|
||||||
CodeWriter writer(this);
|
CodeWriter writer(this);
|
||||||
ASMJIT_PROPAGATE(writer.ensureSpace(this, size));
|
ASMJIT_PROPAGATE(writer.ensureSpace(this, size));
|
||||||
|
|
||||||
pool.fill(writer.cursor());
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger)
|
uint8_t* data = writer.cursor();
|
||||||
_logger->logBinary(writer.cursor(), size);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
pool.fill(writer.cursor());
|
||||||
writer.advance(size);
|
writer.advance(size);
|
||||||
writer.done(this);
|
writer.done(this);
|
||||||
|
|
||||||
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
if (_logger) {
|
||||||
|
uint32_t dataSizeLog2 = Support::min<uint32_t>(Support::ctz(pool.minItemSize()), 3);
|
||||||
|
uint32_t dataSize = 1 << dataSizeLog2;
|
||||||
|
|
||||||
|
StringTmp<512> sb;
|
||||||
|
Formatter::formatData(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize], data, size >> dataSizeLog2);
|
||||||
|
sb.append('\n');
|
||||||
|
_logger->log(sb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +279,9 @@ Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
|
|||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger) {
|
if (_logger) {
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
sb.appendFormat("%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str);
|
sb.append('.');
|
||||||
|
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
||||||
|
sb.append(' ');
|
||||||
Formatter::formatLabel(sb, 0, this, label.id());
|
Formatter::formatLabel(sb, 0, this, label.id());
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
_logger->log(sb);
|
_logger->log(sb);
|
||||||
@@ -320,7 +340,9 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger) {
|
if (_logger) {
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
sb.appendFormat(".%s (", dataSizeByPowerTable[Support::ctz(dataSize)].str);
|
sb.append('.');
|
||||||
|
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
||||||
|
sb.append(" (");
|
||||||
Formatter::formatLabel(sb, 0, this, label.id());
|
Formatter::formatLabel(sb, 0, this, label.id());
|
||||||
sb.append(" - ");
|
sb.append(" - ");
|
||||||
Formatter::formatLabel(sb, 0, this, base.id());
|
Formatter::formatLabel(sb, 0, this, base.id());
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
|
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
|
||||||
ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount = 1) override;
|
ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) override;
|
||||||
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
||||||
|
|
||||||
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
|
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ void ConstPool::reset(Zone* zone) noexcept {
|
|||||||
_gapPool = nullptr;
|
_gapPool = nullptr;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_alignment = 0;
|
_alignment = 0;
|
||||||
|
_minItemSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -186,7 +187,8 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
|
|
||||||
// Add the initial node to the right index.
|
// Add the initial node to the right index.
|
||||||
node = ConstPool::Tree::_newNode(_zone, data, size, offset, false);
|
node = ConstPool::Tree::_newNode(_zone, data, size, offset, false);
|
||||||
if (!node) return DebugUtils::errored(kErrorOutOfMemory);
|
if (ASMJIT_UNLIKELY(!node))
|
||||||
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
_tree[treeIndex].insert(node);
|
_tree[treeIndex].insert(node);
|
||||||
_alignment = Support::max<size_t>(_alignment, size);
|
_alignment = Support::max<size_t>(_alignment, size);
|
||||||
@@ -197,23 +199,30 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
// We stop at size 4, it probably doesn't make sense to split constants down
|
// We stop at size 4, it probably doesn't make sense to split constants down
|
||||||
// to 1 byte.
|
// to 1 byte.
|
||||||
size_t pCount = 1;
|
size_t pCount = 1;
|
||||||
while (size > 4) {
|
size_t smallerSize = size;
|
||||||
size >>= 1;
|
|
||||||
|
while (smallerSize > 4) {
|
||||||
pCount <<= 1;
|
pCount <<= 1;
|
||||||
|
smallerSize >>= 1;
|
||||||
|
|
||||||
ASMJIT_ASSERT(treeIndex != 0);
|
ASMJIT_ASSERT(treeIndex != 0);
|
||||||
treeIndex--;
|
treeIndex--;
|
||||||
|
|
||||||
const uint8_t* pData = static_cast<const uint8_t*>(data);
|
const uint8_t* pData = static_cast<const uint8_t*>(data);
|
||||||
for (size_t i = 0; i < pCount; i++, pData += size) {
|
for (size_t i = 0; i < pCount; i++, pData += smallerSize) {
|
||||||
node = _tree[treeIndex].get(pData);
|
node = _tree[treeIndex].get(pData);
|
||||||
if (node) continue;
|
if (node) continue;
|
||||||
|
|
||||||
node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true);
|
node = ConstPool::Tree::_newNode(_zone, pData, smallerSize, offset + (i * smallerSize), true);
|
||||||
_tree[treeIndex].insert(node);
|
_tree[treeIndex].insert(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_minItemSize == 0)
|
||||||
|
_minItemSize = size;
|
||||||
|
else
|
||||||
|
_minItemSize = Support::min(_minItemSize, size);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,6 +206,8 @@ public:
|
|||||||
size_t _size;
|
size_t _size;
|
||||||
//! Required pool alignment.
|
//! Required pool alignment.
|
||||||
size_t _alignment;
|
size_t _alignment;
|
||||||
|
//! Minimum item size in the pool.
|
||||||
|
size_t _minItemSize;
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -226,6 +228,8 @@ public:
|
|||||||
inline size_t size() const noexcept { return _size; }
|
inline size_t size() const noexcept { return _size; }
|
||||||
//! Returns minimum alignment.
|
//! Returns minimum alignment.
|
||||||
inline size_t alignment() const noexcept { return _alignment; }
|
inline size_t alignment() const noexcept { return _alignment; }
|
||||||
|
//! Returns the minimum size of all items added to the constant pool.
|
||||||
|
inline size_t minItemSize() const noexcept { return _minItemSize; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
|
||||||
|
#include "../core/archtraits.h"
|
||||||
#include "../core/builder.h"
|
#include "../core/builder.h"
|
||||||
#include "../core/codeholder.h"
|
#include "../core/codeholder.h"
|
||||||
#include "../core/compiler.h"
|
#include "../core/compiler.h"
|
||||||
@@ -53,6 +54,24 @@ class VirtReg;
|
|||||||
|
|
||||||
namespace Formatter {
|
namespace Formatter {
|
||||||
|
|
||||||
|
static const char wordNameTable[][8] = {
|
||||||
|
"db",
|
||||||
|
"dw",
|
||||||
|
"dd",
|
||||||
|
"dq",
|
||||||
|
"byte",
|
||||||
|
"half",
|
||||||
|
"word",
|
||||||
|
"hword",
|
||||||
|
"dword",
|
||||||
|
"qword",
|
||||||
|
"xword",
|
||||||
|
"short",
|
||||||
|
"long",
|
||||||
|
"quad"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Error formatTypeId(String& sb, uint32_t typeId) noexcept {
|
Error formatTypeId(String& sb, uint32_t typeId) noexcept {
|
||||||
if (typeId == Type::kIdVoid)
|
if (typeId == Type::kIdVoid)
|
||||||
return sb.append("void");
|
return sb.append("void");
|
||||||
@@ -188,6 +207,84 @@ Error formatOperand(
|
|||||||
return kErrorInvalidArch;
|
return kErrorInvalidArch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASMJIT_API Error formatDataType(
|
||||||
|
String& sb,
|
||||||
|
uint32_t formatFlags,
|
||||||
|
uint32_t arch,
|
||||||
|
uint32_t typeId) noexcept
|
||||||
|
{
|
||||||
|
DebugUtils::unused(formatFlags);
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
|
||||||
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
|
uint32_t typeSize = Type::sizeOf(typeId);
|
||||||
|
if (typeSize == 0 || typeSize > 8)
|
||||||
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
|
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
||||||
|
return sb.append(wordNameTable[size_t(_archTraits[arch].isaWordNameId(typeSizeLog2))]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSize, const uint8_t* data, size_t itemCount) noexcept {
|
||||||
|
sb.append('.');
|
||||||
|
sb.append(typeName);
|
||||||
|
sb.append(' ');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < itemCount; i++) {
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
if (i != 0)
|
||||||
|
ASMJIT_PROPAGATE(sb.append(", ", 2));
|
||||||
|
|
||||||
|
switch (typeSize) {
|
||||||
|
case 1: v = data[0]; break;
|
||||||
|
case 2: v = Support::readU16u(data); break;
|
||||||
|
case 4: v = Support::readU32u(data); break;
|
||||||
|
case 8: v = Support::readU64u(data); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, String::kFormatAlternate));
|
||||||
|
data += typeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error formatData(
|
||||||
|
String& sb,
|
||||||
|
uint32_t formatFlags,
|
||||||
|
uint32_t arch,
|
||||||
|
uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) noexcept
|
||||||
|
{
|
||||||
|
DebugUtils::unused(formatFlags);
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
|
||||||
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
|
uint32_t typeSize = Type::sizeOf(typeId);
|
||||||
|
if (typeSize == 0)
|
||||||
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
|
if (!Support::isPowerOf2(typeSize)) {
|
||||||
|
itemCount *= typeSize;
|
||||||
|
typeSize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (typeSize > 8u) {
|
||||||
|
typeSize >>= 1;
|
||||||
|
itemCount <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
||||||
|
const char* wordName = wordNameTable[size_t(_archTraits[arch].isaWordNameId(typeSizeLog2))];
|
||||||
|
|
||||||
|
if (repeatCount > 1)
|
||||||
|
ASMJIT_PROPAGATE(sb.appendFormat(".repeat %zu ", repeatCount));
|
||||||
|
|
||||||
|
return formatDataHelper(sb, wordName, typeSize, static_cast<const uint8_t*>(data), itemCount);
|
||||||
|
}
|
||||||
|
|
||||||
Error formatInstruction(
|
Error formatInstruction(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
uint32_t formatFlags,
|
||||||
@@ -345,7 +442,7 @@ Error formatNode(
|
|||||||
case BaseNode::kNodeAlign: {
|
case BaseNode::kNodeAlign: {
|
||||||
const AlignNode* alignNode = node->as<AlignNode>();
|
const AlignNode* alignNode = node->as<AlignNode>();
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(
|
||||||
sb.appendFormat("align %u (%s)",
|
sb.appendFormat(".align %u (%s)",
|
||||||
alignNode->alignment(),
|
alignNode->alignment(),
|
||||||
alignNode->alignMode() == kAlignCode ? "code" : "data"));
|
alignNode->alignMode() == kAlignCode ? "code" : "data"));
|
||||||
break;
|
break;
|
||||||
@@ -353,10 +450,9 @@ Error formatNode(
|
|||||||
|
|
||||||
case BaseNode::kNodeEmbedData: {
|
case BaseNode::kNodeEmbedData: {
|
||||||
const EmbedDataNode* embedNode = node->as<EmbedDataNode>();
|
const EmbedDataNode* embedNode = node->as<EmbedDataNode>();
|
||||||
ASMJIT_PROPAGATE(sb.append("embed "));
|
ASMJIT_PROPAGATE(sb.append('.'));
|
||||||
if (embedNode->repeatCount() != 1)
|
ASMJIT_PROPAGATE(formatDataType(sb, formatFlags, builder->arch(), embedNode->typeId()));
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("[repeat=%zu] ", size_t(embedNode->repeatCount())));
|
ASMJIT_PROPAGATE(sb.appendFormat(" {Count=%zu Repeat=%zu TotalSize=%zu}", embedNode->itemCount(), embedNode->repeatCount(), embedNode->dataSize()));
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("%u bytes", embedNode->dataSize()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +473,12 @@ Error formatNode(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BaseNode::kNodeConstPool: {
|
||||||
|
const ConstPoolNode* constPoolNode = node->as<ConstPoolNode>();
|
||||||
|
ASMJIT_PROPAGATE(sb.appendFormat("[ConstPool Size=%zu Alignment=%zu]", constPoolNode->size(), constPoolNode->alignment()));
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
case BaseNode::kNodeComment: {
|
case BaseNode::kNodeComment: {
|
||||||
const CommentNode* commentNode = node->as<CommentNode>();
|
const CommentNode* commentNode = node->as<CommentNode>();
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment()));
|
ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment()));
|
||||||
|
|||||||
@@ -203,6 +203,20 @@ ASMJIT_API Error formatOperand(
|
|||||||
uint32_t arch,
|
uint32_t arch,
|
||||||
const Operand_& op) noexcept;
|
const Operand_& op) noexcept;
|
||||||
|
|
||||||
|
//! Appends a formatted data-type to the output string `sb`.
|
||||||
|
ASMJIT_API Error formatDataType(
|
||||||
|
String& sb,
|
||||||
|
uint32_t formatFlags,
|
||||||
|
uint32_t arch,
|
||||||
|
uint32_t typeId) noexcept;
|
||||||
|
|
||||||
|
//! Appends a formatted data to the output string `sb`.
|
||||||
|
ASMJIT_API Error formatData(
|
||||||
|
String& sb,
|
||||||
|
uint32_t formatFlags,
|
||||||
|
uint32_t arch,
|
||||||
|
uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted instruction to the output string `sb`.
|
//! Appends a formatted instruction to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! \note Emitter is optional, but it's required to format named labels and
|
//! \note Emitter is optional, but it's required to format named labels and
|
||||||
|
|||||||
@@ -59,28 +59,6 @@ Error Logger::logv(const char* fmt, va_list ap) noexcept {
|
|||||||
return log(sb);
|
return log(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Logger::logBinary(const void* data, size_t size) noexcept {
|
|
||||||
static const char prefix[] = "db ";
|
|
||||||
|
|
||||||
StringTmp<256> sb;
|
|
||||||
sb.append(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
|
|
||||||
|
|
||||||
size_t i = size;
|
|
||||||
const uint8_t* s = static_cast<const uint8_t*>(data);
|
|
||||||
|
|
||||||
while (i) {
|
|
||||||
uint32_t n = uint32_t(Support::min<size_t>(i, 16));
|
|
||||||
sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1);
|
|
||||||
sb.appendHex(s, n);
|
|
||||||
sb.append('\n');
|
|
||||||
ASMJIT_PROPAGATE(log(sb));
|
|
||||||
s += n;
|
|
||||||
i -= n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kErrorOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// [asmjit::FileLogger - Construction / Destruction]
|
// [asmjit::FileLogger - Construction / Destruction]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -119,9 +119,6 @@ public:
|
|||||||
//! string to \ref _log().
|
//! string to \ref _log().
|
||||||
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
|
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
|
||||||
|
|
||||||
//! Logs binary `data` of the given `size`.
|
|
||||||
ASMJIT_API Error logBinary(const void* data, size_t size) noexcept;
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
// [asmjit::String - Globals]
|
// [asmjit::String - Globals]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static const char String_baseN[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
static const char String_baseN[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
constexpr size_t kMinAllocSize = 64;
|
constexpr size_t kMinAllocSize = 64;
|
||||||
constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold;
|
constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold;
|
||||||
@@ -256,7 +256,7 @@ Error String::padEnd(size_t n, char c) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept {
|
Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept {
|
||||||
if (base < 2 || base > 36)
|
if (base == 0)
|
||||||
base = 10;
|
base = 10;
|
||||||
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
@@ -284,13 +284,39 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
// [Number]
|
// [Number]
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
do {
|
switch (base) {
|
||||||
uint64_t d = i / base;
|
case 2:
|
||||||
uint64_t r = i % base;
|
case 8:
|
||||||
|
case 16: {
|
||||||
|
uint32_t shift = Support::ctz(base);
|
||||||
|
uint32_t mask = base - 1;
|
||||||
|
|
||||||
*--p = String_baseN[r];
|
do {
|
||||||
i = d;
|
uint64_t d = i >> shift;
|
||||||
} while (i);
|
size_t r = size_t(i & mask);
|
||||||
|
|
||||||
|
*--p = String_baseN[r];
|
||||||
|
i = d;
|
||||||
|
} while (i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 10: {
|
||||||
|
do {
|
||||||
|
uint64_t d = i / 10;
|
||||||
|
uint64_t r = i % 10;
|
||||||
|
|
||||||
|
*--p = char(uint32_t('0') + uint32_t(r));
|
||||||
|
i = d;
|
||||||
|
} while (i);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
size_t numberSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
|
size_t numberSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
|
||||||
|
|
||||||
@@ -540,6 +566,9 @@ UNIT(core_string) {
|
|||||||
EXPECT(s.appendUInt(1234) == kErrorOk);
|
EXPECT(s.appendUInt(1234) == kErrorOk);
|
||||||
EXPECT(s.eq("1234") == true);
|
EXPECT(s.eq("1234") == true);
|
||||||
|
|
||||||
|
EXPECT(s.assignUInt(0xFFFF, 16, 0, String::kFormatAlternate) == kErrorOk);
|
||||||
|
EXPECT(s.eq("0xFFFF"));
|
||||||
|
|
||||||
StringTmp<64> sTmp;
|
StringTmp<64> sTmp;
|
||||||
EXPECT(sTmp.isLarge());
|
EXPECT(sTmp.isLarge());
|
||||||
EXPECT(sTmp.isExternal());
|
EXPECT(sTmp.isExternal());
|
||||||
|
|||||||
@@ -39,22 +39,20 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static const constexpr ArchTraits x86ArchTraits = {
|
static const constexpr ArchTraits x86ArchTraits = {
|
||||||
Gp::kIdSp, // SP.
|
// SP/FP/LR/PC.
|
||||||
Gp::kIdBp, // FP.
|
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
||||||
0xFF, // LR.
|
|
||||||
0xFF, // PC.
|
// Reserved.
|
||||||
{ 0, 0, 0 }, // Reserved.
|
{ 0, 0, 0 },
|
||||||
1, // HW stack alignment.
|
|
||||||
0x7FFFFFFFu, // Min stack offset.
|
// HW stack alignment.
|
||||||
0x7FFFFFFFu, // Max stack offset.
|
1,
|
||||||
|
|
||||||
|
// Min/Max stack offset
|
||||||
|
0x7FFFFFFFu, 0x7FFFFFFFu,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
{
|
{ ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop, 0, 0, 0 },
|
||||||
ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
|
|
||||||
// RegInfo.
|
// RegInfo.
|
||||||
#define V(index) { x86::RegTraits<index>::kSignature }
|
#define V(index) { x86::RegTraits<index>::kSignature }
|
||||||
@@ -83,8 +81,16 @@ static const constexpr ArchTraits x86ArchTraits = {
|
|||||||
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) }
|
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
|
{
|
||||||
|
ISAWordNameId::kDB,
|
||||||
|
ISAWordNameId::kDW,
|
||||||
|
ISAWordNameId::kDD,
|
||||||
|
ISAWordNameId::kDQ
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -92,22 +98,20 @@ static const constexpr ArchTraits x86ArchTraits = {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static const constexpr ArchTraits x64ArchTraits = {
|
static const constexpr ArchTraits x64ArchTraits = {
|
||||||
Gp::kIdSp, // SP.
|
// SP/FP/LR/PC.
|
||||||
Gp::kIdBp, // FP.
|
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
||||||
0xFF, // LR.
|
|
||||||
0xFF, // PC.
|
// Reserved.
|
||||||
{ 0, 0, 0 }, // Reserved.
|
{ 0, 0, 0 },
|
||||||
1, // HW stack alignment.
|
|
||||||
0x7FFFFFFFu, // Min stack offset.
|
// HW stack alignment.
|
||||||
0x7FFFFFFFu, // Max stack offset.
|
1,
|
||||||
|
|
||||||
|
// Min/Max stack offset
|
||||||
|
0x7FFFFFFFu, 0x7FFFFFFFu,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
{
|
{ ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop, 0, 0, 0 },
|
||||||
ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
|
|
||||||
// RegInfo.
|
// RegInfo.
|
||||||
#define V(index) { x86::RegTraits<index>::kSignature }
|
#define V(index) { x86::RegTraits<index>::kSignature }
|
||||||
@@ -138,8 +142,16 @@ static const constexpr ArchTraits x64ArchTraits = {
|
|||||||
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) }
|
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
|
{
|
||||||
|
ISAWordNameId::kDB,
|
||||||
|
ISAWordNameId::kDW,
|
||||||
|
ISAWordNameId::kDD,
|
||||||
|
ISAWordNameId::kDQ
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
Reference in New Issue
Block a user