Skip to content

Commit 37cdb45

Browse files
Support multiple intructions groups for code generated out-of-order
1 parent a202e22 commit 37cdb45

2 files changed

Lines changed: 126 additions & 18 deletions

File tree

src/coreclr/jit/emit.cpp

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,26 @@ int emitLocation::GetInsOffset() const
7171
return emitGetInsOfsFromCodePos(codePos);
7272
}
7373

74-
// Get the instruction offset in the current instruction group, which must be a funclet prolog group.
74+
// Get the instruction offset in the current instruction region, which must be a funclet prolog.
7575
// This is used to find an instruction offset used in unwind data.
76-
// TODO-AMD64-Bug?: We only support a single main function prolog group, but allow for multiple funclet prolog
77-
// groups (not that we actually use that flexibility, since the funclet prolog will be small). How to
78-
// handle that?
7976
UNATIVE_OFFSET emitLocation::GetFuncletPrologOffset(emitter* emit) const
8077
{
8178
assert(ig->igFuncIdx != 0);
8279
assert((ig->igFlags & IGF_FUNCLET_PROLOG) != 0);
83-
assert(ig == emit->emitCurIG);
80+
assert((ig->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0);
81+
assert(GetInsOffset() == 0);
8482

85-
return emit->emitCurIGsize;
86-
}
83+
unsigned offset = 0;
84+
insGroup* lastIG = ig;
85+
while (lastIG != emit->emitCurIG)
86+
{
87+
offset += lastIG->igSize;
88+
lastIG = lastIG->igNext;
89+
}
90+
assert((lastIG->igFlags & IGF_FUNCLET_PROLOG) != 0);
8791

92+
return offset + emit->emitCurIGsize;
93+
}
8894
//------------------------------------------------------------------------
8995
// IsPreviousInsNum: Returns true if the emitter is on the next instruction
9096
// of the same group as this emitLocation.
@@ -120,26 +126,133 @@ void emitLocation::Print(LONG compMethodID) const
120126
}
121127
#endif // DEBUG
122128

129+
//------------------------------------------------------------------------
130+
// InitializeNum: Initialize this IG's order/display number.
131+
//
132+
// Each subsequently allocated group should be assigned a monotonically
133+
// increasing number.
134+
//
135+
// Arguments:
136+
// num - The number
137+
//
123138
void insGroup::InitializeNum(unsigned num)
124139
{
125140
igNum = num;
126141
}
127142

143+
//------------------------------------------------------------------------
144+
// GetDisplayId: Get the ID of this group used for display.
145+
//
146+
// Return Value:
147+
// A unique ID for this group.
148+
//
128149
unsigned insGroup::GetDisplayId() const
129150
{
130151
return igNum;
131152
}
132153

154+
//------------------------------------------------------------------------
155+
// IsBefore: Is this group before 'ig' in layout (IG list) order?
156+
//
157+
// Most groups are generated in-order, such that their 'numbers' reflect
158+
// both the layout and IG linked list order. However, for prologs/epilogs,
159+
// we can have extend groups that are generated after the IR-driven code,
160+
// and this function accounts for that.
161+
//
162+
// Arguments:
163+
// ig - The group to compare to
164+
//
165+
// Return Value:
166+
// Whether 'this' is before 'ig'.
167+
//
133168
bool insGroup::IsBefore(const insGroup* ig) const
134169
{
135-
return igNum < ig->igNum;
170+
assert(ig != nullptr);
171+
172+
// All IGs are generated in order, except the extend groups that may hangs off prologs and epilogs.
173+
// In turn, those groups themselves are generated in order within their respective regions.
174+
unsigned positionOfThis;
175+
if ((igFlags & IGF_OUT_OF_ORDER_MASK) != 0)
176+
{
177+
const insGroup* nextIG = igNext;
178+
while (true)
179+
{
180+
if (nextIG == nullptr)
181+
{
182+
return false;
183+
}
184+
if (((nextIG->igFlags & IGF_OUT_OF_ORDER_MASK) == 0) || ((nextIG->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0))
185+
{
186+
positionOfThis = nextIG->igNum - 1; // Position equal to the in-order 'head' of the region.
187+
break;
188+
}
189+
if (nextIG == ig)
190+
{
191+
return true;
192+
}
193+
194+
nextIG = nextIG->igNext;
195+
}
196+
}
197+
else
198+
{
199+
positionOfThis = igNum;
200+
}
201+
202+
unsigned positionOfIG;
203+
if ((ig->igFlags & IGF_OUT_OF_ORDER_MASK) != 0)
204+
{
205+
const insGroup* nextIG = ig->igNext;
206+
while (true)
207+
{
208+
if (nextIG == nullptr)
209+
{
210+
return true;
211+
}
212+
if (((nextIG->igFlags & IGF_OUT_OF_ORDER_MASK) == 0) || ((nextIG->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0))
213+
{
214+
positionOfIG = nextIG->igNum - 1;
215+
break;
216+
}
217+
if (nextIG == this)
218+
{
219+
return false;
220+
}
221+
222+
nextIG = nextIG->igNext;
223+
}
224+
}
225+
else
226+
{
227+
positionOfIG = ig->igNum;
228+
}
229+
230+
return positionOfThis < positionOfIG;
136231
}
137232

233+
//------------------------------------------------------------------------
234+
// IsBefore: Is this group before 'ig' in layout order, or equal to it?
235+
//
236+
// Arguments:
237+
// ig - The group to compare to
238+
//
239+
// Return Value:
240+
// Whether 'this' is before 'ig' or is equal to it.
241+
//
138242
bool insGroup::IsBeforeOrEqual(const insGroup* ig) const
139243
{
140244
return !IsAfter(ig);
141245
}
142246

247+
//------------------------------------------------------------------------
248+
// IsBefore: Is this group after 'ig' in layout order?
249+
//
250+
// Arguments:
251+
// ig - The group to compare to
252+
//
253+
// Return Value:
254+
// Whether 'this' is after 'ig'.
255+
//
143256
bool insGroup::IsAfter(const insGroup* ig) const
144257
{
145258
return ig->IsBefore(this);
@@ -1623,16 +1736,8 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz)
16231736
{
16241737
#ifdef DEBUG
16251738
// Under STRESS_EMITTER, put every instruction in its own instruction group.
1626-
// We can't do this for a prolog, epilog, funclet prolog, or funclet epilog,
1627-
// because those are generated out of order. We currently have a limitation
1628-
// where the jump shortening pass uses the instruction group number to determine
1629-
// if something is earlier or later in the code stream. This implies that
1630-
// these groups cannot be more than a single instruction group. Note that
1631-
// the prolog/epilog placeholder groups ARE generated in order, and are
1632-
// re-used. But generating additional groups would not work.
16331739
if (m_compiler->compStressCompile(Compiler::STRESS_EMITTER, 1) && emitCurIGinsCnt && !emitIGisInProlog(emitCurIG) &&
1634-
!emitIGisInEpilog(emitCurIG) && !emitCurIG->endsWithAlignInstr() && !emitIGisInFuncletProlog(emitCurIG) &&
1635-
!emitIGisInFuncletEpilog(emitCurIG))
1740+
!emitCurIG->endsWithAlignInstr())
16361741
{
16371742
emitNxtIG(true);
16381743
}
@@ -2161,6 +2266,7 @@ void emitter::emitCreatePlaceholderIG(insGroupPlaceholderType igType,
21612266
{
21622267
igPh->igFlags |= IGF_FUNCLET_EPILOG;
21632268
}
2269+
igPh->igFlags |= IGF_OUT_OF_ORDER_HEAD;
21642270

21652271
/* Link it into the placeholder list */
21662272

@@ -2402,7 +2508,7 @@ void emitter::emitBegPrologEpilog(insGroup* igPh)
24022508
m_compiler->funSetCurrentFunc(ig->igFuncIdx);
24032509

24042510
/* Set the new IG as the place to generate code */
2405-
2511+
emitCurCodeOffset = ig->igOffs;
24062512
emitGenIG(ig);
24072513

24082514
#if EMIT_TRACK_STACK_DEPTH

src/coreclr/jit/emit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ struct insGroup
314314
#ifdef TARGET_ARM64
315315
#define IGF_HAS_REMOVED_INSTR 0x1000 // this group has an instruction that was removed.
316316
#endif
317+
#define IGF_OUT_OF_ORDER_HEAD 0x2000 // first group (generated in-order) of a region generated out-of-order
317318

318319
// Mask of IGF_* flags that should be propagated to new blocks when they are created.
319320
// This allows prologs and epilogs to be any number of IGs, but still be
@@ -323,6 +324,7 @@ struct insGroup
323324
#else // DEBUG
324325
#define IGF_PROPAGATE_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG)
325326
#endif // DEBUG
327+
#define IGF_OUT_OF_ORDER_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG)
326328

327329
// Try to do better packing based on how large regMaskSmall is (8, 16, or 64 bits).
328330

0 commit comments

Comments
 (0)