-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[JIT] X64 - Extend emitter peephole optimization of eliminating unnecessary mov instructions
#79381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f5feaeb
958a84f
755461e
95c7d09
12e3c4f
b42682c
2d806a5
2d5e07f
4d06e05
0c1599a
53ecd41
0f42667
2de6089
bd3b211
9792d0f
0ed30e9
3e452fd
126d6b5
80ac0d7
9497d5e
4ee489b
7d599df
11a1709
e33147a
99cba5a
0356348
2c10d21
189afe0
f0e626a
f1e7c07
ca8813a
c533d54
e0df38e
1f5501a
e34367f
b2c0414
5431a53
07ec7fb
7e0079f
0c71902
25cb4fb
7d6d03d
ee349d3
a2538ca
6fb2694
7e97320
896a32a
49c3c07
f229bc0
920fc7c
7380971
a4e92c7
fa4f6e5
0fd25ca
2ff99ed
d2307d5
f478d53
0afbc01
140fd11
423a72f
c6c5711
cab9705
987e50c
453e00b
710b039
cadbf4d
a68cd3f
26cb484
a88103a
5fe41e2
c1b612f
9f42790
84f076c
12ea52f
cb3b2e8
a007c3b
5e33fad
b35c10e
7576c94
6816216
3a4adfb
5a3acc5
d48e429
90479c5
f7224c2
36ffb3a
d1d7814
8162a38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,7 +38,11 @@ | |
| #define EMIT_INSTLIST_VERBOSE (emitComp->verbose) | ||
| #endif | ||
|
|
||
| #define EMIT_BACKWARDS_NAVIGATION 0 // If 1, enable backwards navigation code for MIR (insGroup/instrDesc). | ||
| #ifdef TARGET_XARCH | ||
| #define EMIT_BACKWARDS_NAVIGATION 1 // If 1, enable backwards navigation code for MIR (insGroup/instrDesc). | ||
| #else | ||
| #define EMIT_BACKWARDS_NAVIGATION 0 | ||
| #endif | ||
|
|
||
| /*****************************************************************************/ | ||
|
|
||
|
|
@@ -2288,31 +2292,111 @@ class emitter | |
| return (emitCurIG && emitCurIGfreeNext > emitCurIGfreeBase); | ||
| } | ||
|
|
||
| #define EMIT_MAX_IG_INS_COUNT 256 | ||
|
|
||
| #if EMIT_BACKWARDS_NAVIGATION | ||
| #define EMIT_MAX_PEEPHOLE_INS_COUNT 32 // The max number of previous instructions to navigate through for peepholes. | ||
| #endif // EMIT_BACKWARDS_NAVIGATION | ||
|
|
||
| instrDesc* emitLastIns; | ||
| insGroup* emitLastInsIG; | ||
|
|
||
| #if EMIT_BACKWARDS_NAVIGATION | ||
| unsigned emitLastInsFullSize; | ||
| #endif // EMIT_BACKWARDS_NAVIGATION | ||
|
|
||
| // Check to see if the last instruction is available. | ||
| inline bool emitHasLastIns() const | ||
| { | ||
| return (emitLastIns != nullptr); | ||
| } | ||
|
|
||
| // Checks to see if we can cross between the two given IG boundaries. | ||
TIHan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // | ||
| // We have the following checks: | ||
| // 1. Looking backwards across an IG boundary can only be done if we're in an extension IG. | ||
| // 2. The IG of the previous instruction must have the same GC interrupt status as the current IG. | ||
| inline bool isInsIGSafeForPeepholeOptimization(insGroup* prevInsIG, insGroup* curInsIG) const | ||
| { | ||
| if (prevInsIG == curInsIG) | ||
| { | ||
| return true; | ||
| } | ||
| else | ||
| { | ||
| return (curInsIG->igFlags & IGF_EXTEND) && | ||
| ((prevInsIG->igFlags & IGF_NOGCINTERRUPT) == (curInsIG->igFlags & IGF_NOGCINTERRUPT)); | ||
| } | ||
| } | ||
|
|
||
| // Check if a peephole optimization involving emitLastIns is safe. | ||
| // | ||
| // We have the following checks: | ||
| // 1. There must be a non-null emitLastIns to consult (thus, we have a known "last" instruction). | ||
| // 2. `emitForceNewIG` is not set: this prevents peepholes from crossing nogc boundaries where | ||
| // the next instruction is forced to create a new IG. | ||
| // 3. Looking backwards across an IG boundary can only be done if we're in an extension IG. | ||
| // 4. The IG of the previous instruction must have the same GC interrupt status as the current IG. | ||
| // This is related to #2; it disallows peephole when the previous IG is GC and the current is NOGC. | ||
| bool emitCanPeepholeLastIns() | ||
| { | ||
| assert((emitLastIns == nullptr) == (emitLastInsIG == nullptr)); | ||
|
|
||
| return (emitLastIns != nullptr) && !emitForceNewIG && | ||
| ((emitCurIGinsCnt > 0) || // we're not at the start of a new IG | ||
| ((emitCurIG->igFlags & IGF_EXTEND) != 0)) && // or we are at the start of a new IG, | ||
| // and it's an extension IG | ||
| ((emitLastInsIG->igFlags & IGF_NOGCINTERRUPT) == (emitCurIG->igFlags & IGF_NOGCINTERRUPT)); | ||
| bool emitCanPeepholeLastIns() const | ||
TIHan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| assert(emitHasLastIns() == (emitLastInsIG != nullptr)); | ||
|
|
||
| return emitHasLastIns() && // there is an emitLastInstr | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is for a separate PR, but I think we need to prevent peephole optimizations when we're in the prolog or epilog. I.e., There is too much special handling in the prolog/epilog (e.g., unwinding) to allow peeps to kick in. There may be very specific cases where they are ok, but that requires some careful thinking. |
||
| !emitForceNewIG && // and we're not about to start a new IG. | ||
| isInsIGSafeForPeepholeOptimization(emitLastInsIG, emitCurIG); | ||
| } | ||
|
|
||
| enum emitPeepholeResult | ||
| { | ||
| PEEPHOLE_CONTINUE, | ||
| PEEPHOLE_ABORT | ||
| }; | ||
|
|
||
| // Visits the last emitted instructions. | ||
| // Must be safe to do - use emitCanPeepholeLastIns for checking. | ||
| // Action is a function type: instrDesc* -> emitPeepholeResult | ||
| template <typename Action> | ||
TIHan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| void emitPeepholeIterateLastInstrs(Action action) | ||
| { | ||
| assert(emitCanPeepholeLastIns()); | ||
|
|
||
| #if EMIT_BACKWARDS_NAVIGATION | ||
| insGroup* curInsIG; | ||
| instrDesc* id; | ||
|
|
||
| if (!emitGetLastIns(&curInsIG, &id)) | ||
| return; | ||
|
|
||
| for (unsigned i = 0; i < EMIT_MAX_PEEPHOLE_INS_COUNT; i++) | ||
| { | ||
| assert(id != nullptr); | ||
|
|
||
| switch (action(id)) | ||
| { | ||
| case PEEPHOLE_ABORT: | ||
| return; | ||
| case PEEPHOLE_CONTINUE: | ||
| { | ||
| insGroup* savedInsIG = curInsIG; | ||
| if (emitPrevID(curInsIG, id)) | ||
| { | ||
| if (isInsIGSafeForPeepholeOptimization(curInsIG, savedInsIG)) | ||
| { | ||
| continue; | ||
| } | ||
| else | ||
| { | ||
| return; | ||
| } | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| default: | ||
| unreached(); | ||
| } | ||
| } | ||
| #else // EMIT_BACKWARDS_NAVIGATION | ||
| action(emitLastIns); | ||
| #endif // !EMIT_BACKWARDS_NAVIGATION | ||
| } | ||
|
|
||
| #ifdef TARGET_ARMARCH | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.