299 lines
7.4 KiB
C++
299 lines
7.4 KiB
C++
// This file is part of AsmJit project <https://asmjit.com>
|
|
//
|
|
// See asmjit.h or LICENSE.md for license and copyright information
|
|
// SPDX-License-Identifier: Zlib
|
|
|
|
#include "../core/api-build_p.h"
|
|
#ifndef ASMJIT_NO_LOGGING
|
|
|
|
#include "../core/misc_p.h"
|
|
#include "../core/support.h"
|
|
#include "../arm/a64formatter_p.h"
|
|
#include "../arm/a64instapi_p.h"
|
|
#include "../arm/a64instdb_p.h"
|
|
#include "../arm/a64operand.h"
|
|
|
|
#ifndef ASMJIT_NO_COMPILER
|
|
#include "../core/compiler.h"
|
|
#endif
|
|
|
|
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
|
|
|
// a64::FormatterInternal - Format Register
|
|
// ========================================
|
|
|
|
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
|
String& sb,
|
|
FormatFlags flags,
|
|
const BaseEmitter* emitter,
|
|
Arch arch,
|
|
RegType regType,
|
|
uint32_t rId,
|
|
uint32_t elementType,
|
|
uint32_t elementIndex) noexcept {
|
|
|
|
DebugUtils::unused(flags);
|
|
DebugUtils::unused(arch);
|
|
|
|
static const char bhsdq[] = "bhsdq";
|
|
|
|
bool virtRegFormatted = false;
|
|
|
|
#ifndef ASMJIT_NO_COMPILER
|
|
if (Operand::isVirtId(rId)) {
|
|
if (emitter && emitter->isCompiler()) {
|
|
const BaseCompiler* cc = static_cast<const BaseCompiler*>(emitter);
|
|
if (cc->isVirtIdValid(rId)) {
|
|
VirtReg* vReg = cc->virtRegById(rId);
|
|
ASMJIT_ASSERT(vReg != nullptr);
|
|
|
|
const char* name = vReg->name();
|
|
if (name && name[0] != '\0')
|
|
ASMJIT_PROPAGATE(sb.append(name));
|
|
else
|
|
ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId))));
|
|
|
|
virtRegFormatted = true;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
DebugUtils::unused(emitter, flags);
|
|
#endif
|
|
|
|
if (!virtRegFormatted) {
|
|
char letter = '\0';
|
|
switch (regType) {
|
|
case RegType::kARM_GpW:
|
|
if (rId == Gp::kIdZr)
|
|
return sb.append("wzr");
|
|
if (rId == Gp::kIdSp)
|
|
return sb.append("wsp");
|
|
|
|
letter = 'w';
|
|
break;
|
|
|
|
case RegType::kARM_GpX:
|
|
if (rId == Gp::kIdZr)
|
|
return sb.append("xzr");
|
|
if (rId == Gp::kIdSp)
|
|
return sb.append("sp");
|
|
|
|
letter = 'x';
|
|
break;
|
|
|
|
case RegType::kARM_VecB:
|
|
case RegType::kARM_VecH:
|
|
case RegType::kARM_VecS:
|
|
case RegType::kARM_VecD:
|
|
case RegType::kARM_VecV:
|
|
letter = bhsdq[uint32_t(regType) - uint32_t(RegType::kARM_VecB)];
|
|
if (elementType)
|
|
letter = 'v';
|
|
break;
|
|
|
|
default:
|
|
ASMJIT_PROPAGATE(sb.appendFormat("<Reg-%u>?$u", uint32_t(regType), rId));
|
|
break;
|
|
}
|
|
|
|
if (letter)
|
|
ASMJIT_PROPAGATE(sb.appendFormat("%c%u", letter, rId));
|
|
}
|
|
|
|
if (elementType) {
|
|
char elementLetter = '\0';
|
|
uint32_t elementCount = 0;
|
|
|
|
switch (elementType) {
|
|
case Vec::kElementTypeB:
|
|
elementLetter = 'b';
|
|
elementCount = 16;
|
|
break;
|
|
|
|
case Vec::kElementTypeH:
|
|
elementLetter = 'h';
|
|
elementCount = 8;
|
|
break;
|
|
|
|
case Vec::kElementTypeS:
|
|
elementLetter = 's';
|
|
elementCount = 4;
|
|
break;
|
|
|
|
case Vec::kElementTypeD:
|
|
elementLetter = 'd';
|
|
elementCount = 2;
|
|
break;
|
|
|
|
default:
|
|
return sb.append(".<Unknown>");
|
|
}
|
|
|
|
if (elementLetter) {
|
|
if (elementIndex == 0xFFFFFFFFu) {
|
|
if (regType == RegType::kARM_VecD)
|
|
elementCount /= 2u;
|
|
ASMJIT_PROPAGATE(sb.appendFormat(".%u%c", elementCount, elementLetter));
|
|
}
|
|
else {
|
|
ASMJIT_PROPAGATE(sb.appendFormat(".%c[%u]", elementLetter, elementIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
return kErrorOk;
|
|
}
|
|
|
|
// a64::FormatterInternal - Format Operand
|
|
// =======================================
|
|
|
|
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
|
String& sb,
|
|
FormatFlags flags,
|
|
const BaseEmitter* emitter,
|
|
Arch arch,
|
|
const Operand_& op) noexcept {
|
|
|
|
if (op.isReg()) {
|
|
const BaseReg& reg = op.as<BaseReg>();
|
|
|
|
uint32_t elementType = op.as<Vec>().elementType();
|
|
uint32_t elementIndex = op.as<Vec>().elementIndex();
|
|
|
|
if (!op.as<Vec>().hasElementIndex())
|
|
elementIndex = 0xFFFFFFFFu;
|
|
|
|
return formatRegister(sb, flags, emitter, arch, reg.type(), reg.id(), elementType, elementIndex);
|
|
}
|
|
|
|
if (op.isMem()) {
|
|
const Mem& m = op.as<Mem>();
|
|
ASMJIT_PROPAGATE(sb.append('['));
|
|
|
|
if (m.hasBase()) {
|
|
if (m.hasBaseLabel()) {
|
|
ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId()));
|
|
}
|
|
else {
|
|
FormatFlags modifiedFlags = flags;
|
|
if (m.isRegHome()) {
|
|
ASMJIT_PROPAGATE(sb.append('&'));
|
|
modifiedFlags &= ~FormatFlags::kRegCasts;
|
|
}
|
|
ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId()));
|
|
}
|
|
}
|
|
else {
|
|
// ARM really requires base.
|
|
if (m.hasIndex() || m.hasOffset()) {
|
|
ASMJIT_PROPAGATE(sb.append("<None>"));
|
|
}
|
|
}
|
|
|
|
// The post index makes it look like there was another operand, but it's
|
|
// still the part of AsmJit's `arm::Mem` operand so it's consistent with
|
|
// other architectures.
|
|
if (m.isPostIndex())
|
|
ASMJIT_PROPAGATE(sb.append(']'));
|
|
|
|
if (m.hasIndex()) {
|
|
ASMJIT_PROPAGATE(sb.append(", "));
|
|
ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId()));
|
|
}
|
|
|
|
if (m.hasOffset()) {
|
|
ASMJIT_PROPAGATE(sb.append(", "));
|
|
|
|
int64_t off = int64_t(m.offset());
|
|
uint32_t base = 10;
|
|
|
|
if (Support::test(flags, FormatFlags::kHexOffsets) && uint64_t(off) > 9)
|
|
base = 16;
|
|
|
|
if (base == 10) {
|
|
ASMJIT_PROPAGATE(sb.appendInt(off, base));
|
|
}
|
|
else {
|
|
ASMJIT_PROPAGATE(sb.append("0x"));
|
|
ASMJIT_PROPAGATE(sb.appendUInt(uint64_t(off), base));
|
|
}
|
|
}
|
|
|
|
if (m.hasShift()) {
|
|
ASMJIT_PROPAGATE(sb.append(' '));
|
|
if (!m.isPreOrPost())
|
|
ASMJIT_PROPAGATE(formatShiftOp(sb, (ShiftOp)m.predicate()));
|
|
ASMJIT_PROPAGATE(sb.appendFormat(" %u", m.shift()));
|
|
}
|
|
|
|
if (!m.isPostIndex())
|
|
ASMJIT_PROPAGATE(sb.append(']'));
|
|
|
|
if (m.isPreIndex())
|
|
ASMJIT_PROPAGATE(sb.append('!'));
|
|
|
|
return kErrorOk;
|
|
}
|
|
|
|
if (op.isImm()) {
|
|
const Imm& i = op.as<Imm>();
|
|
int64_t val = i.value();
|
|
|
|
if (Support::test(flags, FormatFlags::kHexImms) && uint64_t(val) > 9) {
|
|
ASMJIT_PROPAGATE(sb.append("0x"));
|
|
return sb.appendUInt(uint64_t(val), 16);
|
|
}
|
|
else {
|
|
return sb.appendInt(val, 10);
|
|
}
|
|
}
|
|
|
|
if (op.isLabel()) {
|
|
return Formatter::formatLabel(sb, flags, emitter, op.id());
|
|
}
|
|
|
|
return sb.append("<None>");
|
|
}
|
|
|
|
// a64::FormatterInternal - Format Instruction
|
|
// ===========================================
|
|
|
|
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
|
|
String& sb,
|
|
FormatFlags flags,
|
|
const BaseEmitter* emitter,
|
|
Arch arch,
|
|
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
|
|
|
|
DebugUtils::unused(arch);
|
|
|
|
// Format instruction options and instruction mnemonic.
|
|
InstId instId = inst.realId();
|
|
if (instId < Inst::_kIdCount)
|
|
ASMJIT_PROPAGATE(InstInternal::instIdToString(arch, instId, sb));
|
|
else
|
|
ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
|
|
|
|
CondCode cc = inst.armCondCode();
|
|
if (cc != CondCode::kAL) {
|
|
ASMJIT_PROPAGATE(sb.append('.'));
|
|
ASMJIT_PROPAGATE(formatCondCode(sb, cc));
|
|
}
|
|
|
|
for (uint32_t i = 0; i < opCount; i++) {
|
|
const Operand_& op = operands[i];
|
|
if (op.isNone())
|
|
break;
|
|
|
|
ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
|
|
ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, op));
|
|
}
|
|
|
|
return kErrorOk;
|
|
}
|
|
|
|
ASMJIT_END_SUB_NAMESPACE
|
|
|
|
#endif // !ASMJIT_NO_LOGGING
|