diff options
author | Pat Gavlin <pagavlin@microsoft.com> | 2016-12-08 14:14:38 -0800 |
---|---|---|
committer | Pat Gavlin <pagavlin@microsoft.com> | 2016-12-08 14:14:38 -0800 |
commit | 53f78db5a1a12666f40b1648dbeb4d0c34a99415 (patch) | |
tree | 41c6d58e4395bc5b53e5cf4c6687270a33331e9e /src/jit/lsra.cpp | |
parent | bf4ed11eb5cee7123fd0c6fa5b60f09fe7adf23e (diff) | |
download | coreclr-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/lsra.cpp')
-rw-r--r-- | src/jit/lsra.cpp | 46 |
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, |