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

JIT: Switch genCall to new ABI info and unify targets #103866

Merged
merged 5 commits into from
Jun 26, 2024
Merged
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
1 change: 1 addition & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,7 @@ class CodeGen final : public CodeGenInterface
void genCall(GenTreeCall* call);
void genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackArgBytes));
void genDefinePendingCallLabel(GenTreeCall* call);
void genCallPlaceRegArgs(GenTreeCall* call);
void genJmpPlaceArgs(GenTree* jmp);
void genJmpPlaceVarArgs();
BasicBlock* genCallFinally(BasicBlock* block);
Expand Down
63 changes: 5 additions & 58 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3264,60 +3264,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode)
//
void CodeGen::genCall(GenTreeCall* call)
{
// Consume all the arg regs
for (CallArg& arg : call->gtArgs.LateArgs())
{
CallArgABIInformation& abiInfo = arg.AbiInfo;
GenTree* argNode = arg.GetLateNode();

if (abiInfo.GetRegNum() == REG_STK)
continue;

// Deal with multi register passed struct args.
if (argNode->OperGet() == GT_FIELD_LIST)
{
regNumber argReg = abiInfo.GetRegNum();
for (GenTreeFieldList::Use& use : argNode->AsFieldList()->Uses())
{
GenTree* putArgRegNode = use.GetNode();
assert(putArgRegNode->gtOper == GT_PUTARG_REG);

genConsumeReg(putArgRegNode);
inst_Mov_Extend(putArgRegNode->TypeGet(), /* srcInReg */ true, argReg, putArgRegNode->GetRegNum(),
/* canSkip */ true, emitActualTypeSize(TYP_I_IMPL));

argReg = genRegArgNext(argReg);

#if defined(TARGET_ARM)
// A double register is modelled as an even-numbered single one
if (putArgRegNode->TypeGet() == TYP_DOUBLE)
{
argReg = genRegArgNext(argReg);
}
#endif // TARGET_ARM
}
}
else if (abiInfo.IsSplit())
{
assert(compFeatureArgSplit());
assert(abiInfo.NumRegs >= 1);
genConsumeArgSplitStruct(argNode->AsPutArgSplit());
for (unsigned idx = 0; idx < abiInfo.NumRegs; idx++)
{
regNumber argReg = (regNumber)((unsigned)abiInfo.GetRegNum() + idx);
regNumber allocReg = argNode->AsPutArgSplit()->GetRegNumByIdx(idx);
inst_Mov_Extend(argNode->TypeGet(), /* srcInReg */ true, argReg, allocReg, /* canSkip */ true,
emitActualTypeSize(TYP_I_IMPL));
}
}
else
{
regNumber argReg = abiInfo.GetRegNum();
genConsumeReg(argNode);
inst_Mov_Extend(argNode->TypeGet(), /* srcInReg */ true, argReg, argNode->GetRegNum(), /* canSkip */ true,
emitActualTypeSize(TYP_I_IMPL));
}
}
genCallPlaceRegArgs(call);

// Insert a null check on "this" pointer if asked.
if (call->NeedsNullCheck())
Expand Down Expand Up @@ -3548,14 +3495,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call)

for (CallArg& arg : call->gtArgs.Args())
{
for (unsigned j = 0; j < arg.AbiInfo.NumRegs; j++)
for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++)
{
regNumber reg = arg.AbiInfo.GetRegNum(j);
if ((trashedByEpilog & genRegMask(reg)) != 0)
const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i);
if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0))
{
JITDUMP("Tail call node:\n");
DISPTREE(call);
JITDUMP("Register used: %s\n", getRegName(reg));
JITDUMP("Register used: %s\n", getRegName(seg.GetRegister()));
assert(!"Argument to tailcall may be trashed by epilog");
}
}
Expand Down
103 changes: 103 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7444,6 +7444,109 @@ void CodeGen::genStructReturn(GenTree* treeNode)
#endif
}

//------------------------------------------------------------------------
// genCallPlaceRegArgs: Place all arguments into their initial (ABI-decided)
// registers in preparation for a GT_CALL node.
//
// Arguments:
// call - The GT_CALL node
//
void CodeGen::genCallPlaceRegArgs(GenTreeCall* call)
{
// Consume all the arg regs
for (CallArg& arg : call->gtArgs.LateArgs())
{
ABIPassingInformation& abiInfo = arg.NewAbiInfo;
GenTree* argNode = arg.GetLateNode();

#if FEATURE_MULTIREG_ARGS
// Deal with multi register passed struct args.
if (argNode->OperIs(GT_FIELD_LIST))
{
GenTreeFieldList::Use* use = argNode->AsFieldList()->Uses().begin().GetUse();
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
{
const ABIPassingSegment& seg = abiInfo.Segment(i);
if (!seg.IsPassedInRegister())
{
continue;
}

assert(use != nullptr);
GenTree* putArgRegNode = use->GetNode();
assert(putArgRegNode->OperIs(GT_PUTARG_REG));

genConsumeReg(putArgRegNode);
inst_Mov(genActualType(putArgRegNode), seg.GetRegister(), putArgRegNode->GetRegNum(),
/* canSkip */ true);

use = use->GetNext();
}

assert(use == nullptr);
continue;
}
#endif

#if FEATURE_ARG_SPLIT
if (argNode->OperIs(GT_PUTARG_SPLIT))
{
assert(compFeatureArgSplit());
genConsumeArgSplitStruct(argNode->AsPutArgSplit());
unsigned regIndex = 0;
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
{
const ABIPassingSegment& seg = abiInfo.Segment(i);
if (!seg.IsPassedInRegister())
{
continue;
}

regNumber allocReg = argNode->AsPutArgSplit()->GetRegNumByIdx(regIndex);
var_types type = argNode->AsPutArgSplit()->GetRegType(regIndex);
inst_Mov(genActualType(type), seg.GetRegister(), allocReg, /* canSkip */ true);

regIndex++;
}

continue;
}
#endif

if (abiInfo.HasExactlyOneRegisterSegment())
{
regNumber argReg = abiInfo.Segment(0).GetRegister();
genConsumeReg(argNode);
inst_Mov(genActualType(argNode), argReg, argNode->GetRegNum(), /* canSkip */ true);
continue;
}

// Should be a stack argument then.
assert(!abiInfo.HasAnyRegisterSegment());
}

#ifdef WINDOWS_AMD64_ABI
// On win-x64, for varargs, if we placed any arguments in float registers
// they must also be placed in corresponding integer registers.
if (call->IsVarargs())
{
for (CallArg& arg : call->gtArgs.Args())
{
for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++)
{
const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i);
if (seg.IsPassedInRegister() && genIsValidFloatReg(seg.GetRegister()))
{
regNumber targetReg = compiler->getCallArgIntRegister(seg.GetRegister());
inst_Mov(TYP_LONG, targetReg, seg.GetRegister(), /* canSkip */ false,
emitActualTypeSize(TYP_I_IMPL));
}
}
}
}
#endif
}

//------------------------------------------------------------------------
// genJmpPlaceArgs: Place all parameters into their initial (ABI-decided)
// registers in preparation for a GT_JMP node.
Expand Down
60 changes: 5 additions & 55 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6187,57 +6187,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode)
//
void CodeGen::genCall(GenTreeCall* call)
{
// Consume all the arg regs
for (CallArg& arg : call->gtArgs.LateArgs())
{
CallArgABIInformation& abiInfo = arg.AbiInfo;
GenTree* argNode = arg.GetLateNode();

// GT_RELOAD/GT_COPY use the child node
argNode = argNode->gtSkipReloadOrCopy();

if (abiInfo.GetRegNum() == REG_STK)
{
continue;
}

// Deal with multi register passed struct args.
if (argNode->OperGet() == GT_FIELD_LIST)
{
for (GenTreeFieldList::Use& use : argNode->AsFieldList()->Uses())
{
GenTree* putArgRegNode = use.GetNode();
assert(putArgRegNode->gtOper == GT_PUTARG_REG);

genConsumeReg(putArgRegNode);
}
}
else if (abiInfo.IsSplit())
{
assert(compFeatureArgSplit());

GenTreePutArgSplit* splitNode = argNode->AsPutArgSplit();
genConsumeArgSplitStruct(splitNode);

regNumber argReg = abiInfo.GetRegNum();
regNumber allocReg = splitNode->GetRegNumByIdx(0);
var_types regType = splitNode->GetRegType(0);

// For LA64's ABI, the split is only using the A7 and stack for passing arg.
assert(argReg == REG_A7);
assert(emitter::isGeneralRegister(allocReg));
assert(abiInfo.NumRegs == 1);

inst_Mov(regType, argReg, allocReg, /* canSkip */ true);
}
else
{
regNumber argReg = abiInfo.GetRegNum();
genConsumeReg(argNode);
var_types dstType = emitter::isFloatReg(argReg) ? TYP_DOUBLE : argNode->TypeGet();
inst_Mov(dstType, argReg, argNode->GetRegNum(), /* canSkip */ true);
}
}
genCallPlaceRegArgs(call);

// Insert a null check on "this" pointer if asked.
if (call->NeedsNullCheck())
Expand Down Expand Up @@ -6431,14 +6381,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call)

for (CallArg& arg : call->gtArgs.Args())
{
for (unsigned j = 0; j < arg.AbiInfo.NumRegs; j++)
for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++)
{
regNumber reg = arg.AbiInfo.GetRegNum(j);
if ((trashedByEpilog & genRegMask(reg)) != 0)
const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i);
if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0))
{
JITDUMP("Tail call node:\n");
DISPTREE(call);
JITDUMP("Register used: %s\n", getRegName(reg));
JITDUMP("Register used: %s\n", getRegName(seg.GetRegister()));
assert(!"Argument to tailcall may be trashed by epilog");
}
}
Expand Down
60 changes: 5 additions & 55 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6314,57 +6314,7 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode)
//
void CodeGen::genCall(GenTreeCall* call)
{
// Consume all the arg regs
for (CallArg& arg : call->gtArgs.LateArgs())
{
CallArgABIInformation& abiInfo = arg.AbiInfo;
GenTree* argNode = arg.GetLateNode();

// GT_RELOAD/GT_COPY use the child node
argNode = argNode->gtSkipReloadOrCopy();

if (abiInfo.GetRegNum() == REG_STK)
{
continue;
}

// Deal with multi register passed struct args.
if (argNode->OperGet() == GT_FIELD_LIST)
{
for (GenTreeFieldList::Use& use : argNode->AsFieldList()->Uses())
{
GenTree* putArgRegNode = use.GetNode();
assert(putArgRegNode->gtOper == GT_PUTARG_REG);

genConsumeReg(putArgRegNode);
}
}
else if (abiInfo.IsSplit())
{
assert(compFeatureArgSplit());

GenTreePutArgSplit* splitNode = argNode->AsPutArgSplit();
genConsumeArgSplitStruct(splitNode);

regNumber argReg = abiInfo.GetRegNum();
regNumber allocReg = splitNode->GetRegNumByIdx(0);
var_types regType = splitNode->GetRegType(0);

// For RISCV64's ABI, the split is only using the A7 and stack for passing arg.
assert(argReg == REG_A7);
assert(emitter::isGeneralRegister(allocReg));
assert(abiInfo.NumRegs == 1);

inst_Mov(regType, argReg, allocReg, /* canSkip */ true);
}
else
{
regNumber argReg = abiInfo.GetRegNum();
genConsumeReg(argNode);
var_types dstType = emitter::isFloatReg(argReg) ? TYP_DOUBLE : argNode->TypeGet();
inst_Mov(dstType, argReg, argNode->GetRegNum(), /* canSkip */ true);
}
}
genCallPlaceRegArgs(call);

// Insert a null check on "this" pointer if asked.
if (call->NeedsNullCheck())
Expand Down Expand Up @@ -6558,14 +6508,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call)

for (CallArg& arg : call->gtArgs.Args())
{
for (unsigned j = 0; j < arg.AbiInfo.NumRegs; j++)
for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++)
{
regNumber reg = arg.AbiInfo.GetRegNum(j);
if ((trashedByEpilog & genRegMask(reg)) != 0)
const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i);
if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0))
{
JITDUMP("Tail call node:\n");
DISPTREE(call);
JITDUMP("Register used: %s\n", getRegName(reg));
JITDUMP("Register used: %s\n", getRegName(seg.GetRegister()));
assert(!"Argument to tailcall may be trashed by epilog");
}
}
Expand Down
Loading
Loading