/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "opto/addnode.hpp"
#include "opto/compile.hpp"
#include "opto/connode.hpp"
#include "opto/machnode.hpp"
#include "opto/matcher.hpp"
#include "opto/memnode.hpp"
#include "opto/phaseX.hpp"
#include "opto/subnode.hpp"
#include "runtime/sharedRuntime.hpp"
// Optimization - Graph Style
//=============================================================================
//------------------------------hash-------------------------------------------
}
//------------------------------make-------------------------------------------
switch( t->basic_type() ) {
// Expected cases: TypePtr::NULL_PTR, any is_rawptr()
// Also seen: AnyPtr(TopPTR *+top); from command line:
// r -XX:+PrintOpto -XX:CIStart=285 -XX:+CompileTheWorld -XX:CompileTheWorldStartAt=660
// %%%% Stop using TypePtr::NULL_PTR to represent nulls: use either TypeRawPtr::NULL_PTR
// or else TypeOopPtr::NULL_PTR. Then set Type::_basic_type[AnyPtr] = T_ILLEGAL
}
return NULL;
}
//=============================================================================
/*
The major change is for CMoveP and StrComp. They have related but slightly
different problems. They both take in TWO oops which are both null-checked
independently before the using Node. After CCP removes the CastPP's they need
to pick up the guarding test edge - in this case TWO control edges. I tried
various solutions, all have problems:
(1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a
StrComp above a guarding null check. I've seen both cases in normal -Xcomp
testing.
(2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is
to figure out which test post-dominates. The real problem is that it doesn't
matter which one you pick. After you pick up, the dominating-test elider in
IGVN can remove the test and allow you to hoist up to the dominating test on
the chosen oop bypassing the test on the not-chosen oop. Seen in testing.
Oops.
(3) Leave the CastPP's in. This makes the graph more accurate in some sense;
we get to keep around the knowledge that an oop is not-null after some test.
Alas, the CastPP's interfere with GVN (some values are the regular oop, some
are the CastPP of the oop, all merge at Phi's which cannot collapse, etc).
This cost us 10% on SpecJVM, even when I removed some of the more trivial
cases in the optimizer. Removing more useless Phi's started allowing Loads to
illegally float above null checks. I gave up on this approach.
(4) Add BOTH control edges to both tests. Alas, too much code knows that
control edges are in slot-zero ONLY. Many quick asserts fail; no way to do
this one. Note that I really want to allow the CMoveP to float and add both
control edges to the dependent Load op - meaning I can select early but I
cannot Load until I pass both tests.
(5) Do not hoist CMoveP and StrComp. To this end I added the v-call
depends_only_on_test(). No obvious performance loss on Spec, but we are
clearly conservative on CMoveP (also so on StrComp but that's unlikely to
matter ever).
*/
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node.
// Move constants to the right.
// Don't bother trying to transform a dead node
return NULL; // return NULL when Condition is dead
}
}
return NULL;
}
//------------------------------is_cmove_id------------------------------------
// Helper function to check for CMOVE identity. Shared with PhiNode::Identity
// Check for Cmp'ing and CMove'ing same values
// Swapped Cmp is OK
// Give up this identity check for floating points because it may choose incorrect
// value around 0.0 and -0.0
return NULL;
// Check for "(t==f)?t:f;" and replace with "f"
return f;
// Allow the inverted case as well
// Check for "(t!=f)?t:f;" and replace with "t"
return t;
}
return NULL;
}
//------------------------------Identity---------------------------------------
// Conditional-move is an identity if both inputs are the same, or the test
// true or false.
// Check for CMove'ing a constant after comparing against the constant.
// Happens all the time now, since if we compare equality vs a constant in
// the parser, we "know" the variable is constant on one path and we force
// it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a
// conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more
// general in that we don't need constants.
}
}
return this;
}
//------------------------------Value------------------------------------------
// Result is the meet of inputs
}
//------------------------------make-------------------------------------------
// Make a correctly-flavored CMove. Since _type is directly determined
// from the inputs we do not need to specify it here.
CMoveNode *CMoveNode::make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ) {
switch( t->basic_type() ) {
default:
return NULL;
}
}
//=============================================================================
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node.
// Check for conversions to boolean
// Try generic ideal's first
if( x ) return x;
// If zero is on the left (false-case, no-move-case) it must mean another
// constant is on the right (otherwise the shared CMove::Ideal code would
// have moved the constant to the right). This situation is bad for Intel
// and a don't-care for Sparc. It's bad for Intel because the zero has to
// be manifested in a register with a XOR which kills flags, which are live
// on input to the CMoveI, leading to a situation which causes excessive
// spilling on Intel. For Sparc, if the zero in on the left the Sparc will
// zero a register via G0 and conditionally-move the other constant. If the
// zero is on the right, the Sparc will load the first constant with a
// 13-bit set-lo and conditionally move G0. See bug 4677505.
}
}
// Now check for booleans
int flip = 0;
} else return NULL;
} else return NULL;
// Check for vs 0 or 1
// Allow cmp-vs-1 if the other input is bounded by 0-1
return NULL;
} else return NULL;
// Convert to a bool (flipped)
// Build int->bool conversion
#ifndef PRODUCT
#endif
if( flip )
return n;
}
//=============================================================================
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node.
// Check for absolute value
// Try generic ideal's first
if( x ) return x;
// Find the Bool
// Check bool sense
default: return NULL; break;
}
// Find zero input of CmpF; the other input is being abs'd
bool flip = false;
// The test is inverted, we should invert the result...
flip = true;
} else {
return NULL;
}
// If X is found on the appropriate phi input, find the subtract on the other
// Allow only SubF(0,X) and fail out for all others; NegF is not OK
if( flip )
return abs;
}
//=============================================================================
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node.
// Check for absolute value
// Try generic ideal's first
if( x ) return x;
// Find the Bool
// Check bool sense
default: return NULL; break;
}
// Find zero input of CmpD; the other input is being abs'd
bool flip = false;
// The test is inverted, we should invert the result...
flip = true;
} else {
return NULL;
}
// If X is found on the appropriate phi input, find the subtract on the other
// Allow only SubD(0,X) and fail out for all others; NegD is not OK
if( flip )
return abs;
}
//=============================================================================
// If input is already higher or equal to cast type, then this is an identity.
}
//------------------------------Value------------------------------------------
// Take 'join' of input and cast-up type
#ifdef ASSERT
// Previous versions of this function had some special case logic,
// which is no longer necessary. Make sure of the required effects.
switch (Opcode()) {
case Op_CastII:
{
break;
}
case Op_CastPP:
break;
}
#endif //ASSERT
return ft;
}
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies
}
//------------------------------Ideal_DU_postCCP-------------------------------
// Throw away cast after constant propagation
ccp->hash_delete(this);
set_type(t); // Turn into ID function
ccp->hash_insert(this);
return this;
}
//=============================================================================
//------------------------------Ideal_DU_postCCP-------------------------------
// If not converting int->oop, throw away cast after constant propagation
return NULL; // do not transform raw pointers or narrow oops
}
}
//=============================================================================
//------------------------------Identity---------------------------------------
// If input is already higher or equal to cast type, then this is an identity.
// Toned down to rescue meeting at a Phi 3 different oops all implementing
// the same interface. CompileTheWorld starting at 502, kd12rc1.zip.
}
// Determine whether "n" is a node which can cause an alias of one of its inputs. Node types
// which can create aliases are: CheckCastPP, Phi, and any store (if there is also a load from
// the location.)
// Note: this checks for aliases created in this compilation, not ones which may
// be potentially created at call sites.
bool possible_alias = false;
if (n->is_Store()) {
} else {
possible_alias = n->is_Phi() ||
opc == Op_CheckCastPP ||
opc == Op_StorePConditional ||
opc == Op_CompareAndSwapP ||
opc == Op_CompareAndSwapN ||
opc == Op_GetAndSetP ||
opc == Op_GetAndSetN;
}
return possible_alias;
}
//------------------------------Value------------------------------------------
// Take 'join' of input and cast-up type, unless working with an Interface
// Casting a constant oop to an interface?
// (i.e., a String to a Comparable?)
// Then return the interface.
: in_type;
} else {
}
}
return result;
// JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES.
// FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR!
//
// Remove this code after overnight run indicates no performance
// loss from not performing JOIN at CheckCastPPNode
//
// const TypeInstPtr *in_oop = in->isa_instptr();
// const TypeInstPtr *my_oop = _type->isa_instptr();
// // If either input is an 'interface', return destination type
// assert (in_oop == NULL || in_oop->klass() != NULL, "");
// assert (my_oop == NULL || my_oop->klass() != NULL, "");
// if( (in_oop && in_oop->klass()->klass_part()->is_interface())
// ||(my_oop && my_oop->klass()->klass_part()->is_interface()) ) {
// TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR;
// // Preserve cast away nullness for interfaces
// if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) {
// return my_oop->cast_to_ptr_type(TypePtr::NotNull);
// }
// return _type;
// }
//
// // Neither the input nor the destination type is an interface,
//
// // history: JOIN used to cause weird corner case bugs
// // return (in == TypeOopPtr::NULL_PTR) ? in : _type;
// // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops.
// // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr
// const Type *join = in->join(_type);
// // Check if join preserved NotNull'ness for pointers
// if( join->isa_ptr() && _type->isa_ptr() ) {
// TypePtr::PTR join_ptr = join->is_ptr()->_ptr;
// TypePtr::PTR type_ptr = _type->is_ptr()->_ptr;
// // If there isn't any NotNull'ness to preserve
// // OR if join preserved NotNull'ness then return it
// if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null ||
// join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) {
// return join;
// }
// // ELSE return same old type as before
// return _type;
// }
// // Not joining two pointers
// return join;
}
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies
}
// (DecodeN (EncodeP p)) -> p
}
return this;
}
return t->make_ptr();
}
// (EncodeP (DecodeN p)) -> p
}
return this;
}
return t->make_narrowoop();
}
}
//=============================================================================
//------------------------------Identity---------------------------------------
return this;
}
//------------------------------Value------------------------------------------
}
}
// The conversions operations are all Alpha sorted. Please keep it that way!
//=============================================================================
//------------------------------Value------------------------------------------
}
//------------------------------Identity---------------------------------------
// Float's can be converted to doubles with no loss of bits. Hence
// converting a float to a double and back to a float is a NOP.
}
//=============================================================================
//------------------------------Value------------------------------------------
}
//------------------------------Ideal------------------------------------------
// If converting to an int type, skip any rounding nodes
return NULL;
}
//------------------------------Identity---------------------------------------
// Int's can be converted to doubles with no loss of bits. Hence
// converting an integer to a double and back to an integer is a NOP.
}
//=============================================================================
//------------------------------Value------------------------------------------
}
//------------------------------Identity---------------------------------------
// Remove ConvD2L->ConvL2D->ConvD2L sequences.
return this;
}
//------------------------------Ideal------------------------------------------
// If converting to an int type, skip any rounding nodes
return NULL;
}
//=============================================================================
//------------------------------Value------------------------------------------
}
//=============================================================================
//------------------------------Value------------------------------------------
}
//------------------------------Identity---------------------------------------
// Remove ConvF2I->ConvI2F->ConvF2I sequences.
return this;
}
//------------------------------Ideal------------------------------------------
// If converting to an int type, skip any rounding nodes
return NULL;
}
//=============================================================================
//------------------------------Value------------------------------------------
}
//------------------------------Identity---------------------------------------
// Remove ConvF2L->ConvL2F->ConvF2L sequences.
return this;
}
//------------------------------Ideal------------------------------------------
// If converting to an int type, skip any rounding nodes
return NULL;
}
//=============================================================================
//------------------------------Value------------------------------------------
return bottom_type();
}
//=============================================================================
//------------------------------Value------------------------------------------
return bottom_type();
}
//------------------------------Identity---------------------------------------
// Remove ConvI2F->ConvF2I->ConvI2F sequences.
return this;
}
//=============================================================================
//------------------------------Value------------------------------------------
// Join my declared type against my incoming type.
return tl;
}
#ifdef _LP64
// Two ranges overlap iff one range's low point falls in the other range.
}
#endif
//------------------------------Ideal------------------------------------------
// If _major_progress, then more loop optimizations follow. Do NOT
// remove this node's type assertion until no more loop ops can happen.
// The progress bit is set in the major loop optimizations THEN comes the
// call to IterGVN and any chance of hitting this code. Cf. Opaque1Node.
// Although this WORSENS the type, it increases GVN opportunities,
// because I2L nodes with the same input will common up, regardless
// of slightly differing type assertions. Such slight differences
// arise routinely as a result of loop unrolling, so this is a
// post-unrolling graph cleanup. Choose a type which depends only
// on my input. (Exception: Keep a range assertion of >=0 or <0.)
// Overflow leads to wraparound, wraparound leads to range saturation.
} else if (lo1 >= 0) {
// Keep a range assertion of >=0.
} else if (hi1 < 0) {
// Keep a range assertion of <0.
} else {
}
// Note: this_type still has old type value, for the logic below.
this_changed = this;
}
}
}
#ifdef _LP64
// Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) ,
// but only if x and y have subranges that cannot cause 32-bit overflow,
// under the assumption that x+y is in my own subrange this->type().
// This assumption is based on a constraint (i.e., type assertion)
// established in Parse::array_addressing or perhaps elsewhere.
// This constraint has been adjoined to the "natural" type of
// the incoming argument in(0). We know (because of runtime
// checks) - that the result value I2L(x+y) is in the joined range.
// Hence we can restrict the incoming terms (x, y) to values such
// that their sum also lands in that range.
// This optimization is useful only on 64-bit systems, where we hope
// the addition will end up subsumed in an addressing mode.
// It is necessary to do this when optimizing an unrolled array
// copy loop such as x[i++] = y[i++].
// On 32-bit systems, it's better to perform as much 32-bit math as
// possible before the I2L conversion, because 32-bit math is cheaper.
// There's no common reason to "leak" a constant offset through the I2L.
// Addressing arithmetic will not absorb it as part of a 64-bit AddL.
assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal");
}
// See if x+y can cause positive overflow into z+2**32
return this_changed;
}
// See if x+y can cause negative overflow into z-2**32
return this_changed;
}
// Now it's always safe to assume x+y does not overflow.
// This is true even if some pairs x,y might cause overflow, as long
// as that overflow value cannot fall into [zlo,zhi].
// Confident that the arithmetic is "as if infinite precision",
// we can now use z's range to put constraints on those of x and y.
// The "natural" range of x [xlo,xhi] can perhaps be narrowed to a
// more "restricted" range by intersecting [xlo,xhi] with the
// range obtained by subtracting y's range from the asserted range
// of the I2L conversion. Here's the interval arithmetic algebra:
// x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo]
// => x in [zlo-yhi, zhi-ylo]
// => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi]
// => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo]
// And similarly, x changing place with y:
return this_changed; // x or y is dying; don't mess w/ it
}
}
switch (op) {
default: ShouldNotReachHere();
}
}
#endif //_LP64
return this_changed;
}
//=============================================================================
//------------------------------Value------------------------------------------
return bottom_type();
}
//=============================================================================
//------------------------------Value------------------------------------------
return bottom_type();
}
//=============================================================================
//----------------------------Identity-----------------------------------------
// Convert L2I(I2L(x)) => x
return this;
}
//------------------------------Value------------------------------------------
// Easy case.
return bottom_type();
}
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node.
// Blow off prior masking to int
// Blow off prior masking to int
return this;
}
}
// Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
// This replaces an 'AddL' with an 'AddI'.
// Don't do this for nodes which have more than one user since
// we'll end up computing the long add anyway.
}
// Disable optimization: LoadL->ConvL2I ==> LoadI.
// It causes problems (sizes of Load and Store nodes do not match)
// in objects initialization code and Escape Analysis.
return NULL;
}
//=============================================================================
//------------------------------Value------------------------------------------
}
return CastX2PNode::bottom_type();
}
//------------------------------Idealize---------------------------------------
}
bool negate = false) {
if (negate) {
}
}
// convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int
Node* x;
Node* y;
switch (op) {
case Op_SubX:
// Avoid ideal transformations ping-pong between this and AddP for raw pointers.
break;
return addP_of_X2P(phase, x, y, true);
}
break;
case Op_AddX:
return addP_of_X2P(phase, x, y);
}
return addP_of_X2P(phase, y, x);
}
break;
}
return NULL;
}
//------------------------------Identity---------------------------------------
return this;
}
//=============================================================================
//------------------------------Value------------------------------------------
}
return CastP2XNode::bottom_type();
}
}
//------------------------------Identity---------------------------------------
return this;
}
//=============================================================================
//------------------------------Identity---------------------------------------
// Remove redundant roundings
// Do not round constants
// Redundant rounding
// Already rounded
return this;
}
//------------------------------Value------------------------------------------
}
//=============================================================================
//------------------------------Identity---------------------------------------
// Remove redundant roundings. Incoming arguments are already rounded.
// Do not round constants
// Redundant rounding
// Already rounded
return this;
}
//------------------------------Value------------------------------------------
}
//=============================================================================
// Do not allow value-numbering
return (&n == this); // Always fail except on self
}
//------------------------------Identity---------------------------------------
// If _major_progress, then more loop optimizations follow. Do NOT remove
// the opaque Node until no more loop ops can happen. Note the timing of
// _major_progress; it's set in the major loop optimizations THEN comes the
// call to IterGVN and any chance of hitting this code. Hence there's no
// phase-ordering problem with stripping Opaque1 in IGVN followed by some
// more loop optimizations that require it.
}
//=============================================================================
// A node to prevent unwanted optimizations. Allows constant folding. Stops
// value-numbering, most Ideal calls or Identity functions. This Node is
// specifically designed to prevent the pre-increment value of a loop trip
// counter from being live out of the bottom of the loop (hence causing the
// pre- and post-increment values both being live and thus requiring an extra
// temp register and an extra move). If we "accidentally" optimize through
// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus
// it's OK to be slightly sloppy on optimizations here.
// Do not allow value-numbering
return (&n == this); // Always fail except on self
}
//------------------------------Value------------------------------------------
JavaValue v;
}
//------------------------------Value------------------------------------------
JavaValue v;
}
//------------------------------Value------------------------------------------
JavaValue v;
}
//------------------------------Value------------------------------------------
JavaValue v;
}
//------------------------------Value------------------------------------------
// HD, Figure 5-6
if (i == 0)
int n = 1;
unsigned int x = i;
if (x >> 16 == 0) { n += 16; x <<= 16; }
if (x >> 24 == 0) { n += 8; x <<= 8; }
if (x >> 28 == 0) { n += 4; x <<= 4; }
if (x >> 30 == 0) { n += 2; x <<= 2; }
n -= x >> 31;
}
}
//------------------------------Value------------------------------------------
// HD, Figure 5-6
if (l == 0)
int n = 1;
unsigned int x = (((julong) l) >> 32);
if (x == 0) { n += 32; x = (int) l; }
if (x >> 16 == 0) { n += 16; x <<= 16; }
if (x >> 24 == 0) { n += 8; x <<= 8; }
if (x >> 28 == 0) { n += 4; x <<= 4; }
if (x >> 30 == 0) { n += 2; x <<= 2; }
n -= x >> 31;
}
}
//------------------------------Value------------------------------------------
// HD, Figure 5-14
int y;
if (i == 0)
int n = 31;
y = i << 16; if (y != 0) { n = n - 16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
y = i << 1; if (y != 0) { n = n - 1; }
}
}
//------------------------------Value------------------------------------------
// HD, Figure 5-14
int x, y;
if (l == 0)
int n = 63;
y = x << 16; if (y != 0) { n = n - 16; x = y; }
y = x << 8; if (y != 0) { n = n - 8; x = y; }
y = x << 4; if (y != 0) { n = n - 4; x = y; }
y = x << 2; if (y != 0) { n = n - 2; x = y; }
y = x << 1; if (y != 0) { n = n - 1; }
}
}