Skip to content

Commit 010e61a

Browse files
authored
JIT: Model GT_RETURN kills with contained operand (#111230)
When `GT_RETURN` has a contained operand (due to returning a DNER local), it will load the ABI return registers directly from stack. This will kill those registers. However, nothing was modelling this kill. This was noticed while trying to ensure that GC information is correctly marked in codegen when going into epilogs. However, this is potential bad codegen even on its own: before this change LSRA might not properly spill locals that are required to be live around a `GT_RETURN` node even if they are getting killed by the `GT_RETURN`. A concrete case was seen in `<StartupCode$FSharp-Core>.$Tasks+Using@148-5[System.__Canon]:Invoke` under JitStressRegs=2, where the VM requests that the JIT keep "this" alive throughout the function. Before this change we get the following codegen: ```asm G_M51753_IG05: ; bbWeight=0.50, gcVars=0000000000000000 {}, gcrefRegs=0002 {x1}, byrefRegs=0000 {}, gcvars, byref ; gcrRegs -[x0] +[x1] ; GC ptr vars -{V00} stp xzr, xzr, [fp, #0x38] ldp x0, x1, [fp, #0x38] // [V04 loc2], [V04 loc2+0x08] ; gcrRegs -[x1] +[x0] ;; size=8 bbWeight=0.50 PerfScore 2.00 ``` where "this" is in `x1` going into the block, and gets overridden by the return without being available somewhere else. After this change, the codegen becomes ```asm G_M51753_IG05: ; bbWeight=0.50, gcVars=0000000000000000 {}, gcrefRegs=0002 {x1}, byrefRegs=0000 {}, gcvars, byref ; gcrRegs -[x0] +[x1] ; GC ptr vars -{V00} str x1, [fp, #0x20] // [V00 this] ; GC ptr vars +{V00} stp xzr, xzr, [fp, #0x38] ldp x0, x1, [fp, #0x38] // [V04 loc2], [V04 loc2+0x08] ; gcrRegs -[x1] +[x0] ;; size=12 bbWeight=0.50 PerfScore 2.50 ```
1 parent a69d74a commit 010e61a

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

src/coreclr/jit/lsrabuild.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,6 +4300,16 @@ int LinearScan::BuildReturn(GenTree* tree)
43004300
return 1;
43014301
}
43024302
}
4303+
else
4304+
{
4305+
// In other cases we require the incoming operand to be in the
4306+
// right register(s) when we build the use(s), and thus we do not
4307+
// need to model that as a kill. However, in this case we have a
4308+
// contained operand. Codegen will move it to the right return
4309+
// registers; thus they will be killed.
4310+
regMaskTP killedRegs = compiler->compRetTypeDesc.GetABIReturnRegs(compiler->info.compCallConv);
4311+
buildKillPositionsForNode(tree, currentLoc + 1, killedRegs);
4312+
}
43034313

43044314
// No kills or defs.
43054315
return 0;

0 commit comments

Comments
 (0)