Skip to content

Commit a4b8893

Browse files
EgorBoAndyAyersMSSingleAccretion
authored
JIT: Unroll Equals and StartsWith for constant strings and spans. [0..32] chars (#65288)
Co-authored-by: Andy Ayers <andya@microsoft.com> Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
1 parent e63f048 commit a4b8893

16 files changed

+2411
-17
lines changed

src/coreclr/jit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ set( JIT_SOURCES
115115
hostallocator.cpp
116116
indirectcalltransformer.cpp
117117
importer.cpp
118+
importer_vectorization.cpp
118119
inline.cpp
119120
inlinepolicy.cpp
120121
instr.cpp

src/coreclr/jit/compiler.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,7 @@ class Compiler
30283028
// For binary opers.
30293029
GenTree* gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2);
30303030

3031+
GenTreeColon* gtNewColonNode(var_types type, GenTree* elseNode, GenTree* thenNode);
30313032
GenTreeQmark* gtNewQmarkNode(var_types type, GenTree* cond, GenTreeColon* colon);
30323033

30333034
GenTree* gtNewLargeOperNode(genTreeOps oper,
@@ -3037,6 +3038,9 @@ class Compiler
30373038

30383039
GenTreeIntCon* gtNewIconNode(ssize_t value, var_types type = TYP_INT);
30393040
GenTreeIntCon* gtNewIconNode(unsigned fieldOffset, FieldSeqNode* fieldSeq);
3041+
GenTreeIntCon* gtNewNull();
3042+
GenTreeIntCon* gtNewTrue();
3043+
GenTreeIntCon* gtNewFalse();
30403044

30413045
GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
30423046

@@ -3365,7 +3369,7 @@ class Compiler
33653369
GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
33663370
GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type, BasicBlockFlags bbFlags);
33673371

3368-
GenTree* gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
3372+
GenTreeField* gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj = nullptr, DWORD offset = 0);
33693373

33703374
GenTree* gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp);
33713375

@@ -4407,6 +4411,19 @@ class Compiler
44074411
void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
44084412
GenTree* impTypeIsAssignable(GenTree* typeTo, GenTree* typeFrom);
44094413

4414+
GenTree* impStringEqualsOrStartsWith(bool startsWith, CORINFO_SIG_INFO* sig, unsigned methodFlags);
4415+
GenTree* impSpanEqualsOrStartsWith(bool startsWith, CORINFO_SIG_INFO* sig, unsigned methodFlags);
4416+
GenTree* impExpandHalfConstEquals(GenTreeLclVar* data,
4417+
GenTree* lengthFld,
4418+
bool checkForNull,
4419+
bool startsWith,
4420+
WCHAR* cnsData,
4421+
int len,
4422+
int dataOffset);
4423+
GenTree* impExpandHalfConstEqualsSWAR(GenTreeLclVar* data, WCHAR* cns, int len, int dataOffset);
4424+
GenTree* impExpandHalfConstEqualsSIMD(GenTreeLclVar* data, WCHAR* cns, int len, int dataOffset);
4425+
GenTreeStrCon* impGetStrConFromSpan(GenTree* span);
4426+
44104427
GenTree* impIntrinsic(GenTree* newobjThis,
44114428
CORINFO_CLASS_HANDLE clsHnd,
44124429
CORINFO_METHOD_HANDLE method,
@@ -4523,7 +4540,7 @@ class Compiler
45234540
void impInsertTreeBefore(GenTree* tree, const DebugInfo& di, Statement* stmtBefore);
45244541
void impAssignTempGen(unsigned tmp,
45254542
GenTree* val,
4526-
unsigned curLevel,
4543+
unsigned curLevel = (unsigned)CHECK_SPILL_NONE,
45274544
Statement** pAfterStmt = nullptr,
45284545
const DebugInfo& di = DebugInfo(),
45294546
BasicBlock* block = nullptr);

src/coreclr/jit/compiler.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfo
10931093
// Return Value:
10941094
// The created node.
10951095
//
1096-
inline GenTree* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset)
1096+
inline GenTreeField* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset)
10971097
{
10981098
// GT_FIELD nodes are transformed into GT_IND nodes.
10991099
assert(GenTree::s_gtNodeSizes[GT_IND] <= GenTree::s_gtNodeSizes[GT_FIELD]);
@@ -1105,7 +1105,7 @@ inline GenTree* Compiler::gtNewFieldRef(var_types type, CORINFO_FIELD_HANDLE fld
11051105
type = impNormStructType(structHnd);
11061106
}
11071107

1108-
GenTree* fieldNode = new (this, GT_FIELD) GenTreeField(type, obj, fldHnd, offset);
1108+
GenTreeField* fieldNode = new (this, GT_FIELD) GenTreeField(type, obj, fldHnd, offset);
11091109

11101110
// If "obj" is the address of a local, note that a field of that struct local has been accessed.
11111111
if ((obj != nullptr) && obj->OperIs(GT_ADDR) && varTypeIsStruct(obj->AsUnOp()->gtOp1) &&

src/coreclr/jit/gentree.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5735,6 +5735,11 @@ GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1,
57355735
return node;
57365736
}
57375737

5738+
GenTreeColon* Compiler::gtNewColonNode(var_types type, GenTree* elseNode, GenTree* thenNode)
5739+
{
5740+
return new (this, GT_COLON) GenTreeColon(TYP_INT, elseNode, thenNode);
5741+
}
5742+
57385743
GenTreeQmark* Compiler::gtNewQmarkNode(var_types type, GenTree* cond, GenTreeColon* colon)
57395744
{
57405745
compQmarkUsed = true;
@@ -5753,6 +5758,21 @@ GenTreeIntCon* Compiler::gtNewIconNode(ssize_t value, var_types type)
57535758
return new (this, GT_CNS_INT) GenTreeIntCon(type, value);
57545759
}
57555760

5761+
GenTreeIntCon* Compiler::gtNewNull()
5762+
{
5763+
return gtNewIconNode(0, TYP_REF);
5764+
}
5765+
5766+
GenTreeIntCon* Compiler::gtNewTrue()
5767+
{
5768+
return gtNewIconNode(1, TYP_INT);
5769+
}
5770+
5771+
GenTreeIntCon* Compiler::gtNewFalse()
5772+
{
5773+
return gtNewIconNode(0, TYP_INT);
5774+
}
5775+
57565776
GenTreeIntCon* Compiler::gtNewIconNode(unsigned fieldOffset, FieldSeqNode* fieldSeq)
57575777
{
57585778
GenTreeIntCon* node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, static_cast<ssize_t>(fieldOffset));

src/coreclr/jit/importer.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3912,6 +3912,39 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
39123912
retNode = impArrayAccessIntrinsic(clsHnd, sig, memberRef, readonlyCall, ni);
39133913
break;
39143914

3915+
case NI_System_String_Equals:
3916+
{
3917+
retNode = impStringEqualsOrStartsWith(/*startsWith:*/ false, sig, methodFlags);
3918+
break;
3919+
}
3920+
3921+
case NI_System_MemoryExtensions_Equals:
3922+
case NI_System_MemoryExtensions_SequenceEqual:
3923+
{
3924+
retNode = impSpanEqualsOrStartsWith(/*startsWith:*/ false, sig, methodFlags);
3925+
break;
3926+
}
3927+
3928+
case NI_System_String_StartsWith:
3929+
{
3930+
retNode = impStringEqualsOrStartsWith(/*startsWith:*/ true, sig, methodFlags);
3931+
break;
3932+
}
3933+
3934+
case NI_System_MemoryExtensions_StartsWith:
3935+
{
3936+
retNode = impSpanEqualsOrStartsWith(/*startsWith:*/ true, sig, methodFlags);
3937+
break;
3938+
}
3939+
3940+
case NI_System_MemoryExtensions_AsSpan:
3941+
case NI_System_String_op_Implicit:
3942+
{
3943+
assert(sig->numArgs == 1);
3944+
isSpecial = impStackTop().val->OperIs(GT_CNS_STR);
3945+
break;
3946+
}
3947+
39153948
case NI_System_String_get_Chars:
39163949
{
39173950
GenTree* op2 = impPopStack().val;
@@ -5243,14 +5276,45 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
52435276
}
52445277
else if (strcmp(className, "String") == 0)
52455278
{
5246-
if (strcmp(methodName, "get_Chars") == 0)
5279+
if (strcmp(methodName, "Equals") == 0)
5280+
{
5281+
result = NI_System_String_Equals;
5282+
}
5283+
else if (strcmp(methodName, "get_Chars") == 0)
52475284
{
52485285
result = NI_System_String_get_Chars;
52495286
}
52505287
else if (strcmp(methodName, "get_Length") == 0)
52515288
{
52525289
result = NI_System_String_get_Length;
52535290
}
5291+
else if (strcmp(methodName, "op_Implicit") == 0)
5292+
{
5293+
result = NI_System_String_op_Implicit;
5294+
}
5295+
else if (strcmp(methodName, "StartsWith") == 0)
5296+
{
5297+
result = NI_System_String_StartsWith;
5298+
}
5299+
}
5300+
else if (strcmp(className, "MemoryExtensions") == 0)
5301+
{
5302+
if (strcmp(methodName, "AsSpan") == 0)
5303+
{
5304+
result = NI_System_MemoryExtensions_AsSpan;
5305+
}
5306+
if (strcmp(methodName, "SequenceEqual") == 0)
5307+
{
5308+
result = NI_System_MemoryExtensions_SequenceEqual;
5309+
}
5310+
else if (strcmp(methodName, "Equals") == 0)
5311+
{
5312+
result = NI_System_MemoryExtensions_Equals;
5313+
}
5314+
else if (strcmp(methodName, "StartsWith") == 0)
5315+
{
5316+
result = NI_System_MemoryExtensions_StartsWith;
5317+
}
52545318
}
52555319
else if (strcmp(className, "Span`1") == 0)
52565320
{

0 commit comments

Comments
 (0)