diff --git a/compiler/il/OMRNode.cpp b/compiler/il/OMRNode.cpp index eedab756b1d..31a9ee7f1d7 100644 --- a/compiler/il/OMRNode.cpp +++ b/compiler/il/OMRNode.cpp @@ -215,7 +215,7 @@ OMR::Node::Node(TR::Node *originatingByteCodeNode, TR::ILOpCodes op, uint16_t nu + self()->hasBranchDestinationNode() + self()->hasBlock() + self()->hasArrayStride() - + self()->hasPinningArrayPointer() + + (self()->hasPinningArrayPointer() && !self()->supportsPinningArrayPointerInNodeExtension()) + self()->hasDataType() <= 1, "_unionPropertyA union is not disjoint for this node %s (%p):\n" " has({SymbolReference, ...}, ..., DataType) = ({%1d,%1d},%1d,%1d,%1d,%1d,%1d)\n", @@ -225,7 +225,7 @@ OMR::Node::Node(TR::Node *originatingByteCodeNode, TR::ILOpCodes op, uint16_t nu self()->hasBranchDestinationNode(), self()->hasBlock(), self()->hasArrayStride(), - self()->hasPinningArrayPointer(), + (self()->hasPinningArrayPointer() && !self()->supportsPinningArrayPointerInNodeExtension()), self()->hasDataType()); } @@ -5046,10 +5046,16 @@ OMR::Node::hasArrayStride() return self()->getOpCode().isArrayLength(); } +bool +OMR::Node::supportsPinningArrayPointerInNodeExtension() + { + return self()->isDataAddrPointer(); + } + bool OMR::Node::hasPinningArrayPointer() { - return self()->getOpCode().hasPinningArrayPointer(); + return self()->getOpCode().hasPinningArrayPointer() || self()->supportsPinningArrayPointerInNodeExtension(); } bool @@ -5189,16 +5195,28 @@ OMR::Node::setArrayStride(int32_t s) TR::AutomaticSymbol* OMR::Node::getPinningArrayPointer() { - TR_ASSERT(self()->hasPinningArrayPointer(), "attempting to access _pinningArrayPointer field for node %s %p that does not have it", self()->getOpCode().getName(), this); - return _unionPropertyA._pinningArrayPointer; + TR_ASSERT(self()->hasPinningArrayPointer() || _unionBase._extension.getNumElems() >= 6, "attempting to access _pinningArrayPointer field for node %s %p that does not support it", self()->getOpCode().getName(), this); + + if (self()->getOpCode().hasPinningArrayPointer()) + return _unionPropertyA._pinningArrayPointer; + + return _unionBase._extension.getExtensionPtr()->getElem(5); } TR::AutomaticSymbol* OMR::Node::setPinningArrayPointer(TR::AutomaticSymbol *s) { s->setPinningArrayPointer(); - TR_ASSERT(self()->hasPinningArrayPointer(), "attempting to access _pinningArrayPointer field for node %s %p that does not have it", self()->getOpCode().getName(), this); - return (_unionPropertyA._pinningArrayPointer = s); + TR_ASSERT(self()->hasPinningArrayPointer(), "attempting to access _pinningArrayPointer field for node %s %p that does not support it", self()->getOpCode().getName(), this); + + if (self()->getOpCode().hasPinningArrayPointer()) + return _unionPropertyA._pinningArrayPointer = s; + + int extensionElemNum = _unionBase._extension.getNumElems(); + if (extensionElemNum < 6) + self()->addExtensionElements(6 - extensionElemNum); + + return _unionBase._extension.getExtensionPtr()->setElem(5, s); } TR::DataType diff --git a/compiler/il/OMRNode.hpp b/compiler/il/OMRNode.hpp index 8277d906413..8fe696801f3 100644 --- a/compiler/il/OMRNode.hpp +++ b/compiler/il/OMRNode.hpp @@ -1590,6 +1590,7 @@ class OMR_EXTENSIBLE Node public: // For opcode properties bool hasPinningArrayPointer(); + bool supportsPinningArrayPointerInNodeExtension(); // Protected inner classes and structs. protected: @@ -1651,8 +1652,8 @@ class OMR_EXTENSIBLE Node TR::TreeTop *_branchDestinationNode; ///< hasBranchDestinationNode() TR::Block *_block; ///< hasBlock() int32_t _arrayStride; ///< hasArrayStride() - TR::AutomaticSymbol *_pinningArrayPointer; ///< hasPinningArrayPointer() - TR::DataTypes _dataType; ///< hasDataType() TODO: Change to TR::DataType once all target compilers support it + TR::AutomaticSymbol *_pinningArrayPointer; ///< hasPinningArrayPointer() + TR::DataTypes _dataType; ///< hasDataType() TODO: Change to TR::DataType once all target compilers support it UnionPropertyA() { diff --git a/compiler/optimizer/LoopVersioner.cpp b/compiler/optimizer/LoopVersioner.cpp index 0d353d03cdd..19ea5661532 100644 --- a/compiler/optimizer/LoopVersioner.cpp +++ b/compiler/optimizer/LoopVersioner.cpp @@ -8023,6 +8023,9 @@ bool TR_LoopVersioner::requiresPrivatization(TR::Node *node) if (!node->getOpCode().hasSymbolReference()) return false; + if (node->isDataAddrPointer()) + return false; + if (node->getOpCodeValue() == TR::loadaddr || node->getOpCode().isTreeTop()) return false; @@ -8194,19 +8197,26 @@ bool TR_LoopVersioner::depsForLoopEntryPrep( // If this is an indirect access // if (node->isInternalPointer() || - (((node->getOpCode().isIndirect() && node->getOpCode().hasSymbolReference() && !node->getSymbolReference()->getSymbol()->isStatic()) || node->getOpCode().isArrayLength()) && - !node->getFirstChild()->isInternalPointer())) + (((node->getOpCode().isIndirect() && node->getOpCode().hasSymbolReference() && + !node->getSymbolReference()->getSymbol()->isStatic()) || + node->getOpCode().isArrayLength()) && !node->getFirstChild()->isInternalPointer())) { - if (!node->getFirstChild()->isThisPointer()) + TR::Node *firstChild = node->getFirstChild(); + if (!firstChild->isThisPointer()) { - dumpOptDetailsCreatingTest("null", node->getFirstChild()); - TR::Node *ifacmpeqNode = TR::Node::createif(TR::ifacmpeq, node->getFirstChild(), TR::Node::aconst(node, 0), _exitGotoTarget); + // if we are dealing with dataAddr load use the child for null check. + // We can reach here either with dataAddr load or with parent of dataAddr load. + if (firstChild->isDataAddrPointer()) + firstChild = firstChild->getFirstChild(); // Array base is the child of dataAddr load + + dumpOptDetailsCreatingTest("null", firstChild); + TR::Node *ifacmpeqNode = TR::Node::createif(TR::ifacmpeq, firstChild, TR::Node::aconst(node, 0), _exitGotoTarget); LoopEntryPrep *nullTestPrep = addLoopEntryPrepDep(LoopEntryPrep::TEST, ifacmpeqNode, deps, visited); if (nullTestPrep == NULL) { - dumpOptDetailsFailedToCreateTest("null", node->getFirstChild()); + dumpOptDetailsFailedToCreateTest("null", firstChild); return false; } @@ -8214,7 +8224,6 @@ bool TR_LoopVersioner::depsForLoopEntryPrep( _curLoop->_nullTestPreps.insert(std::make_pair(refExpr, nullTestPrep)); } - TR::Node *firstChild = node->getFirstChild(); bool instanceOfReqd = true; TR_OpaqueClassBlock *otherClassObject = NULL; TR::Node *duplicateClassPtr = NULL; @@ -8324,21 +8333,21 @@ bool TR_LoopVersioner::depsForLoopEntryPrep( { if (otherClassObject) { - dumpOptDetailsCreatingTest("type", node->getFirstChild()); - TR::Node *instanceofNode = TR::Node::createWithSymRef(TR::instanceof, 2, 2, node->getFirstChild(), duplicateClassPtr, comp()->getSymRefTab()->findOrCreateInstanceOfSymbolRef(comp()->getMethodSymbol())); + dumpOptDetailsCreatingTest("type", firstChild); + TR::Node *instanceofNode = TR::Node::createWithSymRef(TR::instanceof, 2, 2, firstChild, duplicateClassPtr, comp()->getSymRefTab()->findOrCreateInstanceOfSymbolRef(comp()->getMethodSymbol())); TR::Node *ificmpeqNode = TR::Node::createif(TR::ificmpeq, instanceofNode, TR::Node::create(node, TR::iconst, 0, 0), _exitGotoTarget); if (addLoopEntryPrepDep(LoopEntryPrep::TEST, ificmpeqNode, deps, visited) == NULL) { - dumpOptDetailsFailedToCreateTest("type", node->getFirstChild()); + dumpOptDetailsFailedToCreateTest("type", firstChild); return false; } } else if (testIsArray) { #ifdef J9_PROJECT_SPECIFIC - dumpOptDetailsCreatingTest("array type", node->getFirstChild()); + dumpOptDetailsCreatingTest("array type", firstChild); - TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, node->getFirstChild(), comp()->getSymRefTab()->findOrCreateVftSymbolRef()); + TR::Node *vftLoad = TR::Node::createWithSymRef(TR::aloadi, 1, 1, firstChild, comp()->getSymRefTab()->findOrCreateVftSymbolRef()); //TR::Node *componentTypeLoad = TR::Node::create(TR::aloadi, 1, vftLoad, comp()->getSymRefTab()->findOrCreateArrayComponentTypeSymbolRef()); TR::Node *classFlag = NULL; if (comp()->target().is32Bit()) @@ -8355,7 +8364,7 @@ bool TR_LoopVersioner::depsForLoopEntryPrep( TR::Node *cmp = TR::Node::createif(TR::ificmpne, andNode, andConstNode, _exitGotoTarget); if (addLoopEntryPrepDep(LoopEntryPrep::TEST, cmp, deps, visited) == NULL) { - dumpOptDetailsFailedToCreateTest("array type", node->getFirstChild()); + dumpOptDetailsFailedToCreateTest("array type", firstChild); return false; } #endif @@ -8376,81 +8385,131 @@ bool TR_LoopVersioner::depsForLoopEntryPrep( // This is an array access; so we need to insert explicit // checks to mimic the bounds check for the access. // - TR::Node *offset = node->getFirstChild()->getSecondChild(); TR::Node *childInRequiredForm = NULL; TR::Node *indexNode = NULL; - - int32_t headerSize = static_cast(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()); - static struct temps - { - TR::ILOpCodes addOp; - TR::ILOpCodes constOp; - int32_t k; - } - a[] = - {{TR::iadd, TR::iconst, headerSize}, - {TR::isub, TR::iconst, -headerSize}, - {TR::ladd, TR::lconst, headerSize}, - {TR::lsub, TR::lconst, -headerSize}}; - - for (int32_t index = sizeof(a)/sizeof(temps) - 1; index >= 0; --index) - { - if (offset->getOpCodeValue() == a[index].addOp && - offset->getSecondChild()->getOpCodeValue() == a[index].constOp && - offset->getSecondChild()->getInt() == a[index].k) - { - childInRequiredForm = offset->getFirstChild(); - break; - } - } - - TR::DataType type = offset->getType(); + TR::DataType type = TR::NoType; // compute the right shift width - // int32_t dataWidth = TR::Symbol::convertTypeToSize(node->getDataType()); - if (comp()->useCompressedPointers() && - node->getDataType() == TR::Address) + if (comp()->useCompressedPointers() && node->getDataType() == TR::Address) dataWidth = TR::Compiler->om.sizeofReferenceField(); - int32_t shiftWidth = TR::TransformUtil::convertWidthToShift(dataWidth); - if (childInRequiredForm) + // Holds the array node, or the dataAddr node for off heap + TR::Node *arrayBaseAddressNode = NULL; + + if (node->getFirstChild()->isDataAddrPointer()) + { + // This protects the case when off heap allocation is enabled and array + // access is for the first element in the array, eliminating offset tree. + // *loadi <== node + // aloadi dataAddr_ptr (dataAddrPointer sharedMemory ) + // aload objt_ptr + + // If array access does not have offset tree, its accessing the first element using the dataAddrPointer + arrayBaseAddressNode = node->getFirstChild(); + indexNode = TR::Node::iconst(node, 0); + type = TR::Int32; + } + else { - if (childInRequiredForm->getOpCodeValue() == TR::ishl || childInRequiredForm->getOpCodeValue() == TR::lshl) + int32_t headerSize = static_cast(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()); + arrayBaseAddressNode = node->getFirstChild()->getFirstChild(); + TR::Node *offset = node->getFirstChild()->getSecondChild(); + type = offset->getType(); + + /* childInRequiredForm is expected to be shift/multiply node. When + off heap allocation is enabled and the sibling is dataAddr pointer + node, instead of using objt_ptr + header_size we load address of first + array element from dataAddr field in the header and add the offset. */ + if (arrayBaseAddressNode->isDataAddrPointer()) { - if (childInRequiredForm->getSecondChild()->getOpCode().isLoadConst() && - (childInRequiredForm->getSecondChild()->getInt() == shiftWidth)) - indexNode = childInRequiredForm->getFirstChild(); + // This is what trees will look like with dataAddr load + // aloadi < node + // aladd + // ==>aload dataAddr_ptr (dataAddrPointer sharedMemory ) + // shl/mul < childInRequiredForm/offset + childInRequiredForm = node->getFirstChild()->getSecondChild(); } - else if (childInRequiredForm->getOpCodeValue() == TR::imul || childInRequiredForm->getOpCodeValue() == TR::lmul) + else { - if (childInRequiredForm->getSecondChild()->getOpCode().isLoadConst() && - (childInRequiredForm->getSecondChild()->getInt() == dataWidth)) - indexNode = childInRequiredForm->getFirstChild(); + // aloadi < node + // aladd + // ==>aload objt_ptr + // add < offset + // shl/mul < childInRequiredForm + // const array_header + static struct temps + { + TR::ILOpCodes addOp; + TR::ILOpCodes constOp; + int32_t k; + } + a[] = + {{TR::iadd, TR::iconst, headerSize}, + {TR::isub, TR::iconst, -headerSize}, + {TR::ladd, TR::lconst, headerSize}, + {TR::lsub, TR::lconst, -headerSize}}; + for (int32_t index = sizeof(a)/sizeof(temps) - 1; index >= 0; --index) + { + if (offset->getOpCodeValue() == a[index].addOp && + offset->getSecondChild()->getOpCodeValue() == a[index].constOp && + offset->getSecondChild()->getInt() == a[index].k) + { + childInRequiredForm = offset->getFirstChild(); + break; + } + } } - } + int32_t shiftWidth = TR::TransformUtil::convertWidthToShift(dataWidth); - if (!indexNode) - { - if (!childInRequiredForm) + if (childInRequiredForm) { - TR::Node *constNode = TR::Node::create(node, type.isInt32() ? TR::iconst : TR::lconst, 0, 0); - indexNode = TR::Node::create(type.isInt32() ? TR::isub : TR::lsub, 2, offset, constNode); - if (type.isInt64()) - constNode->setLongInt((int64_t)headerSize); - else - constNode->setInt((int64_t)headerSize); + if (childInRequiredForm->getOpCodeValue() == TR::ishl || childInRequiredForm->getOpCodeValue() == TR::lshl) + { + if (childInRequiredForm->getSecondChild()->getOpCode().isLoadConst() && + (childInRequiredForm->getSecondChild()->getInt() == shiftWidth)) + indexNode = childInRequiredForm->getFirstChild(); + } + else if (childInRequiredForm->getOpCodeValue() == TR::imul || childInRequiredForm->getOpCodeValue() == TR::lmul) + { + if (childInRequiredForm->getSecondChild()->getOpCode().isLoadConst() && + (childInRequiredForm->getSecondChild()->getInt() == dataWidth)) + indexNode = childInRequiredForm->getFirstChild(); + } } - else - indexNode = childInRequiredForm; + + if (!indexNode) + { + if (!childInRequiredForm) + { + // We don't need to subtract the header size when we are using dataAddr pointer node + // because we already have a pointer to the first element in the array. + // For Reference see Walker.cpp:calculateElementAddressInContiguousArray + if (arrayBaseAddressNode->isDataAddrPointer()) + indexNode = offset; + else + { + TR::Node *constNode = TR::Node::create(node, type.isInt32() ? TR::iconst : TR::lconst, 0, 0); + indexNode = TR::Node::create(type.isInt32() ? TR::isub : TR::lsub, 2, offset, constNode); + if (type.isInt64()) + constNode->setLongInt((int64_t)headerSize); + else + constNode->setInt((int64_t)headerSize); + } + } + else + indexNode = childInRequiredForm; - indexNode = TR::Node::create(type.isInt32() ? TR::iushr : TR::lushr, 2, indexNode, - TR::Node::create(node, TR::iconst, 0, shiftWidth)); + indexNode = TR::Node::create(type.isInt32() ? TR::iushr : TR::lushr, 2, indexNode, + TR::Node::create(node, TR::iconst, 0, shiftWidth)); + } } - TR::Node *base = node->getFirstChild()->getFirstChild(); + TR::Node *base = arrayBaseAddressNode; + if (base->isDataAddrPointer()) + base = base->getFirstChild(); TR::Node *arrayLengthNode = TR::Node::create(TR::arraylength, 1, base); arrayLengthNode->setArrayStride(dataWidth); diff --git a/compiler/optimizer/VPHandlers.cpp b/compiler/optimizer/VPHandlers.cpp index bc8b4b8956c..0faa9a4ab62 100644 --- a/compiler/optimizer/VPHandlers.cpp +++ b/compiler/optimizer/VPHandlers.cpp @@ -1375,8 +1375,17 @@ TR::Node *constrainAnyIntLoad(OMR::ValuePropagation *vp, TR::Node *node) { TR::VPConstString *constString = baseVPConstraint->getClassType()->asConstString(); + // Get index from offset of a 2-byte element array uintptr_t offset = vp->comp()->target().is64Bit() ? (uintptr_t)index->getUnsignedLongInt() : (uintptr_t)index->getUnsignedInt(); - uintptr_t chIdx = (offset - (uintptr_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / 2; + uintptr_t chIdx = 0; + if (array->isDataAddrPointer()) + { + chIdx = (offset) / 2; + } + else + { + chIdx = (offset - (uintptr_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / 2; + } uint16_t ch = constString->charAt(static_cast(chIdx), vp->comp()); if (ch != 0) { @@ -2011,86 +2020,6 @@ static TR::Node *findArrayLengthNode(OMR::ValuePropagation *vp, TR::Node *node, return NULL; } - - -static TR::Node *findArrayIndexNode(OMR::ValuePropagation *vp, TR::Node *node, int32_t stride) - { - TR::Node *offset = node->getSecondChild(); - bool usingAladd = (vp->comp()->target().is64Bit() - ) ? - true : false; - - if (usingAladd) - { - int32_t constValue; - if ((offset->getOpCode().isAdd() || offset->getOpCode().isSub()) && - offset->getSecondChild()->getOpCode().isLoadConst()) - { - if (offset->getSecondChild()->getType().isInt64()) - constValue = (int32_t) offset->getSecondChild()->getLongInt(); - else - constValue = offset->getSecondChild()->getInt(); - } - - if ((offset->getOpCode().isAdd() && - (offset->getSecondChild()->getOpCode().isLoadConst() && - (constValue == TR::Compiler->om.contiguousArrayHeaderSizeInBytes()))) || - (offset->getOpCode().isSub() && - (offset->getSecondChild()->getOpCode().isLoadConst() && - (constValue == -(int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes())))) - { - TR::Node *offset2 = offset->getFirstChild(); - if (offset2->getOpCodeValue() == TR::lmul) - { - TR::Node *mulStride = offset2->getSecondChild(); - int32_t constValue; - if (mulStride->getOpCode().isLoadConst()) - { - if (mulStride->getType().isInt64()) - constValue = (int32_t) mulStride->getLongInt(); - else - constValue = mulStride->getInt(); - } - - if (mulStride->getOpCode().isLoadConst() && - constValue == stride) - { - if (offset2->getFirstChild()->getOpCodeValue() == TR::i2l) - return offset2->getFirstChild()->getFirstChild(); - else - return offset2->getFirstChild(); - } - } - else if (stride == 1) - return offset2; - } - } - else - { - if ((offset->getOpCode().isAdd() && - (offset->getSecondChild()->getOpCode().isLoadConst() && - (offset->getSecondChild()->getInt() == TR::Compiler->om.contiguousArrayHeaderSizeInBytes()))) || - (offset->getOpCode().isSub() && - (offset->getSecondChild()->getOpCode().isLoadConst() && - (offset->getSecondChild()->getInt() == -(int32_t)TR::Compiler->om.contiguousArrayHeaderSizeInBytes())))) - { - TR::Node *offset2 = offset->getFirstChild(); - if (offset2->getOpCodeValue() == TR::imul) - { - TR::Node *mulStride = offset2->getSecondChild(); - if (mulStride->getOpCode().isLoadConst() && - mulStride->getInt() == stride) - { - return offset2->getFirstChild(); - } - } - else if (stride == 1) - return offset2; - } - } - return NULL; - } - // For TR::aiadd and TR::aladd TR::Node *constrainAddressRef(OMR::ValuePropagation *vp, TR::Node *node) { @@ -2103,18 +2032,7 @@ TR::Node *constrainAddressRef(OMR::ValuePropagation *vp, TR::Node *node) parent->getOpCode().isStoreIndirect()) && (parent->getFirstChild() == node))) { - TR::Node *arrayLoad = node->getFirstChild(); - TR::Node *arraylengthNode = findArrayLengthNode(vp, arrayLoad, vp->getArraylengthNodes()); - TR::Node *indexNode = NULL; - if (arraylengthNode) - indexNode = findArrayIndexNode(vp, node, arraylengthNode->getArrayStride()); - - if (arraylengthNode && indexNode) - { - //TR::VPLessThanOrEqual *rel = TR::VPLessThanOrEqual::create(vp, -1); - //rel->setHasArtificialIncrement(); - //vp->addBlockConstraint(indexNode, rel, arraylengthNode, false); - } + // Possibly constraint indexNode with arraylength } return node;