summaryrefslogtreecommitdiff
path: root/src/jit/instr.cpp
diff options
context:
space:
mode:
authorBruce Forstall <brucefo@microsoft.com>2016-04-21 15:37:06 -0700
committerBruce Forstall <brucefo@microsoft.com>2016-04-22 22:44:06 -0700
commit9a67c5824baa6887fa2a2cd26da59e26037cf883 (patch)
tree2b2e76a4c407dadabf9ab5491cd699c631d11daf /src/jit/instr.cpp
parent25c0a14c4db495ab452186f5b93b891977d71294 (diff)
downloadcoreclr-9a67c5824baa6887fa2a2cd26da59e26037cf883.tar.gz
coreclr-9a67c5824baa6887fa2a2cd26da59e26037cf883.tar.bz2
coreclr-9a67c5824baa6887fa2a2cd26da59e26037cf883.zip
Fix #3561: assert on RyuJIT x86 when generating shl by 1
This assert hit in the encoder when we were trying to generate an INS_shl_N with a constant of 1, instead of using the special xarch INS_shl_1 encoding, which saves a byte. It turns out, the assert was and in fact amd64 does generate the suboptimal encoding currently. The bad code occurs in the RMW case of genCodeForShift(). It turns out that function is unnecessarily complex, unique (it doesn't use the common RMW code paths), and has a number of other latent bugs. To fix this, I split genCodeForShift() by leaving the non-RMW case there, and adding a genCodeForShiftRMW() function just for the RMW case. I rewrote the RMW case to use the existing emitInsRMW functions. Other related cleanups along the way: 1. I changed emitHandleMemOp to consistently set the idInsFmt field, and changed all callers to stop pre-setting or post-setting this field. This makes the API much easier to understand. I added a big header comment for the function. Now, it takes a "basic" insFmt (using ARD, AWR, or ARW forms), which might be munged to a MRD/MWR/MRW form if necessary. 2. I changed some places to always use the most derived GenTree type for all uses. For instance, if the code has "GenTreeIndir* mem = node->AsIndir()", then always use "mem" from then on, and don't use "node". I changed some functions to take more derived GenTree node types. 3. I rewrote the emitInsRMW() functions to be much simpler, and rewrote their header comments. 4. I added GenTree predicates OperIsShift(), OperIsRotate(), and OperIsShiftOrRotate(). 5. I added function genMapShiftInsToShiftByConstantIns() to encapsulate mapping from INS_shl to INS_shl_N or INS_shl_1 based on a constant. This code was in 3 different places already. 6. The change in assertionprop.cpp is simply to make JitDumps readable. In addition to fixing the bug for RyuJIT/x86, there are a small number of x64 diffs where we now generate smaller encodings for shift by 1.
Diffstat (limited to 'src/jit/instr.cpp')
-rw-r--r--src/jit/instr.cpp80
1 files changed, 13 insertions, 67 deletions
diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp
index 85b8a44769..3c6339ca9f 100644
--- a/src/jit/instr.cpp
+++ b/src/jit/instr.cpp
@@ -2640,46 +2640,15 @@ void CodeGen::inst_RV_SH(instruction ins,
assert(val < 256);
#endif
- assert(ins == INS_rcl ||
- ins == INS_rcr ||
- ins == INS_rol ||
- ins == INS_ror ||
- ins == INS_shl ||
- ins == INS_shr ||
- ins == INS_sar);
-
- /* Which format should we use? */
+ ins = genMapShiftInsToShiftByConstantIns(ins, val);
if (val == 1)
{
- /* Use the shift-by-one format */
-
- assert(INS_rcl + 1 == INS_rcl_1);
- assert(INS_rcr + 1 == INS_rcr_1);
- assert(INS_rol + 1 == INS_rol_1);
- assert(INS_ror + 1 == INS_ror_1);
- assert(INS_shl + 1 == INS_shl_1);
- assert(INS_shr + 1 == INS_shr_1);
- assert(INS_sar + 1 == INS_sar_1);
-
- getEmitter()->emitIns_R((instruction)(ins+1), size, reg);
+ getEmitter()->emitIns_R(ins, size, reg);
}
else
{
- /* Use the shift-by-NNN format */
-
- assert(INS_rcl + 2 == INS_rcl_N);
- assert(INS_rcr + 2 == INS_rcr_N);
- assert(INS_rol + 2 == INS_rol_N);
- assert(INS_ror + 2 == INS_ror_N);
- assert(INS_shl + 2 == INS_shl_N);
- assert(INS_shr + 2 == INS_shr_N);
- assert(INS_sar + 2 == INS_sar_N);
-
- getEmitter()->emitIns_R_I((instruction)(ins+2),
- size,
- reg,
- val);
+ getEmitter()->emitIns_R_I(ins, size, reg, val);
}
#else
@@ -2698,43 +2667,20 @@ void CodeGen::inst_TT_SH(instruction ins,
unsigned offs)
{
#ifdef _TARGET_XARCH_
- /* Which format should we use? */
-
- switch (val)
+ if (val == 0)
{
- case 1:
-
- /* Use the shift-by-one format */
-
- assert(INS_rcl + 1 == INS_rcl_1);
- assert(INS_rcr + 1 == INS_rcr_1);
- assert(INS_shl + 1 == INS_shl_1);
- assert(INS_shr + 1 == INS_shr_1);
- assert(INS_sar + 1 == INS_sar_1);
-
- inst_TT((instruction)(ins+1), tree, offs, 0, emitTypeSize(tree->TypeGet()));
-
- break;
-
- case 0:
-
// Shift by 0 - why are you wasting our precious time????
-
return;
+ }
- default:
-
- /* Use the shift-by-NNN format */
-
- assert(INS_rcl + 2 == INS_rcl_N);
- assert(INS_rcr + 2 == INS_rcr_N);
- assert(INS_shl + 2 == INS_shl_N);
- assert(INS_shr + 2 == INS_shr_N);
- assert(INS_sar + 2 == INS_sar_N);
-
- inst_TT((instruction)(ins+2), tree, offs, val, emitTypeSize(tree->TypeGet()));
-
- break;
+ ins = genMapShiftInsToShiftByConstantIns(ins, val);
+ if (val == 1)
+ {
+ inst_TT(ins, tree, offs, 0, emitTypeSize(tree->TypeGet()));
+ }
+ else
+ {
+ inst_TT(ins, tree, offs, val, emitTypeSize(tree->TypeGet()));
}
#endif // _TARGET_XARCH_