Skip to content

Commit

Permalink
Fold "cns"[cns] for ROS<char> (#78593)
Browse files Browse the repository at this point in the history
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
  • Loading branch information
EgorBo and SingleAccretion authored Nov 21, 2022
1 parent ce3e9fc commit 0ff0f7d
Show file tree
Hide file tree
Showing 24 changed files with 554 additions and 126 deletions.
17 changes: 17 additions & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2496,6 +2496,23 @@ class ICorStaticInfo
CORINFO_OBJECT_HANDLE objPtr
) = 0;

//------------------------------------------------------------------------------
// getStringChar: returns char at the given index if the given object handle
// represents String and index is not out of bounds.
//
// Arguments:
// strObj - object handle
// index - index of the char to return
// value - output char
//
// Return Value:
// Returns true if value was successfully obtained
//
virtual bool getStringChar(
CORINFO_OBJECT_HANDLE strObj,
int index,
uint16_t* value) = 0;

//------------------------------------------------------------------------------
// getObjectType: obtains type handle for given object
//
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ CORINFO_OBJECT_HANDLE getRuntimeTypePointer(
bool isObjectImmutable(
CORINFO_OBJECT_HANDLE objPtr) override;

bool getStringChar(
CORINFO_OBJECT_HANDLE strObj,
int index,
uint16_t* value) override;

CORINFO_CLASS_HANDLE getObjectType(
CORINFO_OBJECT_HANDLE objPtr) override;

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 = { /* 1e794e80-ec63-4d7a-b11f-fcda6e7fe4f4 */
0x1e794e80,
0xec63,
0x4d7a,
{0xb1, 0x1f, 0xfc, 0xda, 0x6e, 0x7f, 0xe4, 0xf4}
constexpr GUID JITEEVersionIdentifier = { /* da097b39-7f43-458a-990a-0b65406d5ff3 */
0xda097b39,
0x7f43,
0x458a,
{0x99, 0xa, 0xb, 0x65, 0x40, 0x6d, 0x5f, 0xf3}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/ICorJitInfo_names_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ DEF_CLR_API(getBoxHelper)
DEF_CLR_API(getUnBoxHelper)
DEF_CLR_API(getRuntimeTypePointer)
DEF_CLR_API(isObjectImmutable)
DEF_CLR_API(getStringChar)
DEF_CLR_API(getObjectType)
DEF_CLR_API(getReadyToRunHelper)
DEF_CLR_API(getReadyToRunDelegateCtorHelper)
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,17 @@ bool WrapICorJitInfo::isObjectImmutable(
return temp;
}

bool WrapICorJitInfo::getStringChar(
CORINFO_OBJECT_HANDLE strObj,
int index,
uint16_t* value)
{
API_ENTER(getStringChar);
bool temp = wrapHnd->getStringChar(strObj, index, value);
API_LEAVE(getStringChar);
return temp;
}

CORINFO_CLASS_HANDLE WrapICorJitInfo::getObjectType(
CORINFO_OBJECT_HANDLE objPtr)
{
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4833,6 +4833,8 @@ class Compiler
void fgValueNumberFieldStore(
GenTree* storeNode, GenTree* baseAddr, FieldSeq* fieldSeq, ssize_t offset, unsigned storeSize, ValueNum value);

bool fgValueNumberConstLoad(GenTreeIndir* tree);

// Compute the value number for a byref-exposed load of the given type via the given pointerVN.
ValueNum fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN);

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

typedef class ICorJitInfo* COMP_HANDLE;

const CORINFO_OBJECT_HANDLE NO_OBJECT_HANDLE = nullptr;
const CORINFO_CLASS_HANDLE NO_CLASS_HANDLE = nullptr;
const CORINFO_FIELD_HANDLE NO_FIELD_HANDLE = nullptr;
const CORINFO_METHOD_HANDLE NO_METHOD_HANDLE = nullptr;
Expand Down
107 changes: 107 additions & 0 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8494,6 +8494,103 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
}
}

//----------------------------------------------------------------------------------
// fgValueNumberConstLoad: Try to detect const_immutable_array[cns_index] tree
// and apply a constant VN representing given element at cns_index in that array.
//
// Arguments:
// tree - the GT_IND node
//
// Return Value:
// true if the pattern was recognized and a new VN is assigned
//
bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree)
{
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
if (!tree->TypeIs(TYP_USHORT) || !tree->gtVNPair.BothEqual() || !vnStore->GetVNFunc(addrVN, &funcApp))
{
return false;
}

// Is given VN representing a frozen object handle
auto isCnsObjHandle = [](ValueNumStore* vnStore, ValueNum vn, CORINFO_OBJECT_HANDLE* handle) -> bool {
if (vnStore->IsVNHandle(vn) && (vnStore->GetHandleFlags(vn) == GTF_ICON_OBJ_HDL))
{
const size_t obj = vnStore->CoercedConstantValue<size_t>(vn);
*handle = reinterpret_cast<CORINFO_OBJECT_HANDLE>(obj);
return true;
}
return false;
};

CORINFO_OBJECT_HANDLE objHandle = NO_OBJECT_HANDLE;
size_t index = -1;

// First, let see if we have PtrToArrElem
ValueNum addr = funcApp.m_args[0];
if (funcApp.m_func == VNF_PtrToArrElem)
{
ValueNum arrVN = funcApp.m_args[1];
ValueNum inxVN = funcApp.m_args[2];
ssize_t offset = vnStore->ConstantValue<ssize_t>(funcApp.m_args[3]);

if (isCnsObjHandle(vnStore, arrVN, &objHandle) && (offset == 0) && vnStore->IsVNConstant(inxVN))
{
index = vnStore->CoercedConstantValue<size_t>(inxVN);
}
}
else if (funcApp.m_func == (VNFunc)GT_ADD)
{
ssize_t dataOffset = 0;
ValueNum baseVN = ValueNumStore::NoVN;

// Loop to accumulate total dataOffset, e.g.:
// ADD(C1, ADD(ObjHandle, C2)) -> C1 + C2
do
{
ValueNum op1VN = funcApp.m_args[0];
ValueNum op2VN = funcApp.m_args[1];

if (vnStore->IsVNConstant(op1VN) && varTypeIsIntegral(vnStore->TypeOfVN(op1VN)) &&
!isCnsObjHandle(vnStore, op1VN, &objHandle))
{
dataOffset += vnStore->CoercedConstantValue<ssize_t>(op1VN);
baseVN = op2VN;
}
else if (vnStore->IsVNConstant(op2VN) && varTypeIsIntegral(vnStore->TypeOfVN(op2VN)) &&
!isCnsObjHandle(vnStore, op2VN, &objHandle))
{
dataOffset += vnStore->CoercedConstantValue<ssize_t>(op2VN);
baseVN = op1VN;
}
else
{
// one of the args is expected to be an integer constant
return false;
}
} while (vnStore->GetVNFunc(baseVN, &funcApp) && (funcApp.m_func == (VNFunc)GT_ADD));

if (isCnsObjHandle(vnStore, baseVN, &objHandle) && (dataOffset >= (ssize_t)OFFSETOF__CORINFO_String__chars) &&
((dataOffset % 2) == 0))
{
static_assert_no_msg((OFFSETOF__CORINFO_String__chars % 2) == 0);
index = (dataOffset - OFFSETOF__CORINFO_String__chars) / 2;
}
}

USHORT charValue;
if (((size_t)index < INT_MAX) && (objHandle != NO_OBJECT_HANDLE) &&
info.compCompHnd->getStringChar(objHandle, (int)index, &charValue))
{
JITDUMP("Folding \"cns_str\"[%d] into %u", (int)index, (unsigned)charValue);

tree->gtVNPair.SetBoth(vnStore->VNForIntCon(charValue));
return true;
}
return false;
}

void Compiler::fgValueNumberTree(GenTree* tree)
{
genTreeOps oper = tree->OperGet();
Expand Down Expand Up @@ -8745,6 +8842,10 @@ void Compiler::fgValueNumberTree(GenTree* tree)
// Note VNF_PtrToStatic statics are currently always "simple".
fgValueNumberFieldLoad(tree, /* baseAddr */ nullptr, fldSeq, offset);
}
else if (tree->OperIs(GT_IND) && fgValueNumberConstLoad(tree->AsIndir()))
{
// VN is assigned inside fgValueNumberConstLoad
}
else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
{
fgValueNumberArrayElemLoad(tree, &funcApp);
Expand Down Expand Up @@ -10502,6 +10603,12 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree
// We should have tree that a unary indirection or a tree node with an implicit indirection
assert(tree->OperIsUnary() || tree->OperIsImplicitIndir());

// if this indirection can be folded into a constant it means it can't trigger NullRef
if (tree->gtVNPair.BothEqual() && vnStore->IsVNConstant(tree->gtVNPair.GetLiberal()))
{
return;
}

// We evaluate the baseAddr ValueNumber further in order
// to obtain a better value to use for the null check exception.
//
Expand Down
Loading

0 comments on commit 0ff0f7d

Please sign in to comment.