Skip to content

Commit 7f1d644

Browse files
Add dump:assembly for close-to-assembly output
1 parent 0bd8015 commit 7f1d644

File tree

4 files changed

+285
-3
lines changed

4 files changed

+285
-3
lines changed

lib/Backend/Encoder.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,165 @@ Encoder::Encode()
320320
}
321321
}
322322

323+
// Assembly Dump Phase
324+
// This phase exists to assist tooling that expects "assemblable" output - that is,
325+
// output that, with minimal manual handling, could theoretically be fed to another
326+
// assembler to make a valid function for the target platform. We don't guarantee a
327+
// dump from this will _actually_ be assemblable, but it is significantly closer to
328+
// that than our normal, annotated output
329+
#if DBG_DUMP
330+
if (PHASE_DUMP(Js::AssemblyPhase, m_func))
331+
{
332+
FOREACH_INSTR_IN_FUNC(instr, m_func)
333+
{
334+
bool hasPrintedForOpnds = false;
335+
Func* localScopeFuncForLambda = m_func;
336+
auto printOpnd = [&hasPrintedForOpnds, localScopeFuncForLambda](IR::Opnd* opnd)
337+
{
338+
if (hasPrintedForOpnds)
339+
{
340+
Output::Print(_u(", "));
341+
}
342+
switch (opnd->m_kind)
343+
{
344+
case IR::OpndKindInvalid:
345+
AssertMsg(false, "Should be unreachable");
346+
break;
347+
case IR::OpndKindIntConst:
348+
Output::Print(_u("%lli"), (long long int)opnd->AsIntConstOpnd()->GetValue());
349+
break;
350+
case IR::OpndKindInt64Const:
351+
case IR::OpndKindFloatConst:
352+
case IR::OpndKindFloat32Const:
353+
case IR::OpndKindSimd128Const:
354+
AssertMsg(false, "Not Yet Implemented");
355+
break;
356+
case IR::OpndKindHelperCall:
357+
Output::Print(_u("%s"), IR::GetMethodName(opnd->AsHelperCallOpnd()->m_fnHelper));
358+
break;
359+
case IR::OpndKindSym:
360+
Output::Print(_u("SYM("));
361+
opnd->Dump(IRDumpFlags_SimpleForm, localScopeFuncForLambda);
362+
Output::Print(_u(")"));
363+
break;
364+
case IR::OpndKindReg:
365+
Output::Print(_u("%S"), RegNames[opnd->AsRegOpnd()->GetReg()]);
366+
break;
367+
case IR::OpndKindAddr:
368+
Output::Print(_u("0x%p"), opnd->AsAddrOpnd()->m_address);
369+
break;
370+
case IR::OpndKindIndir:
371+
{
372+
IR::IndirOpnd* indirOpnd = opnd->AsIndirOpnd();
373+
IR::RegOpnd* baseOpnd = indirOpnd->GetBaseOpnd();
374+
IR::RegOpnd* indexOpnd = indirOpnd->GetIndexOpnd();
375+
Output::Print(_u("["));
376+
bool hasPrintedComponent = false;
377+
if (baseOpnd != nullptr)
378+
{
379+
Output::Print(_u("%S"), RegNames[baseOpnd->GetReg()]);
380+
hasPrintedComponent = true;
381+
}
382+
if (indexOpnd != nullptr)
383+
{
384+
if (hasPrintedComponent)
385+
{
386+
Output::Print(_u(" + "));
387+
}
388+
Output::Print(_u("%S * %u"), RegNames[indexOpnd->GetReg()], indirOpnd->GetScale());
389+
hasPrintedComponent = true;
390+
}
391+
if (hasPrintedComponent)
392+
{
393+
Output::Print(_u(" + "));
394+
}
395+
Output::Print(_u("(%i)]"), indirOpnd->GetOffset());
396+
break;
397+
}
398+
case IR::OpndKindLabel:
399+
opnd->Dump(IRDumpFlags_SimpleForm, localScopeFuncForLambda);
400+
break;
401+
case IR::OpndKindMemRef:
402+
opnd->DumpOpndKindMemRef(true, localScopeFuncForLambda);
403+
break;
404+
case IR::OpndKindRegBV:
405+
AssertMsg(false, "Should be unreachable");
406+
break;
407+
case IR::OpndKindList:
408+
AssertMsg(false, "Should be unreachable");
409+
break;
410+
default:
411+
AssertMsg(false, "Missing operand type");
412+
}
413+
hasPrintedForOpnds = true;
414+
};
415+
switch(instr->GetKind())
416+
{
417+
case IR::InstrKindInvalid:
418+
Assert(false);
419+
break;
420+
case IR::InstrKindJitProfiling:
421+
case IR::InstrKindProfiled:
422+
case IR::InstrKindInstr:
423+
{
424+
Output::SkipToColumn(4);
425+
Output::Print(_u("%s "), Js::OpCodeUtil::GetOpCodeName(instr->m_opcode));
426+
Output::SkipToColumn(18);
427+
IR::Opnd* dst = instr->GetDst();
428+
IR::Opnd* src1 = instr->GetSrc1();
429+
IR::Opnd* src2 = instr->GetSrc2();
430+
if (dst != nullptr && (src1 == nullptr || !dst->IsRegOpnd() || !src1->IsRegOpnd() || dst->AsRegOpnd()->GetReg() != src1->AsRegOpnd()->GetReg())) // Print dst if it's there, and not the same reg as src1 (which is usually an instr that has a srcdest
431+
{
432+
printOpnd(dst);
433+
}
434+
if (src1 != nullptr)
435+
{
436+
printOpnd(src1);
437+
}
438+
if (src2 != nullptr)
439+
{
440+
printOpnd(src2);
441+
}
442+
break;
443+
}
444+
case IR::InstrKindBranch:
445+
Output::SkipToColumn(4);
446+
Output::Print(_u("%s "), Js::OpCodeUtil::GetOpCodeName(instr->m_opcode));
447+
Output::SkipToColumn(18);
448+
if (instr->AsBranchInstr()->IsMultiBranch())
449+
{
450+
Assert(instr->GetSrc1() != nullptr);
451+
printOpnd(instr->GetSrc1());
452+
}
453+
else
454+
{
455+
Output::Print(_u("L%u"), instr->AsBranchInstr()->GetTarget()->m_id);
456+
}
457+
break;
458+
case IR::InstrKindProfiledLabel:
459+
case IR::InstrKindLabel:
460+
Output::Print(_u("L%u:"), instr->AsLabelInstr()->m_id);
461+
break;
462+
case IR::InstrKindEntry:
463+
case IR::InstrKindExit:
464+
case IR::InstrKindPragma:
465+
// No output
466+
break;
467+
case IR::InstrKindByteCodeUses:
468+
AssertMsg(false, "Instruction kind shouldn't be present here");
469+
break;
470+
default:
471+
Assert(false);
472+
break;
473+
}
474+
Output::SetAlignAndPrefix(60, _u("; "));
475+
instr->Dump();
476+
Output::ResetAlignAndPrefix();
477+
} NEXT_INSTR_IN_FUNC;
478+
}
479+
#endif
480+
// End Assembly Dump Phase
481+
323482
BEGIN_CODEGEN_PHASE(m_func, Js::EmitterPhase);
324483

325484
// Copy to permanent buffer.

lib/Common/ConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ PHASE(All)
257257
PHASE(PrologEpilog)
258258
PHASE(InsertNOPs)
259259
PHASE(Encoder)
260+
PHASE(Assembly)
260261
PHASE(Emitter)
261262
PHASE(DebugBreak)
262263
#if defined(_M_IX86) || defined(_M_X64)

lib/Common/Core/Output.cpp

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ THREAD_ST WORD Output::s_color = 0;
4646
THREAD_ST bool Output::s_hasColor = false;
4747
THREAD_ST bool Output::s_capture = false;
4848

49+
THREAD_ST bool Output::hasDoneAlignPrefixForThisLine = false;
50+
THREAD_ST bool Output::usingCustomAlignAndPrefix = false;
51+
THREAD_ST size_t Output::align = 0;
52+
THREAD_ST const char16* Output::prefix = nullptr;
53+
4954
#define MAX_OUTPUT_BUFFER_SIZE 10 * 1024 * 1024 // 10 MB maximum before we force a flush
5055

5156
size_t __cdecl
@@ -282,6 +287,86 @@ Output::VPrint(const char16 *form, va_list argptr)
282287
size_t __cdecl
283288
Output::PrintBuffer(const char16 * buf, size_t size)
284289
{
290+
// Handle custom line prefixing
291+
bool internallyAllocatedBuffer = false;
292+
if (usingCustomAlignAndPrefix)
293+
{
294+
if (hasDoneAlignPrefixForThisLine && wcschr(buf, '\n') == nullptr)
295+
{
296+
// no newlines, and we've already prefixed this line, so nothing to do
297+
}
298+
else
299+
{
300+
size_t newbufsize = size + align;
301+
char16* newbuf = (char16*)calloc(newbufsize, sizeof(char16));
302+
AssertOrFailFastMsg(newbuf != nullptr, "Ran out of memory while printing output");
303+
internallyAllocatedBuffer = true;
304+
const char16* currentReadIndex = buf;
305+
char16* currentWriteIndex = newbuf;
306+
auto ensureSpace = [&currentWriteIndex, &newbuf, &newbufsize](size_t numCharsWantToWrite)
307+
{
308+
size_t charsWritten = (currentWriteIndex - newbuf); // pointer subtraction is number of elements of pointed type between pointers
309+
size_t remaining = newbufsize - charsWritten;
310+
if (numCharsWantToWrite + 1 > remaining)
311+
{
312+
char16* tempbuf = (char16*)realloc(newbuf, newbufsize * sizeof(char16) * 2);
313+
AssertOrFailFastMsg(tempbuf != nullptr, "Ran out of memory while printing output");
314+
newbuf = tempbuf;
315+
newbufsize = newbufsize * 2;
316+
currentWriteIndex = newbuf + charsWritten;
317+
}
318+
};
319+
const size_t prefixlength = wcslen(prefix);
320+
size_t oldS_Column = Output::s_Column;
321+
while (currentReadIndex < buf + size)
322+
{
323+
if (!hasDoneAlignPrefixForThisLine)
324+
{
325+
// attempt to write the alignment
326+
{
327+
unsigned int alignspacesneeded = 1; // always put at least one space
328+
if (oldS_Column < align)
329+
{
330+
alignspacesneeded = (unsigned int)(align - oldS_Column);
331+
}
332+
ensureSpace(alignspacesneeded);
333+
for (unsigned int i = 0; i < alignspacesneeded; i++)
334+
{
335+
*(currentWriteIndex++) = ' ';
336+
}
337+
}
338+
// attempt to write the prefix
339+
ensureSpace(prefixlength);
340+
js_wmemcpy_s(currentWriteIndex, (newbuf + newbufsize) - currentWriteIndex, Output::prefix, prefixlength);
341+
currentWriteIndex += prefixlength;
342+
oldS_Column = align + prefixlength;
343+
hasDoneAlignPrefixForThisLine = true;
344+
}
345+
const char16* endOfLine = wcschr(currentReadIndex, '\n');
346+
size_t charsToCopy = 0;
347+
if (endOfLine != nullptr)
348+
{
349+
charsToCopy = (endOfLine - currentReadIndex) + 1; // We want to grab the newline character as part of this line
350+
oldS_Column = 0; // We're ending this line, and want the next to be calculated properly
351+
hasDoneAlignPrefixForThisLine = false; // The next line will need this
352+
}
353+
else
354+
{
355+
charsToCopy = (buf + size) - currentReadIndex; // the rest of the input buffer
356+
oldS_Column += charsToCopy; // Will be reset anyway later on
357+
}
358+
ensureSpace(endOfLine - currentReadIndex);
359+
js_wmemcpy_s(currentWriteIndex, (newbuf + newbufsize) - currentWriteIndex, currentReadIndex, charsToCopy);
360+
currentReadIndex += charsToCopy;
361+
currentWriteIndex += charsToCopy;
362+
}
363+
// null terminate becuase there's no real reason not to
364+
ensureSpace(1);
365+
*(currentWriteIndex++) = '\0';
366+
buf = newbuf;
367+
size = (currentWriteIndex - newbuf) - 1; // not counting the terminator here though, to align with vsnwprintf_s's behavior
368+
}
369+
}
285370
Output::s_Column += size;
286371
const char16 * endbuf = wcschr(buf, '\n');
287372
while (endbuf != nullptr)
@@ -443,15 +528,27 @@ void Output::DirectPrint(char16 const * string)
443528
void
444529
Output::SkipToColumn(size_t column)
445530
{
446-
if (column <= Output::s_Column)
531+
size_t columnbias = 0;
532+
// If we're using a custom alignment and prefix, we want to do this relative to that
533+
if (usingCustomAlignAndPrefix)
534+
{
535+
// If we've already added the alignment and prefix, we need to add the alignment to our column number here
536+
columnbias = align + wcslen(prefix);
537+
}
538+
size_t reference = 0;
539+
if (Output::s_Column > columnbias)
540+
{
541+
reference = Output::s_Column - columnbias;
542+
}
543+
if (column <= reference)
447544
{
448545
Output::Print(_u(" "));
449546
return;
450547
}
451548

452549
// compute distance to our destination
453550

454-
size_t dist = column - Output::s_Column;
551+
size_t dist = column - reference;
455552

456553
// Print at least one space
457554
while (dist > 0)
@@ -564,3 +661,20 @@ Output::CaptureEnd()
564661

565662
return returnBuffer;
566663
}
664+
665+
void
666+
Output::SetAlignAndPrefix(unsigned int align, const char16 *prefix)
667+
{
668+
Output::hasDoneAlignPrefixForThisLine = false;
669+
Output::usingCustomAlignAndPrefix = true;
670+
Output::prefix = prefix;
671+
Output::align = align;
672+
}
673+
void
674+
Output::ResetAlignAndPrefix()
675+
{
676+
Output::hasDoneAlignPrefixForThisLine = false;
677+
Output::usingCustomAlignAndPrefix = false;
678+
Output::prefix = nullptr;
679+
Output::align = 0;
680+
}

lib/Common/Core/Output.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,10 @@ class Output
114114

115115
static WORD SetConsoleForeground(WORD color);
116116
static void CaptureStart();
117-
static char16* CaptureEnd();
117+
static char16* CaptureEnd();
118+
119+
static void SetAlignAndPrefix(unsigned int align, const char16 *prefix);
120+
static void ResetAlignAndPrefix();
118121

119122
private:
120123
static void DirectPrint(const char16 * string);
@@ -134,6 +137,11 @@ class Output
134137

135138
#define THREAD_ST THREAD_LOCAL
136139

140+
THREAD_ST static bool hasDoneAlignPrefixForThisLine;
141+
THREAD_ST static bool usingCustomAlignAndPrefix;
142+
THREAD_ST static const char16* prefix;
143+
THREAD_ST static size_t align;
144+
137145
THREAD_ST static bool s_capture;
138146
THREAD_ST static FILE * s_file;
139147
#ifdef _WIN32

0 commit comments

Comments
 (0)