// Checks for syntactic equivalence and returns the side-table index // of the syntactically equivalent node if it found one; else it returns // -1 signifying that this is the first time any node similar syntactically // to this node has been seen. Adds the node to the hash table if seen for the // first time. // // int TR_LocalAnalysisInfo::hasOldExpressionOnRhs(TR::Node *node, bool recalcContainsCall, bool storeLhsContainsCall) { // // Get the relevant portion of the subtree // for this node; this is different for a null check // as its null check reference is the only // sub-expression that matters // TR::Node *relevantSubtree = NULL; if (node->getOpCodeValue() == TR::NULLCHK) relevantSubtree = node->getNullCheckReference(); else relevantSubtree = node; // containsCall checks whether the relevant node has some // sub-expression that cannot be commoned, e.g. call or a new // bool nodeContainsCall; if (!recalcContainsCall && (relevantSubtree == node)) { // can use pre-calculated value of containsCall and storeLhsContainsCall, to avoid visitCount overflow nodeContainsCall = node->containsCall(); } else { storeLhsContainsCall = false; nodeContainsCall = containsCall(relevantSubtree, storeLhsContainsCall); } if (nodeContainsCall) { // // If the node is not a store, a call-like sub-expression is inadmissable; // if the node is a store, a call-like sub-expression is allowed on the RHS // of the store as this does not inhibit privatization in any way as // the private temp store's RHS simply points at original RHS. But if a call-like // sub-expression is present in the LHS of the store, that is inadmissable // if (!node->getOpCode().isStore() || storeLhsContainsCall) return 0; } bool seenIndirectStore = false; #ifdef J9_PROJECT_SPECIFIC bool seenIndirectBCDStore = false; #endif bool seenWriteBarrier = false; int32_t storeNumChildren = node->getNumChildren(); // If node is a null check, compare the // null check reference only to establish syntactic equivalence // if (node->getOpCodeValue() == TR::NULLCHK) /////if (node->getOpCode().isNullCheck()) { int32_t k; for (k=0;k<_numNullChecks;k++) { if (!(_nullCheckNodesAsArray[k] == NULL)) { if (areSyntacticallyEquivalent(_nullCheckNodesAsArray[k]->getNullCheckReference(), node->getNullCheckReference())) return _nullCheckNodesAsArray[k]->getLocalIndex(); } } _nullCheckNodesAsArray[_numNullChecks++] = node; } else { // // If this node is a global store, then equivalence check is different. // We try to give a store to field (or static) o.f the same index as // a load of o.f. This is so that privatization happens for fields/statics. // So the store's opcode value is changed temporarily to be a load before // syntactic equivalence is checked; this enables matching stores/loads to // same global symbol. // if (node->getOpCode().isStore() && !node->getSymbolReference()->getSymbol()->isAutoOrParm()) { if (node->getOpCode().isWrtBar()) seenWriteBarrier = true; #ifdef J9_PROJECT_SPECIFIC seenIndirectBCDStore = node->getType().isBCD(); #endif if (node->getOpCode().isStoreIndirect()) { if (seenWriteBarrier) { TR::Node::recreate(node, _compilation->il.opCodeForIndirectArrayLoad(node->getDataType())); } else { TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectStore(node->getOpCodeValue())); } node->setNumChildren(1); } else { TR::Node::recreate(node, _compilation->il.opCodeForDirectLoad(node->getDataType())); node->setNumChildren(0); } #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(true); #endif seenIndirectStore = true; } int32_t hashValue = _hashTable->hash(node); HashTable::Cursor cursor(_hashTable, hashValue); TR::Node *other; for (other = cursor.firstNode(); other; other = cursor.nextNode()) { // Convert other node's opcode to be a load temporarily // (only for syntactic equivalence check; see explanation above) // to enable matching global stores/loads. // bool seenOtherIndirectStore = false; #ifdef J9_PROJECT_SPECIFIC bool seenOtherIndirectBCDStore = false; #endif bool seenOtherWriteBarrier = false; int32_t otherStoreNumChildren = other->getNumChildren(); if (other->getOpCode().isStore() && !other->getSymbolReference()->getSymbol()->isAutoOrParm()) { if (other->getOpCode().isWrtBar()) seenOtherWriteBarrier = true; #ifdef J9_PROJECT_SPECIFIC seenOtherIndirectBCDStore = other->getType().isBCD(); #endif if (other->getOpCode().isStoreIndirect()) { if (seenOtherWriteBarrier) { TR::Node::recreate(other, _compilation->il.opCodeForIndirectArrayLoad(other->getDataType())); } else { TR::Node::recreate(other, _compilation->il.opCodeForCorrespondingIndirectStore(other->getOpCodeValue())); } other->setNumChildren(1); } else { TR::Node::recreate(other, _compilation->il.opCodeForDirectLoad(other->getDataType())); other->setNumChildren(0); } #ifdef J9_PROJECT_SPECIFIC if (seenOtherIndirectBCDStore) other->setBCDStoreIsTemporarilyALoad(true); #endif seenOtherIndirectStore = true; } bool areSame = areSyntacticallyEquivalent(node, other); // Restore the other node's state to what it was originally // (if it was a global store) // if (seenOtherWriteBarrier) { other->setNumChildren(otherStoreNumChildren); if (otherStoreNumChildren == 3) TR::Node::recreate(other, TR::awrtbari); else TR::Node::recreate(other, TR::awrtbar); } else if (seenOtherIndirectStore) { other->setNumChildren(otherStoreNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenOtherIndirectBCDStore) other->setBCDStoreIsTemporarilyALoad(false); #endif if (other->getOpCode().isIndirect()) TR::Node::recreate(other, _compilation->il.opCodeForCorrespondingIndirectLoad(other->getOpCodeValue())); else TR::Node::recreate(other, _compilation->il.opCodeForDirectStore(other->getDataType())); } if (areSame) { if (seenWriteBarrier) { node->setNumChildren(storeNumChildren); if (storeNumChildren == 3) TR::Node::recreate(node, TR::awrtbari); else TR::Node::recreate(node, TR::awrtbar); } else if (seenIndirectStore) { node->setNumChildren(storeNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(false); #endif if (node->getOpCode().isIndirect()) TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectLoad(node->getOpCodeValue())); else TR::Node::recreate(node, _compilation->il.opCodeForDirectStore(node->getDataType())); } return other->getLocalIndex(); } } // No match from existing nodes in the hash table; // add this node to the hash table. // _hashTable->add(node, hashValue); } // Restore this node's state to what it was before // (if it was a global store) // if (seenWriteBarrier) { node->setNumChildren(storeNumChildren); if (storeNumChildren == 3) TR::Node::recreate(node, TR::awrtbari); else TR::Node::recreate(node, TR::awrtbar); } else if (seenIndirectStore) { node->setNumChildren(storeNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(false); #endif if (node->getOpCode().isIndirect()) TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectLoad(node->getOpCodeValue())); else TR::Node::recreate(node, _compilation->il.opCodeForDirectStore(node->getDataType())); } return -1; }