Path: blob/master/runtime/compiler/z/codegen/InMemoryLoadStoreMarking.cpp
6004 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "codegen/InMemoryLoadStoreMarking.hpp"2324#include <stddef.h>25#include <stdint.h>26#include <string.h>27#include "env/FrontEnd.hpp"28#include "compile/Compilation.hpp"29#include "control/Options.hpp"30#include "control/Options_inlines.hpp"31#include "env/VMJ9.h"32#include "il/AliasSetInterface.hpp"33#include "il/Block.hpp"34#include "il/DataTypes.hpp"35#include "il/ILOpCodes.hpp"36#include "il/ILOps.hpp"37#include "il/MethodSymbol.hpp"38#include "il/Node.hpp"39#include "il/Node_inlines.hpp"40#include "il/Symbol.hpp"41#include "il/SymbolReference.hpp"42#include "il/TreeTop.hpp"43#include "il/TreeTop_inlines.hpp"44#include "infra/Assert.hpp"45#include "infra/Bit.hpp"464748#define OPT_DETAILS "O^O IN MEMORY LOAD/STORE MARKING: "4950void InMemoryLoadStoreMarking::perform()51{5253LexicalTimer pt1("InMemoryLoadStoreMarking", comp()->phaseTimer());5455vcount_t visitCount = comp()->incOrResetVisitCount();5657clearAllLists();5859TR::Block *block = NULL;60for (TR::TreeTop *tt = comp()->getStartTree(); tt; tt = tt->getNextTreeTop())61{62TR::Node* node = tt->getNode();6364TR_ASSERT(node->getVisitCount() != visitCount, "Code Gen: error in lowering trees");65TR_ASSERT(node->getReferenceCount() == 0, "Code Gen: error in lowering trees");6667if (node->getOpCodeValue() == TR::BBStart)68{69block = node->getBlock();70if (!block->isExtensionOfPreviousBlock())71{72if (cg->traceBCDCodeGen())73traceMsg(comp(),"block_%d is a new extension so clear all load and store lists\n",block->getNumber());74clearAllLists();75}76}7778// depth first search on children to populate the commoned nodes lists79visitChildren(node, tt, visitCount);8081// after descending to look at the children (and add to the lists) now see if the current treetop82// is a possible def and any nodes have to be removed from the lists83handleDef(node, tt);84}85}8687void InMemoryLoadStoreMarking::visitChildren(TR::Node *parent, TR::TreeTop *tt, vcount_t visitCount)88{89parent->setVisitCount(visitCount);9091if (parent->getOpCode().isBinaryCodedDecimalOp())92cg->setMethodContainsBinaryCodedDecimal();9394if (parent->getOpCode().isBinaryCodedDecimalOp())95{96cg->setAddStorageReferenceHints();97}9899for (int32_t childCount = 0; childCount < parent->getNumChildren(); childCount++)100{101TR::Node *child = parent->getChild(childCount);102refineConditionalCleanLoadList(child, parent);103if (child->getVisitCount() != visitCount)104{105visitChildren(child, tt, visitCount);106examineFirstReference(child, tt);107}108else109{110examineCommonedReference(child, parent, tt);111}112}113}114115void InMemoryLoadStoreMarking::refineConditionalCleanLoadList(TR::Node *child, TR::Node *parent)116{117if (!child->getOpCode().isBCDLoadVar())118return;119if (_BCDConditionalCleanLoadList.find(child))120{121if (cg->traceBCDCodeGen())122traceMsg(comp(),"found %s (%p) in condCleanLoadList : examine parent %s (%p) to see if it relies on clean sign\n",123child->getOpCode().getName(),child,parent->getOpCode().getName(),parent);124if (cg->reliesOnAParticularSignEncoding(parent))125{126if (cg->traceBCDCodeGen())127traceMsg(comp(),"\tz^z : parent %s (%p) does rely on a clean sign so remove child %s (%p) from condCleanLoadList\n",128parent->getOpCode().getName(),parent,child->getOpCode().getName(),child);129_BCDConditionalCleanLoadList.remove(child);130}131else132{133if (cg->traceBCDCodeGen())134traceMsg(comp(),"\tparent %s (%p) does not rely on a clean sign so do not remove child %s (%p) from condCleanLoadList\n",135parent->getOpCode().getName(),parent,child->getOpCode().getName(),child);136}137}138}139140void InMemoryLoadStoreMarking::examineFirstReference(TR::Node *node, TR::TreeTop* tt) // called the first time 'node' is encountered141{142if ((node->getType().isAggregate() || node->getType().isBCD()) &&143node->getReferenceCount() > 1)144{145if (tt->getNode()->getOpCode().isBCDStore() &&146tt->getNode()->getValueChild() == node)147{148if (cg->traceBCDCodeGen())149traceMsg(comp(),"store first encounter: %s (%p) under %s (%p), add store to list and set node futureUseCount %d\n",150node->getOpCode().getName(),node,tt->getNode()->getOpCode().getName(),tt->getNode(),node->getReferenceCount()-1);151node->setFutureUseCount(node->getReferenceCount()-1);152_BCDAggrStoreList.add(tt->getNode());153}154// in cases like:155// pdstore <- tt->getNode()156// pdload <- node157// the pdstore is added the _BCDAggrStoreList and the node is added to the _BCDAggrLoadList and the node futureUseCount is set twice but to the same value158if (node->getOpCode().isBCDLoadVar())159{160if (cg->traceBCDCodeGen())161traceMsg(comp(),"load var first encounter: %s (%p), add load to list and set node futureUseCount %d\n",node->getOpCode().getName(),node,node->getReferenceCount()-1);162node->setFutureUseCount(node->getReferenceCount()-1);163_BCDAggrLoadList.add(node);164}165}166}167168void InMemoryLoadStoreMarking::handleLoadLastReference(TR::Node *node, List<TR::Node> &nodeList, TR_NodeListTypes listType)169{170bool isLastReferenceInList = node->getOpCode().isBCDLoadVar() && nodeList.find(node);171172if (isLastReferenceInList &&173performTransformation(comp(),"%ssetSkipCopyOnLoad to true on %s (0x%p) and remove from %s\n",OPT_DETAILS,node->getOpCode().getName(),node,getName(listType)))174{175node->setSkipCopyOnLoad(true);176nodeList.remove(node);177}178179if (isLastReferenceInList &&180listType == ConditionalCleanLoadList &&181node->hasSignStateOnLoad() &&182performTransformation(comp(),"%ssetHasSignStateOnLoad to false on %s (0x%p) for node in %s\n",OPT_DETAILS,node->getOpCode().getName(),node,getName(listType)))183{184// if every reference does not rely on the sign state then it is safe to consider that the load has no sign state on the load (as all parent will not care about a particular sign)185node->setHasSignStateOnLoad(false);186}187}188189void InMemoryLoadStoreMarking::examineCommonedReference(TR::Node *child, TR::Node *parent, TR::TreeTop *tt)190{191if (!child->getType().isBCD())192return;193int32_t isLastReference = child->decFutureUseCount() == 0;194if (cg->traceBCDCodeGen())195traceMsg(comp(),"looking at commoned reference to %s (%p) with parent %s (%p) and tt %s (%p) (isLastReference %s)\n",196child->getOpCode().getName(),child,197parent?parent->getOpCode().getName():"NULL",parent,198tt?tt->getNode()->getOpCode().getName():"NULL",tt?tt->getNode():0,199isLastReference?"yes":"no");200201if (!isLastReference)202return;203204if (child->getType().isBCD() && !_BCDAggrStoreList.isEmpty())205{206ListIterator<TR::Node> listIt(&_BCDAggrStoreList);207for (TR::Node *store=listIt.getFirst(); store; store = listIt.getNext())208{209if (isLastReference &&210store->getValueChild() == child &&211performTransformation(comp(),"%ssetSkipCopyOnStore to true on %s (0x%p) and remove from list for last commoned ref to valueChild %s (0x%p)\n",212OPT_DETAILS,store->getOpCode().getName(),store,child->getOpCode().getName(),child))213{214store->setSkipCopyOnStore(true);215_BCDAggrStoreList.remove(store);216}217}218}219220if (isLastReference)221{222handleLoadLastReference(child, _BCDAggrLoadList, LoadList);223handleLoadLastReference(child, _BCDConditionalCleanLoadList, ConditionalCleanLoadList);224}225}226227bool InMemoryLoadStoreMarking::allListsAreEmpty()228{229if (_BCDAggrLoadList.isEmpty() &&230_BCDAggrStoreList.isEmpty() &&231_BCDConditionalCleanLoadList.isEmpty())232{233return true;234}235else236{237return false;238}239}240241void InMemoryLoadStoreMarking::handleDef(TR::Node* node, TR::TreeTop* tt)242{243if (!allListsAreEmpty())244{245if (tt->isPossibleDef())246{247TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());248TR::Node *defNode = tt->getNode()->getOpCodeValue() == TR::treetop ? tt->getNode()->getFirstChild() : tt->getNode();249processBCDAggrNodeList(_BCDAggrLoadList, defNode, LoadList);250processBCDAggrNodeList(_BCDConditionalCleanLoadList, defNode, ConditionalCleanLoadList);251processBCDAggrNodeList(_BCDAggrStoreList, defNode, StoreList);252}253}254}255256bool InMemoryLoadStoreMarking::isConditionalCleanLoad(TR::Node *listNode, TR::Node *defNode)257{258if (defNode->getOpCode().isBCDStore() &&259defNode->chkCleanSignInPDStoreEvaluator() &&260listNode->getOpCode().isBCDLoadVar() &&261defNode->getValueChild() == listNode &&262defNode->getDecimalPrecision() == listNode->getDecimalPrecision() &&263cg->loadOrStoreAddressesMatch(defNode, listNode))264{265//266// pdstore "a" clean267// pdload "a"268//269// =>pdload "a"270//271// In this case, if all the parents of pdload "a" do not rely on the sign being clean then this exact store from "a" to "a" does not272// have to be considered a kill and the skipCopyOnLoad flag can still be set.273// The listNode will be added to the _BCDConditionalCleanLoadList so all subsequent references have their parents checked (for not relying on the clean sign).274//275// The _BCDConditionalCleanLoadList also must be checked for other possible kills as with the regular _BCDAggrLoadList276// The caller is removing listNode from _BCDAggrLoadList so a particular listNode will only be in one of (or neither of) _BCDConditionalCleanLoadList and _BCDAggrLoadList277if (cg->traceBCDCodeGen())278traceMsg(comp(),"\t\tfound conditional clean listNode %s (%p) under %s (%p) : do not consider a def but add to condCleanLoadList if not already present\n",279listNode->getOpCode().getName(),listNode,defNode->getOpCode().getName(),defNode);280return true;281}282return false;283}284285void InMemoryLoadStoreMarking::addToConditionalCleanLoadList(TR::Node *listNode)286{287if (_BCDConditionalCleanLoadList.find(listNode))288{289// This condition may be hit if the commoned load is present under two or more different stores to the same location that also clean:290// pdstore "a" clean291// pdload "a"292//293// pdstore "a" clean294// =>pdload "a" <-- will already be in list at this point295//296if (cg->traceBCDCodeGen())297traceMsg(comp(),"\t\tlistNode %s (%p) already present in condCleanLoadList : do not add again\n",298listNode->getOpCode().getName(),listNode);299}300else301{302if (cg->traceBCDCodeGen())303traceMsg(comp(),"\t\tlistNode %s (%p) not already present in condCleanLoadList : add to list\n",304listNode->getOpCode().getName(),listNode);305_BCDConditionalCleanLoadList.add(listNode);306}307}308309void InMemoryLoadStoreMarking::processBCDAggrNodeList(List<TR::Node> &nodeList, TR::Node *defNode, TR_NodeListTypes listType)310{311if (!nodeList.isEmpty())312{313if (cg->traceBCDCodeGen())314traceMsg(comp(),"\titerate through non-empty %s\n",getName(listType));315bool isRegularLoadList = (listType == LoadList);316bool isConditionalCleanLoadList = (listType == ConditionalCleanLoadList);317bool isAnyTypeOfLoadList = (isRegularLoadList || isConditionalCleanLoadList);318ListIterator<TR::Node> listIt(&nodeList);319for (TR::Node *listNode=listIt.getFirst(); listNode; listNode = listIt.getNext())320{321TR_ASSERT((isAnyTypeOfLoadList && listNode->getOpCode().isBCDLoadVar()) || listNode->getOpCode().isBCDStore(),322"only bcd/aggr loadVars or stores should be in the list (%s (%p))\n",listNode->getOpCode().getName(),listNode);323if (isAnyTypeOfLoadList ||324listNode != defNode) // skip the current store treetop node325{326bool defNodeHasSymRef = defNode->getOpCode().hasSymbolReference() && defNode->getSymbolReference();327if (cg->traceBCDCodeGen())328traceMsg(comp(),"\t\tintersect defNode %s (%p) #%d aliases with listNode %s (%p) #%d\n",329defNode->getOpCode().getName(),defNode,defNodeHasSymRef ? defNode->getSymbolReference()->getReferenceNumber() : -1,330listNode->getOpCode().getName(),listNode,listNode->getSymbolReference()->getReferenceNumber());331332if (!defNodeHasSymRef || defNode->getSymbolReference()->getUseDefAliases().contains(listNode->getSymbolReference(), comp()))333{334if (isAnyTypeOfLoadList)335{336// There are two possible list types (condClean and regular load list) that can reach here and two conditions (clean or not clean) so expressing 4 states as a table337//338// | _BCDConditionalCleanLoadList (cleanList) | _BCDAggrLoadList (regList)339//---------------------------|---------------------------------------------|---------------------------------340// isConditionalCleanLoad | 1) add listNode to cleanList | 1) add listNode to cleanList341// | | 2) remove listNode from regList342// --------------------------|---------------------------------------------|----------------------------------343// !isConditionalCleanLoad | 1) remove listNode from cleanList | 1) remove listNode from regList344//345346// first check if we are able to place listNode in the conditional load list vs more conservatively just marking setSkipCopyOnLoad to false347if (isConditionalCleanLoad(listNode, defNode))348{349addToConditionalCleanLoadList(listNode);350if (isRegularLoadList)351{352if (cg->traceBCDCodeGen())353traceMsg(comp(),"\t\t\tremove listNode %s (%p) from regular load list\n",listNode->getOpCode().getName(),listNode);354nodeList.remove(listNode);355}356}357else358{359// this path may either be removing a load from the regular or conditional load list (in the latter case when some other type of def is possibly seen)360if (cg->traceBCDCodeGen())361traceMsg(comp(),"\t\t\tfound an intersection so remove listNode %s (%p) from %s and set setSkipCopyOnLoad flag to false (defNodeHasSymRef=%s)\n",362listNode->getOpCode().getName(),listNode,getName(listType),defNodeHasSymRef?"yes":"no");363listNode->setSkipCopyOnLoad(false);364nodeList.remove(listNode);365}366}367else368{369if (cg->traceBCDCodeGen())370traceMsg(comp(),"\t\t\tfound an intersection so remove listNode %s (%p) from %s and set setSkipCopyOnStore flag to false (defNodeHasSymRef=%s)\n",371listNode->getOpCode().getName(),listNode,getName(listType),defNodeHasSymRef?"yes":"no");372TR_ASSERT(listType == StoreList,"expecting StoreList for listNode %s (%p)\n",listNode->getOpCode().getName(),listNode);373listNode->setSkipCopyOnStore(false);374nodeList.remove(listNode);375}376}377}378else if (cg->traceBCDCodeGen())379{380traceMsg(comp(),"\t\tskipping current store treetop listNode %s (%p)\n",listNode->getOpCode().getName(),listNode);381}382}383}384}385386void InMemoryLoadStoreMarking::clearAllLists()387{388clearLoadLists();389_BCDAggrStoreList.deleteAll();390}391392void InMemoryLoadStoreMarking::clearLoadLists()393{394_BCDAggrLoadList.deleteAll();395_BCDConditionalCleanLoadList.deleteAll();396}397398char *InMemoryLoadStoreMarking::_TR_NodeListTypeNames[NodeList_NumTypes] =399{400"LoadList",401"ConditionalCleanLoadList",402"StoreList"403};404405406