Skip to content

Commit e9ae9a8

Browse files
jaewiefacebook-github-bot
authored andcommitted
Refactor to prepare for inline IRUnit stitching
Summary: Currently, we generate the callee `IRUnit` when calculating the cost of inlining for the first time (which then gets cached). This diff refactors to return back to `irGenTryInlineFCall` the callee's `IRUnit` whenever `Cfg::HHIR::EnableInlingPass` is true or we need to calculate cost for the first time. In order to support that, I had to move the generating `IRUnit` out of `computeTranslationCostSlow` into a new function `computeInlineIRUnit` which returns whether to inline the callee region and also returns back the unit. Reviewed By: paulbiss Differential Revision: D70131260 fbshipit-source-id: 41b3e30d5f4100cb8ed4e88ea322ea58e738082a
1 parent ab9bbae commit e9ae9a8

6 files changed

+128
-63
lines changed

hphp/doc/configs.specification

+1
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,7 @@ The format can be found in hphp/tools/configs/generate_configs.rs
15461546
- bool HHIR.GenOpts = true, UNKNOWN
15471547
- bool HHIR.RefcountOpts = true, UNKNOWN
15481548
- bool HHIR.EnableGenTimeInlining = true, UNKNOWN
1549+
- bool HHIR.EnableInliningPass = false, UNKNOWN
15491550
- uint32_t HHIR.InliningCostFactorMain = 100, UNKNOWN
15501551
- uint32_t HHIR.InliningCostFactorCold = 32, UNKNOWN
15511552
- uint32_t HHIR.InliningCostFactorFrozen = 10, UNKNOWN

hphp/runtime/vm/jit/inlining-decider.cpp

+29-39
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "hphp/runtime/vm/func.h"
2525
#include "hphp/runtime/vm/hhbc.h"
2626
#include "hphp/runtime/vm/jit/irgen.h"
27+
#include "hphp/runtime/vm/jit/irgen-inlining.h"
2728
#include "hphp/runtime/vm/jit/location.h"
2829
#include "hphp/runtime/vm/jit/irlower.h"
2930
#include "hphp/runtime/vm/jit/mcgen.h"
@@ -299,43 +300,30 @@ using InlineCostCache = folly::ConcurrentHashMap<
299300
>;
300301

301302
Vcost computeTranslationCostSlow(SrcKey at,
302-
const RegionDesc& region,
303+
const irgen::RegionAndLazyUnit& regionAndLazyUnit,
303304
AnnotationData* annotationData) {
304-
TransContext ctx {
305-
TransIDSet{},
306-
0, // optIndex
307-
TransKind::Optimize,
308-
at,
309-
&region,
310-
at.packageInfo(),
311-
PrologueID(),
312-
};
313-
314-
tracing::Block _{"compute-inline-cost", [&] { return traceProps(ctx); }};
315-
316-
rqtrace::DisableTracing notrace;
317-
auto const unbumper = mcgen::unbumpFunctions();
318-
319-
auto const unit = irGenInlineRegion(ctx, region);
305+
auto const unit = regionAndLazyUnit.unit();
320306
if (!unit) return {0, true};
321307

322308
// TODO(T52856776) - annotations should be copied from unit into outer unit
323309
// via annotationData
324-
310+
rqtrace::DisableTracing notrace;
311+
auto const unbumper = mcgen::unbumpFunctions();
325312
SCOPE_ASSERT_DETAIL("Inline-IRUnit") { return show(*unit); };
326313
return irlower::computeIRUnitCost(*unit);
327314
}
328315

329316
InlineCostCache s_inlCostCache;
330317

331318
int computeTranslationCost(SrcKey at,
332-
const RegionDesc& region,
319+
const irgen::RegionAndLazyUnit& regionAndLazyUnit,
333320
AnnotationData* annotationData) {
321+
auto const region = *regionAndLazyUnit.region();
334322
InlineRegionKey irk{region};
335323
auto f = s_inlCostCache.find(irk);
336324
if (f != s_inlCostCache.end()) return f->second;
337325

338-
auto const info = computeTranslationCostSlow(at, region, annotationData);
326+
auto const info = computeTranslationCostSlow(at, regionAndLazyUnit, annotationData);
339327
auto cost = info.cost;
340328

341329
// We normally store the computed cost into the cache. However, if the region
@@ -420,7 +408,7 @@ uint64_t adjustedMaxVasmCost(const irgen::IRGS& env,
420408
*/
421409
int costOfInlining(SrcKey callerSk,
422410
const Func* callee,
423-
const RegionDesc& region,
411+
const irgen::RegionAndLazyUnit& regionAndLazyUnit,
424412
AnnotationData* annotationData) {
425413
auto const alwaysInl =
426414
(!Cfg::HHIR::InliningIgnoreHints &&
@@ -430,7 +418,7 @@ int costOfInlining(SrcKey callerSk,
430418
// Functions marked as always inline don't contribute to overall cost
431419
return alwaysInl ?
432420
0 :
433-
computeTranslationCost(callerSk, region, annotationData);
421+
computeTranslationCost(callerSk, regionAndLazyUnit, annotationData);
434422
}
435423

436424
bool isCoeffectsBackdoor(SrcKey callerSk, const Func* callee) {
@@ -463,8 +451,9 @@ bool isCoeffectsBackdoor(SrcKey callerSk, const Func* callee) {
463451
bool shouldInline(const irgen::IRGS& irgs,
464452
SrcKey callerSk,
465453
const Func* callee,
466-
const RegionDesc& region,
454+
const irgen::RegionAndLazyUnit& regionAndUnit,
467455
int& cost) {
456+
auto const region = *regionAndUnit.region();
468457
auto sk = region.empty() ? SrcKey() : region.start();
469458
assertx(callee);
470459
assertx(sk.func() == callee);
@@ -581,7 +570,7 @@ bool shouldInline(const irgen::IRGS& irgs,
581570
// In debug builds compute the cost anyway to catch bugs in the inlining
582571
// machinery. Many inlining tests utilize the __ALWAYS_INLINE attribute.
583572
if (debug) {
584-
computeTranslationCost(callerSk, region, annotationsPtr);
573+
computeTranslationCost(callerSk, regionAndUnit, annotationsPtr);
585574
}
586575
return accept("callee marked as __ALWAYS_INLINE");
587576
}
@@ -590,7 +579,7 @@ bool shouldInline(const irgen::IRGS& irgs,
590579
// We measure the cost of inlining each callstack and stop when it exceeds a
591580
// certain threshold. (Note that we do not measure the total cost of all the
592581
// inlined calls for a given caller---just the cost of each nested stack.)
593-
cost = costOfInlining(callerSk, callee, region, annotationsPtr);
582+
cost = costOfInlining(callerSk, callee, regionAndUnit, annotationsPtr);
594583
if (cost <= Cfg::HHIR::AlwaysInlineVasmCostLimit) {
595584
return accept(folly::sformat("cost={} within always-inline limit", cost));
596585
}
@@ -744,10 +733,10 @@ RegionDescPtr selectCalleeCFG(SrcKey callerSk, SrcKey entry,
744733
}
745734
}
746735

747-
RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
748-
SrcKey entry,
749-
Type ctxType,
750-
SrcKey callerSk) {
736+
irgen::RegionAndLazyUnit selectCalleeRegion(const irgen::IRGS& irgs,
737+
SrcKey entry,
738+
Type ctxType,
739+
SrcKey callerSk) {
751740
assertx(entry.funcEntry());
752741
auto const callee = entry.func();
753742

@@ -761,7 +750,7 @@ RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
761750

762751
if (ctxType == TBottom) {
763752
traceRefusal(callerSk, callee, "ctx is TBottom", annotationsPtr);
764-
return nullptr;
753+
return {callerSk, nullptr};
765754
}
766755
if (callee->isClosureBody()) {
767756
if (!callee->cls()) {
@@ -778,21 +767,21 @@ RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
778767
(!callerSk.hasThis() && isFCallClsMethod(callerSk.op())))) {
779768
traceRefusal(callerSk, callee, "calling static method with an object",
780769
annotationsPtr);
781-
return nullptr;
770+
return {callerSk, nullptr};
782771
}
783772
}
784773

785774
if (callee->cls()) {
786775
if (callee->isStatic() && !ctxType.maybe(TCls)) {
787776
traceRefusal(callerSk, callee, "calling a static method with an instance",
788777
annotationsPtr);
789-
return nullptr;
778+
return {callerSk, nullptr};
790779
}
791780
if (!callee->isStatic() && !ctxType.maybe(TObj)) {
792781
traceRefusal(callerSk, callee,
793782
"calling an instance method without an instance",
794783
annotationsPtr);
795-
return nullptr;
784+
return {callerSk, nullptr};
796785
}
797786
}
798787

@@ -808,7 +797,7 @@ RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
808797

809798
// If we don't have sufficient type information to inline the region return
810799
// early
811-
if (type == TBottom) return nullptr;
800+
if (type == TBottom) return {callerSk, nullptr};
812801
FTRACE(2, "input {}: {}\n", i + 1, type);
813802
inputTypes.push_back(type);
814803
}
@@ -823,21 +812,22 @@ RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
823812
if (profData()) {
824813
auto region = selectCalleeCFG(callerSk, entry, ctxType, inputTypes,
825814
Cfg::Jit::MaxInlineRegionInstrs, annotationsPtr);
826-
if (region) return region;
815+
if (region) return {callerSk, region};
827816
// Special case: even if we don't have prof data for this func, if
828817
// it takes no arguments and returns a constant, it might be a
829818
// trivial function (IE, "return 123;"). Attempt to inline it
830819
// anyways using the tracelet selector.
831-
if (callee->numFuncEntryInputs() > 0) return nullptr;
820+
if (callee->numFuncEntryInputs() > 0) return {callerSk, nullptr};
832821
auto const retType =
833822
typeFromRAT(callee->repoReturnType(), callerSk.func()->cls());
834823
// Deliberately using hasConstVal, not admitsSingleVal, since we
835824
// don't want TInitNull, etc.
836-
if (!retType.hasConstVal()) return nullptr;
825+
if (!retType.hasConstVal()) return {callerSk, nullptr};
837826
}
838827

839-
return selectCalleeTracelet(entry, ctxType, inputTypes,
840-
Cfg::Jit::MaxInlineRegionInstrs);
828+
auto region = selectCalleeTracelet(entry, ctxType, inputTypes,
829+
Cfg::Jit::MaxInlineRegionInstrs);
830+
return {callerSk, region};
841831
}
842832

843833
void setBaseInliningProfCount(uint64_t value) {

hphp/runtime/vm/jit/inlining-decider.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "hphp/runtime/vm/hhbc.h"
2020
#include "hphp/runtime/vm/jit/annotation-data.h"
2121
#include "hphp/runtime/vm/jit/region-selection.h"
22+
#include "hphp/runtime/vm/jit/irgen-inlining.h"
2223

2324
#include <vector>
2425

@@ -86,23 +87,23 @@ bool canInlineAt(SrcKey callSK,
8687
* selector /ought/ to do so.
8788
*/
8889
bool shouldInline(const irgen::IRGS& irgs, SrcKey callerSk, const Func* callee,
89-
const RegionDesc& region, int& cost);
90+
const irgen::RegionAndLazyUnit& regionAndLazyUnit, int& cost);
9091

9192
/*
9293
* Return the cost of inlining the given callee.
9394
*/
9495
int costOfInlining(SrcKey callerSk,
9596
const Func* callee,
96-
const RegionDesc& region,
97+
const irgen::RegionAndLazyUnit& regionAndLazyUnit,
9798
AnnotationData* annotationData);
9899

99100
/*
100101
* Select an inlining region for the call to `callee' at `sk'.
101102
*/
102-
RegionDescPtr selectCalleeRegion(const irgen::IRGS& irgs,
103-
SrcKey entry,
104-
Type ctxType,
105-
SrcKey callerSk);
103+
irgen::RegionAndLazyUnit selectCalleeRegion(const irgen::IRGS& irgs,
104+
SrcKey entry,
105+
Type ctxType,
106+
SrcKey callerSk);
106107

107108
void setBaseInliningProfCount(uint64_t value);
108109

hphp/runtime/vm/jit/irgen-inlining.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,39 @@ Outer: | Inner:
192192
#include "hphp/runtime/vm/hhbc-codec.h"
193193
#include "hphp/runtime/vm/resumable.h"
194194
#include "hphp/runtime/vm/unwind.h"
195+
#include "hphp/runtime/vm/jit/inlining-decider.h"
196+
#include "hphp/runtime/vm/jit/mcgen-translate.h"
197+
#include "hphp/runtime/vm/jit/translate-region.h"
195198

196199
namespace HPHP::jit::irgen {
197200

198201
TRACE_SET_MOD(hhir);
199202

203+
RegionAndLazyUnit::RegionAndLazyUnit(
204+
SrcKey callerSk,
205+
RegionDescPtr region
206+
) : m_callerSk(callerSk)
207+
, m_region(std::move(region)) {}
208+
209+
IRUnit* RegionAndLazyUnit::unit() const {
210+
if (m_unit) return m_unit.get();
211+
always_assert(m_region);
212+
TransContext ctx {
213+
TransIDSet{},
214+
0, // optIndex
215+
TransKind::Optimize,
216+
m_callerSk,
217+
m_region.get(),
218+
m_callerSk.packageInfo(),
219+
PrologueID(),
220+
};
221+
tracing::Block _{"compute-inline-cost", [&] { return traceProps(ctx); }};
222+
rqtrace::DisableTracing notrace;
223+
auto const unbumper = mcgen::unbumpFunctions();
224+
m_unit = irGenInlineRegion(ctx, *m_region);
225+
return m_unit.get();
226+
}
227+
200228
bool isInlining(const IRGS& env) {
201229
return !env.inlineState.frames.empty();
202230
}
@@ -751,6 +779,16 @@ bool spillInlinedFrames(IRGS& env) {
751779
return spilled;
752780
}
753781

782+
void fixCalleeUnit(const IRGS& env, IRUnit& unit) {
783+
}
784+
785+
786+
bool stitchInlinedRegion(irgen::IRGS& irgs, SrcKey callerSk, SrcKey calleeSk,
787+
const RegionDesc& calleeRegion, IRUnit& calleeUnit) {
788+
fixCalleeUnit(irgs, calleeUnit);
789+
return true;
790+
}
791+
754792
//////////////////////////////////////////////////////////////////////
755793

756794
}

hphp/runtime/vm/jit/irgen-inlining.h

+27-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "hphp/runtime/vm/srckey.h"
1919
#include "hphp/runtime/vm/jit/extra-data.h"
20+
#include "hphp/runtime/vm/jit/region-selection.h"
2021

2122
namespace HPHP {
2223

@@ -28,6 +29,26 @@ struct SSATmp;
2829

2930
namespace irgen {
3031

32+
struct RegionAndLazyUnit {
33+
RegionAndLazyUnit(
34+
SrcKey callerSk,
35+
RegionDescPtr region
36+
);
37+
~RegionAndLazyUnit() = default;
38+
RegionAndLazyUnit(RegionAndLazyUnit&&) = default;
39+
RegionAndLazyUnit& operator=(RegionAndLazyUnit&&) = default;
40+
RegionAndLazyUnit(const RegionAndLazyUnit&) = delete;
41+
RegionAndLazyUnit& operator=(const RegionAndLazyUnit&) = delete;
42+
43+
IRUnit* unit() const;
44+
RegionDescPtr region() const { return m_region; }
45+
private:
46+
SrcKey m_callerSk;
47+
RegionDescPtr m_region;
48+
mutable std::unique_ptr<IRUnit> m_unit;
49+
};
50+
51+
3152
struct IRGS;
3253

3354
///////////////////////////////////////////////////////////////////////////////
@@ -65,8 +86,13 @@ bool spillInlinedFrames(IRGS& env);
6586
* FCall bytecode is being translated.
6687
*/
6788
SSATmp* genCalleeFP(IRGS& env, const Func* callee);
89+
90+
/**
91+
* Stitch callee's IRUnit into caller's IRGS.
92+
*/
93+
bool stitchInlinedRegion(irgen::IRGS& irgs, SrcKey callerSk, SrcKey calleeSk,
94+
const RegionDesc& calleeRegion, IRUnit& calleeUnit);
6895

6996
///////////////////////////////////////////////////////////////////////////////
7097

7198
}}}
72-

0 commit comments

Comments
 (0)