void TR_LoadExtensions::flagPreferredLoadExtensions(TR::Node* parent) { if (isSupportedType(parent) && parent->getOpCode().isConversion()) { TR::Node* child = parent->getFirstChild(); bool canSkipConversion = false; if (isSupportedType(child)) { if (parent->getSize() == child->getSize()) { TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "codegen/LoadExtensions/success/unneededConversion/%s", comp()->signature())); parent->setUnneededConversion(true); } else { TR::ILOpCode& childOpCode = child->getOpCode(); if (childOpCode.isLoadReg() && !(parent->getSize() > 4 && TR::Compiler->target.is32Bit()) && excludedNodes->count(parent) == 0) { TR::Node* useRegLoad = child; TR_UseDefInfo* useDefInfo = optimizer()->getUseDefInfo(); if (useDefInfo != NULL && useDefInfo->infoIsValid() && useRegLoad->getUseDefIndex() != 0 && useDefInfo->isUseIndex(useRegLoad->getUseDefIndex() != 0)) { TR_UseDefInfo::BitVector info(comp()->allocator()); if (useDefInfo->getUseDef(info, useRegLoad->getUseDefIndex())) { TR_UseDefInfo::BitVector::Cursor cursor(info); int32_t firstDefIndex = useDefInfo->getFirstRealDefIndex(); int32_t firstUseIndex = useDefInfo->getFirstUseIndex(); canSkipConversion = true; bool forceExtensionOnAnyLoads = false; bool forceExtensionOnAllLoads = true; for (cursor.SetToFirstOne(); cursor.Valid() && canSkipConversion; cursor.SetToNextOne()) { int32_t defIndex = cursor; // We've examined all the defs of this particular use if (defIndex >= firstUseIndex) { break; } // Do not consider defs that correspond to method arguments as we cannot force extension on those if (defIndex < firstDefIndex) { continue; } TR::Node* defRegLoad = useDefInfo->getNode(defIndex); if (defRegLoad != NULL) { TR::Node* defRegLoadChild = defRegLoad->getFirstChild(); bool forceExtension = false; canSkipConversion = TR_LoadExtensions::canSkipConversion(parent, defRegLoadChild, forceExtension); forceExtensionOnAnyLoads |= forceExtension; forceExtensionOnAllLoads &= forceExtension; // If we have to force extension on any loads which feed a def of this use ensure we must also // force extension on all such loads. Conversely the conversion can be skipped if none of the // loads feeding the def of this use need to be extended. This ensures either all loads feeding // into defs of this use should be extended or none of them. canSkipConversion &= forceExtensionOnAllLoads == forceExtensionOnAnyLoads; if (trace()) { traceMsg(comp(), "\t\tPeeked through %s [%p] and found %s [%p] with child %s [%p] - conversion %s be skipped\n", useRegLoad->getOpCode().getName(), useRegLoad, defRegLoad->getOpCode().getName(), defRegLoad, defRegLoadChild->getOpCode().getName(), defRegLoadChild, canSkipConversion ? "can" : "cannot"); } } } if (canSkipConversion && performTransformation(comp(), "%sSkipping conversion %s [%p] after RegLoad\n", optDetailString(), parent->getOpCode().getName(), parent)) { TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "codegen/LoadExtensions/success/unneededConversion/GRA/%s", comp()->signature())); parent->setUnneededConversion(true); if (forceExtensionOnAllLoads) { TR_UseDefInfo::BitVector info(comp()->allocator()); if (useDefInfo->getUseDef(info, useRegLoad->getUseDefIndex())) { TR_UseDefInfo::BitVector::Cursor cursor(info); for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne()) { int32_t defIndex = cursor; // We've examined all the defs of this particular use if (defIndex >= firstUseIndex) { break; } // Do not consider defs that correspond to method arguments as we cannot force extension on those if (defIndex < firstDefIndex) { continue; } TR::Node *defRegLoad = useDefInfo->getNode(defIndex); if (defRegLoad != NULL) { TR::Node* defRegLoadChild = defRegLoad->getFirstChild(); const int32_t preference = getExtensionPreference(defRegLoadChild); if (preference > 0) { if (trace()) { traceMsg(comp(), "\t\t\tForcing sign extension on %s [%p]\n", defRegLoadChild->getOpCode().getName(), defRegLoadChild); } if (parent->getSize() == 8 || parent->useSignExtensionMode()) { defRegLoadChild->setSignExtendTo64BitAtSource(true); } else { defRegLoadChild->setSignExtendTo32BitAtSource(true); } } if (preference < 0) { if (trace()) { traceMsg(comp(), "\t\t\tForcing zero extension on %s [%p]\n", defRegLoadChild->getOpCode().getName(), defRegLoadChild); } if (parent->getSize() == 8 || parent->useSignExtensionMode()) { defRegLoadChild->setZeroExtendTo64BitAtSource(true); } else { defRegLoadChild->setZeroExtendTo32BitAtSource(true); } } } } } } if (parent->getType().isInt64() && parent->getSize() > child->getSize()) { if (trace()) { traceMsg(comp(), "\t\t\tSet global register %s in getExtendedToInt64GlobalRegisters for child %s [%p] with parent node %s [%p]\n", comp()->getDebug()->getGlobalRegisterName(child->getGlobalRegisterNumber()), child->getOpCode().getName(), child, parent->getOpCode().getName(), parent); } // getExtendedToInt64GlobalRegisters is used by the evaluators to force a larger virtual register to be used when // evaluating the regload so any instructions generated by local RA are the correct size to preserve the upper bits cg()->getExtendedToInt64GlobalRegisters()[child->getGlobalRegisterNumber()] = true; } } } } } } } if (!canSkipConversion) { bool forceExtension = false; canSkipConversion = TR_LoadExtensions::canSkipConversion(parent, child, forceExtension); if (canSkipConversion && performTransformation(comp(), "%sSkipping conversion %s [%p]\n", optDetailString(), parent->getOpCode().getName(), parent)) { TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "codegen/LoadExtensions/success/unneededConversion/%s", comp()->signature())); parent->setUnneededConversion(true); if (forceExtension) { const int32_t preference = getExtensionPreference(child); if (preference > 0) { if (trace()) { traceMsg(comp(), "\t\t\tForcing sign extension on %s [%p]\n", child->getOpCode().getName(), child); } if (parent->getSize() == 8 || parent->useSignExtensionMode()) { child->setSignExtendTo64BitAtSource(true); } else { child->setSignExtendTo32BitAtSource(true); } } if (preference < 0) { if (trace()) { traceMsg(comp(), "\t\t\tForcing zero extension on %s [%p]\n", child->getOpCode().getName(), child); } if (parent->getSize() == 8 || parent->useSignExtensionMode()) { child->setZeroExtendTo64BitAtSource(true); } else { child->setZeroExtendTo32BitAtSource(true); } } } } } } }
void TR_LoadExtensions::findPreferredLoadExtensions(TR::Node* parent) { TR::ILOpCode& parentOpCode = parent->getOpCode(); // count how a load is being used. As a signed or unsigned number? if (isSupportedType(parent) && parentOpCode.isConversion()) { TR::Node* child = parent->getFirstChild(); // Only examine non-trivial conversions if (isSupportedType(child) && parent->getSize() != child->getSize()) { if (isSupportedLoad(child)) { setExtensionPreference(child, parent); } else if (child->getOpCode().isLoadReg()) { TR::Node* useRegLoad = child; TR_UseDefInfo* useDefInfo = optimizer()->getUseDefInfo(); // If we have usedef info we can traverse all defs of this particular use and if all the defs are stores // of supported counted loads then we can count such loads as well. If this criteria is not met then there // exists at least one def (store) of this particular use which feeds from a non-load operation (an // addition for example). These are not candidates for skipping extension because we cannot easily extend // a non-load operation. if (useDefInfo != NULL && useDefInfo->infoIsValid() && useRegLoad->getUseDefIndex() != 0 && useDefInfo->isUseIndex(useRegLoad->getUseDefIndex() != 0)) { TR_UseDefInfo::BitVector info(comp()->allocator()); if (useDefInfo->getUseDef(info, useRegLoad->getUseDefIndex())) { if (trace()) { traceMsg(comp(), "\t\tPeeking through RegLoad %p for conversion %s [%p]\n", useRegLoad, parentOpCode.getName(), parent); } TR_UseDefInfo::BitVector::Cursor cursor(info); int32_t firstDefIndex = useDefInfo->getFirstRealDefIndex(); int32_t firstUseIndex = useDefInfo->getFirstUseIndex(); for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne()) { int32_t defIndex = cursor; // We've examined all the defs of this particular use if (defIndex >= firstUseIndex) { break; } // Do not consider defs that correspond to method arguments as we cannot force extension on those if (defIndex < firstDefIndex) { (*excludedNodes)[parent] = true; break; } TR::Node* defRegLoad = useDefInfo->getNode(defIndex); if (defRegLoad != NULL) { TR::Node* defRegLoadChild = defRegLoad->getFirstChild(); if (defRegLoad->getOpCode().isStoreReg() && isSupportedType(defRegLoadChild) && isSupportedLoad(defRegLoadChild)) { if (trace()) { traceMsg(comp(), "\t\tPeeked through use %s [%p] and found def %s [%p] with child %s [%p] - Counting [%p]\n", useRegLoad->getOpCode().getName(), useRegLoad, defRegLoad->getOpCode().getName(), defRegLoad, defRegLoadChild->getOpCode().getName(), defRegLoadChild, defRegLoadChild); } setExtensionPreference(defRegLoadChild, parent); } else { if (trace()) { traceMsg(comp(), "\t\tPeeked through use %s [%p] and found def %s [%p] with child %s [%p] - Excluding [%p]\n", useRegLoad->getOpCode().getName(), useRegLoad, defRegLoad->getOpCode().getName(), defRegLoad, defRegLoadChild != NULL ? defRegLoadChild->getOpCode().getName() : "NULL", defRegLoadChild, parent); } (*excludedNodes)[parent] = true; } } } } } else { (*excludedNodes)[parent] = true; } } } } // Exclude all loads which feed into global register stores which require sign extensions. This must be done // because Load Extensions is a local optimization and it must respect global sign extension decisions made // by GRA. Excluding such loads prevents a situation where GRA decided that a particular global register // should be sign extended at its definitions however Load Extensions has determined that the same load // should be zero extended. If local RA were to pick the same register for the global register as well as // the load then we have a conflicting decision which will result in a conversion to be skipped when it is // not supposed to be. if (parentOpCode.isStoreReg() && parent->needsSignExtension() && parent->getFirstChild()->getOpCode().isLoadVar()) { (*excludedNodes)[parent->getFirstChild()] = true; } }