Added possibility to annotate a code compiled by compiler so it's easier to see which variables were translated to which registers.

This commit is contained in:
kobalicekp
2014-03-22 14:52:36 +01:00
parent 3b82708e39
commit 995730b929
9 changed files with 261 additions and 73 deletions

View File

@@ -78,6 +78,9 @@ If(MSVC)
If(WIN32)
List(APPEND ASMJIT_CFLAGS /D_UNICODE)
EndIf()
If(ASMJIT_STATIC)
List(APPEND ASMJIT_CFLAGS /DASMJIT_STATIC)
EndIf(ASMJIT_STATIC)
EndIf()
# GCC.
@@ -97,6 +100,9 @@ If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
If(WIN32)
List(APPEND ASMJIT_CFLAGS -D_UNICODE)
EndIf()
If(ASMJIT_STATIC)
List(APPEND ASMJIT_CFLAGS -DASMJIT_STATIC)
EndIf(ASMJIT_STATIC)
EndIf()
# Dependencies - Base.

View File

@@ -62,6 +62,7 @@ void BaseContext::reset() {
_memVarTotal = 0;
_memStackTotal = 0;
_memAllTotal = 0;
_annotationLength = 12;
_state = NULL;
}
@@ -327,6 +328,10 @@ Error BaseContext::compile(FuncNode* func) {
ASMJIT_PROPAGATE_ERROR(fetch());
ASMJIT_PROPAGATE_ERROR(removeUnreachableCode());
ASMJIT_PROPAGATE_ERROR(analyze());
if (_compiler->hasLogger())
ASMJIT_PROPAGATE_ERROR(annotate());
ASMJIT_PROPAGATE_ERROR(translate());
// We alter the compiler cursor, because it doesn't make sense to reference

View File

@@ -170,6 +170,12 @@ struct BaseContext {
//! repeats until all variables are resolved.
virtual Error analyze() = 0;
// --------------------------------------------------------------------------
// [Annotate]
// --------------------------------------------------------------------------
virtual Error annotate() = 0;
// --------------------------------------------------------------------------
// [Translate]
// --------------------------------------------------------------------------
@@ -256,6 +262,9 @@ struct BaseContext {
//! @brief Count of bytes used by variables and stack after alignment.
uint32_t _memAllTotal;
//! @brief Default lenght of annotated instruction.
uint32_t _annotationLength;
//! @brief Current state (used by register allocator).
BaseVarState* _state;
};

View File

@@ -500,16 +500,19 @@ struct FuncBuilderX : public FuncPrototype {
}
template<typename T>
ASMJIT_INLINE void setRetT()
{ setRet(TypeId<T>::kId); }
ASMJIT_INLINE void setRetT() {
setRet(TypeId<T>::kId);
}
template<typename T>
ASMJIT_INLINE void setArgT(uint32_t id)
{ setArg(id, TypeId<T>::kId); }
ASMJIT_INLINE void setArgT(uint32_t id) {
setArg(id, TypeId<T>::kId);
}
template<typename T>
ASMJIT_INLINE void addArgT()
{ addArg(TypeId<T>::kId); }
ASMJIT_INLINE void addArgT() {
addArg(TypeId<T>::kId);
}
// --------------------------------------------------------------------------
// [Members]

View File

@@ -107,7 +107,7 @@ struct VirtualMemoryManager : public MemoryManager {
//!
//! This is specialized version of constructor available only for windows and
//! usable to alloc/free memory of different process.
ASMJIT_API VirtualMemoryManager(HANDLE hProcess);
explicit ASMJIT_API VirtualMemoryManager(HANDLE hProcess);
#endif // ASMJIT_OS_WINDOWS
//! @brief Destroy the @c VirtualMemoryManager instance, this means also to

View File

@@ -543,7 +543,7 @@ static ASMJIT_INLINE size_t X86X64Assembler_relocCode(const X86X64Assembler* sel
}
// ============================================================================
// [asmjit::Assembler - Logging]
// [asmjit::x86x64::Assembler - Logging]
// ============================================================================
// Logging helpers.
@@ -578,9 +578,9 @@ static const char X86Assembler_segName[] =
"\0\0\0\0";
static void X86Assembler_dumpRegister(StringBuilder& sb, uint32_t type, uint32_t index) {
// NE == Not-Encodable.
// -- (Not-Encodable).
static const char reg8l[] = "al\0\0" "cl\0\0" "dl\0\0" "bl\0\0" "spl\0" "bpl\0" "sil\0" "dil\0" ;
static const char reg8h[] = "ah\0\0" "ch\0\0" "dh\0\0" "bh\0\0" "NE\0\0" "NE\0\0" "NE\0\0" "NE\0\0";
static const char reg8h[] = "ah\0\0" "ch\0\0" "dh\0\0" "bh\0\0" "--\0\0" "--\0\0" "--\0\0" "--\0\0";
static const char reg16[] = "ax\0\0" "cx\0\0" "dx\0\0" "bx\0\0" "sp\0\0" "bp\0\0" "si\0\0" "di\0\0";
char suffix = '\0';
@@ -606,11 +606,12 @@ static void X86Assembler_dumpRegister(StringBuilder& sb, uint32_t type, uint32_t
case kRegTypeGpbHi:
if (index >= 4)
goto _EmitNE;
sb._appendString(&reg8h[index * 4]);
return;
_EmitNE:
sb._appendString("NE", 2);
sb._appendString("--", 2);
return;
case kRegTypeGpw:
@@ -671,6 +672,7 @@ _EmitNE:
_EmitID:
sb._appendUInt32(index);
if (suffix)
sb._appendChar(suffix);
}
@@ -729,11 +731,11 @@ static void X86Assembler_dumpOperand(StringBuilder& sb, uint32_t arch, const Ope
case kMemVSibYmm: type = kRegTypeYmm; break;
}
sb._appendString(" + ", 3);
sb._appendChar('+');
X86Assembler_dumpRegister(sb, type, m->getIndex());
if (m->getShift()) {
sb._appendString(" * ", 3);
sb._appendChar('*');
sb._appendChar("1248"[m->getShift() & 3]);
}
}
@@ -742,13 +744,13 @@ static void X86Assembler_dumpOperand(StringBuilder& sb, uint32_t arch, const Ope
uint32_t base = 10;
int32_t dispOffset = m->getDisplacement();
const char* prefix = " + ";
char prefix = '+';
if (dispOffset < 0) {
dispOffset = -dispOffset;
prefix = " - ";
prefix = '-';
}
sb._appendString(prefix, 3);
sb._appendChar(prefix);
if ((loggerOptions & (1 << kLoggerOptionHexDisplacement)) != 0 && dispOffset > 9) {
sb._appendString("0x", 2);
base = 16;
@@ -781,8 +783,9 @@ static bool X86Assembler_dumpInstruction(StringBuilder& sb,
const Operand* o0,
const Operand* o1,
const Operand* o2,
uint32_t loggerOptions)
{
const Operand* o3,
uint32_t loggerOptions) {
if (!sb.reserve(sb.getLength() + 128))
return false;
@@ -815,6 +818,11 @@ static bool X86Assembler_dumpInstruction(StringBuilder& sb,
X86Assembler_dumpOperand(sb, arch, o2, loggerOptions);
}
if (!o3->isNone()) {
sb._appendString(", ", 3);
X86Assembler_dumpOperand(sb, arch, o3, loggerOptions);
}
return true;
}
@@ -867,7 +875,7 @@ static bool X86Assembler_dumpComment(StringBuilder& sb, size_t len, const uint8_
}
// ============================================================================
// [asmjit::Assembler - Emit]
// [asmjit::x86x64::Assembler - Emit]
// ============================================================================
//! @brief Encode MODR/M.
@@ -3641,7 +3649,7 @@ _EmitDone:
loggerOptions = self->_logger->getOptions();
}
X86Assembler_dumpInstruction(sb, Arch, code, options, o0, o1, o2, loggerOptions);
X86Assembler_dumpInstruction(sb, Arch, code, options, o0, o1, o2, o3, loggerOptions);
if ((loggerOptions & (1 << kLoggerOptionBinaryForm)) != 0)
X86Assembler_dumpComment(sb, sb.getLength(), self->_cursor, (intptr_t)(cursor - self->_cursor), dispSize, self->_comment);

View File

@@ -2584,7 +2584,7 @@ _NoMemory:
}
// ============================================================================
// [asmjit::x86x64::X86X64Context - AnalyzeFunc]
// [asmjit::x86x64::X86X64Context - Analyze]
// ============================================================================
//! @internal
@@ -2768,6 +2768,150 @@ _NoMemory:
return setError(kErrorNoHeapMemory);
}
// ============================================================================
// [asmjit::x86x64::X86X64Context - Annotate]
// ============================================================================
static void X86X64Context_annotateVariable(X86X64Context* self,
StringBuilder& sb, const VarData* vd) {
const char* name = vd->getName();
if (name != NULL && name[0] != '\0') {
sb._appendString(name);
}
else {
sb._appendChar('v');
sb._appendUInt32(vd->getId() & kOperandIdNum);
}
}
static void X86X64Context_annotateOperand(X86X64Context* self,
StringBuilder& sb, const Operand* op) {
if (op->isVar()) {
X86X64Context_annotateVariable(self, sb, self->_compiler->getVdById(op->getId()));
}
else if (op->isMem()) {
const Mem* m = static_cast<const Mem*>(op);
bool isAbsolute = false;
sb._appendChar('[');
switch (m->getMemType()) {
case kMemTypeBaseIndex:
case kMemTypeStackIndex:
// [base + index << shift + displacement]
X86X64Context_annotateVariable(self, sb, self->_compiler->getVdById(m->getBase()));
break;
case kMemTypeLabel:
// [label + index << shift + displacement]
sb.appendFormat("L%u", m->getBase());
break;
case kMemTypeAbsolute:
// [absolute]
isAbsolute = true;
sb.appendUInt(static_cast<uint32_t>(m->getDisplacement()), 16);
break;
}
if (m->hasIndex()) {
sb._appendChar('+');
X86X64Context_annotateVariable(self, sb, self->_compiler->getVdById(m->getIndex()));
if (m->getShift()) {
sb._appendChar('*');
sb._appendChar("1248"[m->getShift() & 3]);
}
}
if (m->getDisplacement() && !isAbsolute) {
uint32_t base = 10;
int32_t dispOffset = m->getDisplacement();
char prefix = '+';
if (dispOffset < 0) {
dispOffset = -dispOffset;
prefix = '-';
}
sb._appendChar(prefix);
/*
if ((loggerOptions & (1 << kLoggerOptionHexDisplacement)) != 0 && dispOffset > 9) {
sb._appendString("0x", 2);
base = 16;
}
*/
sb.appendUInt(static_cast<uint32_t>(dispOffset), base);
}
sb._appendChar(']');
}
else if (op->isImm()) {
const Imm* i = static_cast<const Imm*>(op);
int64_t val = i->getInt64();
/*
if ((loggerOptions & (1 << kLoggerOptionHexImmediate)) && static_cast<uint64_t>(val) > 9)
sb.appendUInt(static_cast<uint64_t>(val), 16);
else*/
sb.appendInt(val, 10);
}
else if (op->isLabel()) {
sb.appendFormat("L%u", op->getId());
}
else {
sb._appendString("None", 4);
}
}
static bool X86X64Context_annotateInstruction(X86X64Context* self,
StringBuilder& sb, uint32_t code, const Operand* opList, uint32_t opCount) {
if (!sb.reserve(sb.getLength() + 128))
return false;
sb._appendString(_instInfo[code].getName());
for (uint32_t i = 0; i < opCount; i++) {
if (i == 0)
sb._appendChar(' ');
else
sb._appendString(", ", 2);
X86X64Context_annotateOperand(self, sb, &opList[i]);
}
return true;
}
Error X86X64Context::annotate() {
FuncNode* func = getFunc();
BaseNode* node_ = func;
BaseNode* end = func->getEnd();
StringBuilderT<128> sb;
Zone& sa = _compiler->_stringAllocator;
uint32_t maxLen = 0;
while (node_ != end) {
if (node_->getComment() == NULL) {
if (node_->getType() == kNodeTypeInst) {
InstNode* node = static_cast<InstNode*>(node_);
X86X64Context_annotateInstruction(this, sb, node->getCode(), node->getOpList(), node->getOpCount());
node_->setComment(static_cast<char*>(sa.dup(sb.getData(), sb.getLength() + 1)));
maxLen = IntUtil::iMax<uint32_t>(maxLen, static_cast<uint32_t>(sb.getLength()));
sb.clear();
}
}
node_ = node_->getNext();
}
_annotationLength = maxLen + 1;
return kErrorOk;
}
// ============================================================================
// [asmjit::x86x64::X86X64BaseAlloc]
// ============================================================================
@@ -4784,7 +4928,7 @@ static Error X86X64Context_translatePrologEpilog(X86X64Context* self, X86X64Func
}
// ============================================================================
// [asmjit::x86x64::X86X64Context - TranslateJump]
// [asmjit::x86x64::X86X64Context - Translate - Jump]
// ============================================================================
//! @internal
@@ -4820,7 +4964,7 @@ static void X86X64Context_translateJump(X86X64Context* self, JumpNode* jNode, Ta
}
// ============================================================================
// [asmjit::x86x64::X86X64Context - TranslateRet]
// [asmjit::x86x64::X86X64Context - Translate - Ret]
// ============================================================================
static Error X86X64Context_translateRet(X86X64Context* self, RetNode* rNode, TargetNode* exitTarget) {
@@ -5120,10 +5264,14 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As
StringBuilder& sb = self->_stringBuilder;
BaseLogger* logger;
const char* comment;
uint32_t vdCount;
uint32_t annotationLength;
if (LoggingEnabled) {
logger = assembler->getLogger();
vdCount = static_cast<uint32_t>(self->_contextVd.getLength());
annotationLength = self->_annotationLength;
}
// Create labels on Assembler side.
@@ -5132,21 +5280,26 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As
do {
if (LoggingEnabled) {
comment = node_->getComment();
sb.clear();
if (node_->getComment()) {
sb.appendString(node_->getComment());
}
if (sb.getLength() < annotationLength)
sb.appendChars(' ', annotationLength - sb.getLength());
size_t offset = sb.getLength();
sb.appendChars(' ', vdCount);
if (node_->hasLiveness()) {
uint32_t i;
uint32_t vdCount = static_cast<uint32_t>(self->_contextVd.getLength());
VarBits* liveness = node_->getLiveness();
VarInst* vi = static_cast<VarInst*>(node_->getVarInst());
sb.clear();
sb.appendChars(' ', vdCount);
uint32_t i;
for (i = 0; i < vdCount; i++) {
if (liveness->getBit(i))
sb.getData()[i] = '.';
sb.getData()[offset + i] = '.';
}
if (vi != NULL) {
@@ -5166,15 +5319,12 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As
if ((flags & kVarAttrUnuse))
c -= 'a' - 'A';
sb.getData()[vd->getContextId()] = c;
sb.getData()[offset + vd->getContextId()] = c;
}
}
}
assembler->_comment = sb.getData();
}
else {
assembler->_comment = comment;
}
assembler->_comment = sb.getData();
}
switch (node_->getType()) {

View File

@@ -443,6 +443,12 @@ struct X86X64Context : public BaseContext {
virtual Error fetch();
virtual Error analyze();
// --------------------------------------------------------------------------
// [Annotate]
// --------------------------------------------------------------------------
virtual Error annotate();
// --------------------------------------------------------------------------
// [Translate]
// --------------------------------------------------------------------------

View File

@@ -99,7 +99,7 @@ ASMJIT_VAR const VarInfo _varInfo[];
// [asmjit::x86x64::kRegClass]
// ============================================================================
//! @brief X86 variable class.
//! @brief X86/X64 variable class.
ASMJIT_ENUM(kRegClass) {
// kRegClassGp defined in base/defs.h; it's used by all implementations.
@@ -118,6 +118,7 @@ ASMJIT_ENUM(kRegClass) {
// [asmjit::x86x64::kRegCount]
// ============================================================================
//! @brief X86/X64 registers count.
ASMJIT_ENUM(kRegCount) {
//! @brief Count of Fp registers (8).
kRegCountFp = 8,
@@ -131,7 +132,7 @@ ASMJIT_ENUM(kRegCount) {
// [asmjit::x86x64::kRegType]
// ============================================================================
//! @brief X86 register types.
//! @brief X86/X64 register types.
ASMJIT_ENUM(kRegType) {
//! @brief Gpb-lo register (AL, BL, CL, DL, ...).
kRegTypeGpbLo = 0x01,
@@ -170,7 +171,7 @@ ASMJIT_ENUM(kRegType) {
// [asmjit::x86x64::kRegIndex]
// ============================================================================
//! @brief X86 register indices.
//! @brief X86/X64 register indices.
//!
//! These codes are real, don't miss with @c REG enum! and don't use these
//! values if you are not writing AsmJit code.
@@ -313,7 +314,7 @@ ASMJIT_ENUM(kRegIndex) {
// [asmjit::x86x64::kSeg]
// ============================================================================
//! @brief X86 segment codes.
//! @brief X86/X64 segment codes.
ASMJIT_ENUM(kSeg) {
//! @brief No segment.
kSegDefault = 0,
@@ -335,7 +336,7 @@ ASMJIT_ENUM(kSeg) {
// [asmjit::x86x64::kMemVSib]
// ============================================================================
//! @brief X86 index register legacy and AVX2 (VSIB) support.
//! @brief X86/X64 index register legacy and AVX2 (VSIB) support.
ASMJIT_ENUM(kMemVSib) {
//! @brief Memory operand uses Gp or no index register.
kMemVSibGpz = 0,
@@ -351,7 +352,7 @@ ASMJIT_ENUM(kMemVSib) {
//! @internal
//!
//! @brief X86 specific memory flags.
//! @brief X86/X64 specific memory flags.
ASMJIT_ENUM(kMemFlags) {
kMemSegBits = 0x7,
kMemSegIndex = 0,
@@ -374,7 +375,7 @@ ASMJIT_ENUM(kMemFlags) {
// [asmjit::x86x64::kPrefetchHint]
// ============================================================================
//! @brief X86 Prefetch hints.
//! @brief X86/X64 Prefetch hints.
ASMJIT_ENUM(kPrefetchHint) {
//! @brief Prefetch using NT hint.
kPrefetchNta = 0,
@@ -390,7 +391,7 @@ ASMJIT_ENUM(kPrefetchHint) {
// [asmjit::x86x64::kFPSW]
// ============================================================================
//! @brief X86 FPU status Word.
//! @brief X86/X64 FPU status Word.
ASMJIT_ENUM(kFPSW) {
kFPSW_Invalid = 0x0001,
kFPSW_Denormalized = 0x0002,
@@ -412,7 +413,7 @@ ASMJIT_ENUM(kFPSW) {
// [asmjit::x86x64::kFPCW]
// ============================================================================
//! @brief X86 FPU control Word.
//! @brief X86/X64 FPU control Word.
ASMJIT_ENUM(kFPCW) {
kFPCW_EM_Mask = 0x003F, // Bits 0-5.
kFPCW_EM_Invalid = 0x0001,
@@ -443,7 +444,7 @@ ASMJIT_ENUM(kFPCW) {
// [asmjit::x86x64::kInstCode]
// ============================================================================
//! @brief X86 instruction codes.
//! @brief X86/X64 instruction codes.
//!
//! Note that these instruction codes are AsmJit specific. Each instruction has
//! a unique ID that is used as an index to AsmJit instruction table.
@@ -1415,7 +1416,7 @@ ASMJIT_ENUM(kInstCode) {
// [asmjit::x86x64::kInstOptions]
// ============================================================================
//! @brief Instruction emit options, mainly for internal purposes.
//! @brief X86/X64 instruction emit options, mainly for internal purposes.
ASMJIT_ENUM(kInstOptions) {
//! @brief Emit instruction with LOCK prefix.
//!
@@ -1443,7 +1444,7 @@ ASMJIT_ENUM(kInstOptions) {
// [asmjit::x86x64::kInstGroup]
// ============================================================================
//! @brief X86 instruction groups.
//! @brief X86/X64 instruction groups.
//!
//! This should be only used by assembler, because it's @c asmjit::Assembler
//! specific grouping. Each group represents one 'case' in the Assembler's
@@ -1676,7 +1677,7 @@ ASMJIT_ENUM(kInstOpCode) {
// [asmjit::x86x64::kInstFlags]
// ============================================================================
//! @brief X86 instruction type flags.
//! @brief X86/X64 instruction type flags.
ASMJIT_ENUM(kInstFlags) {
//! @brief No flags.
kInstFlagNone = 0x0000,
@@ -1748,7 +1749,7 @@ ASMJIT_ENUM(kInstFlags) {
// [asmjit::x86x64::kInstOp]
// ============================================================================
//! @brief X86 instruction operand flags.
//! @brief X86/X64 instruction operand flags.
ASMJIT_ENUM(kInstOp) {
// Gp, Fp, Mm, Xmm, Ymm, Zmm.
kInstOpGb = 0x0001,
@@ -1796,29 +1797,29 @@ ASMJIT_ENUM(kInstOp) {
// [asmjit::x86x64::kCond]
// ============================================================================
//! @brief X86 Condition codes.
//! @brief X86/X64 Condition codes.
ASMJIT_ENUM(kCond) {
// Condition codes from processor manuals.
kCondA = 0x07, // CF==0 & ZF==0
kCondAE = 0x03, // CF==0
kCondB = 0x02, // CF==1
kCondBE = 0x06, // CF==1 | ZF==1
kCondA = 0x07, // CF==0 & ZF==0 (unsigned)
kCondAE = 0x03, // CF==0 (unsigned)
kCondB = 0x02, // CF==1 (unsigned)
kCondBE = 0x06, // CF==1 | ZF==1 (unsigned)
kCondC = 0x02, // CF==1
kCondE = 0x04, // ZF==1
kCondG = 0x0F, // ZF==0 & SF==OF
kCondGE = 0x0D, // SF==OF
kCondL = 0x0C, // SF!=OF
kCondLE = 0x0E, // ZF==1 | SF!=OF
kCondNA = 0x06, // CF==1 | ZF==1
kCondNAE = 0x02, // CF==1
kCondNB = 0x03, // CF==0
kCondNBE = 0x07, // CF==0 & ZF==0
kCondE = 0x04, // ZF==1 (signed/unsigned)
kCondG = 0x0F, // ZF==0 & SF==OF (signed)
kCondGE = 0x0D, // SF==OF (signed)
kCondL = 0x0C, // SF!=OF (signed)
kCondLE = 0x0E, // ZF==1 | SF!=OF (signed)
kCondNA = 0x06, // CF==1 | ZF==1 (unsigned)
kCondNAE = 0x02, // CF==1 (unsigned)
kCondNB = 0x03, // CF==0 (unsigned)
kCondNBE = 0x07, // CF==0 & ZF==0 (unsigned)
kCondNC = 0x03, // CF==0
kCondNE = 0x05, // ZF==0
kCondNG = 0x0E, // ZF==1 | SF!=OF
kCondNGE = 0x0C, // SF!=OF
kCondNL = 0x0D, // SF==OF
kCondNLE = 0x0F, // ZF==0 & SF==OF
kCondNE = 0x05, // ZF==0 (signed/unsigned)
kCondNG = 0x0E, // ZF==1 | SF!=OF (signed)
kCondNGE = 0x0C, // SF!=OF (signed)
kCondNL = 0x0D, // SF==OF (signed)
kCondNLE = 0x0F, // ZF==0 & SF==OF (signed)
kCondNO = 0x01, // OF==0
kCondNP = 0x0B, // PF==0
kCondNS = 0x09, // SF==0
@@ -1866,7 +1867,7 @@ ASMJIT_ENUM(kCond) {
// [asmjit::x86x64::kVarType]
// ============================================================================
//! @brief X86 variable type.
//! @brief X86/X64 variable type.
ASMJIT_ENUM(kVarType) {
//! @brief Variable is Mm (MMX).
kVarTypeMm = 12,
@@ -1912,7 +1913,7 @@ ASMJIT_ENUM(kVarType) {
// [asmjit::x86x64::kVarDesc]
// ============================================================================
//! @brief X86 variable description.
//! @brief X86/X64 variable description.
ASMJIT_ENUM(kVarDesc) {
//! @brief Variable contains single-precision floating-point(s).
kVarDescSp = 0x10,