1
1
/*
2
- * Copyright (c) 2012, 2021 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2012, 2024 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
@@ -244,8 +244,16 @@ public void virtualize(VirtualizerTool tool) {
244
244
}
245
245
}
246
246
247
- @ SuppressFBWarnings (value = {"NP" }, justification = "We null check it before" )
248
247
public static ValueNode canonical (ValueNode object , Stamp piStamp , GuardingNode guard , ValueNode self ) {
248
+ /*
249
+ * If canonicalization is not explicitly triggered, we need to be conservative and assume
250
+ * that the graph is still building up and some usages/inputs of/to nodes are still missing.
251
+ */
252
+ return canonical (object , piStamp , guard , self , false );
253
+ }
254
+
255
+ @ SuppressFBWarnings (value = {"NP" }, justification = "We null check it before" )
256
+ public static ValueNode canonical (ValueNode object , Stamp piStamp , GuardingNode guard , ValueNode self , boolean allUsagesAvailable ) {
249
257
GraalError .guarantee (piStamp != null && object != null , "Invariant piStamp=%s object=%s guard=%s self=%s" , piStamp , object , guard , self );
250
258
251
259
// Use most up to date stamp.
@@ -256,6 +264,56 @@ public static ValueNode canonical(ValueNode object, Stamp piStamp, GuardingNode
256
264
return object ;
257
265
}
258
266
267
+ /*
268
+ * Extracts a constant node if (1) this pi node's stamp is a non-null pointer stamp, (2)
269
+ * 'object' is phi node that has only the same constant node and else just null constants as
270
+ * inputs, and (3) if the constant's stamp equals this pi node's stamp.
271
+ *
272
+ * @formatter:off
273
+ * ...
274
+ * |
275
+ * Merge
276
+ * |
277
+ * | C(object) null null C(object) (...)
278
+ * | | | | | |
279
+ * | | | | | |
280
+ * | |-------|-----+-----|-------|
281
+ * | |
282
+ * |----------------- phi
283
+ * |
284
+ * piWithNonNullStamp
285
+ * |
286
+ * ...
287
+ * @formatter:on
288
+ *
289
+ * Another important condition is that the phi node already has all inputs. During graph
290
+ * decoding, it may happen that inputs are added later for loop phis. Therefore, either
291
+ * 'allUsagesAvailable' is given or the phi node is not a loop phi.
292
+ *
293
+ * This canonicalization case has some overlap with other optimizations. In particular,
294
+ * aggressive path duplication may get to a very similar result. Also, 'IfNode.splitIfAtPhi'
295
+ * does a similar optimization but with different limitations. This should be considered
296
+ * when touching them. One advantage of this canonicalization is that it happens immediately
297
+ * when creating PiNodes.
298
+ */
299
+ if (StampFactory .objectNonNull ().equals (piStamp ) && object instanceof PhiNode phiNode && (allUsagesAvailable || !phiNode .isLoopPhi ())) {
300
+ ValueNode constantValue = null ;
301
+ for (ValueNode phiValue : phiNode .values ()) {
302
+ if (constantValue == null && phiValue .isConstant () && !phiValue .isNullConstant () && checkPhiValueStamp (piStamp , computedStamp , phiValue .stamp (NodeView .DEFAULT ))) {
303
+ constantValue = phiValue ;
304
+ } else if (!phiValue .isNullConstant () && (constantValue == null || !isSameConstant (constantValue , phiValue ))) {
305
+ // reset value to indicate that condition is violated
306
+ constantValue = null ;
307
+ break ;
308
+ }
309
+ }
310
+ if (constantValue != null ) {
311
+ assert constantValue .isConstant () && !constantValue .isNullConstant () && checkPhiValueStamp (piStamp , computedStamp ,
312
+ constantValue .stamp (NodeView .DEFAULT )) : Assertions .errorMessageContext ("pi" , self , "phi" , phiNode , "constant" , constantValue );
313
+ return constantValue ;
314
+ }
315
+ }
316
+
259
317
if (guard == null ) {
260
318
// Try to merge the pi node with a load node.
261
319
if (object instanceof ReadNode && !object .hasMoreThanOneUsage ()) {
@@ -295,9 +353,24 @@ public static ValueNode canonical(ValueNode object, Stamp piStamp, GuardingNode
295
353
return null ;
296
354
}
297
355
356
+ /**
357
+ * Pi-phi canonicalization is only allowed if the stamp of the phi: (1) is an object stamp
358
+ * (because PiNodes on primitive values are flaky), (2) the computed stamp is equal to the phi
359
+ * value's stamp, and (3) the stamp of the PiNode does not add any information.
360
+ */
361
+ private static boolean checkPhiValueStamp (Stamp piStamp , Stamp computedStamp , Stamp phiValueStamp ) {
362
+ return phiValueStamp .isObjectStamp () && computedStamp .equals (phiValueStamp ) && piStamp .join (phiValueStamp ).equals (phiValueStamp );
363
+ }
364
+
365
+ private static boolean isSameConstant (ValueNode referenceValue , ValueNode phiValue ) {
366
+ assert referenceValue .isConstant () && !referenceValue .isNullConstant () : "reference value must be constant but not the null constant" ;
367
+ assert referenceValue .asConstant () != null : "constant must not be null" ;
368
+ return phiValue .isConstant () && referenceValue .asConstant ().equals (phiValue .asConstant ());
369
+ }
370
+
298
371
@ Override
299
372
public Node canonical (CanonicalizerTool tool ) {
300
- Node value = canonical (object (), piStamp (), getGuard (), this );
373
+ Node value = canonical (object (), piStamp (), getGuard (), this , tool . allUsagesAvailable () );
301
374
if (value != null ) {
302
375
return value ;
303
376
}
0 commit comments