// This file is part of AsmJit project // // 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(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("?$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("."); } 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(); uint32_t elementType = op.as().elementType(); uint32_t elementIndex = op.as().elementIndex(); if (!op.as().hasElementIndex()) elementIndex = 0xFFFFFFFFu; return formatRegister(sb, flags, emitter, arch, reg.type(), reg.id(), elementType, elementIndex); } if (op.isMem()) { const Mem& m = op.as(); 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("")); } } // 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(); 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(""); } // 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