Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Prev Previous commit
Next Next commit
Conservatively disable the optimization when we can't guess alignment
  • Loading branch information
EgorBo committed Oct 3, 2023
commit ebc9dc29119eaeb2a2287adf4f175f532b396e5b
2 changes: 2 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,8 @@ enum GenTreeFlags : unsigned int
// This flag is useful in cases where it is required to generate register
// indirect addressing mode. One such case is virtual stub calls on xarch.
GTF_IND_UNALIGNED = 0x02000000, // OperIsIndir() -- the load or store is unaligned (we assume worst case alignment of 1 byte)
GTF_IND_KNOWN_UNALIGNED = 0x00100000, // GT_IND -- same as GTF_IND_UNALIGNED (it's expected to be set) with a legal allowance
// to use wider loads/stores where needed.
GTF_IND_INVARIANT = 0x01000000, // GT_IND -- the target is invariant (a prejit indirection)
GTF_IND_NONNULL = 0x00400000, // GT_IND -- the indirection never returns null (zero)
GTF_IND_INITCLASS = 0x00200000, // OperIsIndir() -- the indirection requires preceding static cctor
Expand Down
42 changes: 42 additions & 0 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8011,6 +8011,42 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeStoreInd* ind)
return;
}

// Now the hardest part: decide whether it's safe to use an unaligned write.
//
// IND<byte> is always fine (and all IND<X> created here from such)
const bool knownUnaligned =
((ind->gtFlags & GTF_IND_KNOWN_UNALIGNED) != 0) && ((prevInd->gtFlags & GTF_IND_KNOWN_UNALIGNED) != 0);
if (!knownUnaligned && (genTypeSize(ind) > 1))
{
// TODO-CQ: if we see that the target is a local memory (not address exposed)
// we can use any type (including SIMD) for a new load.

// Ignore indices for now, they can invalidate our alignment assumptions.
if (currData.index != nullptr)
{
return;
}

// If the baseAddr is not TYP_REF we likely have no hints about its alignment.
// while TYP_REF guarantees pointer-size alignment.
if (!currData.baseAddr->TypeIs(TYP_REF))
{
return;
}

#ifdef TARGET_XARCH
// Check whether data can be guaranteed to be in a cache line.
// It seems that only x86 can guarantee that.
int startOffset = min(prevData.offset, currData.offset) % genTypeSize(ind);
if ((startOffset + (genTypeSize(ind) * 2)) > TARGET_POINTER_SIZE)
{
return;
}
#else
return;
#endif
}

// Since we're merging two stores of the same type, the new type is twice wider.
var_types oldType = ind->TypeGet();
var_types newType;
Expand Down Expand Up @@ -8102,6 +8138,12 @@ void Lowering::LowerStoreIndirCoalescing(GenTreeStoreInd* ind)
ind->Data()->AsVecCon()->gtSimdVal = newCns;
ind->Data()->ClearContained();
ind->gtFlags |= GTF_IND_UNALIGNED;
if (genTypeSize(oldType) == 1)
{
// A sign that we can promote such TYP_USHORT loads to any wider types
// without taking alignment into account.
ind->gtFlags |= GTF_IND_KNOWN_UNALIGNED;
}
continue;
}
#endif
Expand Down