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