3232import jdk .graal .compiler .nodes .FixedNode ;
3333import jdk .graal .compiler .nodes .GraphState ;
3434import jdk .graal .compiler .nodes .Invoke ;
35+ import jdk .graal .compiler .nodes .LoopBeginNode .SafepointState ;
3536import jdk .graal .compiler .nodes .LoopEndNode ;
3637import jdk .graal .compiler .nodes .NodeView ;
3738import jdk .graal .compiler .nodes .StructuredGraph ;
39+ import jdk .graal .compiler .nodes .cfg .ControlFlowGraph ;
3840import jdk .graal .compiler .nodes .cfg .HIRBlock ;
3941import jdk .graal .compiler .nodes .extended .ForeignCall ;
4042import jdk .graal .compiler .nodes .loop .InductionVariable ;
4951import jdk .vm .ci .meta .ResolvedJavaMethod ;
5052
5153public class LoopSafepointEliminationPhase extends BasePhase <MidTierContext > {
52-
5354 public static class Options {
5455 //@formatter:off
5556 @ Option (help = "Removes safepoints on counted loop ends." , type = OptionType .Expert )
@@ -59,33 +60,7 @@ public static class Options {
5960
6061 private static final long IntegerRangeDistance = NumUtil .unsafeAbs ((long ) Integer .MAX_VALUE - (long ) Integer .MIN_VALUE );
6162
62- /**
63- * To be implemented by subclasses to perform additional checks. Returns <code>true</code> if
64- * the safepoint was also disabled in subclasses and we therefore don't need to continue
65- * traversing.
66- */
67- @ SuppressWarnings ("unused" )
68- protected boolean onCallInLoop (LoopEndNode loopEnd , FixedNode currentCallNode ) {
69- return true ;
70- }
71-
72- /**
73- * To be implemented by subclasses to compute additional fields.
74- */
75- @ SuppressWarnings ("unused" )
76- protected void onSafepointDisabledLoopBegin (Loop loop ) {
77- }
78-
79- /**
80- * Determines whether guest safepoints should be allowed at all. To be implemented by
81- * subclasses. The default implementation returns <code>false</code>, leading to guest
82- * safepoints being disabled for all loops in the graph.
83- */
84- protected boolean allowGuestSafepoints () {
85- return false ;
86- }
87-
88- public static boolean loopIsIn32BitRange (Loop loop ) {
63+ public static boolean iterationRangeIsIn32Bit (Loop loop ) {
8964 if (loop .counted ().getStamp ().getBits () <= 32 ) {
9065 return true ;
9166 }
@@ -126,12 +101,143 @@ public Optional<NotApplicable> notApplicableTo(GraphState graphState) {
126101 }
127102
128103 @ Override
129- protected final void run (StructuredGraph graph , MidTierContext context ) {
130- LoopsData loops = context .getLoopsDataProvider ().getLoopsData (graph );
131- if (Options .RemoveLoopSafepoints .getValue (graph .getOptions ())) {
104+ protected void run (StructuredGraph graph , MidTierContext context ) {
105+ new Instance (graph , context ).optimizeSafepoints ();
106+ }
107+
108+ protected static class Instance {
109+ private final StructuredGraph graph ;
110+ private final MidTierContext context ;
111+
112+ protected Instance (StructuredGraph graph , MidTierContext context ) {
113+ this .graph = graph ;
114+ this .context = context ;
115+ }
116+
117+ /**
118+ * Disable safepoints on loop ends by body nodes. If there is a node that is a guaranteed
119+ * safepoint (like a call) we can disable the safepoint on the dominated loop end because
120+ * there will be a safepoint poll done already on every iteration of the loop.
121+ *
122+ * So for a pattern
123+ *
124+ * <pre>
125+ * while (header) {
126+ * if (someCondition1) {
127+ * call1();
128+ * continue;
129+ * }
130+ * code();
131+ * if (someCondition2) {
132+ * call2();
133+ * continue;
134+ * }
135+ * restOfBody();
136+ * }
137+ * </pre>
138+ *
139+ * we know that both {@code continue} backedges are dominated by a call. {@code call1} and
140+ * {@code call2} dominate the backedges. We can remove safepoint polls from both of them
141+ * because the call will be a guaranteed safepoint.
142+ */
143+ private int disableSafepointsByBodyNodes (Loop loop , ControlFlowGraph cfg ) {
144+ int loopEndSafepointsDisabled = 0 ;
145+ for (LoopEndNode loopEnd : loop .loopBegin ().loopEnds ()) {
146+ HIRBlock b = cfg .blockFor (loopEnd );
147+ blocks : while (b != loop .getCFGLoop ().getHeader ()) {
148+ assert b != null ;
149+ for (FixedNode node : b .getNodes ()) {
150+ boolean canDisableSafepoint = canDisableSafepoint (node , context );
151+ boolean disabledInSubclass = onCallInLoop (loopEnd , node );
152+ if (canDisableSafepoint ) {
153+ loopEnd .disableSafepoint ();
154+ graph .getOptimizationLog ().report (LoopSafepointEliminationPhase .class , "SafepointElimination" , loop .loopBegin ());
155+ loopEndSafepointsDisabled ++;
156+ /*
157+ * we can only stop if subclasses also say we can stop iterating blocks
158+ */
159+ if (disabledInSubclass ) {
160+ break blocks ;
161+ }
162+ }
163+ }
164+ b = b .getDominator ();
165+ }
166+ }
167+ return loopEndSafepointsDisabled ;
168+ }
169+
170+ public void optimizeSafepoints () {
171+ final boolean optimisticallyRemoveLoopSafepoints = Options .RemoveLoopSafepoints .getValue (graph .getOptions ());
172+
173+ LoopsData loops = context .getLoopsDataProvider ().getLoopsData (graph );
132174 loops .detectCountedLoops ();
133- for (Loop loop : loops .countedLoops ()) {
134- if (loop .getCFGLoop ().getChildren ().isEmpty () && (loop .loopBegin ().isPreLoop () || loop .loopBegin ().isPostLoop () || loopIsIn32BitRange (loop ) || loop .loopBegin ().isStripMinedInner ())) {
175+
176+ for (Loop loop : loops .loops ()) {
177+ if (!allowGuestSafepoints ()) {
178+ loop .loopBegin ().disableGuestSafepoint (SafepointState .MUST_NEVER_SAFEPOINT );
179+ }
180+ int loopEndSafepointsDisabled = disableSafepointsByBodyNodes (loop , loops .getCFG ());
181+ final boolean allLoopEndSafepointsDisabled = loopEndSafepointsDisabled == loop .loopBegin ().getLoopEndCount ();
182+ if (!allLoopEndSafepointsDisabled && optimisticallyRemoveLoopSafepoints ) {
183+ if (optimizeSafepointsForCountedLoop (loop )) {
184+ /*
185+ * We removed all loop end safepoints if we do it optimistically for the
186+ * entire loop.
187+ */
188+ loopEndSafepointsDisabled = loop .loopBegin ().getLoopEndCount ();
189+ }
190+ }
191+ final boolean allLoopEndSafepointsEnabled = loopEndSafepointsDisabled == 0 ;
192+ if (allLoopEndSafepointsEnabled ) {
193+ /*
194+ * Only if ALL paths through the loop are guaranteed to safepoint we can drop
195+ * the exit safepoint. If there is any path left that does not safepoint we
196+ * could be only executing that path and then we need an exit safepoint.
197+ */
198+ loop .loopBegin ().disableLoopExitSafepoint (SafepointState .OPTIMIZER_DISABLED );
199+ }
200+
201+ }
202+ loops .deleteUnusedNodes ();
203+ }
204+
205+ /**
206+ * Determines whether guest safepoints should be allowed at all. To be implemented by
207+ * subclasses. The default implementation returns <code>false</code>, leading to guest
208+ * safepoints being disabled for all loops in the graph.
209+ */
210+ protected boolean allowGuestSafepoints () {
211+ return false ;
212+ }
213+
214+ /**
215+ * To be implemented by subclasses to perform additional checks. Returns <code>true</code>
216+ * if the safepoint was also disabled in subclasses and we therefore don't need to continue
217+ * traversing.
218+ */
219+ @ SuppressWarnings ("unused" )
220+ protected boolean onCallInLoop (LoopEndNode loopEnd , FixedNode currentCallNode ) {
221+ return true ;
222+ }
223+
224+ /**
225+ * To be implemented by subclasses to compute additional fields.
226+ */
227+ @ SuppressWarnings ("unused" )
228+ protected void onSafepointDisabledLoopBegin (Loop loop ) {
229+ }
230+
231+ /**
232+ * Tries to optimize away safepoints for the given counted loop completely. We have not been
233+ * able to remove safepoints from the loop ends of the given loop yet. However, the
234+ * optimizer may believe this loop is short running enough to remove safepoints.
235+ */
236+ private boolean optimizeSafepointsForCountedLoop (Loop loop ) {
237+ if (loop .isCounted ()) {
238+ if (loop .getCFGLoop ().getChildren ().isEmpty () &&
239+ (loop .loopBegin ().isPreLoop () || loop .loopBegin ().isPostLoop () || loopIsIn32BitRange (loop ) ||
240+ loop .loopBegin ().isStripMinedInner ())) {
135241 boolean hasSafepoint = false ;
136242 for (LoopEndNode loopEnd : loop .loopBegin ().loopEnds ()) {
137243 hasSafepoint |= loopEnd .canSafepoint ();
@@ -144,51 +250,37 @@ protected final void run(StructuredGraph graph, MidTierContext context) {
144250 if (allowsLoopLimitChecks && allowsFloatingGuards ) {
145251 loop .counted ().createOverFlowGuard ();
146252 } else {
147- // Cannot disable this safepoint, because the loop could overflow.
148- continue ;
253+ /*
254+ * Cannot disable this safepoint, because the loop could overflow.
255+ */
256+ return false ;
149257 }
150258 }
151- loop .loopBegin ().disableSafepoint ();
259+ loop .loopBegin ().disableSafepoint (SafepointState . OPTIMIZER_DISABLED );
152260 if (loop .loopBegin ().isStripMinedInner ()) {
153- // graal strip mined this loop, trust the heuristics and remove the
154- // inner
155- // loop safepoint
156- loop .loopBegin ().disableGuestSafepoint ();
261+ /*
262+ * graal strip mined this loop, trust the heuristics and remove the
263+ * inner loop safepoint
264+ */
265+ loop .loopBegin ().disableGuestSafepoint (SafepointState .OPTIMIZER_DISABLED );
157266 } else {
158- // let the shape of the loop decide whether a guest safepoint is needed
267+ /*
268+ * let the shape of the loop decide whether a guest safepoint is needed
269+ */
159270 onSafepointDisabledLoopBegin (loop );
160271 }
161272 graph .getOptimizationLog ().report (LoopSafepointEliminationPhase .class , "SafepointElimination" , loop .loopBegin ());
273+ return true ;
162274 }
163275 }
164276 }
277+ return false ;
165278 }
166- for (Loop loop : loops .loops ()) {
167- if (!allowGuestSafepoints ()) {
168- loop .loopBegin ().disableGuestSafepoint ();
169- }
170- for (LoopEndNode loopEnd : loop .loopBegin ().loopEnds ()) {
171- HIRBlock b = loops .getCFG ().blockFor (loopEnd );
172- blocks : while (b != loop .getCFGLoop ().getHeader ()) {
173- assert b != null ;
174- for (FixedNode node : b .getNodes ()) {
175- boolean canDisableSafepoint = canDisableSafepoint (node , context );
176- boolean disabledInSubclass = onCallInLoop (loopEnd , node );
177- if (canDisableSafepoint ) {
178- loopEnd .disableSafepoint ();
179- graph .getOptimizationLog ().report (LoopSafepointEliminationPhase .class , "SafepointElimination" , loop .loopBegin ());
180279
181- // we can only stop if subclasses also say we can stop iterating blocks
182- if (disabledInSubclass ) {
183- break blocks ;
184- }
185- }
186- }
187- b = b .getDominator ();
188- }
189- }
280+ public boolean loopIsIn32BitRange (Loop loop ) {
281+ return iterationRangeIsIn32Bit (loop );
190282 }
191- loops . deleteUnusedNodes ();
283+
192284 }
193285
194286 public static boolean canDisableSafepoint (FixedNode node , CoreProviders context ) {
0 commit comments