PandA-2024.02
eSSA.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
44 #include "eSSA.hpp"
45 
46 #include "Dominance.hpp"
47 #include "OrderedInstructions.hpp"
48 #include "Parameter.hpp"
49 #include "Range.hpp"
51 #include "application_manager.hpp"
52 #include "behavioral_helper.hpp"
53 #include "design_flow_manager.hpp"
54 #include "ext_tree_node.hpp"
55 #include "function_behavior.hpp"
56 #include "string_manipulation.hpp"
57 #include "token_interface.hpp"
58 #include "tree_basic_block.hpp"
59 #include "tree_helper.hpp"
60 #include "tree_manager.hpp"
61 #include "tree_manipulation.hpp"
62 #include "tree_reindex.hpp"
63 
64 class Operand
65 {
67 
69 
70  public:
71  Operand(const tree_nodeRef _operand, tree_nodeRef stmt) : operand(_operand), user_stmt(stmt)
72  {
73  THROW_ASSERT(GetPointer<gimple_node>(GET_NODE(stmt)), "stmt should be a gimple_node");
74  }
75 
76  const tree_nodeRef getOperand() const
77  {
78  return operand;
79  }
80 
81  const tree_nodeRef getUser() const
82  {
83  return user_stmt;
84  }
85 
86  bool set(tree_nodeRef new_ssa, tree_managerRef TM)
87  {
88  const auto* ssaOperand = GetPointer<const ssa_name>(GET_CONST_NODE(operand));
89  THROW_ASSERT(GET_NODE(new_ssa)->get_kind() == ssa_name_K, "New variable should be an ssa_name");
90  THROW_ASSERT(ssaOperand, "Old variable should be an ssa_name");
91  THROW_ASSERT(TM, "Null reference to tree manager");
92 
93  if(auto* gp = GetPointer<gimple_phi>(GET_NODE(user_stmt)))
94  {
95  const auto& deList = gp->CGetDefEdgesList();
96  std::vector<gimple_phi::DefEdge> validDE;
97  for(const auto& de : deList)
98  {
99  if(GET_INDEX_CONST_NODE(de.first) == ssaOperand->index)
100  {
101  validDE.push_back(de);
102  }
103  }
104  THROW_ASSERT(static_cast<bool>(validDE.size()), "Required variable to be replaced not found");
105  if(validDE.size() > 1)
106  {
107  const auto newSSADefBBI =
108  GetPointer<const gimple_node>(
109  GET_CONST_NODE(GetPointer<const ssa_name>(GET_CONST_NODE(new_ssa))->CGetDefStmt()))
110  ->bb_index;
111  // Replace only correct DefEdge in the list
112  for(const auto& de : validDE)
113  {
114  if(de.second == newSSADefBBI)
115  {
116  gp->ReplaceDefEdge(TM, de, {new_ssa, newSSADefBBI});
117  bool emptyUses = ssaOperand->CGetUseStmts().empty();
118  operand = new_ssa;
119  return emptyUses;
120  }
121  }
122  // If it is not possible to detect the correct DefEdge skip replacement and keep conservative
123  return false;
124  }
125  }
126 
127  TM->ReplaceTreeNode(user_stmt, operand, new_ssa);
128 
129  // BEWARE: check on ssaOperand is done before operand is reassigned while doing it after could lead to nullptr
130  // exception
131  bool emptyUses = ssaOperand->CGetUseStmts().empty();
132  operand = new_ssa;
133  return emptyUses;
134  }
135 };
136 
138 {
139  public:
141  // The original operand before we renamed it.
142  // This can be use by passes, when destroying predicateinfo, to know
143  // whether they can just drop the intrinsic, or have to merge metadata.
145  PredicateBase(const PredicateBase&) = delete;
146  PredicateBase& operator=(const PredicateBase&) = delete;
147  PredicateBase() = delete;
148  virtual ~PredicateBase() = default;
149 
150  protected:
151  PredicateBase(kind PT, tree_nodeConstRef Op) : Type(PT), OriginalOp(Op)
152  {
153  }
154 };
155 
156 // Mixin class for edge predicates. The FROM block is the block where the
157 // predicate originates, and the TO block is the block where the predicate is
158 // valid.
160 {
161  public:
162  unsigned int From;
163  unsigned int To;
164  PredicateWithEdge() = delete;
165  static bool classof(const PredicateBase* PB)
166  {
167  return PB->Type == gimple_cond_K || PB->Type == gimple_multi_way_if_K;
168  }
169 
170  PredicateWithEdge(kind PType, tree_nodeConstRef Op, unsigned int _From, unsigned int _To)
171  : PredicateBase(PType, Op), From(_From), To(_To)
172  {
173  THROW_ASSERT(PType == gimple_cond_K || PType == gimple_multi_way_if_K,
174  "Only branch or multi-way if types allowd");
175  }
176 };
177 
178 // Given a predicate info that is a type of branching terminator, get the
179 // branching block.
180 unsigned int getBranchBlock(const PredicateBase* PB)
181 {
183  "Only branches and switches should have PHIOnly defs that require branch blocks.");
184  return reinterpret_cast<const PredicateWithEdge*>(PB)->From;
185 }
186 
187 // Used to store information about each value we might rename.
188 struct ValueInfo
189 {
190  // Information about each possible copy. During processing, this is each
191  // inserted info. After processing, we move the uninserted ones to the
192  // uninserted vector.
193  std::vector<PredicateBase*> Infos;
194  std::vector<PredicateBase*> UninsertedInfos;
195 };
196 
198  std::vector<ValueInfo>& ValueInfos)
199 {
200  auto OIN = ValueInfoNums.find(Operand);
201  THROW_ASSERT(OIN != ValueInfoNums.end(), "Operand was not really in the Value Info Numbers");
202  auto OINI = OIN->second;
203  THROW_ASSERT(OINI < ValueInfos.size(), "Value Info Number greater than size of Value Info Table");
204  return ValueInfos.at(OINI);
205 }
206 
208  std::vector<ValueInfo>& ValueInfos)
209 {
210  auto OIN = ValueInfoNums.find(Operand);
211  if(OIN == ValueInfoNums.end())
212  {
213  // This will grow it
214  ValueInfos.resize(ValueInfos.size() + 1);
215  // This will use the new size and give us a 0 based number of the info
216  auto InsertResult = ValueInfoNums.insert({Operand, ValueInfos.size() - 1});
217  THROW_ASSERT(InsertResult.second, "Value info number already existed?");
218  return ValueInfos.at(InsertResult.first->second);
219  }
220  return ValueInfos.at(OIN->second);
221 }
222 
223 void addInfoFor(OperandRef Op, PredicateBase* PB, CustomSet<OperandRef>& OpsToRename,
224  eSSA::ValueInfoLookup& ValueInfoNums, std::vector<ValueInfo>& ValueInfos)
225 {
226  OpsToRename.insert(Op);
227  auto& OperandInfo = getOrCreateValueInfo(Op->getOperand(), ValueInfoNums, ValueInfos);
228  OperandInfo.Infos.push_back(PB);
229 }
230 
231 bool isCompare(const struct binary_expr* condition)
232 {
233  auto c_type = condition->get_kind();
234  return c_type == eq_expr_K || c_type == ne_expr_K || c_type == ltgt_expr_K || c_type == gt_expr_K ||
235  c_type == lt_expr_K || c_type == ge_expr_K || c_type == le_expr_K;
236 }
237 
239 {
240  const auto Op = GET_CONST_NODE(op);
241  if(const auto* nop = GetPointer<const nop_expr>(Op))
242  {
243  return branchOpRecurse(nop->op, stmt);
244  }
245  else if(const auto* ce = GetPointer<const convert_expr>(op))
246  {
247  return branchOpRecurse(ce->op, stmt);
248  }
249  else if(const auto* ssa = GetPointer<const ssa_name>(Op))
250  {
251  const auto DefStmt = ssa->CGetDefStmt();
252  if(const auto* ga = GetPointer<const gimple_assign>(GET_CONST_NODE(DefStmt)))
253  {
254  return branchOpRecurse(ga->op1, DefStmt);
255  }
256  else if(const auto* gp = GetPointer<const gimple_phi>(GET_CONST_NODE(DefStmt)))
257  {
258  const auto& defEdges = gp->CGetDefEdgesList();
259  THROW_ASSERT(not defEdges.empty(), "Branch variable definition from nowhere");
260  return defEdges.size() > 1 ? nullptr : branchOpRecurse(defEdges.front().first, DefStmt);
261  }
262  else if(GetPointer<const gimple_nop>(GET_CONST_NODE(DefStmt)) != nullptr)
263  {
264  // Branch variable is a function parameter
265  return nullptr;
266  }
267  THROW_UNREACHABLE("Branch var definition statement not handled (" + GET_CONST_NODE(DefStmt)->get_kind_text() +
268  " " + GET_CONST_NODE(DefStmt)->ToString() + ")");
269  }
270  else if(GetPointer<const cst_node>(Op))
271  {
272  return op;
273  }
274  return stmt;
275 }
276 
278  std::vector<ValueInfo>& ValueInfos, CustomSet<std::pair<unsigned int, unsigned int>>& EdgeUsesOnly,
279  const std::map<unsigned int, blocRef>& BBs,
280  int
281 #ifndef NDEBUG
282  debug_level
283 #endif
284 )
285 {
286  const auto* BI = GetPointer<const gimple_cond>(GET_CONST_NODE(bi));
287  THROW_ASSERT(BI, "Branch instruction should be gimple_cond");
288  THROW_ASSERT(BBs.count(BI->bb_index), "Branch BB should be a valid BB");
289  const auto BranchBB = BBs.at(BI->bb_index);
290  THROW_ASSERT(BBs.count(BranchBB->true_edge), "True BB should be a valid BB (BB" + STR(BranchBB->true_edge) +
291  " from BB" + STR(BranchBB->number) + ")");
292  THROW_ASSERT(BBs.count(BranchBB->false_edge), "False BB should be a valid BB (BB" + STR(BranchBB->true_edge) +
293  " from BB" + STR(BranchBB->number) + ")");
294  const auto TrueBB = BBs.at(BranchBB->true_edge);
295  const auto FalseBB = BBs.at(BranchBB->false_edge);
296  const std::vector<blocRef> SuccsToProcess = {TrueBB, FalseBB};
297 
298  if(GetPointer<const cst_node>(GET_CONST_NODE(BI->op0)) != nullptr)
299  {
300  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Branch variable is a cst_node, skipping...");
301  return;
302  }
303  THROW_ASSERT(GET_CONST_NODE(BI->op0)->get_kind() == ssa_name_K,
304  "Non SSA variable found in branch (" + GET_CONST_NODE(BI->op0)->ToString() + ")");
305  const auto cond_ssa = BI->op0;
306  const auto cond_stmt = branchOpRecurse(BI->op0);
307  if(cond_stmt == nullptr)
308  {
310  "---Could not retrieve condition from branch variable, skipping... (" +
311  GET_CONST_NODE(BI->op0)->ToString() + ")");
312  return;
313  }
314  if(GetPointer<const cst_node>(GET_CONST_NODE(cond_stmt)))
315  {
317  "---Constant condition from branch variable, skipping... (" +
318  GET_CONST_NODE(cond_stmt)->ToString() + ")");
319  return;
320  }
321  const auto* CondStmt = GetPointer<const gimple_assign>(GET_CONST_NODE(cond_stmt));
322  THROW_ASSERT(CondStmt, "Condition variable should be defined by gimple_assign (" +
323  GET_CONST_NODE(cond_stmt)->ToString() + ")");
324  const auto CondOp = GET_CONST_NODE(CondStmt->op1);
325 
327  "Branch condition is " + CondOp->get_kind_text() + " " + CondOp->ToString());
328 
329  // Can't insert conditional information if they all go to the same place.
330  if(TrueBB->number == FalseBB->number)
331  {
332  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---True and false edge target same block, skipping...");
333  return;
334  }
335 
336  auto InsertHelper = [&](tree_nodeRef Op) {
337  for(const auto& Succ : SuccsToProcess)
338  {
339  if(Succ->number == BranchBB->number)
340  {
341  continue;
342  }
344  GET_NODE(Op)->ToString() + " eligible for renaming in BB" + STR(Succ->number));
345 
346  PredicateBase* PB = new PredicateWithEdge(gimple_cond_K, Op, BranchBB->number, Succ->number);
347  addInfoFor(OperandRef(new Operand(Op, cond_stmt)), PB, OpsToRename, ValueInfoNums, ValueInfos);
348  if(Succ->list_of_pred.size() > 1)
349  {
350  EdgeUsesOnly.insert({BranchBB->number, Succ->number});
351  }
352  }
353  };
354 
355  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->");
356  if(const auto* bin = GetPointer<const binary_expr>(CondOp))
357  {
358  if(isCompare(bin))
359  {
360  const auto lhs = GET_CONST_NODE(bin->op0);
361  const auto rhs = GET_CONST_NODE(bin->op1);
362  if(lhs != rhs)
363  {
364  InsertHelper(cond_ssa);
365 
366  if(!GetPointer<const cst_node>(lhs) && GetPointer<const ssa_name>(lhs)->CGetUseStmts().size() > 1)
367  {
368  InsertHelper(bin->op0);
369  }
370 
371  if(!GetPointer<const cst_node>(rhs) && GetPointer<const ssa_name>(rhs)->CGetUseStmts().size() > 1)
372  {
373  InsertHelper(bin->op1);
374  }
375  }
376  }
377  else if(bin->get_kind() == bit_and_expr_K || bin->get_kind() == bit_ior_expr_K)
378  {
379  InsertHelper(cond_ssa);
380  }
381  }
382  else
383  {
385  "Unhandled condition type, skipping... (" + CondOp->get_kind_text() + " " + CondOp->ToString() +
386  ")");
387  }
388  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
389 }
390 
391 // Process a block terminating switch, and place relevant operations to be
392 // renamed into OpsToRename.
394  std::vector<ValueInfo>& ValueInfos,
395  CustomSet<std::pair<unsigned int, unsigned int>>& EdgeUsesOnly,
396  const std::map<unsigned int, blocRef>& BBs,
397  int
398 #ifndef NDEBUG
399  debug_level
400 #endif
401 )
402 {
403  const auto* MWII = GetPointer<const gimple_multi_way_if>(GET_CONST_NODE(mwii));
404  THROW_ASSERT(MWII, "Multi way if instruction should be gimple_multi_way_if");
405  const auto BranchBBI = MWII->bb_index;
406  const auto BranchBB = BBs.at(BranchBBI);
407  auto InsertHelper = [&](tree_nodeRef ssa_var, tree_nodeRef use_stmt, unsigned int TargetBBI) {
408  THROW_ASSERT(static_cast<bool>(BBs.count(TargetBBI)), "Target BB should be in BB list");
409  const auto& TargetBB = BBs.at(TargetBBI);
410 
412  "---" + GET_CONST_NODE(ssa_var)->ToString() + " eligible for renaming in BB" + STR(TargetBBI));
413  auto* PS = new PredicateWithEdge(gimple_multi_way_if_K, ssa_var, BranchBBI, TargetBBI);
414  addInfoFor(OperandRef(new Operand(ssa_var, use_stmt)), PS, OpsToRename, ValueInfoNums, ValueInfos);
415  if(TargetBB->list_of_pred.size() > 1)
416  {
417  EdgeUsesOnly.insert(std::make_pair(BranchBBI, TargetBBI));
418  }
419  };
420 
421  for(const auto& var_pair : MWII->list_of_cond)
422  {
423  const auto case_var = var_pair.first;
424  const auto BBI = var_pair.second;
425  if(case_var == nullptr)
426  {
427  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Condition: else branch");
428  continue;
429  }
430  if(BBI == BranchBBI)
431  {
433  "Branch loopback detected: variable renaming not safe, skipping...");
434  continue;
435  }
436  if(GetPointer<const cst_node>(GET_CONST_NODE(case_var)) != nullptr)
437  {
438  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Branch variable is a cst_node, skipping...");
439  continue;
440  }
441 
442  const auto* case_ssa = GetPointer<const ssa_name>(GET_CONST_NODE(case_var));
443  THROW_ASSERT(case_ssa,
444  "Case conditional variable should be an ssa_name (" + GET_CONST_NODE(case_var)->ToString() + ")");
445  const auto case_stmt = case_ssa->CGetDefStmt();
446  if(GET_CONST_NODE(case_stmt)->get_kind() == gimple_phi_K)
447  {
449  "Branch variable already defined inside a phi node, skipping...");
450  continue;
451  }
452  const auto* Case_stmt = GetPointer<const gimple_assign>(GET_CONST_NODE(case_stmt));
453  THROW_ASSERT(Case_stmt, "Case statement should be a gimple_assign (" +
454  GET_CONST_NODE(case_stmt)->get_kind_text() + " " +
455  GET_CONST_NODE(case_stmt)->ToString() + ")");
457  "Condition: " + GET_CONST_NODE(Case_stmt->op1)->get_kind_text() + " " +
458  GET_CONST_NODE(Case_stmt->op1)->ToString());
459  if(const auto* case_cmp = GetPointer<const binary_expr>(GET_CONST_NODE(Case_stmt->op1)))
460  {
461  if(isCompare(case_cmp))
462  {
463  const auto lhs = GET_CONST_NODE(case_cmp->op0);
464  const auto rhs = GET_CONST_NODE(case_cmp->op1);
465  if(lhs != rhs)
466  {
467  InsertHelper(case_var, case_stmt, BBI);
468 
469  if(!GetPointer<const cst_node>(lhs) && GetPointer<const ssa_name>(lhs)->CGetUseStmts().size() > 1)
470  {
471  InsertHelper(case_cmp->op0, case_stmt, BBI);
472  }
473 
474  if(!GetPointer<const cst_node>(rhs) && GetPointer<const ssa_name>(rhs)->CGetUseStmts().size() > 1)
475  {
476  InsertHelper(case_cmp->op1, case_stmt, BBI);
477  }
478  }
479  }
480  else if(case_cmp->get_kind() == bit_and_expr_K || case_cmp->get_kind() == bit_ior_expr_K)
481  {
482  InsertHelper(case_var, case_stmt, BBI);
483  }
484  }
485  else
486  {
487  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Unhandled condition type, skipping...");
488  }
489  }
490 }
491 
492 // Perform a strict weak ordering on instructions and arguments.
494 {
495  return OI.dominates(GetPointer<const gimple_node>(GET_CONST_NODE(A)),
496  GetPointer<const gimple_node>(GET_CONST_NODE(B)));
497 }
498 
499 // Given a predicate info that is a type of branching terminator, get the
500 // edge this predicate info represents
501 const std::pair<unsigned int, unsigned int> getBlockEdge(const PredicateBase* PB)
502 {
503  THROW_ASSERT(PredicateWithEdge::classof(PB), "Not a predicate info type we know how to get an edge from.");
504  const auto* PEdge = static_cast<const PredicateWithEdge*>(PB);
505  return std::make_pair(PEdge->From, PEdge->To);
506 }
507 
508 struct DFSInfo
509 {
510  unsigned int DFSIn = 0;
511  unsigned int DFSOut = 0;
512 };
513 
515 {
516  // Operations that must appear first in the block.
518  // Operations that are somewhere in the middle of the block, and are sorted on
519  // demand.
521  // Operations that must appear last in a block, like successor phi node uses.
523 };
524 
525 // Associate global and local DFS info with defs and uses, so we can sort them
526 // into a global domination ordering.
527 struct ValueDFS
528 {
529  unsigned int DFSIn = 0;
530  unsigned int DFSOut = 0;
531  unsigned int LocalNum = LN_Middle;
532  // Only one of Def or Use will be set.
533  tree_nodeRef Def = nullptr;
534  OperandRef U = nullptr;
535  // Neither PInfo nor EdgeOnly participate in the ordering
536  PredicateBase* PInfo = nullptr;
537  bool EdgeOnly = false;
538 
539  std::string ToString()
540  {
541  return "Predicate info: " + (PInfo ? PInfo->OriginalOp->ToString() : "null") +
542  " Def: " + (Def ? Def->ToString() : "null") + " Use: " + (U ? U->getUser()->ToString() : "null") +
543  " EdgeOnly: " + (EdgeOnly ? "true" : "false");
544  }
545 };
546 
547 // This compares ValueDFS structures, creating OrderedBasicBlocks where
548 // necessary to compare uses/defs in the same block. Doing so allows us to walk
549 // the minimum number of instructions necessary to compute our def/use ordering.
551 {
553  explicit ValueDFS_Compare(OrderedInstructions& _OI) : OI(_OI)
554  {
555  }
556 
557  // For a phi use, or a non-materialized def, return the edge it represents.
558  const std::pair<unsigned int, unsigned int> getBlockEdge_local(const ValueDFS& VD) const
559  {
560  if(!VD.Def && VD.U)
561  {
562  const auto* PHI = GetPointer<const gimple_phi>(GET_CONST_NODE(VD.U->getUser()));
563  auto phiDefEdge = std::find_if(
564  PHI->CGetDefEdgesList().begin(), PHI->CGetDefEdgesList().end(), [&](const gimple_phi::DefEdge& de) {
565  return GET_INDEX_CONST_NODE(de.first) == GET_INDEX_CONST_NODE(VD.U->getOperand());
566  });
567  THROW_ASSERT(phiDefEdge != PHI->CGetDefEdgesList().end(), "Unable to find variable in phi definitions");
568  return std::make_pair(phiDefEdge->second, PHI->bb_index);
569  }
570  // This is really a non-materialized def.
571  return getBlockEdge(VD.PInfo);
572  }
573 
574  // For two phi related values, return the ordering.
575  bool comparePHIRelated(const ValueDFS& A, const ValueDFS& B) const
576  {
577  const auto ABlockEdge = getBlockEdge_local(A);
578  const auto BBlockEdge = getBlockEdge_local(B);
579  // Now sort by block edge and then defs before uses.
580  return std::tie(ABlockEdge, A.Def, A.U) < std::tie(BBlockEdge, B.Def, B.U);
581  }
582 
583  // Get the definition of an instruction that occurs in the middle of a block.
585  {
586  if(VD.Def)
587  {
588  return VD.Def;
589  }
590  return nullptr;
591  }
592 
593  // Return either the Def, if it's not null, or the user of the Use, if the def
594  // is null.
595  tree_nodeRef getDefOrUser(const tree_nodeRef Def, const OperandRef U) const
596  {
597  if(Def)
598  {
599  return Def;
600  }
601  return U->getUser();
602  }
603 
604  // This performs the necessary local basic block ordering checks to tell
605  // whether A comes before B, where both are in the same basic block.
606  bool localComesBefore(const ValueDFS& A, const ValueDFS& B) const
607  {
608  auto ADef = getMiddleDef(A);
609  auto BDef = getMiddleDef(B);
610  auto AInst = getDefOrUser(ADef, A.U);
611  auto BInst = getDefOrUser(BDef, B.U);
612  return valueComesBefore(OI, AInst, BInst);
613  }
614 
615  bool operator()(const ValueDFS& A, const ValueDFS& B) const
616  {
617  if(&A == &B)
618  {
619  return false;
620  }
621  // The only case we can't directly compare them is when they in the same
622  // block, and both have localnum == middle. In that case, we have to use
623  // comesbefore to see what the real ordering is, because they are in the
624  // same basic block.
625 
626  bool SameBlock = std::tie(A.DFSIn, A.DFSOut) == std::tie(B.DFSIn, B.DFSOut);
627 
628  // We want to put the def that will get used for a given set of phi uses,
629  // before those phi uses.
630  // So we sort by edge, then by def.
631  // Note that only phi nodes uses and defs can come last.
632  if(SameBlock && A.LocalNum == LN_Last && B.LocalNum == LN_Last)
633  {
634  return comparePHIRelated(A, B);
635  }
636 
637  if(!SameBlock || A.LocalNum != LN_Middle || B.LocalNum != LN_Middle)
638  {
639  return std::tie(A.DFSIn, A.DFSOut, A.LocalNum, A.Def, A.U) <
640  std::tie(B.DFSIn, B.DFSOut, B.LocalNum, B.Def, B.U);
641  }
642  return localComesBefore(A, B);
643  }
644 };
645 using ValueDFSStack = std::vector<ValueDFS>;
646 
647 bool stackIsInScope(const ValueDFSStack& Stack, const ValueDFS& VDUse, const OrderedInstructions& OI)
648 {
649  if(Stack.empty())
650  {
651  return false;
652  }
653  // If it's a phi only use, make sure it's for this phi node edge, and that the
654  // use is in a phi node. If it's anything else, and the top of the stack is
655  // EdgeOnly, we need to pop the stack. We deliberately sort phi uses next to
656  // the defs they must go with so that we can know it's time to pop the stack
657  // when we hit the end of the phi uses for a given def.
658  if(Stack.back().EdgeOnly)
659  {
660  if(!VDUse.U)
661  {
662  return false;
663  }
664  const auto* PHI = GetPointer<const gimple_phi>(GET_CONST_NODE(VDUse.U->getUser()));
665  if(!PHI)
666  {
667  return false;
668  }
669  // Check edge
670  auto EdgePredIt = std::find_if(
671  PHI->CGetDefEdgesList().begin(), PHI->CGetDefEdgesList().end(), [&](const gimple_phi::DefEdge& de) {
672  return GET_INDEX_CONST_NODE(de.first) == GET_INDEX_CONST_NODE(VDUse.U->getOperand());
673  });
674  if(EdgePredIt->second != getBranchBlock(Stack.back().PInfo))
675  {
676  return false;
677  }
678 
679  const auto bbedge = getBlockEdge(Stack.back().PInfo);
680  if(PHI->bb_index == bbedge.second && EdgePredIt->second == bbedge.first)
681  {
682  return true;
683  }
684  return OI.dominates(bbedge.second, EdgePredIt->second);
685  }
686 
687  return (VDUse.DFSIn >= Stack.back().DFSIn && VDUse.DFSOut <= Stack.back().DFSOut);
688 }
689 
691 {
692  while(!Stack.empty() && !stackIsInScope(Stack, VD, OI))
693  {
694  Stack.pop_back();
695  }
696 }
697 
698 // Convert the uses of Op into a vector of uses, associating global and local
699 // DFS info with each one.
700 void convertUsesToDFSOrdered(tree_nodeRef Op, std::vector<ValueDFS>& DFSOrderedSet, BBGraphRef DT,
701  const CustomMap<unsigned int, DFSInfo>& DFSInfos,
702  int
703 #ifndef NDEBUG
704  debug_level
705 #endif
706 )
707 {
708  const auto* op = GetPointer<const ssa_name>(GET_CONST_NODE(Op));
709  THROW_ASSERT(op, "Op is not an ssa_name (" + GET_CONST_NODE(Op)->get_kind_text() + ")");
710  const auto defBBI = GetPointer<const gimple_node>(GET_CONST_NODE(op->CGetDefStmt()))->bb_index;
711  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->");
712  for(auto& Usize : op->CGetUseStmts())
713  {
714  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Checking " + Usize.first->ToString());
715  const auto* gp = GetPointer<const gimple_phi>(GET_CONST_NODE(Usize.first));
716  if(gp)
717  {
718  if(gp->CGetDefEdgesList().size() == 1)
719  {
720  // Sigma uses not intresting (already e-SSA)
721  continue;
722  }
723  }
724 
725  const auto& U = Usize.first;
726  const auto* I = GetPointer<const gimple_node>(GET_CONST_NODE(U));
727  THROW_ASSERT(I, "Use statement should be a gimple_node");
728  if(I->bb_index == defBBI)
729  {
730  // Uses within the same basic block not intresting (they are casts or the actual branch eveluating the
731  // condition)
732  continue;
733  }
734 
735  const auto dfs_gen = [&](unsigned int IBlock) {
736  ValueDFS VD;
737  if(gp)
738  {
739  VD.LocalNum = LN_Last;
740  }
741  else
742  {
743  VD.LocalNum = LN_Middle;
744  }
745  const auto& BBmap = DT->CGetBBGraphInfo()->bb_index_map;
746  auto DomNode_vertex = BBmap.find(IBlock);
747  THROW_ASSERT(DomNode_vertex != BBmap.end(), "BB" + STR(IBlock) + " not found in DT");
748  // It's possible our use is in an unreachable block. Skip it if so.
749  if(!DT->IsReachable(BBmap.at(bloc::ENTRY_BLOCK_ID), DomNode_vertex->second))
750  {
752  "---BB" + STR(IBlock) + " is unreachable from DT root");
753  return;
754  }
755  const auto& DomNode_DFSInfo = DFSInfos.at(IBlock);
756  VD.DFSIn = DomNode_DFSInfo.DFSIn;
757  VD.DFSOut = DomNode_DFSInfo.DFSOut;
758  VD.U = OperandRef(new Operand(Op, U));
759  DFSOrderedSet.push_back(VD);
760  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Pushed on renaming stack");
761  };
762 
763  if(gp)
764  {
765  // #if HAVE_ASSERTS
766  // bool found = false;
767  // #endif
768  for(const auto& def_edge : gp->CGetDefEdgesList())
769  {
770  if(GET_INDEX_CONST_NODE(def_edge.first) == GET_INDEX_CONST_NODE(Op))
771  {
772  // #if HAVE_ASSERTS
773  // found = true;
774  // #endif
775  dfs_gen(def_edge.second);
776  }
777  }
778  // THROW_ASSERT(found, "");
779  }
780  else
781  {
782  dfs_gen(I->bb_index);
783  }
784  }
785  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
786 }
787 
788 // Given the renaming stack, make all the operands currently on the stack real
789 // by inserting them into the IR. Return the last operation's value.
790 tree_nodeRef materializeStack(ValueDFSStack& RenameStack, unsigned int function_id, statement_list* sl,
792  const BBGraphRef DT, tree_managerRef TM, tree_manipulationRef tree_man,
793  CustomMap<std::pair<unsigned int, unsigned int>, blocRef>& interBranchBBs,
795 #ifndef NDEBUG
796  ,
797  int debug_level
798 #endif
799 )
800 {
801  // Find the first thing we have to materialize
802  auto RevIter = RenameStack.rbegin();
803  for(; RevIter != RenameStack.rend(); ++RevIter)
804  {
805  if(RevIter->Def)
806  {
807  break;
808  }
809  }
810 
811  auto Start = RevIter - RenameStack.rbegin();
812  auto& BBmap = DT->GetBBGraphInfo()->bb_index_map;
813  // The maximum number of things we should be trying to materialize at once
814  // right now is 4, depending on if we had an assume, a branch, and both used
815  // and of conditions.
816  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->");
817  for(auto RenameIter = RenameStack.end() - Start; RenameIter != RenameStack.end(); ++RenameIter)
818  {
819  auto Op = OrigOp;
820  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Checking variable " + GET_CONST_NODE(Op)->ToString());
821  if(RenameIter != RenameStack.begin())
822  {
823  THROW_ASSERT((RenameIter - 1)->Def, "A valid definition shold be on the stack at this point");
824  const auto* gp = GetPointer<const gimple_phi>(GET_CONST_NODE((RenameIter - 1)->Def));
825  THROW_ASSERT(gp, "Previous definition on stack should be a gimple_phi (" +
826  GET_CONST_NODE((RenameIter - 1)->Def)->ToString() + ")");
827  Op = gp->res;
828  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Moving check to " + GET_CONST_NODE(Op)->ToString());
829  }
830  ValueDFS& Result = *RenameIter;
831  const auto* ValInfo = Result.PInfo;
832  // For edge predicates, we can just place the operand in the block before
833  // the terminator. For assume, we have to place it right before the assume
834  // to ensure we dominate all of our uses. Always insert right before the
835  // relevant instruction (terminator, assume), so that we insert in proper
836  // order in the case of multiple predicateinfo in the same block.
837  if(PredicateWithEdge::classof(ValInfo))
838  {
839  const auto* pwe = static_cast<const PredicateWithEdge*>(ValInfo);
840  THROW_ASSERT(BBmap.contains(pwe->To), "Basic block should be in dominator tree");
841  const auto& ToBB_vertex = BBmap.at(pwe->To);
842  const auto& ToBB = DT->CGetBBNodeInfo(ToBB_vertex)->block;
843  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Inserting into BB" + STR(ToBB->number));
844 
845  tree_nodeRef pic, new_ssa_var;
846  std::vector<std::pair<tree_nodeRef, unsigned int>> list_of_def_edge = {{Op, pwe->From}};
847  if(ToBB->list_of_pred.size() > 1) // New intermediate BB has to be created
848  {
849  blocRef interBB;
850  // Check if intermediate BB has already been created by previous renaming operation
851  auto from_number = std::make_pair(pwe->From, ToBB->number);
852  auto interBBIt = interBranchBBs.find(from_number);
853  if(interBBIt != interBranchBBs.end())
854  {
855  interBB = interBBIt->second;
856  }
857  else // When intermediate branch BB isn't present, create a new one
858  {
859  THROW_ASSERT(static_cast<bool>(BBmap.count(pwe->From)), "");
860  const auto& FromBB = DT->CGetBBNodeInfo(BBmap.at(pwe->From))->block;
861 
862  // Create new intermediate BB
863  const auto interBBI = (sl->list_of_bloc.rbegin())->first + 1;
864  interBB = sl->list_of_bloc[interBBI] = blocRef(new bloc(interBBI));
865  interBB->loop_id = FromBB->loop_id;
866  interBB->SetSSAUsesComputed();
867  interBB->schedule = FromBB->schedule;
868 
869  // Fix BB connections
870  FromBB->list_of_succ.erase(
871  std::remove(FromBB->list_of_succ.begin(), FromBB->list_of_succ.end(), ToBB->number),
872  FromBB->list_of_succ.end());
873  ToBB->list_of_pred.erase(
874  std::remove(ToBB->list_of_pred.begin(), ToBB->list_of_pred.end(), FromBB->number),
875  ToBB->list_of_pred.end());
876  FromBB->list_of_succ.push_back(interBBI);
877  interBB->list_of_pred.push_back(FromBB->number);
878  interBB->list_of_succ.push_back(ToBB->number);
879  ToBB->list_of_pred.push_back(interBBI);
880 
881  // Add new BB to intermediate branch block lookup list
882  interBranchBBs.insert({{FromBB->number, ToBB->number}, interBB});
883 
884  // Shadow incoming BB in dominator tree mapping
885  BBmap.insert({interBBI, BBmap.at(FromBB->number)});
886  DFSInfos.insert({interBBI, DFSInfos.at(FromBB->number)});
887 
888  // Fix branch routes
889  if(FromBB->false_edge == ToBB->number)
890  {
891  FromBB->false_edge = interBBI;
892  }
893  if(FromBB->true_edge == ToBB->number)
894  {
895  FromBB->true_edge = interBBI;
896  }
897 
898  // Fix multi_way_if routes
899  if(auto* mwi = GetPointer<gimple_multi_way_if>(GET_NODE(FromBB->CGetStmtList().back())))
900  {
901  for(auto& cond : mwi->list_of_cond)
902  {
903  if(cond.second == ToBB->number)
904  {
905  cond.second = interBBI;
906  }
907  }
908  }
909 
910  // Fix destination BB phis
911  for(const auto& phi : ToBB->CGetPhiList())
912  {
913  auto* gp = GetPointer<gimple_phi>(GET_NODE(phi));
914  const auto defFrom =
915  std::find_if(gp->CGetDefEdgesList().begin(), gp->CGetDefEdgesList().end(),
916  [&](const gimple_phi::DefEdge& de) { return de.second == FromBB->number; });
917  if(defFrom != gp->CGetDefEdgesList().end())
918  {
919  gp->ReplaceDefEdge(TM, *defFrom, {defFrom->first, interBBI});
920  }
921  }
922  }
923 
924  // Insert required sigma operation into the intermediate basic block
925  pic = tree_man->create_phi_node(new_ssa_var, list_of_def_edge, function_id);
926  const auto gp = GetPointer<gimple_phi>(GET_NODE(pic));
927  gp->SetSSAUsesComputed();
928  gp->artificial = true;
929  interBB->AddPhi(pic);
931  "---Insertion moved to intermediate BB" + STR(interBB->number));
932  }
933  else
934  {
935  // Insert required sigma operation into the destination basic block
936  pic = tree_man->create_phi_node(new_ssa_var, list_of_def_edge, function_id);
937  const auto gp = GetPointer<gimple_phi>(GET_NODE(pic));
938  gp->SetSSAUsesComputed();
939  gp->artificial = true;
940  ToBB->AddPhi(pic);
941  }
942 
943  // Clone renamed ssa properties
944  const auto* op = GetPointer<const ssa_name>(GET_CONST_NODE(Op));
945  auto* newSSA = GetPointer<ssa_name>(GET_NODE(new_ssa_var));
946  newSSA->bit_values = op->bit_values;
947  newSSA->range = RangeRef(op->range ? op->range->clone() : nullptr);
948  newSSA->min = op->min;
949  newSSA->max = op->max;
950  newSSA->var = op->var;
951 
952  PredicateMap.insert({pic, ValInfo});
953  Result.Def = pic;
954  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Materialized " + GET_CONST_NODE(pic)->ToString());
955  }
956  else
957  {
958  THROW_UNREACHABLE("Invalid PredicateInfo type");
959  }
960  }
961  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
962  return RenameStack.back().Def;
963 }
964 
965 // Instead of the standard SSA renaming algorithm, which is O(Number of
966 // instructions), and walks the entire dominator tree, we walk only the defs +
967 // uses. The standard SSA renaming algorithm does not really rely on the
968 // dominator tree except to order the stack push/pops of the renaming stacks, so
969 // that defs end up getting pushed before hitting the correct uses. This does
970 // not require the dominator tree, only the *order* of the dominator tree. The
971 // complete and correct ordering of the defs and uses, in dominator tree is
972 // contained in the DFS numbering of the dominator tree. So we sort the defs and
973 // uses into the DFS ordering, and then just use the renaming stack as per
974 // normal, pushing when we hit a def (which is a predicateinfo instruction),
975 // popping when we are out of the dfs scope for that def, and replacing any uses
976 // with top of stack if it exists. In order to handle liveness without
977 // propagating liveness info, we don't actually insert the predicateinfo
978 // instruction def until we see a use that it would dominate. Once we see such
979 // a use, we materialize the predicateinfo instruction in the right place and
980 // use it.
981 //
983  std::vector<ValueInfo>& ValueInfos, CustomMap<unsigned int, DFSInfo>& DFSInfos,
984  CustomSet<std::pair<unsigned int, unsigned int>>& EdgeUsesOnly, statement_list* sl)
985 {
986  const auto TM = AppM->get_tree_manager();
987  const auto tree_man = tree_manipulationRef(new tree_manipulation(TM, parameters, AppM));
988  CustomMap<std::pair<unsigned int, unsigned int>, blocRef> interBranchBBs;
989  bool modified = false;
990  // This maps from copy operands to Predicate Info. Note that it does not own
991  // the Predicate Info, they belong to the ValueInfo structs in the ValueInfos
992  // vector.
994  // Sort OpsToRename since we are going to iterate it.
995  std::vector<OperandRef> OpsToRename(OpSet.begin(), OpSet.end());
996  OrderedInstructions OI(DT);
997  auto Comparator = [&](const OperandRef A, const OperandRef B) {
998  return valueComesBefore(OI, A->getUser(), B->getUser());
999  };
1000  std::sort(OpsToRename.begin(), OpsToRename.end(), Comparator);
1001  ValueDFS_Compare Compare(OI);
1002 
1003  for(auto& Op : OpsToRename)
1004  {
1005  std::vector<ValueDFS> OrderedUses;
1006  const auto& ValueInfo = getValueInfo(Op->getOperand(), ValueInfoNums, ValueInfos);
1008  "Analysing " + Op->getOperand()->ToString() + " with " + STR(ValueInfo.Infos.size()) +
1009  " possible copies");
1010  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->");
1011  // Insert the possible copies into the def/use list.
1012  // They will become real copies if we find a real use for them, and never
1013  // created otherwise.
1014  for(auto& PossibleCopy : ValueInfo.Infos)
1015  {
1016  ValueDFS VD;
1017  if(PredicateWithEdge::classof(PossibleCopy))
1018  {
1019  // If we can only do phi uses, we treat it like it's in the branch
1020  // block, and handle it specially. We know that it goes last, and only
1021  // dominate phi uses.
1022  const auto BlockEdge = getBlockEdge(PossibleCopy);
1023  if(EdgeUsesOnly.count(BlockEdge))
1024  {
1025  // If we can only do phi uses, we treat it like it's in the branch
1026  // block, and handle it specially. We know that it goes last, and only
1027  // dominate phi uses.
1028  VD.LocalNum = LN_Last;
1029  const auto& DomNode = BlockEdge.first;
1030  if(DomNode)
1031  {
1032  THROW_ASSERT(DFSInfos.contains(DomNode), "Invalid DT node");
1033  const auto& DomNode_DFSInfo = DFSInfos.at(DomNode);
1034  VD.DFSIn = DomNode_DFSInfo.DFSIn;
1035  VD.DFSOut = DomNode_DFSInfo.DFSOut;
1036  VD.PInfo = PossibleCopy;
1037  VD.EdgeOnly = true;
1038  OrderedUses.push_back(VD);
1039  }
1040  }
1041  else
1042  {
1043  // Otherwise, we are in the split block (even though we perform
1044  // insertion in the branch block).
1045  // Insert a possible copy at the split block and before the branch.
1046  VD.LocalNum = LN_First;
1047  const auto& DomNode = BlockEdge.second;
1048  if(DomNode)
1049  {
1050  THROW_ASSERT(DFSInfos.contains(DomNode), "Invalid DT node");
1051  const auto& DomNode_DFSInfo = DFSInfos.at(DomNode);
1052  VD.DFSIn = DomNode_DFSInfo.DFSIn;
1053  VD.DFSOut = DomNode_DFSInfo.DFSOut;
1054  VD.PInfo = PossibleCopy;
1055  OrderedUses.push_back(VD);
1056  }
1057  }
1058  }
1059  }
1060 
1061  convertUsesToDFSOrdered(Op->getOperand(), OrderedUses, DT, DFSInfos, debug_level);
1062  // Here we require a stable sort because we do not bother to try to
1063  // assign an order to the operands the uses represent. Thus, two
1064  // uses in the same instruction do not have a strict sort order
1065  // currently and will be considered equal. We could get rid of the
1066  // stable sort by creating one if we wanted.
1067  std::stable_sort(OrderedUses.begin(), OrderedUses.end(), Compare);
1068  std::vector<ValueDFS> RenameStack;
1069  // For each use, sorted into dfs order, push values and replaces uses with
1070  // top of stack, which will represent the reaching def.
1071  for(auto& VD : OrderedUses)
1072  {
1073  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Analysing " + VD.ToString());
1074  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->");
1075 
1076  // We currently do not materialize copy over copy, but we should decide if
1077  // we want to.
1078  bool PossibleCopy = VD.PInfo != nullptr;
1079 #ifndef NDEBUG
1080  if(RenameStack.empty())
1081  {
1082  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "RenameStack empty");
1083  }
1084  else
1085  {
1087  "RenameStack top DFS numbers are (" + STR(RenameStack.back().DFSIn) + "," +
1088  STR(RenameStack.back().DFSOut) + ")");
1089  }
1090 #endif
1092  "Current DFS numbers are (" + STR(VD.DFSIn) + "," + STR(VD.DFSOut) + ")");
1093  bool ShouldPush = (VD.Def || PossibleCopy);
1094  bool OutOfScope = !stackIsInScope(RenameStack, VD, OI);
1095  if(OutOfScope || ShouldPush)
1096  {
1097  // Sync to our current scope.
1098  popStackUntilDFSScope(RenameStack, VD, OI);
1099  if(ShouldPush)
1100  {
1101  RenameStack.push_back(VD);
1102  }
1103  }
1104  // If we get to this point, and the stack is empty we must have a use
1105  // with no renaming needed, just skip it.
1106  if(RenameStack.empty())
1107  {
1108  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Current use needs no renaming");
1109  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1110  continue;
1111  }
1112  // Skip values, only want to rename the uses
1113  if(VD.Def || PossibleCopy)
1114  {
1115  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1116  continue;
1117  }
1118 
1119  ValueDFS& Result = RenameStack.back();
1120  THROW_ASSERT(VD.U, "A use sohuld be in scope for current renaming operation");
1121 #if HAVE_ASSERTS
1122  if(const auto* gp = GetPointer<const gimple_phi>(GET_CONST_NODE(VD.U->getUser())))
1123  {
1124  THROW_ASSERT(gp->CGetDefEdgesList().size() > 1,
1125  "Sigma operation should not be renamed (BB" + STR(gp->bb_index) + " " + gp->ToString() + ")");
1126  }
1127 #endif
1128 
1129  // If the possible copy dominates something, materialize our stack up to
1130  // this point. This ensures every comparison that affects our operation
1131  // ends up with predicateinfo.
1132  if(!Result.Def)
1133  {
1134  if(not AppM->ApplyNewTransformation())
1135  {
1136  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1137  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1138  return modified;
1139  }
1140  Result.Def = materializeStack(RenameStack, function_id, sl, Op->getOperand(), PredicateMap, DT, TM,
1141  tree_man, interBranchBBs, DFSInfos
1142 #ifndef NDEBUG
1143  ,
1144  debug_level
1145 #endif
1146  );
1147  }
1148 
1150  "---Found replacement " + GET_CONST_NODE(Result.Def)->ToString() + " for " +
1151  GET_CONST_NODE(VD.U->getOperand())->ToString() + " in " +
1152  GET_CONST_NODE(VD.U->getUser())->ToString());
1153  const auto* phi = GetPointer<const gimple_phi>(GET_CONST_NODE(Result.Def));
1154 #if 0
1155  if(!valueComesBefore(OI, Result.Def, VD.U->getUser()))
1156  {
1157  const auto defVertex = DT->CGetBBGraphInfo()->bb_index_map.at(GetPointer<const gimple_node>(GET_CONST_NODE(Result.Def))->bb_index);
1158  const auto defBB = DT->CGetBBNodeInfo(defVertex)->block;
1159  const auto defBB_succ = defBB->list_of_succ;
1160  if(std::find(defBB_succ.begin(), defBB_succ.end(), defBB->number) == defBB_succ.end())
1161  {
1162  THROW_UNREACHABLE("PredicateInfo def should have dominated this use at least in the CFG");
1163  }
1164  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---New definition not dominating use in DT, but in CFG only");
1165  }
1166 #endif
1167  if(not AppM->ApplyNewTransformation())
1168  {
1169  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1170  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1171  return modified;
1172  }
1173  AppM->RegisterTransformation(GetName(), VD.U->getUser());
1174  VD.U->set(phi->res, TM);
1175  modified = true;
1176  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1177  }
1178  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--");
1179  }
1180  return modified;
1181 }
1182 
1183 eSSA::eSSA(const ParameterConstRef params, const application_managerRef AM, unsigned int f_id,
1184  const DesignFlowManagerConstRef dfm)
1185  : FunctionFrontendFlowStep(AM, f_id, ESSA, dfm, params)
1186 {
1187  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
1188 }
1189 
1190 eSSA::~eSSA() = default;
1191 
1194 {
1196  switch(relationship_type)
1197  {
1199  {
1200  relationships.insert(std::make_pair(BLOCK_FIX, SAME_FUNCTION));
1201  relationships.insert(std::make_pair(EXTRACT_GIMPLE_COND_OP, SAME_FUNCTION));
1202  relationships.insert(std::make_pair(IR_LOWERING, SAME_FUNCTION));
1203  relationships.insert(std::make_pair(USE_COUNTING, SAME_FUNCTION));
1204  break;
1205  }
1207  {
1208  relationships.insert(std::make_pair(DETERMINE_MEMORY_ACCESSES, SAME_FUNCTION));
1209  relationships.insert(std::make_pair(UN_COMPARISON_LOWERING, SAME_FUNCTION));
1210  break;
1211  }
1213  {
1214  break;
1215  }
1216  default:
1217  THROW_UNREACHABLE("");
1218  }
1219  return relationships;
1220 }
1221 
1223 {
1224 }
1225 
1227 {
1228  auto TM = AppM->get_tree_manager();
1229  const auto* fd = GetPointer<const function_decl>(TM->get_tree_node_const(function_id));
1230  auto* sl = GetPointer<statement_list>(GET_NODE(fd->body));
1231 
1232  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Extended SSA step");
1233  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Dominator tree computation...");
1234 
1236  BBGraphsCollectionRef GCC_bb_graphs_collection(
1238  BBGraph GCC_bb_graph(GCC_bb_graphs_collection, CFG_SELECTOR);
1239  CustomUnorderedMap<unsigned int, vertex> inverse_vertex_map;
1241  for(const auto& block : sl->list_of_bloc)
1242  {
1243  inverse_vertex_map.try_emplace(block.first,
1244  GCC_bb_graphs_collection->AddVertex(BBNodeInfoRef(new BBNodeInfo(block.second))));
1245  }
1246 
1248  for(const auto& curr_bb_pair : sl->list_of_bloc)
1249  {
1250  unsigned int curr_bb = curr_bb_pair.first;
1251  for(const auto& lop : sl->list_of_bloc.at(curr_bb)->list_of_pred)
1252  {
1253  THROW_ASSERT(static_cast<bool>(inverse_vertex_map.count(lop)),
1254  "BB" + STR(lop) + " (successor of BB" + STR(curr_bb) + ") does not exist");
1255  GCC_bb_graphs_collection->AddEdge(inverse_vertex_map.at(lop), inverse_vertex_map.at(curr_bb), CFG_SELECTOR);
1256  }
1257 
1258  for(const auto& los : sl->list_of_bloc.at(curr_bb)->list_of_succ)
1259  {
1260  if(los == bloc::EXIT_BLOCK_ID)
1261  {
1262  GCC_bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bb), inverse_vertex_map.at(los), CFG_SELECTOR);
1263  }
1264  }
1265 
1266  if(sl->list_of_bloc.at(curr_bb)->list_of_succ.empty())
1267  {
1268  GCC_bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bb), inverse_vertex_map.at(bloc::EXIT_BLOCK_ID),
1269  CFG_SELECTOR);
1270  }
1271  }
1272 
1274  GCC_bb_graphs_collection->AddEdge(inverse_vertex_map.at(bloc::ENTRY_BLOCK_ID),
1275  inverse_vertex_map.at(bloc::EXIT_BLOCK_ID), CFG_SELECTOR);
1276 
1277  dominance<BBGraph> bb_dominators(GCC_bb_graph, inverse_vertex_map.at(bloc::ENTRY_BLOCK_ID),
1278  inverse_vertex_map.at(bloc::EXIT_BLOCK_ID), parameters);
1280 
1281  DT.reset(new BBGraph(GCC_bb_graphs_collection, D_SELECTOR));
1282  for(const auto& it : bb_dominators.get_dominator_map())
1283  {
1284  if(it.first != inverse_vertex_map.at(bloc::ENTRY_BLOCK_ID))
1285  {
1286  GCC_bb_graphs_collection->AddEdge(it.second, it.first, D_SELECTOR);
1287  }
1288  }
1289  DT->GetBBGraphInfo()->bb_index_map = std::move(inverse_vertex_map);
1291  "Dominator tree computation completed (" + STR(DT->num_bblocks()) + " BB generated)");
1292 
1293  // This stores info about each operand or comparison result we make copies
1294  // of. The real ValueInfos start at index 1, index 0 is unused so that we can
1295  // more easily detect invalid indexing.
1296  std::vector<ValueInfo> ValueInfos;
1297  ValueInfos.resize(1);
1298  // This gives the index into the ValueInfos array for a given Value. Because
1299  // 0 is not a valid Value Info index, you can use DenseMap::lookup and tell
1300  // whether it returned a valid result.
1301  ValueInfoLookup ValueInfoNums;
1302  // The set of edges along which we can only handle phi uses, due to critical edges.
1304  // Collect operands to rename from all conditional branch terminators, as well
1305  // as multi-way if.
1306  CustomSet<OperandRef> OpsToRename;
1307 
1308  const auto BBvisit = [&](blocRef BB) {
1309  const auto& stmt_list = BB->CGetStmtList();
1310 
1311  // Skip empty BB
1312  if(stmt_list.empty())
1313  {
1315  return;
1316  }
1317 
1318  const auto terminator = stmt_list.back();
1320  "Block terminates with " + GET_NODE(terminator)->get_kind_text());
1322  if(GET_CONST_NODE(terminator)->get_kind() == gimple_cond_K)
1323  {
1324  processBranch(terminator, OpsToRename, ValueInfoNums, ValueInfos, EdgeUsesOnly, sl->list_of_bloc, debug_level);
1325  }
1326  else if(GET_CONST_NODE(terminator)->get_kind() == gimple_multi_way_if_K)
1327  {
1328  processMultiWayIf(terminator, OpsToRename, ValueInfoNums, ValueInfos, EdgeUsesOnly, sl->list_of_bloc,
1329  debug_level);
1330  }
1332  };
1333 
1334  // This map stores DFS numeration for each DT node
1336 
1337  std::stack<std::pair<vertex, boost::iterator_range<BBGraph::adjacency_iterator>>> workStack;
1338  const auto entryVertex = DT->GetBBGraphInfo()->bb_index_map.at(bloc::ENTRY_BLOCK_ID);
1339  workStack.push({entryVertex, boost::make_iterator_range(boost::adjacent_vertices(entryVertex, *DT))});
1340 
1341  unsigned int DFSNum = 0;
1342  const auto& BBentry = DT->CGetBBNodeInfo(workStack.top().first)->block;
1343  DFSInfos[BBentry->number].DFSIn = DFSNum++;
1344  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Analysing BB" + STR(BBentry->number));
1346  BBvisit(BBentry);
1348 
1349  while(!workStack.empty())
1350  {
1351  const auto& BB = DT->CGetBBNodeInfo(workStack.top().first)->block;
1352  auto ChildRange = workStack.top().second;
1353 
1354  // If we visited all of the children of this node, "recurse" back up the
1355  // stack setting the DFOutNum.
1356  if(ChildRange.empty())
1357  {
1358  DFSInfos[BB->number].DFSOut = DFSNum++;
1359  workStack.pop();
1360  }
1361  else
1362  {
1363  // Otherwise, recursively visit this child.
1364  const auto& Child = DT->CGetBBNodeInfo(ChildRange.front())->block;
1365  workStack.top().second.pop_front();
1366 
1367  workStack.push(
1368  {ChildRange.front(), boost::make_iterator_range(boost::adjacent_vertices(ChildRange.front(), *DT))});
1369  DFSInfos[Child->number].DFSIn = DFSNum++;
1370 
1371  // Perform BB analysis for eSSA purpose
1372  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Analysing BB" + STR(Child->number));
1374  BBvisit(Child);
1376  }
1377  }
1378 #ifndef NDEBUG
1379  if(static_cast<size_t>(DFSInfos.size()) < (DT->num_bblocks() + 2))
1380  {
1381  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Dominator tree has some unreachable blocks");
1382  }
1383 #endif
1385  "Analysis detected " + STR(OpsToRename.size()) + " operations to rename");
1386  if(OpsToRename.empty())
1387  {
1388  DT.reset();
1391  }
1392 
1393  const auto modified = renameUses(OpsToRename, ValueInfoNums, ValueInfos, DFSInfos, EdgeUsesOnly, sl);
1394  DT.reset();
1396 
1397  modified ? function_behavior->UpdateBBVersion() : 0;
1399 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
bool dominates(const unsigned int BBIA, const unsigned int BBIB) const
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
This struct specifies the field bloc (basic block).
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
tree_nodeRef Def
Definition: eSSA.cpp:533
bool localComesBefore(const ValueDFS &A, const ValueDFS &B) const
Definition: eSSA.cpp:606
Definition: eSSA.cpp:64
DesignFlowStep_Status InternalExec() override
compute the e-SSA form
Definition: eSSA.cpp:1226
std::string ToString() const
Print this node as string in gimple format.
Step successfully executed.
const std::pair< unsigned int, unsigned int > getBlockEdge(const PredicateBase *PB)
Definition: eSSA.cpp:501
std::vector< ValueDFS > ValueDFSStack
Definition: eSSA.cpp:645
Definition of the node_info object for the basic_block graph.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
tree_nodeRef branchOpRecurse(tree_nodeRef op, tree_nodeRef stmt=nullptr)
Definition: eSSA.cpp:238
BBGraphInfoRef GetBBGraphInfo()
Returns the property associated with the graph.
LocalNum
Definition: eSSA.cpp:514
tree_nodeRef operand
Definition: eSSA.cpp:66
bool comparePHIRelated(const ValueDFS &A, const ValueDFS &B) const
Definition: eSSA.cpp:575
This struct specifies the statement_list node.
Definition: tree_node.hpp:4662
Definition of the class representing a generic C application.
refcount< tree_manipulation > tree_manipulationRef
void addInfoFor(OperandRef Op, PredicateBase *PB, CustomSet< OperandRef > &OpsToRename, eSSA::ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos)
Definition: eSSA.cpp:223
RelationshipType
The relationship type.
Source must be executed to satisfy target.
PredicateWithEdge(kind PType, tree_nodeConstRef Op, unsigned int _From, unsigned int _To)
Definition: eSSA.cpp:170
const std::pair< unsigned int, unsigned int > getBlockEdge_local(const ValueDFS &VD) const
Definition: eSSA.cpp:558
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
bool stackIsInScope(const ValueDFSStack &Stack, const ValueDFS &VDUse, const OrderedInstructions &OI)
Definition: eSSA.cpp:647
bool EdgeOnly
Definition: eSSA.cpp:537
#define D_SELECTOR
Selectors used only in basic block graphs; numbers continue from cdfg_edge_info.hpp.
Definition: basic_block.hpp:85
A simple interface to token object of the raw files.
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
Definition: eSSA.cpp:1222
std::map< unsigned int, blocRef > list_of_bloc
list_of_bloc field is the list of basic block. If this field is null then the list_of_stmt field is n...
Definition: tree_node.hpp:4673
static const unsigned int EXIT_BLOCK_ID
constant identifying the exit basic block
Data structure describing a basic block at tree level.
kind Type
Definition: eSSA.cpp:140
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define A
Definition: generate.c:13
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
eSSA(const ParameterConstRef Param, const application_managerRef AM, unsigned int f_id, const DesignFlowManagerConstRef dfm)
Constructor.
Definition: eSSA.cpp:1183
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
void processMultiWayIf(tree_nodeConstRef mwii, CustomSet< OperandRef > &OpsToRename, eSSA::ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos, CustomSet< std::pair< unsigned int, unsigned int >> &EdgeUsesOnly, const std::map< unsigned int, blocRef > &BBs, int debug_level)
Definition: eSSA.cpp:393
OperandRef U
Definition: eSSA.cpp:534
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
void popStackUntilDFSScope(ValueDFSStack &Stack, const ValueDFS &VD, const OrderedInstructions &OI)
Definition: eSSA.cpp:690
Class used to describe a particular graph with basic blocks as nodes.
~eSSA() override
Destructor.
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
ValueInfo & getOrCreateValueInfo(tree_nodeConstRef Operand, eSSA::ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos)
Definition: eSSA.cpp:207
tree_nodeRef getMiddleDef(const ValueDFS &VD) const
Definition: eSSA.cpp:584
Information associated with the whole basic-block graph.
unsigned int DFSIn
Definition: eSSA.cpp:529
kind
std::pair< tree_nodeRef, unsigned int > DefEdge
The type of the def edge.
Definition: tree_node.hpp:3750
unsigned int From
Definition: eSSA.cpp:162
unsigned int To
Definition: eSSA.cpp:163
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
tree_nodeRef getDefOrUser(const tree_nodeRef Def, const OperandRef U) const
Definition: eSSA.cpp:595
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
const tree_nodeRef user_stmt
Definition: eSSA.cpp:68
void calculate_dominance_info(enum dominance::cdi_direction dir)
The main entry point into this module.
Definition: Dominance.hpp:701
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
Wrapper of design_flow.
This struct specifies the block node.
Definition: tree_node.hpp:1820
This file collects some utility functions.
unsigned int LocalNum
Definition: eSSA.cpp:531
bool renameUses(CustomSet< OperandRef > &OpSet, ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos, CustomMap< unsigned int, DFSInfo > &DFSInfos, CustomSet< std::pair< unsigned int, unsigned int >> &EdgeUsesOnly, statement_list *sl)
Definition: eSSA.cpp:982
void processBranch(tree_nodeConstRef bi, CustomSet< OperandRef > &OpsToRename, eSSA::ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos, CustomSet< std::pair< unsigned int, unsigned int >> &EdgeUsesOnly, const std::map< unsigned int, blocRef > &BBs, int debug_level)
Definition: eSSA.cpp:277
ValueDFS_Compare(OrderedInstructions &_OI)
Definition: eSSA.cpp:553
const unsigned int function_id
The index of the function to be analyzed.
static bool classof(const PredicateBase *PB)
Definition: eSSA.cpp:165
std::vector< PredicateBase * > Infos
Definition: eSSA.cpp:193
const application_managerRef AppM
The application manager.
Class specification of the tree_reindex support class.
static const unsigned int ENTRY_BLOCK_ID
constant identifying the entry basic block
PredicateBase(kind PT, tree_nodeConstRef Op)
Definition: eSSA.cpp:151
const tree_nodeRef getOperand() const
Definition: eSSA.cpp:76
OrderedInstructions & OI
Definition: eSSA.cpp:552
const BBNodeInfoConstRef CGetBBNodeInfo(const vertex node) const
Return the info associated with a basic block.
Operand(const tree_nodeRef _operand, tree_nodeRef stmt)
Definition: eSSA.cpp:71
unsigned int DFSOut
Definition: eSSA.cpp:530
void convertUsesToDFSOrdered(tree_nodeRef Op, std::vector< ValueDFS > &DFSOrderedSet, BBGraphRef DT, const CustomMap< unsigned int, DFSInfo > &DFSInfos, int debug_level)
Definition: eSSA.cpp:700
const ValueInfo & getValueInfo(tree_nodeConstRef Operand, eSSA::ValueInfoLookup &ValueInfoNums, std::vector< ValueInfo > &ValueInfos)
Definition: eSSA.cpp:197
Classes specification of the tree_node data structures not present in the gcc.
this class is used to manage the command-line or XML options.
tree_nodeRef materializeStack(ValueDFSStack &RenameStack, unsigned int function_id, statement_list *sl, tree_nodeRef OrigOp, CustomMap< tree_nodeConstRef, const PredicateBase *> &PredicateMap, const BBGraphRef DT, tree_managerRef TM, tree_manipulationRef tree_man, CustomMap< std::pair< unsigned int, unsigned int >, blocRef > &interBranchBBs, CustomMap< unsigned int, DFSInfo > &DFSInfos, int debug_level)
Definition: eSSA.cpp:790
bool isCompare(const struct binary_expr *condition)
Definition: eSSA.cpp:231
bool valueComesBefore(OrderedInstructions &OI, tree_nodeConstRef A, tree_nodeConstRef B)
Definition: eSSA.cpp:493
const tree_nodeRef getUser() const
Definition: eSSA.cpp:81
size_t num_bblocks() const
Returns the number of basic blocks contained into the graph.
const CustomUnorderedSet< std::pair< FrontendFlowStepType, FunctionRelationship > > ComputeFrontendRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
Definition: eSSA.cpp:1193
int debug_level
The debug level.
tree_nodeConstRef OriginalOp
Definition: eSSA.cpp:144
tree_nodeRef create_phi_node(tree_nodeRef &ssa_res, const std::vector< std::pair< tree_nodeRef, unsigned int >> &list_of_def_edge, unsigned int function_decl_nid, bool virtual_flag=false) const
GIMPLE_PHI.
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
struct definition of the binary node structures.
Definition: tree_node.hpp:1206
#define CFG_SELECTOR
Control flow graph edge selector.
#define B
Definition: generate.c:14
CustomMap< tree_nodeConstRef, unsigned int > ValueInfoLookup
Definition: eSSA.hpp:61
refcount< BBGraphInfo > BBGraphInfoRef
refcount definition of the class
This class contains the base representation for a generic frontend flow step which works on the whole...
BBGraphRef DT
Definition: eSSA.hpp:64
unsigned int getBranchBlock(const PredicateBase *PB)
Definition: eSSA.cpp:180
std::vector< PredicateBase * > UninsertedInfos
Definition: eSSA.cpp:194
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
bool operator()(const ValueDFS &A, const ValueDFS &B) const
Definition: eSSA.cpp:615
std::string ToString()
Definition: eSSA.cpp:539
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
int sl
Definition: adpcm.c:105
This structure defines graphs where nodes are basic_blocks.
PredicateBase * PInfo
Definition: eSSA.cpp:536
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:51 for PandA-2024.02 by doxygen 1.8.13