1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef jit_IonOptimizationLevels_h
8 #define jit_IonOptimizationLevels_h
9
10 #include "mozilla/EnumeratedArray.h"
11
12 #include "jstypes.h"
13
14 #include "jit/JitOptions.h"
15 #include "js/TypeDecls.h"
16
17 namespace js {
18 namespace jit {
19
20 enum class OptimizationLevel : uint8_t { Normal, Wasm, Count, DontCompile };
21
22 #ifdef JS_JITSPEW
OptimizationLevelString(OptimizationLevel level)23 inline const char* OptimizationLevelString(OptimizationLevel level) {
24 switch (level) {
25 case OptimizationLevel::DontCompile:
26 return "Optimization_DontCompile";
27 case OptimizationLevel::Normal:
28 return "Optimization_Normal";
29 case OptimizationLevel::Wasm:
30 return "Optimization_Wasm";
31 case OptimizationLevel::Count:;
32 }
33 MOZ_CRASH("Invalid OptimizationLevel");
34 }
35 #endif
36
37 class OptimizationInfo {
38 public:
39 OptimizationLevel level_;
40
41 // Toggles whether Effective Address Analysis is performed.
42 bool eaa_;
43
44 // Toggles whether Alignment Mask Analysis is performed.
45 bool ama_;
46
47 // Toggles whether Edge Case Analysis is used.
48 bool edgeCaseAnalysis_;
49
50 // Toggles whether redundant checks get removed.
51 bool eliminateRedundantChecks_;
52
53 // Toggles whether interpreted scripts get inlined.
54 bool inlineInterpreted_;
55
56 // Toggles whether native scripts get inlined.
57 bool inlineNative_;
58
59 // Toggles whether eager unboxing of SIMD is used.
60 bool eagerSimdUnbox_;
61
62 // Toggles whether global value numbering is used.
63 bool gvn_;
64
65 // Toggles whether loop invariant code motion is performed.
66 bool licm_;
67
68 // Toggles whether Range Analysis is used.
69 bool rangeAnalysis_;
70
71 // Toggles whether loop unrolling is performed.
72 bool loopUnrolling_;
73
74 // Toggles whether instruction reordering is performed.
75 bool reordering_;
76
77 // Toggles whether Truncation based on Range Analysis is used.
78 bool autoTruncate_;
79
80 // Toggles whether sincos is used.
81 bool sincos_;
82
83 // Toggles whether sink is used.
84 bool sink_;
85
86 // Describes which register allocator to use.
87 IonRegisterAllocator registerAllocator_;
88
89 // The maximum total bytecode size of an inline call site. We use a lower
90 // value if off-thread compilation is not available, to avoid stalling the
91 // active thread.
92 uint32_t inlineMaxBytecodePerCallSiteHelperThread_;
93 uint32_t inlineMaxBytecodePerCallSiteActiveCooperatingThread_;
94
95 // The maximum value we allow for baselineScript->inlinedBytecodeLength_
96 // when inlining.
97 uint16_t inlineMaxCalleeInlinedBytecodeLength_;
98
99 // The maximum bytecode length we'll inline in a single compilation.
100 uint32_t inlineMaxTotalBytecodeLength_;
101
102 // The maximum bytecode length the caller may have,
103 // before we stop inlining large functions in that caller.
104 uint32_t inliningMaxCallerBytecodeLength_;
105
106 // The maximum inlining depth.
107 uint32_t maxInlineDepth_;
108
109 // Toggles whether scalar replacement is used.
110 bool scalarReplacement_;
111
112 // The maximum inlining depth for functions.
113 //
114 // Inlining small functions has almost no compiling overhead
115 // and removes the otherwise needed call overhead.
116 // The value is currently very low.
117 // Actually it is only needed to make sure we don't blow out the stack.
118 uint32_t smallFunctionMaxInlineDepth_;
119
120 // How many invocations or loop iterations are needed before functions
121 // are compiled.
122 uint32_t compilerWarmUpThreshold_;
123
124 // Default compiler warmup threshold, unless it is overridden.
125 static const uint32_t CompilerWarmupThreshold;
126
127 // How many invocations or loop iterations are needed before small functions
128 // are compiled.
129 uint32_t compilerSmallFunctionWarmUpThreshold_;
130
131 // Default small function compiler warmup threshold, unless it is overridden.
132 static const uint32_t CompilerSmallFunctionWarmupThreshold;
133
134 // How many invocations or loop iterations are needed before calls
135 // are inlined, as a fraction of compilerWarmUpThreshold.
136 double inliningWarmUpThresholdFactor_;
137
138 // How many invocations or loop iterations are needed before a function
139 // is hot enough to recompile the outerScript to inline that function,
140 // as a multiplication of inliningWarmUpThreshold.
141 uint32_t inliningRecompileThresholdFactor_;
142
OptimizationInfo()143 OptimizationInfo() {}
144
145 void initNormalOptimizationInfo();
146 void initWasmOptimizationInfo();
147
level()148 OptimizationLevel level() const { return level_; }
149
inlineInterpreted()150 bool inlineInterpreted() const {
151 return inlineInterpreted_ && !JitOptions.disableInlining;
152 }
153
inlineNative()154 bool inlineNative() const {
155 return inlineNative_ && !JitOptions.disableInlining;
156 }
157
158 uint32_t compilerWarmUpThreshold(JSScript* script,
159 jsbytecode* pc = nullptr) const;
160
eagerSimdUnboxEnabled()161 bool eagerSimdUnboxEnabled() const {
162 return eagerSimdUnbox_ && !JitOptions.disableEagerSimdUnbox;
163 }
164
gvnEnabled()165 bool gvnEnabled() const { return gvn_ && !JitOptions.disableGvn; }
166
licmEnabled()167 bool licmEnabled() const { return licm_ && !JitOptions.disableLicm; }
168
rangeAnalysisEnabled()169 bool rangeAnalysisEnabled() const {
170 return rangeAnalysis_ && !JitOptions.disableRangeAnalysis;
171 }
172
loopUnrollingEnabled()173 bool loopUnrollingEnabled() const {
174 return loopUnrolling_ && !JitOptions.disableLoopUnrolling;
175 }
176
instructionReorderingEnabled()177 bool instructionReorderingEnabled() const {
178 return reordering_ && !JitOptions.disableInstructionReordering;
179 }
180
autoTruncateEnabled()181 bool autoTruncateEnabled() const {
182 return autoTruncate_ && rangeAnalysisEnabled();
183 }
184
sincosEnabled()185 bool sincosEnabled() const { return sincos_ && !JitOptions.disableSincos; }
186
sinkEnabled()187 bool sinkEnabled() const { return sink_ && !JitOptions.disableSink; }
188
eaaEnabled()189 bool eaaEnabled() const { return eaa_ && !JitOptions.disableEaa; }
190
amaEnabled()191 bool amaEnabled() const { return ama_ && !JitOptions.disableAma; }
192
edgeCaseAnalysisEnabled()193 bool edgeCaseAnalysisEnabled() const {
194 return edgeCaseAnalysis_ && !JitOptions.disableEdgeCaseAnalysis;
195 }
196
eliminateRedundantChecksEnabled()197 bool eliminateRedundantChecksEnabled() const {
198 return eliminateRedundantChecks_;
199 }
200
flowAliasAnalysisEnabled()201 bool flowAliasAnalysisEnabled() const { return !JitOptions.disableFlowAA; }
202
registerAllocator()203 IonRegisterAllocator registerAllocator() const {
204 return JitOptions.forcedRegisterAllocator.valueOr(registerAllocator_);
205 }
206
scalarReplacementEnabled()207 bool scalarReplacementEnabled() const {
208 return scalarReplacement_ && !JitOptions.disableScalarReplacement;
209 }
210
smallFunctionMaxInlineDepth()211 uint32_t smallFunctionMaxInlineDepth() const {
212 return smallFunctionMaxInlineDepth_;
213 }
214
215 bool isSmallFunction(JSScript* script) const;
216
maxInlineDepth()217 uint32_t maxInlineDepth() const { return maxInlineDepth_; }
218
inlineMaxBytecodePerCallSite(bool offThread)219 uint32_t inlineMaxBytecodePerCallSite(bool offThread) const {
220 return (offThread || !JitOptions.limitScriptSize)
221 ? inlineMaxBytecodePerCallSiteHelperThread_
222 : inlineMaxBytecodePerCallSiteActiveCooperatingThread_;
223 }
224
inlineMaxCalleeInlinedBytecodeLength()225 uint16_t inlineMaxCalleeInlinedBytecodeLength() const {
226 return inlineMaxCalleeInlinedBytecodeLength_;
227 }
228
inlineMaxTotalBytecodeLength()229 uint32_t inlineMaxTotalBytecodeLength() const {
230 return inlineMaxTotalBytecodeLength_;
231 }
232
inliningMaxCallerBytecodeLength()233 uint32_t inliningMaxCallerBytecodeLength() const {
234 return inliningMaxCallerBytecodeLength_;
235 }
236
inliningWarmUpThreshold()237 uint32_t inliningWarmUpThreshold() const {
238 uint32_t compilerWarmUpThreshold =
239 JitOptions.forcedDefaultIonWarmUpThreshold.valueOr(
240 compilerWarmUpThreshold_);
241 return compilerWarmUpThreshold * inliningWarmUpThresholdFactor_;
242 }
243
inliningRecompileThreshold()244 uint32_t inliningRecompileThreshold() const {
245 return inliningWarmUpThreshold() * inliningRecompileThresholdFactor_;
246 }
247 };
248
249 class OptimizationLevelInfo {
250 private:
251 mozilla::EnumeratedArray<OptimizationLevel, OptimizationLevel::Count,
252 OptimizationInfo>
253 infos_;
254
255 public:
256 OptimizationLevelInfo();
257
get(OptimizationLevel level)258 const OptimizationInfo* get(OptimizationLevel level) const {
259 return &infos_[level];
260 }
261
262 OptimizationLevel nextLevel(OptimizationLevel level) const;
263 OptimizationLevel firstLevel() const;
264 bool isLastLevel(OptimizationLevel level) const;
265 OptimizationLevel levelForScript(JSScript* script,
266 jsbytecode* pc = nullptr) const;
267 };
268
269 extern OptimizationLevelInfo IonOptimizations;
270
271 } // namespace jit
272 } // namespace js
273
274 #endif /* jit_IonOptimizationLevels_h */
275