Author: zx Date: 2011-11-28 01:47:10 -0500 (Mon, 28 Nov 2011) New Revision: 3826
Added: trunk/osprey/ipa/main/analyze/ipa_pcg.cxx trunk/osprey/ipa/main/analyze/ipa_pcg.h Modified: trunk/osprey/be/com/ipa_be_read.cxx trunk/osprey/be/com/ipa_be_summary.h trunk/osprey/be/com/wssa_mgr.cxx trunk/osprey/be/opt/opt_main.cxx trunk/osprey/common/com/be_ipa_util.h trunk/osprey/common/com/config_ipa.cxx trunk/osprey/common/com/config_ipa.h trunk/osprey/ipa/local/ipl_summarize_template.h trunk/osprey/ipa/main/Makefile.gbase trunk/osprey/ipa/main/analyze/ipa_be_write.cxx trunk/osprey/ipa/main/analyze/ipa_be_write.h trunk/osprey/ipa/main/analyze/ipa_main.cxx trunk/osprey/ipa/main/optimize/ipo_main.cxx Log: Add Siloed Reference Analysis pass in IPA. Commandline option: "-IPA:siloed=on", depending on the options "-IPA:preopt=on" and "-OPT:alias=field_sensitive". Modified: trunk/osprey/be/com/ipa_be_read.cxx =================================================================== --- trunk/osprey/be/com/ipa_be_read.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/be/com/ipa_be_read.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -48,12 +48,13 @@ if (Get_Trace(TP_ALIAS,NYSTROM_SUMMARY_FLAG)) fprintf(stderr, "BE: cg_nodes = %d, cg_stinfos = %d, cg_callsites = %d," - " cg_nodeids = %d cg_modranges = %d\n", + " cg_nodeids = %d, cg_modranges = %d, siloed_refereces = %d\n", header->GetCGNodesSize(), header->GetCGStInfosSize(), header->GetCGCallsitesSize(), header->GetCGNodeIdsSize(), - header->GetCGModRangesSize()); + header->GetCGModRangesSize(), + header->GetSiloedReferencesSize()); CURRENT_BE_SUMMARY.SetCGNodesCount(header->GetCGNodesSize()); @@ -76,4 +77,7 @@ ((SUMMARY_CONSTRAINT_GRAPH_MODRANGE*) (base + header->GetCGModRangesOffset())); + CURRENT_BE_SUMMARY.SetSiloedReferenceArray + ((SUMMARY_SILOED_REFERENCE*) (base + header->GetSiloedReferencesOffset())); + } Modified: trunk/osprey/be/com/ipa_be_summary.h =================================================================== --- trunk/osprey/be/com/ipa_be_summary.h 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/be/com/ipa_be_summary.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -44,6 +44,9 @@ mUINT32 cgReturnsIdx() { return _constraint_graph_formal_ret_idx; } mUINT32 cgReturnsCount() { return _constraint_graph_formal_ret_count; } + mUINT32 siloedReferenceIdx() { return _siloed_reference_idx; } + mUINT32 siloedReferenceCount() { return _siloed_reference_count; } + void stIdx(ST_IDX s) { _st_idx = s; } void cgNodesIdx(UINT32 s) { _constraint_graph_nodes_idx = s; } void cgNodesCount(UINT32 s) { _constraint_graph_nodes_count = s; } @@ -58,6 +61,9 @@ void cgReturnsIdx(UINT32 s) { _constraint_graph_formal_ret_idx = s; } void cgReturnsCount(UINT32 s) { _constraint_graph_formal_ret_count = s; } + void siloedReferenceIdx(UINT32 s) { _siloed_reference_idx = s; } + void siloedReferenceCount(UINT32 s) { _siloed_reference_count = s; } + private: ST_IDX _st_idx; mUINT32 _constraint_graph_nodes_idx; @@ -75,6 +81,8 @@ mUINT32 _constraint_graph_formal_ret_idx; mUINT32 _constraint_graph_formal_ret_count; + mUINT32 _siloed_reference_idx; + mUINT32 _siloed_reference_count; }; // Constraint graph node summary for Nystrom Alias Analyzer @@ -318,4 +326,27 @@ TY_IDX _ty_idx; }; +class SUMMARY_SILOED_REFERENCE +{ +public: + SUMMARY_SILOED_REFERENCE() {} + + void aliasTag(UINT32 tag) { _aliasTag = tag; } + UINT32 aliasTag() const { return _aliasTag; } + + void Init() + { + BZERO(this, sizeof(SUMMARY_SILOED_REFERENCE)); + } + + // TODO unimplmented yet + void Print_array(FILE *fp, INT32 size) const; + void Trace_array(INT32 size) const ; + void Print(FILE *f) const; + void Trace(void) const; + +private: + UINT32 _aliasTag; +}; + #endif // ipa_be_summary_INCLUDED Modified: trunk/osprey/be/com/wssa_mgr.cxx =================================================================== --- trunk/osprey/be/com/wssa_mgr.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/be/com/wssa_mgr.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -777,8 +777,8 @@ ("bad wn and def type")); WST_Version_Entry& ver = _ver_table[idx]; WST_Symbol_Entry& wst = _sym_table[ver.Get_wst()]; - Is_True(ver.Is_zero() || ver.Get_def_wn() == NULL, ("ver already has a def wn")); - Is_True(ver.Is_zero() || ver.Get_def_type() == WSSA_UNKNOWN, ("ver already has a def type")); + Is_True(ver.Get_ver() == 0 || ver.Is_zero() || ver.Get_def_wn() == NULL, ("ver already has a def wn")); + Is_True(ver.Get_ver() == 0 || ver.Is_zero() || ver.Get_def_type() == WSSA_UNKNOWN, ("ver already has a def type")); // update version ver.Set_def_wn(def_wn); ver.Set_def_type(def_type); Modified: trunk/osprey/be/opt/opt_main.cxx =================================================================== --- trunk/osprey/be/opt/opt_main.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/be/opt/opt_main.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -605,7 +605,7 @@ WOPT_Enable_Call_Zero_Version = FALSE; WOPT_Enable_Combine_Operations = FALSE; WOPT_Enable_Goto = FALSE; - OPT_Enable_WHIRL_SSA = FALSE; +// OPT_Enable_WHIRL_SSA = FALSE; WOPT_Enable_WOVP = FALSE; WOPT_Enable_Tail_Recur = FALSE; break; Modified: trunk/osprey/common/com/be_ipa_util.h =================================================================== --- trunk/osprey/common/com/be_ipa_util.h 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/common/com/be_ipa_util.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -44,6 +44,7 @@ SUMMARY_CONSTRAINT_GRAPH_CALLSITE* _cg_callsites_array; UINT32* _cg_nodeids_array; SUMMARY_CONSTRAINT_GRAPH_MODRANGE* _cg_modranges_array; + SUMMARY_SILOED_REFERENCE *_siloed_references_array; mINT32 _pu_hdrs_count; mINT32 _cg_nodes_count; @@ -70,6 +71,9 @@ SUMMARY_CONSTRAINT_GRAPH_MODRANGE* GetCGModRangesArray() { return _cg_modranges_array; } + SUMMARY_SILOED_REFERENCE* GetSiloedReferenceArray() + { return _siloed_references_array; } + mINT32 GetPUHdrsCount() { return _pu_hdrs_count; } mINT32 GetCGNodesCount() { return _cg_nodes_count; } mINT32 GetCGStInfosCount() { return _cg_stinfos_count; } @@ -90,6 +94,9 @@ { _cg_nodeids_array = p; } void SetCGModRangesArray(SUMMARY_CONSTRAINT_GRAPH_MODRANGE* p) { _cg_modranges_array = p; } + + void SetSiloedReferenceArray(SUMMARY_SILOED_REFERENCE* p) + { _siloed_references_array = p; } void SetPUHdrsCount(mINT32 c) { _pu_hdrs_count = c; } @@ -130,6 +137,9 @@ Elf64_Word _constraint_graph_nodeids_offset; Elf64_Word _constraint_graph_modranges_offset; + // be_summary for siloed references + Elf64_Word _siloed_references_offset; + // Constraint graph summary for Nystrom Alias Analyzer // mUINT64 mod_ref_info_size; mINT32 _procedure_headers_size; @@ -139,6 +149,9 @@ mINT32 _constraint_graph_nodeids_size; mINT32 _constraint_graph_modranges_size; + // be_summary for siloed references + mINT32 _siloed_references_size; + public: NEW_BE_SUMMARY_HEADER() { BZERO(this, sizeof(NEW_BE_SUMMARY_HEADER)); @@ -157,6 +170,9 @@ void SetCGModRangesOffset(Elf64_Word s) { _constraint_graph_modranges_offset = s; } + void SetSiloedReferencesOffset(Elf64_Word s) + { _siloed_references_offset = s; } + void SetProcHeadersSize(mINT32 s) { _procedure_headers_size = s; } void SetCGNodesSize(mINT32 s) @@ -170,6 +186,9 @@ void SetCGModRangesSize(mINT32 s) { _constraint_graph_modranges_size = s; } + void SetSiloedReferencesSize(mINT32 s) + { _siloed_references_size = s; } + Elf64_Word GetProcHeadersOffset() { return _procedure_headers_offset; } Elf64_Word GetCGNodesOffset() @@ -183,6 +202,9 @@ Elf64_Word GetCGModRangesOffset() { return _constraint_graph_modranges_offset; } + Elf64_Word GetSiloedReferencesOffset() + { return _siloed_references_offset; } + mINT32 GetProcHeadersSize() { return _procedure_headers_size; } mINT32 GetCGNodesSize() @@ -195,6 +217,9 @@ { return _constraint_graph_nodeids_size; } mINT32 GetCGModRangesSize() { return _constraint_graph_modranges_size; } + + mINT32 GetSiloedReferencesSize() + { return _siloed_references_size; } }; struct pu_mod_ref_info Modified: trunk/osprey/common/com/config_ipa.cxx =================================================================== --- trunk/osprey/common/com/config_ipa.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/common/com/config_ipa.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -311,6 +311,10 @@ BOOL IPA_Enable_Preopt = FALSE; BOOL IPA_Enable_Preopt_Set = FALSE; +// perform siloed reference analysis during IPA +BOOL IPA_Enable_Siloed_Ref = FALSE; +BOOL IPA_Enable_Siloed_Ref_Set = FALSE; + // maximum number of clones for a call graph node UINT32 IPA_Max_Node_Clones = 0; BOOL IPA_Max_Node_Clones_Set = FALSE; @@ -564,6 +568,10 @@ { OVK_BOOL, OV_INTERNAL, FALSE, "preopt", "", 0, 0, 0, &IPA_Enable_Preopt, &IPA_Enable_Preopt_Set, "Enable calling the preopt" }, + // option -IPA:siloed=on requires -IPA:preopt=on and -OPT:alias=field_sensitive + { OVK_BOOL, OV_INTERNAL, FALSE, "siloed", "", + 0, 0, 0, &IPA_Enable_Siloed_Ref, &IPA_Enable_Siloed_Ref_Set, + "Enable siloed reference analysis" }, { OVK_BOOL, OV_INTERNAL, FALSE, "struct", "", 0, 0, 0, &IPA_Enable_Inline_Struct, NULL, "Enable inlining of PU with F90 structures " }, Modified: trunk/osprey/common/com/config_ipa.h =================================================================== --- trunk/osprey/common/com/config_ipa.h 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/common/com/config_ipa.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -133,6 +133,9 @@ extern BOOL IPA_Enable_Preopt; /* call preopt during IPA */ extern BOOL IPA_Enable_Preopt_Set; +extern BOOL IPA_Enable_Siloed_Ref; /* perform siloed reference analysis */ +extern BOOL IPA_Enable_Siloed_Ref_Set; + #ifdef KEY extern BOOL IPA_Enable_Icall_Opt; // allow ipa change icall to call extern BOOL IPA_Enable_EH_Region_Removal; // remove useless exception regions Modified: trunk/osprey/ipa/local/ipl_summarize_template.h =================================================================== --- trunk/osprey/ipa/local/ipl_summarize_template.h 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/local/ipl_summarize_template.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -1922,8 +1922,8 @@ // label definition case OPR_LABEL: { - Is_True (Do_Altentry || !WN_Label_Is_Not_Used (w2), - ("Label should not be marked yet")); +// Is_True (Do_Altentry || !WN_Label_Is_Not_Used (w2), +// ("Label should not be marked yet")); label_wn &label = label_use_map [WN_label_number (w2)]; Is_True (label.wn == NULL, ("Process_procedure: Duplicate labels?")); label.wn = w2; Modified: trunk/osprey/ipa/main/Makefile.gbase =================================================================== --- trunk/osprey/ipa/main/Makefile.gbase 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/main/Makefile.gbase 2011-11-28 06:47:10 UTC (rev 3826) @@ -206,7 +206,8 @@ ipa_builtins.cxx \ ipa_struct_opt.cxx \ ipa_nystrom_alias_analyzer.cxx \ - ipa_be_write.cxx + ipa_be_write.cxx \ + ipa_pcg.cxx IPA_OPTIMIZE_SRCS = \ # ipo_parent.c \ Modified: trunk/osprey/ipa/main/analyze/ipa_be_write.cxx =================================================================== --- trunk/osprey/ipa/main/analyze/ipa_be_write.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/main/analyze/ipa_be_write.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -29,6 +29,7 @@ #include "ipa_be_summary.h" #include "ipa_nystrom_alias_analyzer.h" #include "be_ipa_util.h" +#include "ipa_pcg.h" void IPA_Summary_ProcessPointsToSet(DYN_ARRAY<UINT32>* cg_nodeids, @@ -169,6 +170,8 @@ DYN_ARRAY<UINT32> cg_nodeids(Malloc_Mem_Pool); DYN_ARRAY<SUMMARY_CONSTRAINT_GRAPH_MODRANGE> cg_modranges(Malloc_Mem_Pool); + DYN_ARRAY<SUMMARY_SILOED_REFERENCE> siloed_references(Malloc_Mem_Pool); + // flatten the hierachy put_info_tree then, we can use the loop to iterate. // otherwise we need pass all DYN_Arrays. DYN_ARRAY<PU_Info*> pu_infos(Malloc_Mem_Pool); @@ -188,6 +191,8 @@ mUINT32 num_stinfos = 0; mUINT32 num_callsites = 0; mUINT32 num_nodeids = 0; + + mUINT32 num_siloedrefs = 0; INT hdr_idx = cg_headers.Newidx(); cg_headers[hdr_idx].Init(); @@ -377,6 +382,25 @@ cur_hdr->cgNodeIdsIdx(cg_nodeids.Lastidx() - num_nodeids + 1); cur_hdr->cgNodeIdsCount(num_nodeids); + // Siloed refrences + const ALIAS_TAG_SET &siloed_tag_set = + IPA_Concurrency_Graph->Get_siloed_references(ipa_node); + + for(ALIAS_TAG_SET::iterator it = siloed_tag_set.begin(); + it != siloed_tag_set.end(); it++) { + AliasTag tag = *it; + num_siloedrefs++; + + INT new_idx = siloed_references.Newidx(); + siloed_references[new_idx].Init(); + SUMMARY_SILOED_REFERENCE *summSiloedRef = &(siloed_references[new_idx]); + + summSiloedRef->aliasTag(tag); + } + + cur_hdr->siloedReferenceIdx(siloed_references.Lastidx() - num_siloedrefs + 1); + cur_hdr->siloedReferenceCount(num_siloedrefs); + if (Get_Trace(TP_ALIAS,NYSTROM_SUMMARY_FLAG)) fprintf(stderr,"xxx nodes = %d, stinfos = %d, callsites = %d, nodeids = %d\n", cur_hdr->cgNodesCount(), cur_hdr->cgStInfosCount(), @@ -393,6 +417,8 @@ INT offset_cg_nodeids = 0; INT offset_cg_modranges = 0; + INT offset_siloed_references = 0; + Elf64_Word temp; INT cur_sec_disp = fl->file_size; @@ -442,6 +468,13 @@ (INT) ir_b_save_buf(&(cg_modranges[0]), size, sizeof(INT64), 0, fl); offset_cg_modranges = offset_cg_modranges - cur_sec_disp; + // write the siloed references + size = + (siloed_references.Lastidx() + 1) * sizeof(SUMMARY_SILOED_REFERENCE); + offset_siloed_references = + (INT) ir_b_save_buf(&(siloed_references[0]), size, sizeof(INT64), 0, fl); + offset_siloed_references = offset_siloed_references - cur_sec_disp; + // now update the pointer to the header and the actual header NEW_BE_SUMMARY_HEADER header; offset = (INT) ir_b_save_buf(&header, sizeof(NEW_BE_SUMMARY_HEADER), @@ -456,6 +489,8 @@ header_addr->SetCGCallsitesOffset(offset_cg_callsites); header_addr->SetCGModRangesOffset(offset_cg_modranges); + header_addr->SetSiloedReferencesOffset(offset_siloed_references); + header_addr->SetProcHeadersSize(cg_headers.Lastidx() + 1); header_addr->SetCGNodesSize(cg_nodes.Lastidx() + 1); header_addr->SetCGStInfosSize(cg_stinfos.Lastidx() + 1); @@ -463,6 +498,8 @@ header_addr->SetCGNodeIdsSize(cg_nodeids.Lastidx() + 1); header_addr->SetCGModRangesSize(cg_modranges.Lastidx() + 1); + header_addr->SetSiloedReferencesSize(siloed_references.Lastidx() + 1); + if (Get_Trace(TP_ALIAS,NYSTROM_SUMMARY_FLAG)) fprintf(stderr, "cg_nodes = %d, cg_stinfos = %d, cg_callsites = %d," " cg_nodeids = %d cg_modranges = %d\n", Modified: trunk/osprey/ipa/main/analyze/ipa_be_write.h =================================================================== --- trunk/osprey/ipa/main/analyze/ipa_be_write.h 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/main/analyze/ipa_be_write.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -30,6 +30,9 @@ extern void IPA_irb_write_nystrom_alias_info(PU_Info*, Output_File *); +extern void +IPA_write_siloed_reference_summary (PU_Info* pu_info_tree, Output_File *fl); + #ifdef __cplusplus } #endif Modified: trunk/osprey/ipa/main/analyze/ipa_main.cxx =================================================================== --- trunk/osprey/ipa/main/analyze/ipa_main.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/main/analyze/ipa_main.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -87,6 +87,8 @@ #include "ipa_nystrom_alias_analyzer.h" +#include "ipa_pcg.h" + FILE* STDOUT = stdout; //----------------------------------------------------------------------- @@ -761,6 +763,12 @@ } } + if (IPA_Enable_Siloed_Ref) { + IPA_Concurrency_Graph = CXX_NEW(IPA_PCG(IPA_Call_Graph, Malloc_Mem_Pool), + Malloc_Mem_Pool); + IPA_Concurrency_Graph->Collect_siloed_references(); + } + MEM_POOL_Pop (MEM_local_nz_pool_ptr); // solve interprocedural array section analysis Added: trunk/osprey/ipa/main/analyze/ipa_pcg.cxx =================================================================== --- trunk/osprey/ipa/main/analyze/ipa_pcg.cxx (rev 0) +++ trunk/osprey/ipa/main/analyze/ipa_pcg.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -0,0 +1,958 @@ +// ==================================================================== +// +// Copyright (C) 2011, Hewlett-Packard Development Company, L.P. +// All Rights Reserved. +// +// Open64 is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// Open64 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +// +// ==================================================================== + +#include "ipo_defs.h" // IPO_NODE_CONTEXT +#include "wssa_utils.h" +#include "wssa_mgr.h" +#include "ir_bread.h" // Read_Local_Info +#include "wn_tree_util.h" // WN_TREE_ITER +#include "wssa_update.h" +#include "cfg_util.h" // DOM_BUILDER +#include "region_main.h" // REGION_Initialize +#include "ipa_nystrom_alias_analyzer.h" +#include "nystrom_alias_analyzer.h" // NystromAliasAnalyzer +#include "lwn_util.h" // LWN_Get_Parent +#include "ipa_pcg.h" + +using namespace CFG_UTIL; + +// the base class of PCG_NODE, containing a bit-vector flag of +// PCG_NODE kind and a visit flag +template<typename FLAG_TYPE> +class PCG_NODE_BASE { +protected: + unsigned _flags, _visit_flags; + typedef std::set<PCG_NODE_BASE<FLAG_TYPE> *> PCG_NODE_SET; + PCG_NODE_SET _prev_list, _succ_list; + + PCG_NODE_BASE(): _flags(0), _visit_flags(0) {} + + void Propagate(FLAG_TYPE mask, bool up, bool updated); + + void Set_flag(FLAG_TYPE mask) { _flags |= mask; } + void Clear_flag(FLAG_TYPE mask) { _flags &= ~(unsigned)mask; } + bool Is_flag_set(FLAG_TYPE mask) const { return (_flags & mask) != 0; } + bool Is_flag_all_set(FLAG_TYPE mask) const { return (_flags & mask) == mask; } + void Set_visited(FLAG_TYPE mask) { _visit_flags |= mask; } + void Clear_visited(FLAG_TYPE mask) { _visit_flags &= ~(unsigned)mask; } + bool Is_all_visited(FLAG_TYPE mask) const { return (_visit_flags & mask) == mask; } +public: + void Propagate_up(FLAG_TYPE mask) { Propagate(mask, true, false); } + void Propagate_down(FLAG_TYPE mask) { Propagate(mask, false, false); } + + void Add_prev(PCG_NODE_BASE<FLAG_TYPE> * prev) { _prev_list.insert(prev); } + void Add_succ(PCG_NODE_BASE<FLAG_TYPE> * succ) { _succ_list.insert(succ); } +}; + +// propagate the flags with mask of current node up or down +template<typename FLAG_TYPE> +void +PCG_NODE_BASE<FLAG_TYPE>::Propagate(FLAG_TYPE mask, bool up, bool updated) { + // A naive propagate algorithm at present. + // A better approach should be some SCC-based algorithm + if(!Is_all_visited(mask) || updated) { + Set_visited(mask); + if(Is_flag_set(mask)) { + std::set<PCG_NODE_BASE<FLAG_TYPE> *> &edge_list = + up ? _prev_list : _succ_list; + for(typename PCG_NODE_SET::iterator it = edge_list.begin(); + it != edge_list.end(); it++) { + PCG_NODE_BASE<FLAG_TYPE> *end_point = *it; +// if(!end_point->Is_flag_all_set(mask)) +// end_point->Clear_visited(mask); + bool update = !end_point->Is_flag_all_set(mask); + end_point->Set_flag((FLAG_TYPE)(_flags & mask)); + end_point->Propagate(mask, up, update); + } + } + } +} + +typedef std::vector<WN *> WN_VEC; +typedef std::set<WN *> WN_SET; +typedef std::pair<WN *, AliasTag> WN_TAG_PAIR; +typedef std::set<WN_TAG_PAIR> WN_TAG_PAIR_SET; +typedef std::map<WN *, AliasTag> WN_TAG_MAP; +typedef std::map<AliasTag, WN *> TAG_WN_MAP; + +static void Print_aliasTag_set(const ALIAS_TAG_SET &tag_set, FILE *fout = stderr) +{ + fprintf(fout, "\nCount: %d\n", tag_set.size()); + for(ALIAS_TAG_SET::const_iterator cit = tag_set.begin(); + cit != tag_set.end(); cit++) { + AliasTag tag = *cit; + fprintf(fout, "%d\n", tag); + } +} + +// PU representation for in PCG +class PCG_NODE : public PCG_NODE_BASE<PCG_FLAG> { +private: + MEM_POOL *_pool; + IPA_NODE *_node; + std::set<ST *> _icall_list; + + // indirect memory accesses: iload and istore + // prefix of "_follow_" means the WN nodes may be executed after + // a thread-spawn site or an invocation to a SPAWNER PU + WN_TAG_MAP *_follow_load_set, *_follow_store_set, *_load_set, *_store_set; + + // call sites + WN_SET *_call_set, *_follow_call_set; + + // ldids: map from alias tag to WN nodes + TAG_WN_MAP _ldid_set, _follow_ldid_set; + + // alias tags of loads or stores that may happen concurrently + ALIAS_TAG_SET _concurrent_load, _concurrent_store; + + // alias tags of the siloed reference in this PU + ALIAS_TAG_SET _siloed_ref_set; + + friend class IPA_PCG; +public: + PCG_NODE(IPA_NODE *ipa_node, MEM_POOL *mem_pool) + : _node(ipa_node), _pool(mem_pool) { + _load_set = CXX_NEW(WN_TAG_MAP(), _pool); + _store_set = CXX_NEW(WN_TAG_MAP(), _pool); + _follow_load_set = CXX_NEW(WN_TAG_MAP(), _pool); + _follow_store_set = CXX_NEW(WN_TAG_MAP(), _pool); + _call_set = CXX_NEW(WN_SET(), _pool); + _follow_call_set = CXX_NEW(WN_SET(), _pool); + } + + ~PCG_NODE() { + if(_load_set != NULL) + CXX_DELETE(_load_set, _pool); + if(_store_set != NULL) + CXX_DELETE(_store_set, _pool); + if(_follow_load_set != NULL) + CXX_DELETE(_follow_load_set, _pool); + if(_follow_store_set != NULL) + CXX_DELETE(_follow_store_set, _pool); + if(_call_set != NULL) + CXX_DELETE(_call_set, _pool); + if(_follow_call_set != NULL) + CXX_DELETE(_follow_call_set, _pool); + } + + IPA_NODE *Get_ipa_node() const { return _node; } + const char* Get_name() const { return IPA_Node_Name(_node); } + + void Add_caller(PCG_NODE *caller) { + _prev_list.insert(caller); + } + + void Add_callee(PCG_NODE *callee) { + _succ_list.insert(callee); + } + + std::set<ST *> &Get_icall_list() { return _icall_list; } + const std::set<ST *> &Get_icall_list() const { return _icall_list; } + + void Set_entry() { Set_flag(PCG_ENTRY); } + bool Is_entry() const { return Is_flag_set(PCG_ENTRY); } + void Set_spawner() { Set_flag(PCG_SPAWNER); } + bool Is_spawner() const { return Is_flag_set(PCG_SPAWNER); } + void Set_start() { Set_flag(PCG_START); } + bool Is_start() const { return Is_flag_set(PCG_START); } + void Set_spawnee() { Set_flag(PCG_SPAWNEE); } + bool Is_spawnee() const { return Is_flag_set(PCG_SPAWNEE); } + void Set_follow() { Set_flag(PCG_FOLLOW); } + bool Is_follow() const { return Is_flag_set(PCG_FOLLOW); } + + // only PCG_NODE of SPAWNEE FOLLOW can happen concurrently + bool Is_concurrent() const { return Is_spawnee() || Is_follow(); } + + void add_call(WN *wn, bool follow) { + (follow?_follow_call_set:_call_set)->insert(wn); + } + void add_load(WN *stmt, AliasTag tag, bool follow) { + (*(follow?_follow_load_set:_load_set))[stmt] = tag; + } + void add_store(WN *stmt, AliasTag tag, bool follow) { + if(tag == InvalidAliasTag) { + // TODO Store with InvalidAliasTag? + return; + } + (*(follow?_follow_store_set : _store_set))[stmt] = tag; + } + + void add_ldid(WN *wn, AliasTag tag, bool follow) { + if(follow) + _follow_ldid_set[tag] = wn; + else + _ldid_set[tag] = wn; + } + + // To save memory space, after PCG is built + // release the memory space of _follow_xxx_set for concurrent PCG_NODE + // release the memory space of _xxx_set for none-concurrent PCG_NODE + void Tidy_load_store_set() { + if(Is_concurrent()) { + CXX_DELETE(_follow_load_set, _pool); + _follow_load_set = NULL; + CXX_DELETE(_follow_store_set, _pool); + _follow_store_set = NULL; + } else { + CXX_DELETE(_load_set, _pool); + _load_set = NULL; + CXX_DELETE(_store_set, _pool); + _store_set = NULL; + } + } + + const WN_SET *Get_concurrent_call_set() const { + return Is_concurrent() ? _call_set : _follow_call_set; + } + + const WN_TAG_MAP *Get_concurrent_load_set() const { + return Is_concurrent() ? _load_set : _follow_load_set; + } + + const WN_TAG_MAP *Get_concurrent_store_set() const { + return Is_concurrent() ? _store_set : _follow_store_set; + } + + void Print(FILE *fout = stderr); +}; + +void +PCG_NODE::Print(FILE *fout) +{ + fprintf(fout, "[%s]: ", Get_name()); + if(Is_entry()) + fprintf(fout, "ENTRY "); + if(Is_spawner()) + fprintf(fout, "SPAWNER "); + if(Is_start()) + fprintf(fout, "START "); + if(Is_spawnee()) + fprintf(fout, "SPAWNEE "); + if(Is_follow()) + fprintf(fout, "FOLLOW "); + fprintf(fout, "\n"); + + fprintf(fout, "\tCallers: "); + for(PCG_NODE_SET::iterator it = _prev_list.begin(); + it != _prev_list.end(); it++) { + PCG_NODE *end_point = (PCG_NODE *)*it; + fprintf(fout, "%s ", end_point->Get_name()); + } + fprintf(fout, "\n"); + + fprintf(fout, "\tCallees: "); + for(PCG_NODE_SET::iterator it = _succ_list.begin(); + it != _succ_list.end(); it++) { + PCG_NODE *end_point = (PCG_NODE *)*it; + fprintf(fout, "%s ", end_point->Get_name()); + } + fprintf(fout, "\n"); +} + +// BB representation in PCG_NODE +// used to compute "follow" set of statements in a PU +class PCG_BB_NODE : public PCG_NODE_BASE<char> { +private: + const WN_CFG::BB_NODE *bb_node; +public: + PCG_BB_NODE(const WN_CFG::BB_NODE *bb_node): bb_node(bb_node) {} + const WN_CFG::BB_NODE *get_bb_node() const { return bb_node; } + + void Set_flag() { PCG_NODE_BASE<char>::Set_flag(1); } + void Clear_flag() { PCG_NODE_BASE<char>::Clear_flag(1); } + bool Is_flag_set() const { return PCG_NODE_BASE<char>::Is_flag_set(1); } + + void Propagate_down() { PCG_NODE_BASE<char>::Propagate(1, false, false); } +}; + +typedef std::map<const WN_CFG::BB_NODE *, PCG_BB_NODE *> BB_TO_PCG_BB_MAP; + +// CFG representation in PCG +// used to compute "follow" set of statements in a PU +class PCG_CFG { +public: + class ITERATOR { + private: + BB_TO_PCG_BB_MAP::iterator it; + friend class PCG_CFG; + + ITERATOR(const BB_TO_PCG_BB_MAP::iterator &it): it(it) {} + public: + ITERATOR(const ITERATOR &pcg_cfg_it): it(pcg_cfg_it.it) {} + + PCG_BB_NODE *operator *() { + return it->second; + } + + ITERATOR &operator++() { + it++; + return *this; + } + + bool operator!=(const ITERATOR &pcg_cfg_it) { + return it != pcg_cfg_it.it; + } + }; + +private: + MEM_POOL *_pool; + BB_TO_PCG_BB_MAP _bb_to_pcg_bb_map; + friend class ITERATOR; + +public: + PCG_CFG(WN_CFG &wn_cfg, MEM_POOL *mem_pool); + PCG_BB_NODE *get_pcg_bb_node(const WN_CFG::BB_NODE *bb_node) { + BB_TO_PCG_BB_MAP::iterator it = _bb_to_pcg_bb_map.find(bb_node); + if(it != _bb_to_pcg_bb_map.end()) + return it->second; + return NULL; + } + + ITERATOR begin() { + BB_TO_PCG_BB_MAP::iterator it = _bb_to_pcg_bb_map.begin(); + return ITERATOR(it); + } + ITERATOR end() { + BB_TO_PCG_BB_MAP::iterator it = _bb_to_pcg_bb_map.end(); + return ITERATOR(it); + } +}; + +PCG_CFG::PCG_CFG(WN_CFG &wn_cfg, MEM_POOL *mem_pool) : _pool(mem_pool) +{ + for (WN_CFG::bb_iterator bb_it = wn_cfg.BB_begin(); + bb_it != wn_cfg.BB_end(); ++bb_it) { + const WN_CFG::BB_NODE *bb = *bb_it; + PCG_BB_NODE *pcg_bb_node = CXX_NEW(PCG_BB_NODE(bb), _pool); + _bb_to_pcg_bb_map[bb] = pcg_bb_node; + } + + for(BB_TO_PCG_BB_MAP::iterator it = _bb_to_pcg_bb_map.begin(); + it != _bb_to_pcg_bb_map.end(); it++) { + PCG_BB_NODE *pcg_bb_node = it->second; + const WN_CFG::BB_NODE *bb = pcg_bb_node->get_bb_node(); + + for(int i = 0; i < bb->Get_preds_count(); i++) { + const WN_CFG::BB_NODE *pred = bb->Get_pred(i); + Is_True(_bb_to_pcg_bb_map.find(pred) != _bb_to_pcg_bb_map.end(), + ("WN_CFG::BB_NODE has no corresponding PCG_BB_NODE!")); + PCG_BB_NODE *pcg_pred = _bb_to_pcg_bb_map[pred]; + pcg_bb_node->Add_prev(pcg_pred); + } + + for(int i = 0; i < bb->Get_succs_count(); i++) { + const WN_CFG::BB_NODE *succ = bb->Get_succ(i); + Is_True(_bb_to_pcg_bb_map.find(succ) != _bb_to_pcg_bb_map.end(), + ("WN_CFG::BB_NODE has no corresponding PCG_BB_NODE!")); + PCG_BB_NODE *pcg_succ = _bb_to_pcg_bb_map[succ]; + pcg_bb_node->Add_succ(pcg_succ); + } + } +} + +// currently hard-coded to search for function ST with the name "main" +static bool is_main(ST *func_st) +{ + const char *func_name = ST_name(func_st); + if(func_name != NULL) + return strcmp(func_name, "main") == 0; + return false; +} + +// currently hard-coded to search for function ST with the name "pthread_create" +static bool is_spawn_api(ST *func_st) +{ + const char *func_name = ST_name(func_st); + if(func_name != NULL) + return strcmp(func_name, "pthread_create") == 0; + return false; +} + +// currently hard-coded to search for function ST with the name "pthread_mutex_lock" +static bool is_lock_api(ST *func_st) +{ + const char *func_name = ST_name(func_st); + if(func_name != NULL) + return strcmp(func_name, "pthread_mutex_lock") == 0; + return false; +} + +// currently hard-coded to search for function ST with the name "pthread_mutex_unlock" +static bool is_unlock_api(ST *func_st) +{ + const char *func_name = ST_name(func_st); + if(func_name != NULL) + return strcmp(func_name, "pthread_mutex_unlock") == 0; + return false; +} + +void +IPA_PCG::Find_use_in_tree(PCG_NODE *pcg_node, WN *stmt, WN *tree, bool follow) +{ + AliasAnalyzer *aa = AliasAnalyzer::aliasAnalyzer(); + if(WN_operator(tree) == OPR_LDID) { + ST *st = WN_st(tree); + WN_OFFSET offset = WN_load_offset(tree); + INT32 size = WN_object_size(tree); + AliasTag tag = aa->genAliasTag(st, offset, size, false); + pcg_node->add_ldid(tree, tag, follow); + } + + for(int i = 0; i < WN_kid_count(tree); i++) { + Find_use_in_tree(pcg_node, stmt, WN_kid(tree, i), follow); + } +} + +void +IPA_PCG::Proccess_stmt(PCG_NODE *pcg_node, WN *stmt, bool follow) +{ + AliasAnalyzer *aa = AliasAnalyzer::aliasAnalyzer(); + + Find_use_in_tree(pcg_node, stmt, stmt, follow); + + OPERATOR op = WN_operator(stmt); + if(OPERATOR_is_call(op)) { + pcg_node->add_call(stmt, follow); + switch(op) { + case OPR_CALL: { + ST *callee_st = WN_st(stmt); + if(is_spawn_api(callee_st)) { + // empty + } else if(is_lock_api(callee_st) || is_unlock_api(callee_st)) { + // empty + } else { + ST_TO_PCG_NODE_VEC_MAP::iterator it = + st_to_node_vec_map.find(callee_st); + if(it == st_to_node_vec_map.end()) { + + const char *func_name = ST_name(callee_st); + // TODO we find an opaque function: + // A rounded solution should be a table of known external + // functions with known sides effects; otherwise we should + // assume that an opaque function of every exposed memory + // locations, such as non-static global variables, escaping + // local variables and the possible destination of any pointer- + // arguments. + // I did not add handling for opaque function here for now, + // because I don't have such external functions table, and + // if I just treat every opaque function in a general approach, + // I wouldn't get any opportunity for siloed reference analysis. + + // fprintf(stderr, "opaque function %s\n", func_name); + } else { + if(follow) { + PCG_NODE_VEC &node_vec = it->second; + for(int i = 0; i < node_vec.size(); i++) { + node_vec[i]->Set_follow(); + } + } + } + } + } + break; + case OPR_ICALL: + case OPR_INTRINSIC_CALL: + // TODO should be handled similarly with opaque functions + break; + default: + Is_True(FALSE, ("Unhandled call OPERATOR")); + break; + } + } + else if(OPERATOR_is_load(op)) { + switch(op) { + case OPR_PARM: + case OPR_MLOAD: + case OPR_LDBITS: + case OPR_LDID: { + ST *st = WN_st(stmt); + if(st->export_class != EXPORT_LOCAL) { + WN_OFFSET offset = WN_load_offset(stmt); + INT32 size = WN_object_size(stmt); + AliasTag tag = aa->genAliasTag(st, offset, size, false); + pcg_node->add_load(stmt, tag, follow); + } + } + break; + case OPR_ILOADX: + case OPR_ILDBITS: + case OPR_ILOAD: { + AliasTag tag = aa->getAliasTag(stmt, Current_IPANode_File_PU_Idx); + pcg_node->add_load(stmt, tag, follow); + } + break; + default: + Is_True(FALSE, ("Unhandled load OPERATOR")); + break; + } + } else if(OPERATOR_is_store(op)) { + switch(op) { + case OPR_MSTORE: + case OPR_STBITS: + case OPR_STID: + { + ST *st = WN_st(stmt); + if(st->export_class != EXPORT_LOCAL) { + WN_OFFSET offset = WN_store_offset(stmt); + INT32 size = WN_object_size(stmt); + AliasTag tag = aa->genAliasTag(st, offset, size, false); + pcg_node->add_store(stmt, tag, follow); + } + } + break; + case OPR_ISTOREX: + case OPR_ISTBITS: + case OPR_ISTORE: + { + AliasTag tag = aa->getAliasTag(stmt, Current_IPANode_File_PU_Idx); + pcg_node->add_store(stmt, tag, follow); + } + break; + default: + Is_True(FALSE, ("Unhandled store OPERATOR")); + break; + } + } +} + +// Traverse the PU in a flow sensitive way to compute _follow_xxx_set for each PCG_NODE +void +IPA_PCG::Flow_sensitive_traverse(PCG_NODE *pcg_node, + CFG_UTIL::WN_CFG &wn_cfg, std::vector<WN *> &spawn_site_set) +{ + PCG_CFG pcg_cfg(wn_cfg, _pool); + + // find the BBs which can be reached by spawn_site + // note that the flag of the BBs containing spawn_site may not be set + for(int i = 0; i < spawn_site_set.size(); i++) { + WN_CFG::BB_NODE *spawn_site_bb = wn_cfg.Get_wn_node(spawn_site_set[i]); + PCG_BB_NODE *pcg_bb_node = pcg_cfg.get_pcg_bb_node(spawn_site_bb); + if(!pcg_bb_node->Is_flag_set()) { + pcg_bb_node->Set_flag(); + pcg_bb_node->Propagate_down(); + pcg_bb_node->Clear_flag(); // may not be the first stmt of the BB + } + } + + // make up the BBs containing spawn_site but flag is not set + for(int i = 0; i < spawn_site_set.size(); i++) { + WN *spawn_site_stmt = spawn_site_set[i]; + WN_CFG::BB_NODE *spawn_site_bb = wn_cfg.Get_wn_node(spawn_site_stmt); + PCG_BB_NODE *pcg_bb_node = pcg_cfg.get_pcg_bb_node(spawn_site_bb); + if(!pcg_bb_node->Is_flag_set()) { + for (WN_CFG::BB_NODE::stmt_iterator stmt_it = + spawn_site_bb->Stmt_begin(spawn_site_stmt); + stmt_it != spawn_site_bb->Stmt_end(); ++stmt_it) { + WN *stmt = &(*stmt_it); + Proccess_stmt(pcg_node, stmt, true); + } + } + } + + for(PCG_CFG::ITERATOR it = pcg_cfg.begin(); it != pcg_cfg.end(); ++it) { + PCG_BB_NODE *pcg_bb_node = *it; + + if(pcg_bb_node->Is_flag_set()) { + // why const_stmt_iterator does not support ++? + WN_CFG::BB_NODE *bb = (WN_CFG::BB_NODE *)pcg_bb_node->get_bb_node(); + for (WN_CFG::BB_NODE::stmt_iterator stmt_it = bb->Stmt_begin(); + stmt_it != bb->Stmt_end(); ++stmt_it) { + WN *stmt = &(*stmt_it); + Proccess_stmt(pcg_node, stmt, true); + } + } + } +} + +// Traverse the PU in a flow insensitive way to compute _xxx_set for each PCG_NODE +void +IPA_PCG::Flow_insensitive_traverse(PCG_NODE *pcg_node, + CFG_UTIL::WN_CFG &wn_cfg, std::vector<WN *> &spawn_site_set) +{ + AliasAnalyzer *aa = AliasAnalyzer::aliasAnalyzer(); + + for (WN_CFG::dfs_fwd_iterator bb_it = wn_cfg.Dfs_fwd_begin(); + bb_it != wn_cfg.Dfs_fwd_end(); ++bb_it) { + WN_CFG::BB_NODE *bb = &(*bb_it); + for (WN_CFG::BB_NODE::stmt_iterator stmt_it = bb->Stmt_begin(); + stmt_it != bb->Stmt_end(); ++stmt_it) { + WN *stmt = &(*stmt_it); + OPERATOR op = WN_operator(stmt); + if(OPERATOR_is_call(op)) { + switch(op) { + case OPR_CALL: { + ST *callee_st = WN_st(stmt); + if(is_spawn_api(callee_st)) { + spawn_site_set.push_back(stmt); + } else if(is_lock_api(callee_st) || is_unlock_api(callee_st)) { + // empty + } else { + if(st_to_node_vec_map.find(callee_st) == + st_to_node_vec_map.end()) { + // TODO handle opaque function + } else { + PCG_NODE_VEC &node_vec = st_to_node_vec_map[callee_st]; + for(int i = 0; i < node_vec.size(); i++) + if(node_vec[i]->Is_spawner()) { + spawn_site_set.push_back(stmt); + break; + } + } + } + } + break; + case OPR_ICALL: + case OPR_INTRINSIC_CALL: + // TODO handle indirect calls and intrinsic calls + break; + default: + Is_True(FALSE, ("Unhandled call OPERATOR")); + break; + } + } + + Proccess_stmt(pcg_node, stmt, false); + } + } +} +void +IPA_PCG::Traverse_WN_CFG(PCG_NODE *pcg_node) +{ + IPA_NODE *ipa_node = pcg_node->Get_ipa_node(); + IPA_NODE_CONTEXT context(ipa_node); + WN *wn = ipa_node->Whirl_Tree(TRUE); + REGION_Initialize (wn, PU_has_region(ipa_node->Get_PU())); + + WN_CFG wn_cfg(_pool); + wn_cfg.Set_wn_root(wn); + wn_cfg.Build(); + + if (Alias_Nystrom_Analyzer) { + Alias_Analyzer_in_IPA = TRUE; + UINT16 fileIdx = (UINT16)(ipa_node->File_Index()); + UINT16 puIdx = (UINT16)(ipa_node->Proc_Info_Index()); + Current_IPANode_File_PU_Idx = (fileIdx << 16) | puIdx; + + IPA_NystromAliasAnalyzer *ipan = IPA_NystromAliasAnalyzer::aliasAnalyzer(); + ConstraintGraph::IPANodeCG(ipan->cg(ipa_node->Node_Index())); + + IPA_NystromAliasAnalyzer::aliasAnalyzer()->mapWNToUniqCallSiteCGNodeId(ipa_node); + } + + std::vector<WN *> spawn_site_set; + Flow_insensitive_traverse(pcg_node, wn_cfg, spawn_site_set); + Flow_sensitive_traverse(pcg_node, wn_cfg, spawn_site_set); + + REGION_Finalize(); +} + +// A simple algorithm to find the set of STs that a pointer MAY point to +static ST_SET & +Find_pt_st(IPA_CALL_GRAPH *graph, const SUMMARY_VALUE &val, IPA_NODE *ipa_node, + SUMMARY_FORMAL *formal_array, SUMMARY_SYMBOL *symbol_array, ST_SET &res) +{ + IPA_CONST_TYPE const_type = val.Get_const_type(); + switch(const_type) { + case VALUE_FORMAL: { + INT32 formal_idx = val.Get_formal_index(); + SUMMARY_FORMAL &formal = formal_array[formal_idx]; + INT32 position = formal.Get_position(); + + IPA_PRED_ITER pred_iter (graph, ipa_node); + for (pred_iter.First(); !pred_iter.Is_Empty(); pred_iter.Next()) { + if (IPA_EDGE* edge = pred_iter.Current_Edge()) { + IPA_NODE* caller = graph->Caller(edge); + SUMMARY_CALLSITE *callsite = edge->Summary_Callsite(); + INT32 actual_idx = callsite->Get_actual_index() + position; + SUMMARY_ACTUAL *actual_array = IPA_get_actual_array(caller); + const SUMMARY_ACTUAL &actual = actual_array[actual_idx]; + if(actual.Get_pass_type() == PASS_LDA) { + if(actual.Is_value_parm()) { + INT32 value_idx = actual.Get_value_index(); + SUMMARY_VALUE *value_array = IPA_get_value_array(caller); + SUMMARY_VALUE &value = value_array[value_idx]; + Find_pt_st(graph, value, caller, IPA_get_formal_array(caller), + IPA_get_symbol_array(caller), res); + } else { + INT32 symbol_idx = actual.Get_symbol_index(); + SUMMARY_SYMBOL &symbol = symbol_array[symbol_idx]; + ST *symbol_st = &St_Table[symbol.St_idx()]; + res.insert(symbol_st); + } + } else { + Is_True(FALSE,("Cannot determine ST for func pointer!")); + } + } + } + } + break; + case VALUE_GLOBAL: { + ST_IDX st_idx; + if(val.Is_global_st_idx()) { + st_idx = val.Get_global_st_idx(); + } else { + INT32 global_idx = val.Get_global_index(); + SUMMARY_SYMBOL &symbol = symbol_array[global_idx]; + st_idx = symbol.St_idx(); + } + ST *symbol_st = &St_Table[st_idx]; + res.insert(symbol_st); + } + break; + case VALUE_UNKNOWN: + default: + break; + } + return res; +} + +// Construct the PCG +IPA_PCG::IPA_PCG(IPA_CALL_GRAPH *call_graph, MEM_POOL *mem_pool) + : _graph(call_graph), _pool(mem_pool), entry_node(NULL) +{ + std::set<ST *> spawnee_st_set; + BOOL spawned_func_pointer = FALSE; + IPA_NODE_ITER cg_iter(_graph, DONTCARE); + for (cg_iter.First(); !cg_iter.Is_Empty(); cg_iter.Next()) { + if (IPA_NODE *ipa_node = cg_iter.Current()) { + + ST *pu_st = ipa_node->Func_ST(); + PCG_NODE *pcg_node = Get_node(ipa_node); + + if(st_to_node_vec_map.find(pu_st) == + st_to_node_vec_map.end()) { + std::vector<PCG_NODE *> tmp; + tmp.push_back(pcg_node); + st_to_node_vec_map[pu_st] = tmp; + } else { + st_to_node_vec_map[pu_st].push_back(pcg_node); + } + + if(is_main(pu_st)) { + pcg_node->Set_entry(); + entry_node = pcg_node; + } + + SUMMARY_VALUE *value_array = IPA_get_value_array(ipa_node); + SUMMARY_FORMAL *fomal_array = IPA_get_formal_array(ipa_node); + SUMMARY_ACTUAL *actual_array = IPA_get_actual_array(ipa_node); + SUMMARY_SYMBOL *symbol_array = IPA_get_symbol_array(ipa_node); + + // determine whether current node is a spawner + // by checking if it calls pthread_create + IPA_ICALL_LIST &ocall_list = ipa_node->Ocall_List(); + for(int i = 0; i < ocall_list.size(); i++) { + IPA_ICALL_NODE *ocall = ocall_list[i]; + SUMMARY_CALLSITE *site = ocall->Callsite(); + INT32 func_sym_idx = site->Get_symbol_index(); + SUMMARY_SYMBOL &func_sym = symbol_array[func_sym_idx]; + ST_IDX st_idx = func_sym.St_idx(); + ST* callee_st = &St_Table[st_idx]; + if (is_spawn_api(callee_st)) { + pcg_node->Set_spawner(); + + SUMMARY_CALLSITE *callsite = ocall->Callsite(); + int acount = callsite->Get_param_count(); + Is_True(acount >= 3, + ("pthread_create should have no less than 3 arguments")); + const SUMMARY_ACTUAL &actual = + actual_array[callsite->Get_actual_index() + 2]; + if (actual.Get_pass_type() == PASS_LDA) { + INT32 symbol_idx = actual.Get_symbol_index(); + SUMMARY_SYMBOL &symbol = symbol_array[symbol_idx]; + ST *symbol_st = &St_Table[symbol.St_idx()]; + spawnee_st_set.insert(symbol_st); + } else { + spawned_func_pointer = TRUE; + } + } + } + + // find callees through ICALL + IPA_ICALL_LIST &icall_list = ipa_node->Icall_List(); + for(int i = 0; i < icall_list.size(); i++) { + IPA_ICALL_NODE *icall = icall_list[i]; + INT32 func_pt_val_idx = icall->Callsite()->Get_value_index(); + SUMMARY_VALUE &func_pt_val = value_array[func_pt_val_idx]; + Find_pt_st(_graph, func_pt_val, ipa_node, fomal_array, symbol_array, + pcg_node->Get_icall_list()); + } + + // find it's callers + IPA_PRED_ITER pred_iter (_graph, ipa_node); + for (pred_iter.First(); !pred_iter.Is_Empty(); + pred_iter.Next()) { + if (IPA_EDGE* edge = pred_iter.Current_Edge()) { + IPA_NODE* caller = _graph->Caller(edge); + PCG_NODE *caller_node = Get_node(caller); + caller_node->Add_callee(pcg_node); + pcg_node->Add_caller(caller_node); + } + } + } + } + + + // find spawnee + for(IPA_NODE_TO_PCG_NODE_MAP::iterator it = _ipa_node_to_pcg_node_map.begin(); + it != _ipa_node_to_pcg_node_map.end(); it++) { + PCG_NODE *pcg_node = it->second; + IPA_NODE *ipa_node = pcg_node->Get_ipa_node(); + + // find spawnees and set flag + if(spawned_func_pointer || + // very conservative now + spawnee_st_set.find(ipa_node->Func_ST()) != spawnee_st_set.end()) { + pcg_node->Set_spawnee(); + pcg_node->Set_start(); + } + + // add callees from icall + for(ST_SET::iterator it = pcg_node->Get_icall_list().begin(); + it != pcg_node->Get_icall_list().end(); it++) { + ST *callee_st = *it; + if(st_to_node_vec_map.find(callee_st) != st_to_node_vec_map.end()) { + std::vector<PCG_NODE *> &callees = st_to_node_vec_map[callee_st]; + for(int i = 0; i < callees.size(); i++) { + pcg_node->Add_callee(callees[i]); + callees[i]->Add_caller(pcg_node); + } + } + } + } + + // propagate PCG_SPAWNER and PCG_SPAWNEE flags + for(IPA_NODE_TO_PCG_NODE_MAP::iterator it = _ipa_node_to_pcg_node_map.begin(); + it != _ipa_node_to_pcg_node_map.end(); it++) { + PCG_NODE *pcg_node = it->second; + pcg_node->Propagate_up(PCG_SPAWNER); + pcg_node->Propagate_down(PCG_SPAWNEE); + } + + // traverse WN_CFG for each node + // find follow + for(PCG_NODE_VEC::iterator it = _pcg_node_vec.begin(); + it != _pcg_node_vec.end(); it++) { + PCG_NODE *pcg_node = *it; + Traverse_WN_CFG(pcg_node); + } + + // propagate PCG_FOLLOW flags + for(PCG_NODE_VEC::iterator it = _pcg_node_vec.begin(); + it != _pcg_node_vec.end(); it++) { + PCG_NODE *pcg_node = *it; + pcg_node->Propagate_down(PCG_FOLLOW); + } + + // choose alias tag set + for(PCG_NODE_VEC::iterator it = _pcg_node_vec.begin(); + it != _pcg_node_vec.end(); it++) { + PCG_NODE *pcg_node = *it; + pcg_node->Tidy_load_store_set(); + } + + + // comput whole program interference set + for(PCG_NODE_VEC::iterator it = _pcg_node_vec.begin(); + it != _pcg_node_vec.end(); it++) { + PCG_NODE *node_i = *it; + const WN_TAG_MAP *store_set = node_i->Get_concurrent_store_set(); + for(WN_TAG_MAP::const_iterator cit = store_set->begin(); + cit != store_set->end(); cit++) { + _wp_interference_set.insert(cit->second); + } + } + +// Print(); +} + +PCG_NODE * +IPA_PCG::Get_node(IPA_NODE *ipa_node) +{ + IPA_NODE_TO_PCG_NODE_MAP::iterator it = + _ipa_node_to_pcg_node_map.find(ipa_node); + + if(it == _ipa_node_to_pcg_node_map.end()) { + PCG_NODE *pcg_node = CXX_NEW(PCG_NODE(ipa_node, _pool), _pool); + _pcg_node_vec.push_back(pcg_node); + _ipa_node_to_pcg_node_map[ipa_node] = pcg_node; + return pcg_node; + } else + return it->second; +} + +void +IPA_PCG::Print(FILE *fout) +{ + for(IPA_NODE_TO_PCG_NODE_MAP::iterator it = _ipa_node_to_pcg_node_map.begin(); + it != _ipa_node_to_pcg_node_map.end(); it++) { + PCG_NODE *pcg_node = it->second; + pcg_node->Print(fout); + } +} + +bool +IPA_PCG::Is_siloed(AliasTag tag) const +{ + AliasAnalyzer *aa = AliasAnalyzer::aliasAnalyzer(); + + for(ALIAS_TAG_SET::const_iterator cit = _wp_interference_set.begin(); + cit != _wp_interference_set.end(); cit++) { + AliasTag t = *cit; + if(aa->aliased(t, tag)) + return false; + } + + return true; +} + +void +IPA_PCG::Collect_siloed_references() +{ + for(PCG_NODE_VEC::iterator it = _pcg_node_vec.begin(); + it != _pcg_node_vec.end(); it++) { + PCG_NODE *pcg_node = *it; + + TAG_WN_MAP &candidates = pcg_node->_ldid_set; + + for(TAG_WN_MAP::iterator it = candidates.begin(); + it != candidates.end(); it++) { + AliasTag tag = it->first; + + if(tag != EmptyAliasTag && tag != InvalidAliasTag && + Is_siloed(tag)) { + pcg_node->_siloed_ref_set.insert(tag); + } + } + } +} + +const ALIAS_TAG_SET & +IPA_PCG::Get_siloed_references(IPA_NODE *ipa_node) const +{ + IPA_NODE_TO_PCG_NODE_MAP::const_iterator cit = _ipa_node_to_pcg_node_map.find(ipa_node); + Is_True(cit != _ipa_node_to_pcg_node_map.end(), ("Cannot find PCG node from IPA_NODE")); + return cit->second->_siloed_ref_set; +} + +IPA_PCG *IPA_Concurrency_Graph = NULL; Added: trunk/osprey/ipa/main/analyze/ipa_pcg.h =================================================================== --- trunk/osprey/ipa/main/analyze/ipa_pcg.h (rev 0) +++ trunk/osprey/ipa/main/analyze/ipa_pcg.h 2011-11-28 06:47:10 UTC (rev 3826) @@ -0,0 +1,99 @@ +// ==================================================================== +// +// Copyright (C) 2011, Hewlett-Packard Development Company, L.P. +// All Rights Reserved. +// +// Open64 is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// Open64 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +// +// ==================================================================== + +#ifndef ipa_pcg_INCLUDED +#define ipa_pcg_INCLUDED "ipa_pcg.h" + +#include "ipa_cg.h" +#include "wn_cfg.h" +#include "wssa_mgr.h" +#include <map> +#include <set> + +typedef enum { + PCG_ENTRY = 0x1, // The entry of this program, 'main' + PCG_SPAWNER = 0x2, // A PU which may spawn new threads + PCG_START = 0x4, // The entry PU of theads + PCG_SPAWNEE = 0x8, // A PU which may be executed in spawned threads + PCG_FOLLOW = 0x10, // A PU which can be executed after a thread-spawn site + // or an invocation to a SPAWNER PU +} PCG_FLAG; + +// each IPA_NODE is mapped to a PCG_NODE in siloed reference analysis +class PCG_NODE; + +typedef std::map<IPA_NODE *, PCG_NODE *> IPA_NODE_TO_PCG_NODE_MAP; +typedef std::set<ST *> ST_SET; +typedef std::vector<PCG_NODE *> PCG_NODE_VEC; +typedef std::map<ST *, PCG_NODE_VEC> ST_TO_PCG_NODE_VEC_MAP; +typedef std::set<AliasTag> ALIAS_TAG_SET; + +// Class for Procedural Concurrency Graph +class IPA_PCG { +private: + // memory pool + MEM_POOL *_pool; + + // point to IPA call graph + IPA_CALL_GRAPH *_graph; + + // all pcg nodes + PCG_NODE_VEC _pcg_node_vec; + + // map from an ipa node to a pcg node + IPA_NODE_TO_PCG_NODE_MAP _ipa_node_to_pcg_node_map; + + // map from as ST to pcg nodes with this ST + ST_TO_PCG_NODE_VEC_MAP st_to_node_vec_map; + + // the entry PU of the program + PCG_NODE *entry_node; + + // whole program interference set + ALIAS_TAG_SET _wp_interference_set; + + PCG_NODE *Get_node(IPA_NODE *ipa_node); + void Traverse_WN_CFG(PCG_NODE *pcg_node); + void Proccess_stmt(PCG_NODE *pcg_node, WN *stmt, bool follow); + void Flow_insensitive_traverse(PCG_NODE *pcg_node, + CFG_UTIL::WN_CFG &wn_cfg, std::vector<WN *> &spawn_site_set); + void Flow_sensitive_traverse(PCG_NODE *pcg_node, + CFG_UTIL::WN_CFG &wn_cfg, std::vector<WN *> &spawn_site_set); + void Find_use_in_tree(PCG_NODE *pcg_node, WN *stmt, WN *tree, bool follow); + bool Is_siloed(AliasTag tag) const; +public: + // PCG is built during constructor + IPA_PCG(IPA_CALL_GRAPH *call_graph, MEM_POOL *mem_pool); + + // do siloed reference and collect the alias tags of + // siloed_references for each PU + void Collect_siloed_references(); + + // get the alias tags of siloed_references for each PU + const ALIAS_TAG_SET &Get_siloed_references(IPA_NODE *ipa_node) const; + + void Print(FILE *fout = stderr); +}; + +extern IPA_PCG *IPA_Concurrency_Graph; + +#endif // ipa_pcg_INCLUDED Modified: trunk/osprey/ipa/main/optimize/ipo_main.cxx =================================================================== --- trunk/osprey/ipa/main/optimize/ipo_main.cxx 2011-11-25 12:39:44 UTC (rev 3825) +++ trunk/osprey/ipa/main/optimize/ipo_main.cxx 2011-11-28 06:47:10 UTC (rev 3826) @@ -1633,7 +1633,6 @@ { IPA_write_alias_summary(pu_info_tree, output_file); } - #if defined(TARG_SL) if (ld_ipa_opt[LD_IPA_IPISR].flag) ------------------------------------------------------------------------------ All the data continuously generated in your IT infrastructure contains a definitive record of customers, application performance, security threats, fraudulent activity, and more. Splunk takes this data and makes sense of it. IT sense. And common sense. http://p.sf.net/sfu/splunk-novd2d _______________________________________________ Open64-devel mailing list Open64-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/open64-devel