Skip to content

Commit

Permalink
Inline TLS field access for linux/osx x64/arm64 (#87082)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
kunalspathak authored Jul 6, 2023
1 parent d6d383e commit a3981dd
Show file tree
Hide file tree
Showing 19 changed files with 536 additions and 266 deletions.
7 changes: 5 additions & 2 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1727,8 +1727,11 @@ struct CORINFO_FIELD_INFO

struct CORINFO_THREAD_STATIC_BLOCKS_INFO
{
CORINFO_CONST_LOOKUP tlsIndex;
uint32_t offsetOfThreadLocalStoragePointer;
CORINFO_CONST_LOOKUP tlsIndex; // windows specific
void* tlsGetAddrFtnPtr; // linux/x64 specific - address of __tls_get_addr() function
void* tlsIndexObject; // linux/x64 specific - address of tls_index object
void* threadVarsSection; // osx x64/arm64 specific - address of __thread_vars section of `t_ThreadStatics`
uint32_t offsetOfThreadLocalStoragePointer; // windows specific
uint32_t offsetOfMaxThreadStaticBlocks;
uint32_t offsetOfThreadStaticBlocks;
uint32_t offsetOfGCDataPointer;
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

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

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2944,6 +2944,13 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
inst_Mov_Extend(targetType, /* srcInReg */ true, targetReg, dataReg, /* canSkip */ true,
emitActualTypeSize(targetType));
}
else if (TargetOS::IsUnix && data->IsIconHandle(GTF_ICON_TLS_HDL))
{
assert(data->AsIntCon()->IconValue() == 0);
emitAttr attr = emitActualTypeSize(targetType);
// On non-windows, need to load the address from system register.
emit->emitIns_R(INS_mrs_tpid0, attr, targetReg);
}
else
{
inst_Mov(targetType, targetReg, dataReg, /* canSkip */ true);
Expand Down
7 changes: 2 additions & 5 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5026,11 +5026,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
// Partially inline static initializations
DoPhase(this, PHASE_EXPAND_STATIC_INIT, &Compiler::fgExpandStaticInit);

if (TargetOS::IsWindows)
{
// Currently this is only applicable for Windows
DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess);
}
// Expand thread local access
DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess);

// Insert GC Polls
DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7124,7 +7124,7 @@ class Compiler
optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
}

bool doesMethodHasTlsFieldAccess()
bool methodHasTlsFieldAccess()
{
return (optMethodFlags & OMF_HAS_TLS_FIELD) != 0;
}
Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10205,9 +10205,9 @@ void emitter::emitRecordCallSite(ULONG instrOffset, /* IN */

if (callSig == nullptr)
{
assert(methodHandle != nullptr);

if (Compiler::eeGetHelperNum(methodHandle) == CORINFO_HELP_UNDEF)
// For certain calls whose target is non-containable (e.g. tls access targets), `methodHandle`
// will be nullptr, because the target is present in a register.
if ((methodHandle != nullptr) && (Compiler::eeGetHelperNum(methodHandle) == CORINFO_HELP_UNDEF))
{
emitComp->eeGetMethodSig(methodHandle, &sigInfo);
callSig = &sigInfo;
Expand Down
22 changes: 18 additions & 4 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ void emitter::emitInsSanityCheck(instrDesc* id)
case IF_SI_0B: // SI_0B ................ ....bbbb........ imm4 - barrier
break;

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

case INS_mrs_tpid0:
id = emitNewInstrSmall(attr);
id->idReg1(reg);
fmt = IF_SR_1A;
break;

default:
unreached();
}
Expand Down Expand Up @@ -11793,7 +11799,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;

case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva)
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
assert(insOptsNone(id->idInsOpt()));
code = emitInsCode(ins, fmt);
code |= insEncodeReg_Rt(id->idReg1()); // ttttt
Expand Down Expand Up @@ -13921,8 +13927,16 @@ void emitter::emitDispInsHelp(
emitDispBarrier((insBarrier)emitGetInsSC(id));
break;

case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva)
emitDispReg(id->idReg1(), size, false);
case IF_SR_1A: // SR_1A ................ ...........ttttt Rt (dc zva, mrs)
if (ins == INS_mrs_tpid0)
{
emitDispReg(id->idReg1(), size, true);
printf("tpidr_el0");
}
else
{
emitDispReg(id->idReg1(), size, false);
}
break;

default:
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emitfmtsarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ IF_DEF(SN_0A, IS_NONE, NONE) // SN_0A ................ ................
IF_DEF(SI_0A, IS_NONE, NONE) // SI_0A ...........iiiii iiiiiiiiiii..... imm16
IF_DEF(SI_0B, IS_NONE, NONE) // SI_0B ................ ....bbbb........ imm4 - barrier

IF_DEF(SR_1A, IS_NONE, NONE) // SR_1A ................ ...........ttttt Rt (dc zva)
IF_DEF(SR_1A, IS_NONE, NONE) // SR_1A ................ ...........ttttt Rt (dc zva, mrs)

IF_DEF(INVALID, IS_NONE, NONE) //

Expand Down
179 changes: 134 additions & 45 deletions src/coreclr/jit/helperexpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess()
{
PhaseStatus result = PhaseStatus::MODIFIED_NOTHING;

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

assert(!opts.IsReadyToRun());

if (TargetOS::IsUnix)
{
#if defined(TARGET_ARM) || !defined(TARGET_64BIT)
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
// field access using TLS.
noway_assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
#endif
}
else
{
#ifdef TARGET_ARM
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
// field access using TLS.
assert(!"Unsupported scenario of optimizing TLS access on Arm32");
// On Arm, Thread execution blocks are accessed using co-processor registers and instructions such
// as MRC and MCR are used to access them. We do not support them and so should never optimize the
// field access using TLS.
noway_assert(!"Unsupported scenario of optimizing TLS access on Windows Arm32");
#endif
}

JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum);
DISPTREE(call);
JITDUMP("\n");

bool isGCThreadStatic =
eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;

CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo;
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic);
memset(&threadStaticBlocksInfo, 0, sizeof(CORINFO_THREAD_STATIC_BLOCKS_INFO));

uint32_t offsetOfMaxThreadStaticBlocksVal = 0;
uint32_t offsetOfThreadStaticBlocksVal = 0;
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic);

JITDUMP("getThreadLocalStaticBlocksInfo (%s)\n:", isGCThreadStatic ? "GC" : "Non-GC");
offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks;
offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks;

JITDUMP("tlsIndex= %u\n", (ssize_t)threadStaticBlocksInfo.tlsIndex.addr);
JITDUMP("offsetOfThreadLocalStoragePointer= %u\n", threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer);
JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", offsetOfMaxThreadStaticBlocksVal);
JITDUMP("offsetOfThreadStaticBlocks= %u\n", offsetOfThreadStaticBlocksVal);
JITDUMP("offsetOfGCDataPointer= %u\n", threadStaticBlocksInfo.offsetOfGCDataPointer);
JITDUMP("tlsIndex= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndex.addr));
JITDUMP("tlsGetAddrFtnPtr= %p\n", dspPtr(threadStaticBlocksInfo.tlsGetAddrFtnPtr));
JITDUMP("tlsIndexObject= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndexObject));
JITDUMP("threadVarsSection= %p\n", dspPtr(threadStaticBlocksInfo.threadVarsSection));
JITDUMP("offsetOfThreadLocalStoragePointer= %u\n",
dspOffset(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer));
JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks));
JITDUMP("offsetOfThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfThreadStaticBlocks));
JITDUMP("offsetOfGCDataPointer= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfGCDataPointer));

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

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

GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode();
GenTree* tlsValue = nullptr;
unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access"));
lvaTable[tlsLclNum].lvType = TYP_I_IMPL;
GenTree* maxThreadStaticBlocksValue = nullptr;
GenTree* threadStaticBlocksValue = nullptr;
GenTree* tlsValueDef = nullptr;

if (TargetOS::IsWindows)
{
size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr;
GenTree* dllRef = nullptr;

void** pIdAddr = nullptr;
if (tlsIndexValue != 0)
{
dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL);
}

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

if (tlsIndexValue != 0)
{
dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL);
if (dllRef != nullptr)
{
// Add the dllRef to produce thread local storage reference for coreclr
tlsValue = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsValue, dllRef);
}

// Base of coreclr's thread local storage
tlsValue = gtNewIndir(TYP_I_IMPL, tlsValue, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
}
else if (TargetOS::IsMacOS)
{
// For OSX x64/arm64, we need to get the address of relevant __thread_vars section of
// the thread local variable `t_ThreadStatics`. Address of `tlv_get_address` is stored
// in this entry, which we dereference and invoke it, passing the __thread_vars address
// present in `threadVarsSection`.
//
// Code sequence to access thread local variable on osx/x64:
//
// mov rdi, threadVarsSection
// call [rdi]
//
// Code sequence to access thread local variable on osx/arm64:
//
// mov x0, threadVarsSection
// mov x1, [x0]
// blr x1
//
size_t threadVarsSectionVal = (size_t)threadStaticBlocksInfo.threadVarsSection;
GenTree* tls_get_addr_val = gtNewIconHandleNode(threadVarsSectionVal, GTF_ICON_FTN_ADDR);

tls_get_addr_val = gtNewIndir(TYP_I_IMPL, tls_get_addr_val, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);

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

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

if (dllRef != nullptr)
fgMorphArgs(tlsRefCall);

tlsRefCall->gtFlags |= GTF_EXCEPT | (tls_get_addr_val->gtFlags & GTF_GLOB_EFFECT);
}
else if (TargetOS::IsUnix)
{
// Add the dllRef to produce thread local storage reference for coreclr
tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef);
#if defined(TARGET_AMD64)
// Code sequence to access thread local variable on linux/x64:
//
// mov rdi, 0x7FE5C418CD28 ; tlsIndexObject
// mov rax, 0x7FE5C47AFDB0 ; _tls_get_addr
// call rax
//
GenTree* tls_get_addr_val =
gtNewIconHandleNode((size_t)threadStaticBlocksInfo.tlsGetAddrFtnPtr, GTF_ICON_FTN_ADDR);
tlsValue = gtNewIndCallNode(tls_get_addr_val, TYP_I_IMPL);
GenTreeCall* tlsRefCall = tlsValue->AsCall();

// This is an indirect call which takes an argument.
// Populate and set the ABI appropriately.
assert(opts.altJit || threadStaticBlocksInfo.tlsIndexObject != 0);
GenTree* tlsArg = gtNewIconNode((size_t)threadStaticBlocksInfo.tlsIndexObject, TYP_I_IMPL);
tlsRefCall->gtArgs.PushBack(this, NewCallArg::Primitive(tlsArg));

fgMorphArgs(tlsRefCall);

tlsRefCall->gtFlags |= GTF_EXCEPT | (tls_get_addr_val->gtFlags & GTF_GLOB_EFFECT);
#ifdef UNIX_X86_ABI
tlsRefCall->gtFlags &= ~GTF_CALL_POP_ARGS;
#endif // UNIX_X86_ABI
#elif defined(TARGET_ARM64)
// Code sequence to access thread local variable on linux/arm64:
//
// mrs xt, tpidr_elf0
// mov xd, [xt+cns]
tlsValue = gtNewIconHandleNode(0, GTF_ICON_TLS_HDL);
#else
assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
#endif
}

// Base of coreclr's thread local storage
GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);

// Cache the tls value
unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access"));
lvaTable[tlsLclNum].lvType = TYP_I_IMPL;
GenTree* tlsValueDef = gtNewStoreLclVarNode(tlsLclNum, tlsValue);
GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum);
tlsValueDef = gtNewStoreLclVarNode(tlsLclNum, tlsValue);
GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum);

size_t offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks;
size_t offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks;

// Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]"
GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(offsetOfMaxThreadStaticBlocksVal, TYP_I_IMPL);
GenTree* maxThreadStaticBlocksRef =
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfMaxThreadStaticBlocks);
GenTree* maxThreadStaticBlocksValue =
gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
maxThreadStaticBlocksValue = gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);

GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse),
gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL));
threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);

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

// Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]"
GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL);
GenTree* threadStaticBlocksRef =
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfThreadStaticBlocks);
GenTree* threadStaticBlocksValue =
gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);

// Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]"
typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_INT, gtCloneExpr(typeThreadStaticBlockIndexValue),
gtNewIconNode(TARGET_POINTER_SIZE, TYP_INT));
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/instrsarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,9 @@ INST1(isb, "isb", 0, IF_SI_0B, 0xD50330DF)
INST1(dczva, "dczva", 0, IF_SR_1A, 0xD50B7420)
// dc zva,Rt SR_1A 1101010100001011 01110100001ttttt D50B 7420 Rt

INST1(mrs_tpid0, "mrs", 0, IF_SR_1A, 0xD53BD040)
// mrs Rt,tpidr_el0 SR_1A 1101010100111011 11010000010ttttt D53B D040 Rt, tpidr_el0

INST1(umov, "umov", 0, IF_DV_2B, 0x0E003C00)
// umov Rd,Vn[] DV_2B 0Q001110000iiiii 001111nnnnnddddd 0E00 3C00 Rd,Vn[]

Expand Down
Loading

0 comments on commit a3981dd

Please sign in to comment.