summaryrefslogtreecommitdiff
path: root/src/jit
diff options
context:
space:
mode:
authorPat Gavlin <pagavlin@microsoft.com>2016-12-08 14:14:38 -0800
committerPat Gavlin <pagavlin@microsoft.com>2016-12-08 14:14:38 -0800
commit53f78db5a1a12666f40b1648dbeb4d0c34a99415 (patch)
tree41c6d58e4395bc5b53e5cf4c6687270a33331e9e /src/jit
parentbf4ed11eb5cee7123fd0c6fa5b60f09fe7adf23e (diff)
downloadcoreclr-53f78db5a1a12666f40b1648dbeb4d0c34a99415.tar.gz
coreclr-53f78db5a1a12666f40b1648dbeb4d0c34a99415.tar.bz2
coreclr-53f78db5a1a12666f40b1648dbeb4d0c34a99415.zip
Disable special put args for LIMIT_CALLER on x86.
On x86, `LSRA_LIMIT_CALLER` is too restrictive to allow the use of special put args: this stress mode leaves only three registers allocatable--eax, ecx, and edx--of which the latter two are also used for the first two integral arguments to a call. This can leave us with too few registers to succesfully allocate in situations like the following: t1026 = lclVar ref V52 tmp35 u:3 REG NA <l:$3a1, c:$98d> /--* t1026 ref t1352 = * putarg_reg ref REG NA t342 = lclVar int V14 loc6 u:4 REG NA $50c t343 = const int 1 REG NA $41 /--* t342 int +--* t343 int t344 = * + int REG NA $495 t345 = lclVar int V04 arg4 u:2 REG NA $100 /--* t344 int +--* t345 int t346 = * % int REG NA $496 /--* t346 int t1353 = * putarg_reg int REG NA t1354 = lclVar ref V52 tmp35 (last use) REG NA /--* t1354 ref t1355 = * lea(b+0) byref REG NA Here, the first `putarg_reg` would normally be considered a special put arg, which would remove `ecx` from the set of allocatable registers, leaving only `eax` and `edx`. The allocator will then fail to allocate a register for the def of `t345` if arg4 is not a register candidate: the corresponding ref position will be constrained to { `ecx`, `ebx`, `esi`, `edi` }, which `LSRA_LIMIT_CALLER` will further constrain to `ecx`, which will not be available due to the special put arg.
Diffstat (limited to 'src/jit')
-rw-r--r--src/jit/lsra.cpp46
1 files changed, 45 insertions, 1 deletions
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 6813beb288..3e0f29e5cf 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -3684,7 +3684,51 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
// (i.e. the target is read-modify-write), preference the dst to op1.
bool hasDelayFreeSrc = tree->gtLsraInfo.hasDelayFreeSrc;
- if (tree->OperGet() == GT_PUTARG_REG && isCandidateLocalRef(tree->gtGetOp1()) &&
+
+#if defined(DEBUG) && defined(_TARGET_X86_)
+ // On x86, `LSRA_LIMIT_CALLER` is too restrictive to allow the use of special put args: this stress mode
+ // leaves only three registers allocatable--eax, ecx, and edx--of which the latter two are also used for the
+ // first two integral arguments to a call. This can leave us with too few registers to succesfully allocate in
+ // situations like the following:
+ //
+ // t1026 = lclVar ref V52 tmp35 u:3 REG NA <l:$3a1, c:$98d>
+ //
+ // /--* t1026 ref
+ // t1352 = * putarg_reg ref REG NA
+ //
+ // t342 = lclVar int V14 loc6 u:4 REG NA $50c
+ //
+ // t343 = const int 1 REG NA $41
+ //
+ // /--* t342 int
+ // +--* t343 int
+ // t344 = * + int REG NA $495
+ //
+ // t345 = lclVar int V04 arg4 u:2 REG NA $100
+ //
+ // /--* t344 int
+ // +--* t345 int
+ // t346 = * % int REG NA $496
+ //
+ // /--* t346 int
+ // t1353 = * putarg_reg int REG NA
+ //
+ // t1354 = lclVar ref V52 tmp35 (last use) REG NA
+ //
+ // /--* t1354 ref
+ // t1355 = * lea(b+0) byref REG NA
+ //
+ // Here, the first `putarg_reg` would normally be considered a special put arg, which would remove `ecx` from the
+ // set of allocatable registers, leaving only `eax` and `edx`. The allocator will then fail to allocate a register
+ // for the def of `t345` if arg4 is not a register candidate: the corresponding ref position will be constrained to
+ // { `ecx`, `ebx`, `esi`, `edi` }, which `LSRA_LIMIT_CALLER` will further constrain to `ecx`, which will not be
+ // available due to the special put arg.
+ const bool supportsSpecialPutArg = getStressLimitRegs() != LSRA_LIMIT_CALLER;
+#else
+ const bool supportsSpecialPutArg = true;
+#endif
+
+ if (supportsSpecialPutArg && tree->OperGet() == GT_PUTARG_REG && isCandidateLocalRef(tree->gtGetOp1()) &&
(tree->gtGetOp1()->gtFlags & GTF_VAR_DEATH) == 0)
{
// This is the case for a "pass-through" copy of a lclVar. In the case where it is a non-last-use,