Skip to content

Commit a3981dd

Browse files
authored
Inline TLS field access for linux/osx x64/arm64 (#87082)
* wip * add __tls_get_addr() code in jitinterface * working model * linux rely on __tls_get_addr() value * Add fields for both max/threadSTaticBlocks, have separate for GC/non-gc * code cleanup * code cleanup * add comments * jit format * update guid * review feedback * fix the offset * arm64: wip * linux arm64 model * arm64: offsetOfThreadStaticBlock adjustment * Add mrs and tpid0 register * arm64: use the new mrs/tpidr0 * fix arm64 build and offset calculation: * arm64: working * arm64: move to struct model * arm64: fixed the struct model * x64: move to struct model * code refactoring * #define for field access * change mrs -> mrs_tpid0 * fix a bug * remove unwanted method * another fix * Add entries in CorInfoType.cs * Update the #ifdef * fix the windows scenario: * review feedback * fix the data-type * add osx-arm64 support * fix osx-arm64 issues * fix build error * fix build error after merge * add osx/x64 support * fix errors * fix the macos/x64 * disable for alpine linux * Disable for R2R * review feedback * fix r2r check * move windows to struct model * review feedback * fix the register clobbering in release bits * Move the linux/x64 logic to .S file * Use TargetOS::IsMacOS * disable optimization for single file * working for linux/x64 * fix some errors for osx/x64 * fix for osx x64/arm64 * fix for arm64 linux/osx * try disable for musl/arm64 * rename variable * Rename variable to tlsIndexObject * Make offset variables as uint32_t * change the type of indexObj/ftnAddr to void* * replace ifdef(msc_ver) with ifdef(windows) * Revert to JIT_TO_EE_TRANSITION_LEAF * Move code to asmHelpers.S and rename method * rename the methods per the platform * fix osx builds * fix build break * fix some errors around osx * rename some more methods * review feedback * review feedback * delete the comment * make methods static * remove macos/x64 check * fix the check for linux/x64 * detect early for single-file linux/x64 * move the assert * review feedback * misc fixup * use fgMorphArgs() * remove commented code
1 parent d6d383e commit a3981dd

File tree

19 files changed

+536
-266
lines changed

19 files changed

+536
-266
lines changed

src/coreclr/inc/corinfo.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,8 +1727,11 @@ struct CORINFO_FIELD_INFO
17271727

17281728
struct CORINFO_THREAD_STATIC_BLOCKS_INFO
17291729
{
1730-
CORINFO_CONST_LOOKUP tlsIndex;
1731-
uint32_t offsetOfThreadLocalStoragePointer;
1730+
CORINFO_CONST_LOOKUP tlsIndex; // windows specific
1731+
void* tlsGetAddrFtnPtr; // linux/x64 specific - address of __tls_get_addr() function
1732+
void* tlsIndexObject; // linux/x64 specific - address of tls_index object
1733+
void* threadVarsSection; // osx x64/arm64 specific - address of __thread_vars section of `t_ThreadStatics`
1734+
uint32_t offsetOfThreadLocalStoragePointer; // windows specific
17321735
uint32_t offsetOfMaxThreadStaticBlocks;
17331736
uint32_t offsetOfThreadStaticBlocks;
17341737
uint32_t offsetOfGCDataPointer;

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* ba2c087c-9b8b-49c1-a52f-3514eb489308 */
47-
0xba2c087c,
48-
0x9b8b,
49-
0x49c1,
50-
{0xa5, 0x2f, 0x35, 0x14, 0xeb, 0x48, 0x93, 0x08}
46+
constexpr GUID JITEEVersionIdentifier = { /* 02e334af-4e6e-4a68-9feb-308d3d2661bc */
47+
0x2e334af,
48+
0x4e6e,
49+
0x4a68,
50+
{0x9f, 0xeb, 0x30, 0x8d, 0x3d, 0x26, 0x61, 0xbc}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/jit/codegenarm64.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,6 +2944,13 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
29442944
inst_Mov_Extend(targetType, /* srcInReg */ true, targetReg, dataReg, /* canSkip */ true,
29452945
emitActualTypeSize(targetType));
29462946
}
2947+
else if (TargetOS::IsUnix && data->IsIconHandle(GTF_ICON_TLS_HDL))
2948+
{
2949+
assert(data->AsIntCon()->IconValue() == 0);
2950+
emitAttr attr = emitActualTypeSize(targetType);
2951+
// On non-windows, need to load the address from system register.
2952+
emit->emitIns_R(INS_mrs_tpid0, attr, targetReg);
2953+
}
29472954
else
29482955
{
29492956
inst_Mov(targetType, targetReg, dataReg, /* canSkip */ true);

src/coreclr/jit/compiler.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5026,11 +5026,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
50265026
// Partially inline static initializations
50275027
DoPhase(this, PHASE_EXPAND_STATIC_INIT, &Compiler::fgExpandStaticInit);
50285028

5029-
if (TargetOS::IsWindows)
5030-
{
5031-
// Currently this is only applicable for Windows
5032-
DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess);
5033-
}
5029+
// Expand thread local access
5030+
DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess);
50345031

50355032
// Insert GC Polls
50365033
DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls);

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7124,7 +7124,7 @@ class Compiler
71247124
optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
71257125
}
71267126

7127-
bool doesMethodHasTlsFieldAccess()
7127+
bool methodHasTlsFieldAccess()
71287128
{
71297129
return (optMethodFlags & OMF_HAS_TLS_FIELD) != 0;
71307130
}

src/coreclr/jit/emit.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10205,9 +10205,9 @@ void emitter::emitRecordCallSite(ULONG instrOffset, /* IN */
1020510205

1020610206
if (callSig == nullptr)
1020710207
{
10208-
assert(methodHandle != nullptr);
10209-
10210-
if (Compiler::eeGetHelperNum(methodHandle) == CORINFO_HELP_UNDEF)
10208+
// For certain calls whose target is non-containable (e.g. tls access targets), `methodHandle`
10209+
// will be nullptr, because the target is present in a register.
10210+
if ((methodHandle != nullptr) && (Compiler::eeGetHelperNum(methodHandle) == CORINFO_HELP_UNDEF))
1021110211
{
1021210212
emitComp->eeGetMethodSig(methodHandle, &sigInfo);
1021310213
callSig = &sigInfo;

src/coreclr/jit/emitarm64.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ void emitter::emitInsSanityCheck(instrDesc* id)
937937
case IF_SI_0B: // SI_0B ................ ....bbbb........ imm4 - barrier
938938
break;
939939

940-
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva)
940+
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
941941
datasize = id->idOpSize();
942942
assert(isGeneralRegister(id->idReg1()));
943943
assert(datasize == EA_8BYTE);
@@ -3741,6 +3741,12 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
37413741
fmt = IF_SR_1A;
37423742
break;
37433743

3744+
case INS_mrs_tpid0:
3745+
id = emitNewInstrSmall(attr);
3746+
id->idReg1(reg);
3747+
fmt = IF_SR_1A;
3748+
break;
3749+
37443750
default:
37453751
unreached();
37463752
}
@@ -11793,7 +11799,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
1179311799
dst += emitOutput_Instr(dst, code);
1179411800
break;
1179511801

11796-
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva)
11802+
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
1179711803
assert(insOptsNone(id->idInsOpt()));
1179811804
code = emitInsCode(ins, fmt);
1179911805
code |= insEncodeReg_Rt(id->idReg1()); // ttttt
@@ -13921,8 +13927,16 @@ void emitter::emitDispInsHelp(
1392113927
emitDispBarrier((insBarrier)emitGetInsSC(id));
1392213928
break;
1392313929

13924-
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva)
13925-
emitDispReg(id->idReg1(), size, false);
13930+
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
13931+
if (ins == INS_mrs_tpid0)
13932+
{
13933+
emitDispReg(id->idReg1(), size, true);
13934+
printf("tpidr_el0");
13935+
}
13936+
else
13937+
{
13938+
emitDispReg(id->idReg1(), size, false);
13939+
}
1392613940
break;
1392713941

1392813942
default:

src/coreclr/jit/emitfmtsarm64.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ IF_DEF(SN_0A, IS_NONE, NONE) // SN_0A ................ ................
227227
IF_DEF(SI_0A, IS_NONE, NONE) // SI_0A ...........iiiii iiiiiiiiiii..... imm16
228228
IF_DEF(SI_0B, IS_NONE, NONE) // SI_0B ................ ....bbbb........ imm4 - barrier
229229

230-
IF_DEF(SR_1A, IS_NONE, NONE) // SR_1A ................ ...........ttttt Rt (dc zva)
230+
IF_DEF(SR_1A, IS_NONE, NONE) // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
231231

232232
IF_DEF(INVALID, IS_NONE, NONE) //
233233

src/coreclr/jit/helperexpansion.cpp

Lines changed: 134 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess()
421421
{
422422
PhaseStatus result = PhaseStatus::MODIFIED_NOTHING;
423423

424-
if (!doesMethodHasTlsFieldAccess())
424+
if (!methodHasTlsFieldAccess())
425425
{
426426
// TP: nothing to expand in the current method
427427
JITDUMP("Nothing to expand.\n")
@@ -478,36 +478,50 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
478478
return false;
479479
}
480480

481+
assert(!opts.IsReadyToRun());
482+
483+
if (TargetOS::IsUnix)
484+
{
485+
#if defined(TARGET_ARM) || !defined(TARGET_64BIT)
486+
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
487+
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
488+
// field access using TLS.
489+
noway_assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
490+
#endif
491+
}
492+
else
493+
{
481494
#ifdef TARGET_ARM
482-
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
483-
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
484-
// field access using TLS.
485-
assert(!"Unsupported scenario of optimizing TLS access on Arm32");
495+
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
496+
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
497+
// field access using TLS.
498+
noway_assert(!"Unsupported scenario of optimizing TLS access on Windows Arm32");
486499
#endif
500+
}
487501

488502
JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum);
489503
DISPTREE(call);
490504
JITDUMP("\n");
505+
491506
bool isGCThreadStatic =
492507
eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
493508

494509
CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo;
495-
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic);
510+
memset(&threadStaticBlocksInfo, 0, sizeof(CORINFO_THREAD_STATIC_BLOCKS_INFO));
496511

497-
uint32_t offsetOfMaxThreadStaticBlocksVal = 0;
498-
uint32_t offsetOfThreadStaticBlocksVal = 0;
512+
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic);
499513

500514
JITDUMP("getThreadLocalStaticBlocksInfo (%s)\n:", isGCThreadStatic ? "GC" : "Non-GC");
501-
offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks;
502-
offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks;
503-
504-
JITDUMP("tlsIndex= %u\n", (ssize_t)threadStaticBlocksInfo.tlsIndex.addr);
505-
JITDUMP("offsetOfThreadLocalStoragePointer= %u\n", threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer);
506-
JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", offsetOfMaxThreadStaticBlocksVal);
507-
JITDUMP("offsetOfThreadStaticBlocks= %u\n", offsetOfThreadStaticBlocksVal);
508-
JITDUMP("offsetOfGCDataPointer= %u\n", threadStaticBlocksInfo.offsetOfGCDataPointer);
515+
JITDUMP("tlsIndex= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndex.addr));
516+
JITDUMP("tlsGetAddrFtnPtr= %p\n", dspPtr(threadStaticBlocksInfo.tlsGetAddrFtnPtr));
517+
JITDUMP("tlsIndexObject= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndexObject));
518+
JITDUMP("threadVarsSection= %p\n", dspPtr(threadStaticBlocksInfo.threadVarsSection));
519+
JITDUMP("offsetOfThreadLocalStoragePointer= %u\n",
520+
dspOffset(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer));
521+
JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks));
522+
JITDUMP("offsetOfThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfThreadStaticBlocks));
523+
JITDUMP("offsetOfGCDataPointer= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfGCDataPointer));
509524

510-
assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE);
511525
assert((eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) ||
512526
(eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED));
513527

@@ -546,56 +560,131 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
546560
gtUpdateStmtSideEffects(stmt);
547561

548562
GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode();
563+
GenTree* tlsValue = nullptr;
564+
unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access"));
565+
lvaTable[tlsLclNum].lvType = TYP_I_IMPL;
566+
GenTree* maxThreadStaticBlocksValue = nullptr;
567+
GenTree* threadStaticBlocksValue = nullptr;
568+
GenTree* tlsValueDef = nullptr;
569+
570+
if (TargetOS::IsWindows)
571+
{
572+
size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr;
573+
GenTree* dllRef = nullptr;
549574

550-
void** pIdAddr = nullptr;
575+
if (tlsIndexValue != 0)
576+
{
577+
dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL);
578+
}
551579

552-
size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr;
553-
GenTree* dllRef = nullptr;
580+
// Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns]
581+
tlsValue = gtNewIconHandleNode(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL);
582+
tlsValue = gtNewIndir(TYP_I_IMPL, tlsValue, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
554583

555-
if (tlsIndexValue != 0)
556-
{
557-
dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL);
584+
if (dllRef != nullptr)
585+
{
586+
// Add the dllRef to produce thread local storage reference for coreclr
587+
tlsValue = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsValue, dllRef);
588+
}
589+
590+
// Base of coreclr's thread local storage
591+
tlsValue = gtNewIndir(TYP_I_IMPL, tlsValue, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
558592
}
593+
else if (TargetOS::IsMacOS)
594+
{
595+
// For OSX x64/arm64, we need to get the address of relevant __thread_vars section of
596+
// the thread local variable `t_ThreadStatics`. Address of `tlv_get_address` is stored
597+
// in this entry, which we dereference and invoke it, passing the __thread_vars address
598+
// present in `threadVarsSection`.
599+
//
600+
// Code sequence to access thread local variable on osx/x64:
601+
//
602+
// mov rdi, threadVarsSection
603+
// call [rdi]
604+
//
605+
// Code sequence to access thread local variable on osx/arm64:
606+
//
607+
// mov x0, threadVarsSection
608+
// mov x1, [x0]
609+
// blr x1
610+
//
611+
size_t threadVarsSectionVal = (size_t)threadStaticBlocksInfo.threadVarsSection;
612+
GenTree* tls_get_addr_val = gtNewIconHandleNode(threadVarsSectionVal, GTF_ICON_FTN_ADDR);
613+
614+
tls_get_addr_val = gtNewIndir(TYP_I_IMPL, tls_get_addr_val, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
559615

560-
// Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns]
561-
GenTree* tlsRef = gtNewIconHandleNode(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL);
616+
tlsValue = gtNewIndCallNode(tls_get_addr_val, TYP_I_IMPL);
617+
GenTreeCall* tlsRefCall = tlsValue->AsCall();
562618

563-
tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
619+
// This is a call which takes an argument.
620+
// Populate and set the ABI appropriately.
621+
assert(opts.altJit || threadVarsSectionVal != 0);
622+
GenTree* tlsArg = gtNewIconNode(threadVarsSectionVal, TYP_I_IMPL);
623+
tlsRefCall->gtArgs.PushBack(this, NewCallArg::Primitive(tlsArg));
564624

565-
if (dllRef != nullptr)
625+
fgMorphArgs(tlsRefCall);
626+
627+
tlsRefCall->gtFlags |= GTF_EXCEPT | (tls_get_addr_val->gtFlags & GTF_GLOB_EFFECT);
628+
}
629+
else if (TargetOS::IsUnix)
566630
{
567-
// Add the dllRef to produce thread local storage reference for coreclr
568-
tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef);
631+
#if defined(TARGET_AMD64)
632+
// Code sequence to access thread local variable on linux/x64:
633+
//
634+
// mov rdi, 0x7FE5C418CD28 ; tlsIndexObject
635+
// mov rax, 0x7FE5C47AFDB0 ; _tls_get_addr
636+
// call rax
637+
//
638+
GenTree* tls_get_addr_val =
639+
gtNewIconHandleNode((size_t)threadStaticBlocksInfo.tlsGetAddrFtnPtr, GTF_ICON_FTN_ADDR);
640+
tlsValue = gtNewIndCallNode(tls_get_addr_val, TYP_I_IMPL);
641+
GenTreeCall* tlsRefCall = tlsValue->AsCall();
642+
643+
// This is an indirect call which takes an argument.
644+
// Populate and set the ABI appropriately.
645+
assert(opts.altJit || threadStaticBlocksInfo.tlsIndexObject != 0);
646+
GenTree* tlsArg = gtNewIconNode((size_t)threadStaticBlocksInfo.tlsIndexObject, TYP_I_IMPL);
647+
tlsRefCall->gtArgs.PushBack(this, NewCallArg::Primitive(tlsArg));
648+
649+
fgMorphArgs(tlsRefCall);
650+
651+
tlsRefCall->gtFlags |= GTF_EXCEPT | (tls_get_addr_val->gtFlags & GTF_GLOB_EFFECT);
652+
#ifdef UNIX_X86_ABI
653+
tlsRefCall->gtFlags &= ~GTF_CALL_POP_ARGS;
654+
#endif // UNIX_X86_ABI
655+
#elif defined(TARGET_ARM64)
656+
// Code sequence to access thread local variable on linux/arm64:
657+
//
658+
// mrs xt, tpidr_elf0
659+
// mov xd, [xt+cns]
660+
tlsValue = gtNewIconHandleNode(0, GTF_ICON_TLS_HDL);
661+
#else
662+
assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
663+
#endif
569664
}
570665

571-
// Base of coreclr's thread local storage
572-
GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
573-
574666
// Cache the tls value
575-
unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access"));
576-
lvaTable[tlsLclNum].lvType = TYP_I_IMPL;
577-
GenTree* tlsValueDef = gtNewStoreLclVarNode(tlsLclNum, tlsValue);
578-
GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum);
667+
tlsValueDef = gtNewStoreLclVarNode(tlsLclNum, tlsValue);
668+
GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum);
669+
670+
size_t offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks;
671+
size_t offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks;
579672

580673
// Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]"
581674
GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(offsetOfMaxThreadStaticBlocksVal, TYP_I_IMPL);
582675
GenTree* maxThreadStaticBlocksRef =
583676
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfMaxThreadStaticBlocks);
584-
GenTree* maxThreadStaticBlocksValue =
585-
gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
677+
maxThreadStaticBlocksValue = gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
678+
679+
GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse),
680+
gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL));
681+
threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
586682

587683
// Create tree for "if (maxThreadStaticBlocks < typeIndex)"
588684
GenTree* maxThreadStaticBlocksCond =
589685
gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue));
590686
maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond);
591687

592-
// Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]"
593-
GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL);
594-
GenTree* threadStaticBlocksRef =
595-
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfThreadStaticBlocks);
596-
GenTree* threadStaticBlocksValue =
597-
gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
598-
599688
// Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]"
600689
typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_INT, gtCloneExpr(typeThreadStaticBlockIndexValue),
601690
gtNewIconNode(TARGET_POINTER_SIZE, TYP_INT));

src/coreclr/jit/instrsarm64.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,9 @@ INST1(isb, "isb", 0, IF_SI_0B, 0xD50330DF)
15951595
INST1(dczva, "dczva", 0, IF_SR_1A, 0xD50B7420)
15961596
// dc zva,Rt SR_1A 1101010100001011 01110100001ttttt D50B 7420 Rt
15971597

1598+
INST1(mrs_tpid0, "mrs", 0, IF_SR_1A, 0xD53BD040)
1599+
// mrs Rt,tpidr_el0 SR_1A 1101010100111011 11010000010ttttt D53B D040 Rt, tpidr_el0
1600+
15981601
INST1(umov, "umov", 0, IF_DV_2B, 0x0E003C00)
15991602
// umov Rd,Vn[] DV_2B 0Q001110000iiiii 001111nnnnnddddd 0E00 3C00 Rd,Vn[]
16001603

0 commit comments

Comments
 (0)