Skip to content

Commit

Permalink
JIT: Rewrite register parameter homing (#100572)
Browse files Browse the repository at this point in the history
Generalize register parameter homing to handle float and integer parameters
simultaneously, and to handle all parameters (including the Swift self
register). Base it on the new ABI representation. This implements the alternate
ideal fix mentioned in #96439.

The new algorithm constructs a graph in which nodes are the source and
destination registers of all parameters. Edges in the graph indicate that (part
of) a register has to be moved into (part of) another register. To home
parameters we repeatedly pick a register (preferring nodes without any outgoing
edges) and perform the reg-reg moves indicated by its incoming edges. If we pick
a register that has any outgoing edges it means there is circularity, so we need
a temporary register to save its value.

LA64 and RISCV64 should be able to reuse this implementation and get rid of
their two own copies as well, but first it requires adding the new style ABI
classifiers for them.

Diffs from:

- Improvements on xarch due to stack homing not rounding up sizes of structs to
  TYP_I_IMPL size unnecessarily, leading to smaller encodings

- Improvements from no longer zeroing initReg after register homing when
  unnecessary because it is still zero

- Improvements on arm32 from storing doubles to stack in a single store rather
  than two stores

- Some improvements and regressions on arm64 from different homing order,
  leading to differences in stp optimizations

- Some regressions on arm32 from reserving an extra callee save in functions
  with all callee trashed float registers used by parameters
  • Loading branch information
jakobbotsch authored Apr 9, 2024
1 parent e60d9a3 commit 0764864
Show file tree
Hide file tree
Showing 13 changed files with 586 additions and 1,392 deletions.
16 changes: 11 additions & 5 deletions src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ unsigned ABIPassingSegment::GetStackOffset() const
}

//-----------------------------------------------------------------------------
// GetRegisterStoreType:
// Return a type that can be used to store from the register this segment is
// in, taking the segment's size into account.
// GetRegisterType:
// Return the smallest type larger or equal to Size that most naturally
// represents the register this segment is passed in.
//
// Return Value:
// A type that matches ABIPassingSegment::Size and the register type.
// A type that matches ABIPassingSegment::Size and the register.
//
var_types ABIPassingSegment::GetRegisterStoreType() const
var_types ABIPassingSegment::GetRegisterType() const
{
assert(IsPassedInRegister());
if (genIsValidFloatReg(m_register))
Expand All @@ -110,6 +110,7 @@ var_types ABIPassingSegment::GetRegisterStoreType() const
return TYP_SIMD16;
#endif
default:
assert(!"Unexpected size for floating point register");
return TYP_UNDEF;
}
}
Expand All @@ -121,13 +122,18 @@ var_types ABIPassingSegment::GetRegisterStoreType() const
return TYP_UBYTE;
case 2:
return TYP_USHORT;
case 3:
case 4:
return TYP_INT;
#ifdef TARGET_64BIT
case 5:
case 6:
case 7:
case 8:
return TYP_LONG;
#endif
default:
assert(!"Unexpected size for integer register");
return TYP_UNDEF;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ABIPassingSegment
// offset, relative to the base of stack arguments.
unsigned GetStackOffset() const;

var_types GetRegisterStoreType() const;
var_types GetRegisterType() const;

static ABIPassingSegment InRegister(regNumber reg, unsigned offset, unsigned size);
static ABIPassingSegment OnStack(unsigned stackOffset, unsigned offset, unsigned size);
Expand Down
14 changes: 7 additions & 7 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,13 @@ class CodeGen final : public CodeGenInterface
// Prolog functions and data (there are a few exceptions for more generally used things)
//

void genEstablishFramePointer(int delta, bool reportUnwindData);
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
void genFnPrologCalleeRegArgs();
#else
void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
#endif
void genEnregisterIncomingStackArgs();
void genEstablishFramePointer(int delta, bool reportUnwindData);
void genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed);
regMaskTP genGetParameterHomingTempRegisterCandidates();

var_types genParamStackStoreType(LclVarDsc* dsc, const ABIPassingSegment& seg);
void genSpillOrAddRegisterParam(unsigned lclNum, class RegGraph* graph);
void genEnregisterIncomingStackArgs();
#if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
void genEnregisterOSRArgsAndLocals(regNumber initReg, bool* pInitRegZeroed);
#else
Expand Down
Loading

0 comments on commit 0764864

Please sign in to comment.