summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/inc/corinfo.h3
-rw-r--r--src/jit/importer.cpp81
-rw-r--r--src/jit/optimizer.cpp9
-rw-r--r--src/vm/jitinterface.cpp23
-rw-r--r--src/vm/method.cpp2
-rw-r--r--src/vm/mscorlib.h2
6 files changed, 114 insertions, 6 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index cbc4464e1d..97f395800e 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -213,7 +213,6 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif
-// Update this one
SELECTANY const GUID JITEEVersionIdentifier = { /* f00b3f49-ddd2-49be-ba43-6e49ffa66959 */
0xf00b3f49,
0xddd2,
@@ -959,6 +958,8 @@ enum CorInfoIntrinsics
CORINFO_INTRINSIC_GetManagedThreadId,
CORINFO_INTRINSIC_ByReference_Ctor,
CORINFO_INTRINSIC_ByReference_Value,
+ CORINFO_INTRINSIC_Span_GetItem,
+ CORINFO_INTRINSIC_ReadOnlySpan_GetItem,
CORINFO_INTRINSIC_Count,
CORINFO_INTRINSIC_Illegal = -1, // Not a true intrinsic,
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 989130a247..a07c55c62d 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -3620,6 +3620,87 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
retNode = field;
break;
}
+ case CORINFO_INTRINSIC_Span_GetItem:
+ case CORINFO_INTRINSIC_ReadOnlySpan_GetItem:
+ {
+ // Have index, stack pointer-to Span<T> s on the stack. Expand to:
+ //
+ // For Span<T>
+ // Comma
+ // BoundsCheck(index, s->_length)
+ // s->_pointer + index * sizeof(T)
+ //
+ // For ReadOnlySpan<T>
+ // Comma
+ // BoundsCheck(index, s->_length)
+ // *(s->_pointer + index * sizeof(T))
+ //
+ // Signature should show one class type parameter, which
+ // we need to examine.
+ assert(sig->sigInst.classInstCount == 1);
+ CORINFO_CLASS_HANDLE spanElemHnd = sig->sigInst.classInst[0];
+ const unsigned elemSize = info.compCompHnd->getClassSize(spanElemHnd);
+ assert(elemSize > 0);
+
+ const bool isReadOnly = (intrinsicID == CORINFO_INTRINSIC_ReadOnlySpan_GetItem);
+
+ JITDUMP("\nimpIntrinsic: Expanding %sSpan<T>.get_Item, T=%s, sizeof(T)=%u\n", isReadOnly ? "ReadOnly" : "",
+ info.compCompHnd->getClassName(spanElemHnd), elemSize);
+
+ GenTreePtr index = impPopStack().val;
+ GenTreePtr ptrToSpan = impPopStack().val;
+ GenTreePtr indexClone = nullptr;
+ GenTreePtr ptrToSpanClone = nullptr;
+
+#if defined(DEBUG)
+ if (verbose)
+ {
+ printf("with ptr-to-span\n");
+ gtDispTree(ptrToSpan);
+ printf("and index\n");
+ gtDispTree(index);
+ }
+#endif // defined(DEBUG)
+
+ // We need to use both index and ptr-to-span twice, so clone or spill.
+ index = impCloneExpr(index, &indexClone, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
+ nullptr DEBUGARG("Span.get_Item index"));
+ ptrToSpan = impCloneExpr(ptrToSpan, &ptrToSpanClone, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
+ nullptr DEBUGARG("Span.get_Item ptrToSpan"));
+
+ // Bounds check
+ CORINFO_FIELD_HANDLE lengthHnd = info.compCompHnd->getFieldInClass(clsHnd, 1);
+ const unsigned lengthOffset = info.compCompHnd->getFieldOffset(lengthHnd);
+ GenTreePtr length = gtNewFieldRef(TYP_INT, lengthHnd, ptrToSpan, lengthOffset, false);
+ GenTreePtr boundsCheck = new (this, GT_ARR_BOUNDS_CHECK)
+ GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, index, length, SCK_RNGCHK_FAIL);
+
+ // Element access
+ GenTreePtr indexIntPtr = impImplicitIorI4Cast(indexClone, TYP_I_IMPL);
+ GenTreePtr sizeofNode = gtNewIconNode(elemSize);
+ GenTreePtr mulNode = gtNewOperNode(GT_MUL, TYP_I_IMPL, indexIntPtr, sizeofNode);
+ CORINFO_FIELD_HANDLE ptrHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
+ const unsigned ptrOffset = info.compCompHnd->getFieldOffset(ptrHnd);
+ GenTreePtr data = gtNewFieldRef(TYP_BYREF, ptrHnd, ptrToSpanClone, ptrOffset, false);
+ GenTreePtr result = gtNewOperNode(GT_ADD, TYP_BYREF, data, mulNode);
+
+ // Prepare result
+ var_types resultType = JITtype2varType(sig->retType);
+
+ if (isReadOnly)
+ {
+ result = gtNewOperNode(GT_IND, resultType, result);
+ }
+ else
+ {
+ assert(resultType == result->TypeGet());
+ }
+
+ retNode = gtNewOperNode(GT_COMMA, resultType, boundsCheck, result);
+
+ break;
+ }
+
default:
/* Unknown intrinsic */
break;
diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp
index c18ebc55d0..710dac540c 100644
--- a/src/jit/optimizer.cpp
+++ b/src/jit/optimizer.cpp
@@ -7638,6 +7638,15 @@ bool Compiler::optExtractArrIndex(GenTreePtr tree, ArrIndex* result, unsigned lh
{
return false;
}
+
+ // For span we may see gtArrLen is a local var or local field.
+ // We won't try and extract those.
+ const genTreeOps arrayOp = arrBndsChk->gtArrLen->gtOper;
+
+ if ((arrayOp == GT_LCL_VAR) || (arrayOp == GT_LCL_FLD))
+ {
+ return false;
+ }
if (arrBndsChk->gtArrLen->gtGetOp1()->gtOper != GT_LCL_VAR)
{
return false;
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index a82cf00448..5ef7700896 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -8623,7 +8623,7 @@ CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
else
{
MethodTable * pMT = method->GetMethodTable();
- if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem())
+ if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
{
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
{
@@ -8637,10 +8637,25 @@ CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
_ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
result = CORINFO_INTRINSIC_ByReference_Value;
}
- *pMustExpand = true;
+ if (pMustExpand != nullptr)
+ {
+ *pMustExpand = true;
+ }
+ }
+ else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
+ {
+ if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
+ {
+ result = CORINFO_INTRINSIC_Span_GetItem;
+ }
+ }
+ else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
+ {
+ if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
+ {
+ result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
+ }
}
-
- // TODO-SPAN: Span<T> intrinsics for optimizations
}
}
diff --git a/src/vm/method.cpp b/src/vm/method.cpp
index a72b07b404..77a6a0d37f 100644
--- a/src/vm/method.cpp
+++ b/src/vm/method.cpp
@@ -2404,7 +2404,7 @@ BOOL MethodDesc::IsFCallOrIntrinsic()
if (IsFCall() || IsArray())
return TRUE;
- // Intrinsic methods on ByReference<T> or Span<T>
+ // Intrinsic methods on ByReference<T>, Span<T>, or ReadOnlySpan<T>
MethodTable * pMT = GetMethodTable();
if (pMT->IsByRefLike() && pMT->GetModule()->IsSystem())
return TRUE;
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index 4b82de0a2c..87927f687d 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -653,7 +653,9 @@ DEFINE_CLASS(NULLABLE, System, Nullable`1)
DEFINE_CLASS(BYREFERENCE, System, ByReference`1)
DEFINE_CLASS(SPAN, System, Span`1)
+DEFINE_METHOD(SPAN, GET_ITEM, get_Item, NoSig)
DEFINE_CLASS(READONLY_SPAN, System, ReadOnlySpan`1)
+DEFINE_METHOD(READONLY_SPAN, GET_ITEM, get_Item, NoSig)
// Keep this in sync with System.Globalization.NumberFormatInfo
DEFINE_CLASS_U(Globalization, NumberFormatInfo, NumberFormatInfo)