Skip to content

Commit caa7b4d

Browse files
Slightly more precise null checking (#3130)
1 parent ce33e12 commit caa7b4d

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

src/coreclr/jit/llvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ class Llvm
657657

658658
Value* consumeAddressAndEmitNullCheck(GenTreeIndir* indir);
659659
void emitNullCheckForAddress(GenTree* addr, Value* addrValue DEBUGARG(GenTree* indir));
660+
bool isAddressNullOrValid(GenTree* addr);
660661
void emitAlignmentCheckForAddress(GenTree* addr, Value* addrValue, unsigned alignment DEBUGARG(GenTree* indir));
661662
bool isAddressAligned(GenTree* addr, unsigned alignment);
662663

src/coreclr/jit/llvmcodegen.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,10 +2340,10 @@ void Llvm::emitNullCheckForAddress(GenTree* addr, Value* addrValue DEBUGARG(GenT
23402340
{
23412341
// The frontend's contract with the backend is that it will not insert null checks for accesses which
23422342
// are inside the "[0..compMaxUncheckedOffsetForNullObject]" range. Thus, we usually need to check not
2343-
// just for "null", but "null + small offset". However, for TYP_REF, we know it will either be a valid
2344-
// object on heap, or null, and can utilize the more direct form.
2343+
// just for "null", but "null + small offset". However, for certain addresses, we know it will either
2344+
// be a valid address, or null.
23452345
Value* isNullValue;
2346-
if (addr->TypeIs(TYP_REF))
2346+
if (isAddressNullOrValid(addr))
23472347
{
23482348
// LLVM's FastISel, used for unoptimized code, is not able to generate sensible WASM unless we do
23492349
// a comparison using an integer zero here. This workaround saves 5+% on debug code size.
@@ -2368,6 +2368,30 @@ void Llvm::emitNullCheckForAddress(GenTree* addr, Value* addrValue DEBUGARG(GenT
23682368
emitJumpToThrowHelper(isNullValue, CORINFO_HELP_THROWNULLREF DEBUGARG(indir));
23692369
}
23702370

2371+
bool Llvm::isAddressNullOrValid(GenTree* addr)
2372+
{
2373+
if (addr->TypeIs(TYP_REF))
2374+
{
2375+
return true;
2376+
}
2377+
2378+
// Weed out transient byrefs that could've been created by "fgMorphField". This is not as easy as it may look
2379+
// as we must accomodate for the possibility of the frontend transforming these in arbitrary ways. We do this
2380+
// by taking advantage of the managed ABI which prohibits passing such byrefs across call boundaries.
2381+
if (addr->OperIs(GT_LCL_VAR) && (addr->AsLclVar()->GetSsaNum() == SsaConfig::FIRST_SSA_NUM) &&
2382+
_compiler->lvaGetDesc(addr->AsLclVar())->lvIsParam)
2383+
{
2384+
return true;
2385+
}
2386+
2387+
if (addr->IsCall())
2388+
{
2389+
return true;
2390+
}
2391+
2392+
return false;
2393+
}
2394+
23712395
void Llvm::emitAlignmentCheckForAddress(GenTree* addr, Value* addrValue, unsigned alignment DEBUGARG(GenTree* indir))
23722396
{
23732397
if (isAddressAligned(addr, alignment))

src/coreclr/jit/llvmlower.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ void Llvm::lowerAddressToAddressMode(GenTreeIndir* indir)
977977
(size_t)offset);
978978

979979
// Invariant access can be assumed to be in bounds by construction.
980-
if (((indir->gtFlags & GTF_IND_INVARIANT) == 0) && !isAddressInBounds(baseAddr, fieldSeq, offset))
980+
if (!indir->IsInvariantLoad() && !isAddressInBounds(baseAddr, fieldSeq, offset))
981981
{
982982
JITDUMP("no, not in bounds\n");
983983
return;

0 commit comments

Comments
 (0)