Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARM32: stop allocating a register for null checks on instance calls #68100

Closed
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
38 changes: 12 additions & 26 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3182,33 +3182,27 @@ void CodeGen::genCall(GenTreeCall* call)
}
}

GenTree* target = getCallTarget(call, nullptr);

if (target != nullptr)
{
genConsumeReg(target);
}

// Insert a null check on "this" pointer if asked.
if (call->NeedsNullCheck())
{
const regNumber regThis = genGetThisArgReg(call);

#if defined(TARGET_ARM)
const regNumber tmpReg = call->ExtractTempReg();
GetEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, tmpReg, regThis, 0);
#elif defined(TARGET_ARM64)
GetEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, regThis, 0);
#endif // TARGET*
GetEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_LR, genGetThisArgReg(call), 0);
}

// If fast tail call, then we are done here, we just have to load the call
// target into the right registers. We ensure in RA that target is loaded
// into a volatile register that won't be restored by epilog sequence.
// target into the right registers if we used an internal register for it.
// We ensure in RA that target is loaded into a volatile register that
// won't be restored by epilog sequence.
if (call->IsFastTailCall())
{
GenTree* target = getCallTarget(call, nullptr);

if (target != nullptr)
{
// Indirect fast tail calls materialize call target either in gtControlExpr or in gtCallAddr.
genConsumeReg(target);
}
#ifdef FEATURE_READYTORUN
else if (call->IsR2ROrVirtualStubRelativeIndir())
if ((target == nullptr) && call->IsR2ROrVirtualStubRelativeIndir())
{
assert(((call->IsR2RRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_PVALUE)) ||
((call->IsVirtualStubRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_VALUE)));
Expand Down Expand Up @@ -3431,14 +3425,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
// A call target can not be a contained indirection
assert(!target->isContainedIndir());

// For fast tailcall we have already consumed the target. We ensure in
// RA that the target was allocated into a volatile register that will
// not be messed up by epilog sequence.
if (!call->IsFastTailCall())
{
genConsumeReg(target);
}

// We have already generated code for gtControlExpr evaluating it into a register.
// We just need to emit "call reg" in this case.
//
Expand Down
52 changes: 19 additions & 33 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5405,33 +5405,34 @@ void CodeGen::genCall(GenTreeCall* call)
}
#endif // defined(TARGET_X86) || defined(UNIX_AMD64_ABI)

GenTree* target = getCallTarget(call, nullptr);

if (target != nullptr)
{
if (target->isContainedIndir())
{
genConsumeAddress(target->AsIndir()->Addr());
}
else
{
assert(!target->isContained());
genConsumeReg(target);
}
}

// Insert a null check on "this" pointer if asked.
if (call->NeedsNullCheck())
{
const regNumber regThis = genGetThisArgReg(call);
GetEmitter()->emitIns_AR_R(INS_cmp, EA_4BYTE, regThis, regThis, 0);
}

// If fast tail call, then we are done here, we just have to load the call
// target into the right registers. We ensure in RA that the registers used
// for the target (e.g. contained indir) are loaded into volatile registers
// that won't be restored by epilog sequence.
// If fast tail call, then we are done here as we loaded the call target
// above. We ensure in RA that the registers used for the target (e.g.
// contained indir) are loaded into volatile registers that won't be
// restored by epilog sequence.
if (call->IsFastTailCall())
{
GenTree* target = getCallTarget(call, nullptr);
if (target != nullptr)
{
if (target->isContainedIndir())
{
genConsumeAddress(target->AsIndir()->Addr());
}
else
{
assert(!target->isContained());
genConsumeReg(target);
}
}

return;
}

Expand Down Expand Up @@ -5745,7 +5746,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
GenTree* addr = target->AsIndir()->Addr();
assert(addr->isUsedFromReg());

genConsumeReg(addr);
genCopyRegIfNeeded(addr, REG_VIRTUAL_STUB_TARGET);

GetEmitter()->emitIns_Nop(3);
Expand Down Expand Up @@ -5794,13 +5794,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
}
else
{
// For fast tailcalls this is happening in epilog, so we should
// have already consumed target in genCall.
if (!call->IsFastTailCall())
{
genConsumeAddress(target->AsIndir()->Addr());
}

// clang-format off
genEmitCallIndir(emitter::EC_INDIR_ARD,
methHnd,
Expand All @@ -5820,13 +5813,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
// We just need to emit "call reg" in this case.
assert(genIsValidIntReg(target->GetRegNum()));

// For fast tailcalls this is happening in epilog, so we should
// have already consumed target in genCall.
if (!call->IsFastTailCall())
{
genConsumeReg(target);
}

// clang-format off
genEmitCall(emitter::EC_INDIR_R,
methHnd,
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/jit/lsraarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,6 @@ int LinearScan::BuildCall(GenTreeCall* call)
buildInternalIntRegisterDefForNode(call);
}

if (call->NeedsNullCheck())
{
buildInternalIntRegisterDefForNode(call);
}

#endif // TARGET_ARM

RegisterType registerType = call->TypeGet();
Expand Down