/*******************************************************************************
 * Copyright IBM Corp. and others 2000
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution
 * and is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception [1] and GNU General Public
 * License, version 2 with the OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#ifndef FIELDPRIV_INCL
#define FIELDPRIV_INCL

#include <stdint.h>
#include "env/TRMemory.hpp"
#include "il/Node.hpp"
#include "il/SymbolReference.hpp"
#include "infra/HashTab.hpp"
#include "infra/List.hpp"
#include "optimizer/OptimizationManager.hpp"
#include "optimizer/IsolatedStoreElimination.hpp"
#include "optimizer/LoopCanonicalizer.hpp"

class TR_BitVector;
class TR_OpaqueClassBlock;
class TR_PostDominators;

namespace TR {
class RegisterCandidate;
}
class TR_Structure;
class TR_ValueNumberInfo;

namespace TR {
class Block;
class Optimization;
class TreeTop;
} // namespace TR

/*
 * Class TR_FieldPrivatizer
 * ========================
 *
 * Field privatizer aims to replace accesses to fields and statics inside loops
 * with accesses of new temps that it creates (allowing the loop to run faster
 * since the temp is an access from the stack, plus the temp gets to be a
 * candidate for global register allocation whereas the original field or static
 * would not be).

 * Field privatizer would attempt to replace loads as well as stores of fields
 * and statics and so if there are calls inside the loop or any other implicit
 * use points for the original field or static (e.g. an exception check,
 * that could fail and reach an exception handler that uses the field or static)
 * then the transformation cannot be done (since omitting stores to the field
 * or static inside the loop may change program behaviour at those use points
 * inside the loop). Assuming field privatizer finds a field or static without
 * any potential use inside the loop and subject to certain other conditions it
 * checks to keep the implementation simple, the transformation is to
 *
 * a) initialize the new temp it creates with the field or static value in
 * the loop preheader
 * b) change every load and store of the field or static inside the loop to
 * use the new temp
 * c) restore the field or static value on all exits out of the loop by using
 * the temp value on exit from the loop
 *
 * This optimization differs from what PRE (a form of load elimination as
 * part of the global commoning it does) may do in the same loop in that
 * field privatizer eliminates stores as well as loads, whereas PRE could
 * only have eliminated the loads of the field or static; PRE would not omit
 * the store to the field or static.
 *
 * As a very simple example...
 *
 * Original loop
 *
 * while (o.f < n)
 * o.f = o.f + 1;
 *
 * Field Privatizer optimized loop
 *
 * t = o.f;
 * while (t < n)
 * t = t + 1;
 * o.f = t;
 *
 * PRE optimized loop
 *
 * t = o.f;
 * while (t < n)
 * {
 * o.f = t + 1;
 * t = t + 1;
 * }
 *
 * So, what PRE would do to the loop is somewhat similar but still less powerful;
 * however PRE can do such optimizations even outside of loops and more importantly
 * can do exactly the same thing even if there were implicit uses of o.f inside
 * the loop. So it's more general in that sense.
 */

class TR_FieldPrivatizer : public TR_LoopTransformer {
    class TR_RemovedNode {
    public:
        TR_RemovedNode(TR::Node *storeNode, TR::Node *removedSign)
            : _storeNode(storeNode)
            , _removedSign(removedSign)
        {}

        TR::Node *_storeNode;
        TR::Node *_removedSign;
    };

public:
    TR_FieldPrivatizer(TR::OptimizationManager *manager);

    static TR::Optimization *create(TR::OptimizationManager *manager)
    {
        return new (manager->allocator()) TR_FieldPrivatizer(manager);
    }

    virtual int32_t perform();
    virtual const char *optDetailString() const throw();

    virtual int32_t detectCanonicalizedPredictableLoops(TR_Structure *, TR_BitVector **, int32_t);
    bool storesBackMustBePlacedInExitBlock(TR::Block *, TR::Block *, TR_BitVector *);
    void placeStoresBackInExits(List<TR::Block> *, List<TR::Block> *);
    void placeStoresBackInExit(TR::Block *, bool);
    void placeInitializersInLoopInvariantBlock(TR::Block *);
    bool subtreeIsInvariantInLoop(TR::Node *);
    bool bothSubtreesMatch(TR::Node *, TR::Node *);
    TR::SymbolReference *getPrivatizedFieldAutoSymRef(TR::Node *);
    void privatizeFields(TR::Node *, bool, vcount_t);
    void privatizeNonEscapingLoop(TR_Structure *, TR::Block *, vcount_t);
    void detectFieldsThatCannotBePrivatized(TR::Node *, vcount_t);
    void detectFieldsThatCannotBePrivatized(TR_Structure *, vcount_t);
    bool canPrivatizeFieldSymRef(TR::Node *);

    /**
     * Checks whether \c currentNode represents a \ref TR::instanceof
     * operation or whether any of its subtrees do.
     *
     * @param currentNode the node to check
     * @return \c true if the subtree contains a \c TR::instanceof
     * operation; \c false, otherwise.
     */
    bool subtreeHasSpecialCondition(TR::Node *currentNode);
    bool containsEscapePoints(TR_Structure *, bool &);
    void addPrivatizedRegisterCandidates(TR_Structure *);
    bool isStringPeephole(TR::Node *, TR::TreeTop *);
    void cleanupStringPeephole();
    void placeStringEpiloguesBackInExit(TR::Block *, bool);
    void placeStringEpilogueInExits(List<TR::Block> *, List<TR::Block> *);
    void addStringInitialization(TR::Block *);
    bool isFieldAliasAccessed(TR::SymbolReference *symRef);

    TR_BitVector *_privatizedFields, *_fieldsThatCannotBePrivatized;
    TR_BitVector *_needToStoreBack;
    List<TR::Node> _privatizedFieldNodes;
    TR_HashTabInt _privatizedFieldSymRefs;
    List<TR::RegisterCandidate> _privatizedRegCandidates;
    TR::Block *_criticalEdgeBlock;
    TR::SymbolReference *_stringSymRef, *_valueOfSymRef, *_tempStringSymRef, *_appendSymRef, *_toStringSymRef,
        *_initSymRef;
    TR::TreeTop *_stringPeepholeTree;
    TR_OpaqueClassBlock *_stringBufferClass;
    TR_Structure *_currLoopStructure;
    int32_t _counter;
    List<TR::TreeTop> _appendCalls;

    TR_PostDominators *_postDominators;

    /**
     * Tracks whether the subtree rooted at a node has been
     * checked via a call to \ref subtreeHasSpecialCondition(TR::Node*)
     * to see whether it contains any "special conditions".
     *
     * If this checklist does not contain the node, that
     * method must be called to perform the checking;
     * if it does contain the node, the node is present in
     * \ref _subtreeHasSpecialCondition if and only if the
     * subtree rooted at the node contains any of those special
     * conditions.
     */
    TR::NodeChecklist _subtreeCheckedForSpecialConditions;

    /**
     * Tracks whether a node or one or its subtrees performs a
     * \ref TR::instanceof operation or a comparison to \c null.
     */
    TR::NodeChecklist _subtreeHasSpecialCondition;
};

#endif
