From dfafa6b05ff68426f34af86754b2f2b3bf6aae59 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Tue, 8 May 2018 22:36:14 +0300 Subject: [PATCH 1/4] Include the data section in disassembly --- src/jit/emit.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++++++ src/jit/emit.h | 3 ++ 2 files changed, 125 insertions(+) diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp index cd733d76b952..cc1817f7c128 100644 --- a/src/jit/emit.cpp +++ b/src/jit/emit.cpp @@ -5437,6 +5437,11 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, BYTE* dst) printf("\nEmitting data sections: %u total bytes\n", sec->dsdOffs); } + if (emitComp->opts.disAsm) + { + emitDispDataSec(sec); + } + unsigned secNum = 0; #endif @@ -5534,6 +5539,123 @@ void emitter::emitOutputDataSec(dataSecDsc* sec, BYTE* dst) } } +#ifdef DEBUG + +//------------------------------------------------------------------------ +// emitDispDataSec: Dump a data section to stdout. +// +// Arguments: +// section - the data section description +// +// Notes: +// The output format attempts to mirror typical assembler syntax. +// Data section entries lack type information so float/double entries +// are displayed as if they are integers/longs. +// +void emitter::emitDispDataSec(dataSecDsc* section) +{ + printf("\n"); + + unsigned offset = 0; + + for (dataSection* data = section->dsdList; data != nullptr; data = data->dsNext) + { + const char* labelFormat = "%-7s"; + char label[64]; + sprintf_s(label, _countof(label), "RWD%02u", offset); + printf(labelFormat, label); + offset += data->dsSize; + + if ((data->dsType == dataSection::blockRelative32) || (data->dsType == dataSection::blockAbsoluteAddr)) + { + insGroup* igFirst = static_cast(emitCodeGetCookie(emitComp->fgFirstBB)); + bool isRelative = (data->dsType == dataSection::blockRelative32); + size_t blockCount = data->dsSize / (isRelative ? 4 : TARGET_POINTER_SIZE); + + for (unsigned i = 0; i < blockCount; i++) + { + if (i > 0) + { + printf(labelFormat, ""); + } + + BasicBlock* block = reinterpret_cast(data->dsCont)[i]; + insGroup* ig = static_cast(emitCodeGetCookie(block)); + + const char* blockLabelFormat = "G_M%03u_IG%02u"; + char blockLabel[64]; + char firstLabel[64]; + sprintf_s(blockLabel, _countof(blockLabel), blockLabelFormat, Compiler::s_compMethodsCount, ig->igNum); + sprintf_s(firstLabel, _countof(firstLabel), blockLabelFormat, Compiler::s_compMethodsCount, + igFirst->igNum); + + if (isRelative) + { + if (emitComp->opts.disDiffable) + { + printf("dd\t%s - %s\n", blockLabel, firstLabel); + } + else + { + printf("dd\t%08Xh", ig->igOffs - igFirst->igOffs); + } + } + else if (TARGET_POINTER_SIZE == 4) + { + if (emitComp->opts.disDiffable) + { + printf("dd\t%s\n", blockLabel); + } + else + { + printf("dd\t%08Xh", reinterpret_cast(emitOffsetToPtr(ig->igOffs))); + } + } + else + { + if (emitComp->opts.disDiffable) + { + printf("dq\t%s\n", blockLabel); + } + else + { + printf("dq\t%016llXh", reinterpret_cast(emitOffsetToPtr(ig->igOffs))); + } + } + + if (!emitComp->opts.disDiffable) + { + printf(" ; case %s\n", blockLabel); + } + } + } + else + { + assert(data->dsType == dataSection::data); + switch (data->dsSize) + { + case 2: + printf("dw\t%04Xh\n", *reinterpret_cast(&data->dsCont)); + break; + case 4: + printf("dd\t%08Xh\n", *reinterpret_cast(&data->dsCont)); + break; + case 8: + printf("dq\t%016llXh\n", *reinterpret_cast(&data->dsCont)); + break; + default: + printf("db\t"); + for (UNATIVE_OFFSET i = 0; i < data->dsSize; i++) + { + printf("%s0%02Xh", i > 0 ? ", " : "", data->dsCont[i]); + } + printf("\n"); + } + } + } +} +#endif + /*****************************************************************************/ /***************************************************************************** * diff --git a/src/jit/emit.h b/src/jit/emit.h index 261302a10676..3387e6a98cbb 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -2043,6 +2043,9 @@ class emitter dataSection* emitDataSecCur; void emitOutputDataSec(dataSecDsc* sec, BYTE* dst); +#ifdef DEBUG + void emitDispDataSec(dataSecDsc* section); +#endif /************************************************************************/ /* Handles to the current class and method. */ From f1ca994efaec093e0f7f4b16cbce4675aa5648e3 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Tue, 8 May 2018 22:54:32 +0300 Subject: [PATCH 2/4] Add support for 16 byte aligned constants --- src/jit/codegenxarch.cpp | 2 +- src/jit/emit.cpp | 71 +++++++++++++++++++++++++++++----------- src/jit/emit.h | 12 ++++++- src/jit/emitpub.h | 2 +- 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp index 81b087109d73..1a14d3eeeda0 100644 --- a/src/jit/codegenxarch.cpp +++ b/src/jit/codegenxarch.cpp @@ -7051,7 +7051,7 @@ void CodeGen::genSSE2BitwiseOp(GenTree* treeNode) if (*bitMask == nullptr) { assert(cnsAddr != nullptr); - *bitMask = getEmitter()->emitAnyConst(cnsAddr, genTypeSize(targetType), dblAlign); + *bitMask = getEmitter()->emitAnyConst(cnsAddr, genTypeSize(targetType), emitDataAlignment::Preferred); } // We need an additional register for bitmask. diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp index cc1817f7c128..27d99fa4929d 100644 --- a/src/jit/emit.cpp +++ b/src/jit/emit.cpp @@ -4490,6 +4490,11 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, } #endif + if (emitConsDsc.align16) + { + allocMemFlag = static_cast(allocMemFlag | CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN); + } + #ifdef _TARGET_ARM64_ // For arm64, we want to allocate JIT data always adjacent to code similar to what native compiler does. // This way allows us to use a single `ldr` to access such data like float constant/jmp table. @@ -5178,7 +5183,7 @@ UNATIVE_OFFSET emitter::emitFindOffset(insGroup* ig, unsigned insNum) * block. */ -UNATIVE_OFFSET emitter::emitDataGenBeg(UNATIVE_OFFSET size, bool dblAlign, bool codeLtab) +UNATIVE_OFFSET emitter::emitDataGenBeg(UNATIVE_OFFSET size, bool align) { unsigned secOffs; dataSection* secDesc; @@ -5193,20 +5198,30 @@ UNATIVE_OFFSET emitter::emitDataGenBeg(UNATIVE_OFFSET size, bool dblAlign, bool secOffs = emitConsDsc.dsdOffs; - /* Are we require to align this request on an eight byte boundry? */ - if (dblAlign && (secOffs % sizeof(double) != 0)) + if (align) { - /* Need to skip 4 bytes to honor dblAlign */ - /* Must allocate a dummy 4 byte integer */ - int zero = 0; - emitDataGenBeg(4, false, false); - emitDataGenData(0, &zero, 4); - emitDataGenEnd(); + // Data can have any size but since alignment is deduced from the size there's no + // way to have a larger data size (e.g. 128) and request 4/8/16 byte alignment. + // 32 bytes (and more) alignment requires VM support (see ICorJitInfo::allocMem). + assert(size <= 16); + + if (size == 16) + { + emitConsDsc.align16 = true; + } + + while ((secOffs % size) != 0) + { + /* Need to skip 4 bytes to honor alignment */ + /* Must allocate a dummy 4 byte integer */ + int zero = 0; + emitDataGenBeg(4, false); + emitDataGenData(0, &zero, 4); + emitDataGenEnd(); - /* Get the new secOffs */ - secOffs = emitConsDsc.dsdOffs; - /* Now it should be a multiple of 8 */ - assert(secOffs % sizeof(double) == 0); + /* Get the new secOffs */ + secOffs = emitConsDsc.dsdOffs; + } } /* Advance the current offset */ @@ -5357,7 +5372,7 @@ UNATIVE_OFFSET emitter::emitDataConst(const void* cnsAddr, unsigned cnsSize, boo dblAlign = false; } - UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, dblAlign, false); + UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, dblAlign); emitDataGenData(0, cnsAddr, cnsSize); emitDataGenEnd(); @@ -5368,16 +5383,34 @@ UNATIVE_OFFSET emitter::emitDataConst(const void* cnsAddr, unsigned cnsSize, boo // emitAnyConst: Create a data section constant of arbitrary size. // // Arguments: -// cnsAddr - pointer to the data to be placed in the data section -// cnsSize - size of the data -// dblAlign - whether to align the data section to an 8 byte boundary +// cnsAddr - pointer to the data to be placed in the data section +// cnsSize - size of the data +// alignment - indicates how to align the constant // // Return Value: // A field handle representing the data offset to access the constant. // -CORINFO_FIELD_HANDLE emitter::emitAnyConst(const void* cnsAddr, unsigned cnsSize, bool dblAlign) +CORINFO_FIELD_HANDLE emitter::emitAnyConst(const void* cnsAddr, unsigned cnsSize, emitDataAlignment alignment) { - UNATIVE_OFFSET cnum = emitDataConst(cnsAddr, cnsSize, dblAlign); + bool align; + + switch (alignment) + { + case emitDataAlignment::None: + align = false; + break; + case emitDataAlignment::Preferred: + align = (emitComp->compCodeOpt() != Compiler::SMALL_CODE); + break; + case emitDataAlignment::Required: + default: + align = true; + break; + } + + UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, align); + emitDataGenData(0, cnsAddr, cnsSize); + emitDataGenEnd(); return emitComp->eeFindJitDataOffs(cnum); } diff --git a/src/jit/emit.h b/src/jit/emit.h index 3387e6a98cbb..7e0250ff0454 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -216,6 +216,15 @@ class emitLocation unsigned codePos; // the code position within the IG (see emitCurOffset()) }; +#ifndef LEGACY_BACKEND +enum class emitDataAlignment +{ + None, + Preferred, + Required +}; +#endif + /************************************************************************/ /* The following describes an instruction group */ /************************************************************************/ @@ -1580,7 +1589,7 @@ class emitter void emitSetMediumJump(instrDescJmp* id); UNATIVE_OFFSET emitSizeOfJump(instrDescJmp* jmp); UNATIVE_OFFSET emitInstCodeSz(instrDesc* id); - CORINFO_FIELD_HANDLE emitAnyConst(const void* cnsAddr, unsigned cnsSize, bool dblAlign); + CORINFO_FIELD_HANDLE emitAnyConst(const void* cnsAddr, unsigned cnsSize, emitDataAlignment alignment); CORINFO_FIELD_HANDLE emitFltOrDblConst(double constValue, emitAttr attr); regNumber emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src); regNumber emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2); @@ -2036,6 +2045,7 @@ class emitter dataSection* dsdList; dataSection* dsdLast; UNATIVE_OFFSET dsdOffs; + bool align16; }; dataSecDsc emitConsDsc; diff --git a/src/jit/emitpub.h b/src/jit/emitpub.h index 61769c45b9d7..7fbcd22a79c0 100644 --- a/src/jit/emitpub.h +++ b/src/jit/emitpub.h @@ -84,7 +84,7 @@ void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0); /* Emit initialized data sections */ /************************************************************************/ -UNATIVE_OFFSET emitDataGenBeg(UNATIVE_OFFSET size, bool dblAlign, bool codeLtab); +UNATIVE_OFFSET emitDataGenBeg(UNATIVE_OFFSET size, bool align); UNATIVE_OFFSET emitBBTableDataGenBeg(unsigned numEntries, bool relativeAddr); From 3d58487a9ef7f5b0fcb628f96c2af55c805a87c1 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Wed, 9 May 2018 18:19:13 +0300 Subject: [PATCH 3/4] Optimize `new Vector4(c1,c2,c3,c4)` --- src/jit/emit.cpp | 6 ------ src/jit/emit.h | 10 ++++++++++ src/jit/gentree.h | 8 ++++++++ src/jit/lowerxarch.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp index 27d99fa4929d..1347bcc2265e 100644 --- a/src/jit/emit.cpp +++ b/src/jit/emit.cpp @@ -1035,12 +1035,6 @@ void emitter::emitBegFN(bool hasFramePtr emitCntStackDepth = sizeof(int); #endif - /* No data sections have been created */ - - emitDataSecCur = nullptr; - - memset(&emitConsDsc, 0, sizeof(emitConsDsc)); - #ifdef PSEUDORANDOM_NOP_INSERTION // for random NOP insertion diff --git a/src/jit/emit.h b/src/jit/emit.h index 7e0250ff0454..38e5438e3fbf 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -439,6 +439,8 @@ class emitter SetUseSSE4(false); SetUseVEXEncoding(false); #endif // _TARGET_XARCH_ + + emitDataSecCur = nullptr; } #include "emitpub.h" @@ -1589,7 +1591,11 @@ class emitter void emitSetMediumJump(instrDescJmp* id); UNATIVE_OFFSET emitSizeOfJump(instrDescJmp* jmp); UNATIVE_OFFSET emitInstCodeSz(instrDesc* id); + +public: CORINFO_FIELD_HANDLE emitAnyConst(const void* cnsAddr, unsigned cnsSize, emitDataAlignment alignment); + +private: CORINFO_FIELD_HANDLE emitFltOrDblConst(double constValue, emitAttr attr); regNumber emitInsBinary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src); regNumber emitInsTernary(instruction ins, emitAttr attr, GenTree* dst, GenTree* src1, GenTree* src2); @@ -2046,6 +2052,10 @@ class emitter dataSection* dsdLast; UNATIVE_OFFSET dsdOffs; bool align16; + + dataSecDsc() : dsdList(nullptr), dsdLast(nullptr), dsdOffs(0), align16(false) + { + } }; dataSecDsc emitConsDsc; diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 12bb9aaed8e9..0b178dfe53a1 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -5007,6 +5007,14 @@ struct GenTreeClsVar : public GenTree { gtFlags |= GTF_GLOB_REF; } + + GenTreeClsVar(genTreeOps oper, var_types type, CORINFO_FIELD_HANDLE clsVarHnd, FieldSeqNode* fldSeq) + : GenTree(oper, type), gtClsVarHnd(clsVarHnd), gtFieldSeq(fldSeq) + { + assert((oper == GT_CLS_VAR) || (oper == GT_CLS_VAR_ADDR)); + gtFlags |= GTF_GLOB_REF; + } + #if DEBUGGABLE_GENTREE GenTreeClsVar() : GenTree() { diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp index 7f06f128e9d5..df53edcb7dae 100644 --- a/src/jit/lowerxarch.cpp +++ b/src/jit/lowerxarch.cpp @@ -780,6 +780,49 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) simdNode->gtType = TYP_SIMD16; } + if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInitN) + { + assert(simdNode->gtSIMDBaseType == TYP_FLOAT); + + int argCount = 0; + int constArgCount = 0; + float constArgValues[4]{0, 0, 0, 0}; + + for (GenTreeArgList* list = simdNode->gtGetOp1()->AsArgList(); list != nullptr; list = list->Rest()) + { + GenTree* arg = list->Current(); + + assert(arg->TypeGet() == simdNode->gtSIMDBaseType); + assert(argCount < _countof(constArgValues)); + + if (arg->IsCnsFltOrDbl()) + { + constArgValues[constArgCount] = static_cast(arg->AsDblCon()->gtDconVal); + constArgCount++; + } + + argCount++; + } + + if (constArgCount == argCount) + { + for (GenTreeArgList* list = simdNode->gtGetOp1()->AsArgList(); list != nullptr; list = list->Rest()) + { + BlockRange().Remove(list->Current()); + } + + CORINFO_FIELD_HANDLE hnd = + comp->getEmitter()->emitAnyConst(constArgValues, sizeof(constArgValues), emitDataAlignment::Required); + GenTree* clsVarAddr = new (comp, GT_CLS_VAR_ADDR) GenTreeClsVar(GT_CLS_VAR_ADDR, TYP_I_IMPL, hnd, nullptr); + BlockRange().InsertBefore(simdNode, clsVarAddr); + simdNode->ChangeOper(GT_IND); + simdNode->gtOp1 = clsVarAddr; + ContainCheckIndir(simdNode->AsIndir()); + + return; + } + } + #ifdef _TARGET_XARCH_ if ((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGetItem) && (simdNode->gtGetOp1()->OperGet() == GT_IND)) { From bae72694ddf8da1746a7231c4d36f0bd086de702 Mon Sep 17 00:00:00 2001 From: Mike Danes Date: Wed, 23 Jan 2019 22:44:29 +0200 Subject: [PATCH 4/4] Remove obsolete LEGACY_BACKEND ifdef --- src/jit/emit.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/jit/emit.h b/src/jit/emit.h index 38e5438e3fbf..8a1d32afcf27 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -216,14 +216,12 @@ class emitLocation unsigned codePos; // the code position within the IG (see emitCurOffset()) }; -#ifndef LEGACY_BACKEND enum class emitDataAlignment { None, Preferred, Required }; -#endif /************************************************************************/ /* The following describes an instruction group */