Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2679,6 +2679,101 @@ GenTree* Compiler::optVNBasedFoldExpr_Call_Memmove(GenTreeCall* call)
return result;
}

GenTree* Compiler::optVNBasedFoldExpr_Call_Memcmp(GenTreeCall* call)
{
JITDUMP("See if we can optimize NI_System_SpanHelpers_Memmove with help of VN...\n")
assert(call->IsSpecialIntrinsic(this, NI_System_SpanHelpers_SequenceEqual));

CallArg* leftArg = call->gtArgs.GetUserArgByIndex(0);
CallArg* rightArg = call->gtArgs.GetUserArgByIndex(1);
CallArg* lenArg = call->gtArgs.GetUserArgByIndex(2);
ValueNum lenVN = vnStore->VNConservativeNormalValue(lenArg->GetNode()->gtVNPair);
if (!vnStore->IsVNConstant(lenVN))
{
JITDUMP("...length is not a constant - bail out.\n");
return nullptr;
}

size_t len = vnStore->CoercedConstantValue<size_t>(lenVN);
if (len == 0)
{
JITDUMP("...length is 0 -> optimize to true\n");
return gtWrapWithSideEffects(gtNewTrue(), call, GTF_ALL_EFFECT, true);
}

if (len > 32)
{
JITDUMP("...length is too big to unroll - bail out.\n");
return nullptr;
}

CallArg* varArg = rightArg;
uint8_t* buffer = new (this, CMK_AssertionProp) uint8_t[len];
if (!GetImmutableDataFromAddress(leftArg->GetNode(), (int)len, buffer))
{
if (!GetImmutableDataFromAddress(rightArg->GetNode(), (int)len, buffer))
{
JITDUMP("...src is not a constant - fallback to LowerCallMemmove.\n");
return nullptr;
}
varArg = leftArg;
}

GenTree* varPtr = fgInsertCommaFormTemp(&varArg->LateNodeRef());
GenTree* result = nullptr;
var_types readType = roundDownMaxType((unsigned)len);

if (genTypeSize(readType) > TARGET_POINTER_SIZE)
{
// Don't use SIMD
readType = TYP_I_IMPL;
}

unsigned lenRemaining = (unsigned)len;
while (lenRemaining > 0)
{
if (lenRemaining < genTypeSize(readType))
lenRemaining = genTypeSize(readType);

ssize_t offset = (ssize_t)len - (ssize_t)lenRemaining;

// Clone dst and add offset if necessary.
GenTree* currVarPtr = gtCloneExpr(varPtr);
if (offset != 0)
currVarPtr = gtNewOperNode(GT_ADD, varPtr->TypeGet(), currVarPtr, gtNewIconNode(offset, TYP_I_IMPL));

GenTree* srcCns = gtNewGenericCon(readType, buffer + offset);
GenTree* varChunk = gtNewIndir(readType, currVarPtr, GTF_IND_UNALIGNED);

if (genTypeSize(readType) == len)
{
result = gtNewOperNode(GT_EQ, TYP_INT, srcCns, varChunk);
break;
}

GenTree* xorNode = gtNewOperNode(GT_XOR, genActualType(readType), varChunk, srcCns);

// Merge with the previous result.
result = result == nullptr ? xorNode : gtNewOperNode(GT_OR, genActualType(readType), result, xorNode);
lenRemaining -= genTypeSize(readType);
}

if (!result->OperIs(GT_EQ))
{
result = gtNewOperNode(GT_EQ, TYP_INT, result, gtNewZeroConNode(readType));
}

GenTree* sideEffects = nullptr;
gtExtractSideEffList(call, &sideEffects, GTF_ALL_EFFECT, true);
if (sideEffects != nullptr)
{
result = gtNewOperNode(GT_COMMA, TYP_INT, sideEffects, result);
}

DISPTREE(result);
return result;
}

//------------------------------------------------------------------------------
// optVNBasedFoldExpr_Call: Folds given call using VN to a simpler tree.
//
Expand Down Expand Up @@ -2748,6 +2843,11 @@ GenTree* Compiler::optVNBasedFoldExpr_Call(BasicBlock* block, GenTree* parent, G
return optVNBasedFoldExpr_Call_Memmove(call);
}

if (call->IsSpecialIntrinsic(this, NI_System_SpanHelpers_SequenceEqual))
{
return optVNBasedFoldExpr_Call_Memcmp(call);
}

return nullptr;
}

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8041,6 +8041,7 @@ class Compiler
GenTree* optVNBasedFoldExpr(BasicBlock* block, GenTree* parent, GenTree* tree);
GenTree* optVNBasedFoldExpr_Call(BasicBlock* block, GenTree* parent, GenTreeCall* call);
GenTree* optVNBasedFoldExpr_Call_Memmove(GenTreeCall* call);
GenTree* optVNBasedFoldExpr_Call_Memcmp(GenTreeCall* call);
GenTree* optExtractSideEffListFromConst(GenTree* tree);

AssertionIndex GetAssertionCount()
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/jit/importervectorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,11 @@ GenTree* Compiler::impUtf16StringComparison(StringComparisonKind kind, CORINFO_S
}
else
{
if (kind == StringComparisonKind::Equals)
{
return nullptr;
}

assert(argsCount == 2);
op1 = impStackTop(1).val;
op2 = impStackTop(0).val;
Expand Down Expand Up @@ -774,6 +779,11 @@ GenTree* Compiler::impUtf16SpanComparison(StringComparisonKind kind, CORINFO_SIG
}
else
{
if (kind == StringComparisonKind::Equals)
{
return nullptr;
}

assert(argsCount == 2);
op1 = impStackTop(1).val;
op2 = impStackTop(0).val;
Expand Down
Loading