/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_COMPILER_DEX_POST_OPT_PASSES_H_
#define ART_COMPILER_DEX_POST_OPT_PASSES_H_
#include "base/casts.h"
#include "base/logging.h"
#include "compiler_ir.h"
#include "dex_flags.h"
#include "mir_graph.h"
#include "pass_me.h"
namespace art {
/**
* @class PassMEMirSsaRep
* @brief Convenience class for passes that check MIRGraph::MirSsaRepUpToDate().
*/
class PassMEMirSsaRep : public PassME {
public:
PassMEMirSsaRep(const char* name, DataFlowAnalysisMode type = kAllNodes)
: PassME(name, type) {
}
bool Gate(const PassDataHolder* data) const OVERRIDE {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
return !c_unit->mir_graph->MirSsaRepUpToDate();
}
};
/**
* @class InitializeSSATransformation
* @brief There is some data that needs to be initialized before performing
* the post optimization passes.
*/
class InitializeSSATransformation : public PassMEMirSsaRep {
public:
InitializeSSATransformation() : PassMEMirSsaRep("InitializeSSATransformation", kNoNodes) {
}
void Start(PassDataHolder* data) const {
// New blocks may have been inserted so the first thing we do is ensure that
// the c_unit's number of blocks matches the actual count of basic blocks.
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph->SSATransformationStart();
c_unit->mir_graph->CompilerInitializeSSAConversion();
}
};
/**
* @class ClearPhiInformation
* @brief Clear the PHI nodes from the CFG.
*/
class ClearPhiInstructions : public PassMEMirSsaRep {
public:
ClearPhiInstructions() : PassMEMirSsaRep("ClearPhiInstructions") {
}
bool Worker(PassDataHolder* data) const;
};
/**
* @class CalculatePredecessors
* @brief Calculate the predecessor BitVector of each Basicblock.
*/
class CalculatePredecessors : public PassME {
public:
CalculatePredecessors() : PassME("CalculatePredecessors", kNoNodes) {
}
void Start(PassDataHolder* data) const;
};
/**
* @class DFSOrders
* @brief Compute the DFS order of the MIR graph
*/
class DFSOrders : public PassME {
public:
DFSOrders() : PassME("DFSOrders", kNoNodes) {
}
bool Gate(const PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
return !c_unit->mir_graph->DfsOrdersUpToDate();
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->ComputeDFSOrders();
}
};
/**
* @class BuildDomination
* @brief Build the domination information of the MIR Graph
*/
class BuildDomination : public PassME {
public:
BuildDomination() : PassME("BuildDomination", kNoNodes) {
}
bool Gate(const PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
return !c_unit->mir_graph->DominationUpToDate();
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph->ComputeDominators();
}
void End(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
// Verify the dataflow information after the pass.
if (c_unit->enable_debug & (1 << kDebugVerifyDataflow)) {
c_unit->mir_graph->VerifyDataflow();
}
}
};
/**
* @class TopologicalSortOrders
* @brief Compute the topological sort order of the MIR graph
*/
class TopologicalSortOrders : public PassME {
public:
TopologicalSortOrders() : PassME("TopologicalSortOrders", kNoNodes) {
}
bool Gate(const PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
return !c_unit->mir_graph->TopologicalOrderUpToDate();
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->ComputeTopologicalSortOrder();
}
};
/**
* @class DefBlockMatrix
* @brief Calculate the matrix of definition per basic block
*/
class DefBlockMatrix : public PassMEMirSsaRep {
public:
DefBlockMatrix() : PassMEMirSsaRep("DefBlockMatrix", kNoNodes) {
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->ComputeDefBlockMatrix();
}
};
/**
* @class FindPhiNodeBlocksPass
* @brief Pass to find out where we need to insert the phi nodes for the SSA conversion.
*/
class FindPhiNodeBlocksPass : public PassMEMirSsaRep {
public:
FindPhiNodeBlocksPass() : PassMEMirSsaRep("FindPhiNodeBlocks", kNoNodes) {
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->FindPhiNodeBlocks();
}
};
/**
* @class SSAConversion
* @brief Pass for SSA conversion of MIRs
*/
class SSAConversion : public PassMEMirSsaRep {
public:
SSAConversion() : PassMEMirSsaRep("SSAConversion", kNoNodes) {
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
MIRGraph *mir_graph = c_unit->mir_graph.get();
mir_graph->ClearAllVisitedFlags();
mir_graph->DoDFSPreOrderSSARename(mir_graph->GetEntryBlock());
}
};
/**
* @class PhiNodeOperands
* @brief Pass to insert the Phi node operands to basic blocks
*/
class PhiNodeOperands : public PassMEMirSsaRep {
public:
PhiNodeOperands() : PassMEMirSsaRep("PhiNodeOperands", kPreOrderDFSTraversal) {
}
bool Worker(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
BasicBlock* bb = down_cast<PassMEDataHolder*>(data)->bb;
DCHECK(bb != nullptr);
c_unit->mir_graph->InsertPhiNodeOperands(bb);
// No need of repeating, so just return false.
return false;
}
};
/**
* @class InitRegLocations
* @brief Initialize Register Locations.
*/
class PerformInitRegLocations : public PassMEMirSsaRep {
public:
PerformInitRegLocations() : PassMEMirSsaRep("PerformInitRegLocation", kNoNodes) {
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph->InitRegLocations();
}
};
/**
* @class TypeInferencePass
* @brief Type inference pass.
*/
class TypeInferencePass : public PassMEMirSsaRep {
public:
TypeInferencePass() : PassMEMirSsaRep("TypeInference", kRepeatingPreOrderDFSTraversal) {
}
void Start(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph->InferTypesStart();
}
bool Worker(PassDataHolder* data) const {
DCHECK(data != nullptr);
PassMEDataHolder* pass_me_data_holder = down_cast<PassMEDataHolder*>(data);
CompilationUnit* c_unit = pass_me_data_holder->c_unit;
DCHECK(c_unit != nullptr);
BasicBlock* bb = pass_me_data_holder->bb;
DCHECK(bb != nullptr);
return c_unit->mir_graph->InferTypes(bb);
}
void End(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->InferTypesEnd();
}
};
/**
* @class FinishSSATransformation
* @brief There is some data that needs to be freed after performing the post optimization passes.
*/
class FinishSSATransformation : public PassMEMirSsaRep {
public:
FinishSSATransformation() : PassMEMirSsaRep("FinishSSATransformation", kNoNodes) {
}
void End(PassDataHolder* data) const {
DCHECK(data != nullptr);
CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit;
DCHECK(c_unit != nullptr);
c_unit->mir_graph.get()->SSATransformationEnd();
}
};
} // namespace art
#endif // ART_COMPILER_DEX_POST_OPT_PASSES_H_