mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-12 10:40:30 +09:00
JIT: Fold more casts (#98528)
This commit is contained in:
parent
8cc7586135
commit
8fb9f4b9fa
5 changed files with 182 additions and 35 deletions
|
@ -2464,6 +2464,87 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN)
|
|||
return resultVN;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// VNForCast: Returns VN associated with castclass/isinst
|
||||
//
|
||||
// Arguments:
|
||||
// func - Either VNF_CastClass or VNF_IsInstanceOf
|
||||
// castToVN - VN of the "Cast to" argument
|
||||
// objVN - VN of the "Cast object" argument
|
||||
//
|
||||
// Return Value:
|
||||
// ValueNum associated with castclass/isinst
|
||||
//
|
||||
ValueNum ValueNumStore::VNForCast(VNFunc func, ValueNum castToVN, ValueNum objVN)
|
||||
{
|
||||
assert((func == VNF_CastClass) || (func == VNF_IsInstanceOf));
|
||||
|
||||
if (objVN == VNForNull())
|
||||
{
|
||||
// CastClass(cls, null) -> null
|
||||
// IsInstanceOf(cls, null) -> null
|
||||
//
|
||||
return VNForNull();
|
||||
}
|
||||
|
||||
//
|
||||
// Fold "CAST(IsInstanceOf(obj, cls), cls)" to "IsInstanceOf(obj, cls)"
|
||||
// where CAST is either ISINST or CASTCLASS.
|
||||
//
|
||||
VNFuncApp funcApp;
|
||||
if (GetVNFunc(objVN, &funcApp) && (funcApp.m_func == VNF_IsInstanceOf) && (funcApp.m_args[0] == castToVN))
|
||||
{
|
||||
// The outer cast is redundant, remove it and preserve its side effects
|
||||
// We do ignoreRoot here because the actual cast node never throws any exceptions.
|
||||
return objVN;
|
||||
}
|
||||
|
||||
// Check if we can fold the cast based on the runtime types of the arguments.
|
||||
//
|
||||
if (IsVNTypeHandle(castToVN))
|
||||
{
|
||||
bool isExact;
|
||||
bool isNonNull;
|
||||
CORINFO_CLASS_HANDLE castFrom = GetObjectType(objVN, &isExact, &isNonNull);
|
||||
CORINFO_CLASS_HANDLE castTo;
|
||||
if ((castFrom != NO_CLASS_HANDLE) &&
|
||||
EmbeddedHandleMapLookup(ConstantValue<ssize_t>(castToVN), (ssize_t*)&castTo))
|
||||
{
|
||||
TypeCompareState castResult = m_pComp->info.compCompHnd->compareTypesForCast(castFrom, castTo);
|
||||
if (castResult == TypeCompareState::Must)
|
||||
{
|
||||
// IsInstanceOf/CastClass is guaranteed to succeed (we don't need to check for isExact here)
|
||||
return objVN;
|
||||
}
|
||||
|
||||
if ((castResult == TypeCompareState::MustNot) && isExact && (func == VNF_IsInstanceOf))
|
||||
{
|
||||
// IsInstanceOf is guaranteed to fail -> return null (we need to check for isExact here)
|
||||
return VNForNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (func == VNF_CastClass)
|
||||
{
|
||||
// CastClass(cls, obj) -> obj (may throw InvalidCastException)
|
||||
//
|
||||
ValueNum vnExcSet = VNExcSetSingleton(VNForFuncNoFolding(TYP_REF, VNF_InvalidCastExc, objVN, castToVN));
|
||||
return VNWithExc(objVN, vnExcSet);
|
||||
}
|
||||
|
||||
// IsInstanceOf(cls, obj) -> either obj or null - we don't know
|
||||
//
|
||||
assert(func == VNF_IsInstanceOf);
|
||||
Chunk* const c = GetAllocChunk(TYP_REF, CEA_Func2);
|
||||
unsigned const offsetWithinChunk = c->AllocVN();
|
||||
VNDefFuncAppFlexible* fapp = c->PointerToFuncApp(offsetWithinChunk, 2);
|
||||
fapp->m_func = VNF_IsInstanceOf;
|
||||
fapp->m_args[0] = castToVN;
|
||||
fapp->m_args[1] = objVN;
|
||||
return c->m_baseVN + offsetWithinChunk;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// VNForFunc - Returns the ValueNum associated with 'func'('arg0VN','arg1VN')
|
||||
// There is a one-to-one relationship between the ValueNum
|
||||
|
@ -2527,24 +2608,9 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
|
|||
}
|
||||
else
|
||||
{
|
||||
if (func == VNF_CastClass)
|
||||
if ((func == VNF_CastClass) || (func == VNF_IsInstanceOf))
|
||||
{
|
||||
if (arg1VN == VNForNull())
|
||||
{
|
||||
// CastClass(cls, null) -> null
|
||||
resultVN = VNForNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
// CastClass(cls, obj) -> obj (may throw InvalidCastException)
|
||||
ValueNum vnExcSet = VNExcSetSingleton(VNForFuncNoFolding(TYP_REF, VNF_InvalidCastExc, arg1VN, arg0VN));
|
||||
resultVN = VNWithExc(arg1VN, vnExcSet);
|
||||
}
|
||||
}
|
||||
else if ((func == VNF_IsInstanceOf) && (arg1VN == VNForNull()))
|
||||
{
|
||||
// IsInstanceOf(cls, null) -> null
|
||||
resultVN = VNForNull();
|
||||
resultVN = VNForCast(func, arg0VN, arg1VN);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -13910,3 +13976,68 @@ bool ValueNumPair::BothDefined() const
|
|||
{
|
||||
return (m_liberal != ValueNumStore::NoVN) && (m_conservative != ValueNumStore::NoVN);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// GetObjectType: Try to get a class handle (hopefully, exact) for given object via VN
|
||||
//
|
||||
// Arguments:
|
||||
// vn - Value number of the object
|
||||
// pIsExact - [out] set to true if the class handle is exact
|
||||
// pIsNonNull - [out] set to true if the object is known to be non-null
|
||||
//
|
||||
// Return Value:
|
||||
// Class handle for the object, or NO_CLASS_HANDLE if not available
|
||||
//
|
||||
CORINFO_CLASS_HANDLE ValueNumStore::GetObjectType(ValueNum vn, bool* pIsExact, bool* pIsNonNull)
|
||||
{
|
||||
*pIsNonNull = false;
|
||||
*pIsExact = false;
|
||||
|
||||
if (TypeOfVN(vn) != TYP_REF)
|
||||
{
|
||||
// Not an object
|
||||
return NO_CLASS_HANDLE;
|
||||
}
|
||||
|
||||
if (IsVNObjHandle(vn))
|
||||
{
|
||||
// We know exact type for nongc objects, and they can never be null
|
||||
*pIsNonNull = true;
|
||||
*pIsExact = true;
|
||||
size_t handle = CoercedConstantValue<size_t>(vn);
|
||||
return m_pComp->info.compCompHnd->getObjectType((CORINFO_OBJECT_HANDLE)handle);
|
||||
}
|
||||
|
||||
VNFuncApp funcApp;
|
||||
if (!GetVNFunc(vn, &funcApp))
|
||||
{
|
||||
// We can't make any assumptions about the object
|
||||
return NO_CLASS_HANDLE;
|
||||
}
|
||||
|
||||
// CastClass/IsInstanceOf/JitNew all have the class handle as the first argument
|
||||
const VNFunc func = funcApp.m_func;
|
||||
if ((func == VNF_CastClass) || (func == VNF_IsInstanceOf) || (func == VNF_JitNew))
|
||||
{
|
||||
ssize_t clsHandle;
|
||||
ValueNum clsVN = funcApp.m_args[0];
|
||||
if (IsVNTypeHandle(clsVN) && EmbeddedHandleMapLookup(ConstantValue<ssize_t>(clsVN), &clsHandle))
|
||||
{
|
||||
// JitNew returns an exact and non-null obj, castclass and isinst do not have this guarantee.
|
||||
*pIsNonNull = func == VNF_JitNew;
|
||||
*pIsExact = func == VNF_JitNew;
|
||||
return (CORINFO_CLASS_HANDLE)clsHandle;
|
||||
}
|
||||
}
|
||||
|
||||
// obj.GetType() is guaranteed to return a non-null RuntimeType object
|
||||
if (func == VNF_ObjGetType)
|
||||
{
|
||||
*pIsNonNull = true;
|
||||
// Let's not assume whether RuntimeType is exact or not here (it was not in the past for NAOT)
|
||||
// Callers usually call isExact anyway.
|
||||
return m_pComp->info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE);
|
||||
}
|
||||
|
||||
return NO_CLASS_HANDLE;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue