PandA-2024.02
soft_float_cg_ext.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  */
42 #include "soft_float_cg_ext.hpp"
44 
46 #include "design_flow_graph.hpp"
47 #include "design_flow_manager.hpp"
48 #include "design_flow_step.hpp"
49 
51 #include "FunctionCallOpt.hpp"
52 
54 #include "application_manager.hpp"
55 #include "behavioral_helper.hpp"
56 #include "call_graph.hpp"
57 #include "call_graph_manager.hpp"
58 #include "function_behavior.hpp"
59 
61 #include "basic_block.hpp"
63 #include "op_graph.hpp"
64 
66 #include "Parameter.hpp"
67 
69 #include "custom_map.hpp"
70 #include <algorithm>
71 #include <deque>
72 #include <list>
73 #include <set>
74 #include <string>
75 
77 #include "ext_tree_node.hpp"
78 #include "tree_basic_block.hpp"
79 #include "tree_helper.hpp"
80 #include "tree_manager.hpp"
81 #include "tree_manipulation.hpp"
82 #include "tree_node.hpp"
83 #include "tree_node_dup.hpp"
84 #include "tree_reindex.hpp"
85 
86 #include "var_pp_functor.hpp"
87 
89 #include "dbgPrintHelper.hpp"
90 #include "exceptions.hpp"
91 #include "math.h"
92 #include "string_manipulation.hpp" // for GET_CLASS
93 #include <boost/multiprecision/integer.hpp>
94 #include <regex>
95 
104 
105 static const FloatFormatRef float32FF(new FloatFormat(8, 23, -127));
106 static const FloatFormatRef float64FF(new FloatFormat(11, 52, -1023));
107 
108 static const std::set<std::string> supported_libm_calls = {
109  "copysign", "fabs", "finite", "fpclassify", "huge_val", "inf", "infinity", "isfinite",
110  "isinf", "isinf_sign", "isnan", "isnormal", "nan", "nans", "signbit"};
111 static const std::set<std::string> supported_libm_calls_inlined = {"copysign", "fabs"};
112 
118 static const std::set<std::string> libm_func = {
119  "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "cbrt", "ceil",
120  "copysign", "cos", "cosh", "erf", "erfc", "exp", "exp2", "expm1", "fabs",
121  "fdim", "finite", "floor", "fma", "fmod", "fpclassify", "frexp", "huge_val", "hypot",
122  "ilogb", "inf", "infinity", "isfinite", "isinf", "isinf_sign", "isnan", "isnormal", "ldexp",
123  "lgamma", "llrint", "llround", "log", "log10", "log1p", "log2", "logb", "lrint",
124  "lround", "modf", "nan", "nans", "nearbyint", "nextafter", "nexttoward", "pow", "remainder",
125  "remquo", "rint", "round", "scalb", "scalbln", "scalbn", "sin", "signbit", "sinh",
126  "sincos", "sqrt", "tan", "tanh", "tgamma", "trunc"};
127 
128 static std::string strip_fname(std::string fname, bool* single_prec = nullptr)
129 {
130  if(single_prec)
131  {
132  *single_prec = false;
133  }
134  if(fname.find("__internal_") == 0)
135  {
136  fname = fname.substr(sizeof("__internal_") - 1);
137  }
138  else if(fname.find("__builtin_") == 0)
139  {
140  fname = fname.substr(sizeof("__builtin_") - 1);
141  }
142  else if(fname.find("__") == 0)
143  {
144  fname = fname.substr(sizeof("__") - 1);
145  }
146  if(fname.back() == 'f' && libm_func.count(fname.substr(0, fname.size() - 1)))
147  {
148  fname = fname.substr(0, fname.size() - 1);
149  if(single_prec)
150  {
151  *single_prec = true;
152  }
153  }
154  return fname;
155 }
156 
158  unsigned int _function_id, const DesignFlowManagerConstRef _design_flow_manager)
159  : FunctionFrontendFlowStep(_AppM, _function_id, SOFT_FLOAT_CG_EXT, _design_flow_manager, _parameters),
160  TreeM(_AppM->get_tree_manager()),
161  tree_man(new tree_manipulation(TreeM, parameters, _AppM)),
162  fd(GetPointer<function_decl>(TreeM->GetTreeNode(function_id))),
163  isTopFunction(AppM->CGetCallGraphManager()->GetRootFunctions().count(function_id)),
164  bindingCompleted(fd->list_of_args.size() == 0),
165  paramBinding(fd->list_of_args.size(), nullptr)
166 {
167  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
168 
169  if(!float32_type)
170  {
175  if(parameters->isOption(OPT_fp_subnormal) && parameters->getOption<bool>(OPT_fp_subnormal))
176  {
177  float32FF->has_subnorm = true;
178  float64FF->has_subnorm = true;
179  }
180  if(parameters->isOption(OPT_fp_rounding_mode))
181  {
182  const auto rnd_mode = parameters->getOption<std::string>(OPT_fp_rounding_mode);
183  if(rnd_mode == "nearest_even")
184  {
187  }
188  else if(rnd_mode == "truncate")
189  {
192  }
193  else
194  {
195  THROW_UNREACHABLE("Floating-point rounding mode not supported: " + STR(rnd_mode));
196  }
197  }
198  if(parameters->isOption(OPT_fp_exception_mode))
199  {
200  const auto exc_mode = parameters->getOption<std::string>(OPT_fp_exception_mode);
201  if(exc_mode == "ieee")
202  {
203  float32FF->exception_mode = FloatFormat::FPException_IEEE;
204  float64FF->exception_mode = FloatFormat::FPException_IEEE;
205  }
206  else if(exc_mode == "saturation")
207  {
210  }
211  else if(exc_mode == "overflow")
212  {
215  }
216  else
217  {
218  THROW_UNREACHABLE("Floating-point exception mode not supported: " + STR(exc_mode));
219  }
220  }
221  }
222 
223  if(funcFF.empty() && !parameters->getOption<std::string>(OPT_fp_format).empty())
224  {
225  const auto CGM = AppM->CGetCallGraphManager();
226  auto opts = SplitString(parameters->getOption<std::string>(OPT_fp_format), ",");
227  const auto inline_math_it = std::find(opts.begin(), opts.end(), "inline-math");
228  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "-->Soft-float fp format specialization required:");
229  if(inline_math_it != opts.end())
230  {
231  opts.erase(inline_math_it);
232  inline_math = true;
233  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Full inlining of floating-point arithmetic operators");
234  }
235  const auto inline_conversion_it = std::find(opts.begin(), opts.end(), "inline-conversion");
236  if(inline_conversion_it != opts.end())
237  {
238  opts.erase(inline_conversion_it);
239  inline_conversion = true;
240  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Full inlining of floating-point conversion operators");
241  }
243  for(const auto& opt : opts)
244  {
245  auto format = SplitString(opt, "*");
246 
247  const auto f_index = [&]() {
248  if(format[0] == "@")
249  {
250  const auto top_symbols = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
251  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
252  if(top_symbols.size() > 1)
253  {
254  THROW_WARNING("Multiple top functions defined, @ is replaced with first one.");
255  }
256  format[0] = top_symbols.front();
257  }
258  const auto f_node = TreeM->GetFunction(format[0]);
259  return f_node ? GET_INDEX_CONST_NODE(f_node) : 0;
260  }();
261 
262  if(!f_index)
263  {
264  THROW_ERROR("Function " + format[0] + " does not exists. (Maybe it has been inlined)");
265  }
266  const auto function_v = CGM->GetVertex(f_index);
267  if(funcFF.count(function_v))
268  {
269  THROW_ERROR("Function " + format[0] + " already specialized.");
270  }
271 
272  const auto userFF = FloatFormat::FromString(format[1]);
273  THROW_ASSERT(userFF, "FP format for function " + STR(format[0]) + " not valid");
274  funcFF.insert({function_v, FunctionVersionRef(new FunctionVersion(function_v, userFF))});
276  format[0] + " specialized with fp format " + userFF->ToString());
277  }
279 
280  // Propagate floating-point format specialization over to called functions
281  if(parameters->isOption(OPT_fp_format_propagate) && parameters->getOption<bool>(OPT_fp_format_propagate))
282  {
283  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Soft-float fp format propagation enabled:");
285  for(const auto& root_func : CGM->GetRootFunctions())
286  {
287  std::list<CallGraph::vertex_descriptor> func_sort;
289  const auto reached_from_top = CGM->GetReachedFunctionsFrom(root_func);
290  for(const auto func_id : reached_from_top)
291  {
292  reached_v.insert(CGM->GetVertex(func_id));
293  }
294  const auto TopCG = CGM->CGetCallSubGraph(reached_v);
295  TopCG->TopologicalSort(func_sort);
296 
297  for(const auto func : func_sort)
298  {
299  // Initialize current function version
300  FunctionVersionRef current_v;
301  if(static_cast<bool>(funcFF.count(func)))
302  {
303  current_v = funcFF.at(func);
304  }
305  else
306  {
307  current_v = FunctionVersionRef(new FunctionVersion(func));
308 #if HAVE_ASSERTS
309  const auto insertion =
310 #endif
311  funcFF.insert({func, current_v});
312  THROW_ASSERT(insertion.second, "");
313  }
314 
315  // Check callers' function version
316  FloatFormatRef callers_ff =
317  !current_v->callers.empty() ? current_v->callers.front()->userRequired : nullptr;
318  const auto common_null = callers_ff == nullptr;
319  for(const auto& caller : current_v->callers)
320  {
321  const auto caller_null = caller->userRequired == nullptr;
322  if((caller_null ^ common_null) || (!common_null && *callers_ff != *caller->userRequired))
323  {
324  callers_ff = nullptr;
325  break;
326  }
327  }
328 
329  // Update current function fp format
330  if(current_v->userRequired == nullptr)
331  {
332  current_v->userRequired = callers_ff;
333  current_v->internal = true;
334  }
335  else if(callers_ff == nullptr)
336  {
337  current_v->internal = current_v->callers.empty();
338  }
339  else
340  {
341  current_v->internal = *current_v->userRequired == *callers_ff;
342  }
343 
344  const auto func_id = AppM->CGetCallGraphManager()->get_function(func);
347  "Analysing function " +
348  tree_helper::print_type(TreeM, func_id, false, true, false, 0U,
350  AppM->CGetFunctionBehavior(func_id)->CGetBehavioralHelper()))));
351  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "---FP format " + current_v->ToString());
352 
353  // Propagate current fp format to the called functions
354  CallGraph::out_edge_iterator ei, ei_end;
355  for(boost::tie(ei, ei_end) = boost::out_edges(func, *TopCG); ei != ei_end; ++ei)
356  {
357  const auto called = boost::target(*ei, *TopCG);
358  const auto fname = tree_helper::print_function_name(
359  TreeM, GetPointerS<const function_decl>(TreeM->CGetTreeNode(CGM->get_function(called))));
360  const auto called_fname = strip_fname(fname);
361  if(static_cast<bool>(libm_func.count(called_fname)))
362  {
363  // Do not propagate format to libm functions, specialization will be handled successively
364  continue;
365  }
366  FunctionVersionRef called_v;
367  if(static_cast<bool>(funcFF.count(called)))
368  {
369  called_v = funcFF.at(called);
370  }
371  else
372  {
373  called_v = FunctionVersionRef(new FunctionVersion(called));
374 #if HAVE_ASSERTS
375  const auto insertion =
376 #endif
377  funcFF.insert({called, called_v});
378  THROW_ASSERT(insertion.second, "");
379  }
380  called_v->callers.push_back(current_v);
381  }
382  }
383  }
385  }
387  }
388  THROW_ASSERT(AppM->CGetCallGraphManager()->IsVertex(function_id), "");
389  const auto function_v = AppM->CGetCallGraphManager()->GetVertex(function_id);
390  if(static_cast<bool>(funcFF.count(function_v)))
391  {
392  _version = funcFF.at(function_v);
393  }
394  else
395  {
396  _version = FunctionVersionRef(new FunctionVersion(function_v));
397 #if HAVE_ASSERTS
398  const auto insertion =
399 #endif
400  funcFF.insert({function_v, _version});
401  THROW_ASSERT(insertion.second, "");
402  }
403  int_type = !_version->ieee_format() ?
405  static_cast<unsigned int>(static_cast<uint8_t>(_version->userRequired->sign == bit_lattice::U) +
406  _version->userRequired->exp_bits + _version->userRequired->frac_bits),
407  true) :
408  nullptr;
409  int_ptr_type =
410  int_type ? tree_man->GetPointerType(int_type, GetPointer<integer_type>(GET_NODE(int_type))->algn) : nullptr;
411 }
412 
414 
417 {
419  switch(relationship_type)
420  {
422  {
423  relationships.insert(std::make_pair(DETERMINE_MEMORY_ACCESSES, SAME_FUNCTION));
424  relationships.insert(std::make_pair(EXTRACT_GIMPLE_COND_OP, SAME_FUNCTION));
425  relationships.insert(std::make_pair(FUNCTION_CALL_TYPE_CLEANUP, ALL_FUNCTIONS));
426  relationships.insert(std::make_pair(IR_LOWERING, SAME_FUNCTION));
427  relationships.insert(std::make_pair(SOFT_FLOAT_CG_EXT, CALLED_FUNCTIONS));
428  relationships.insert(std::make_pair(UN_COMPARISON_LOWERING, SAME_FUNCTION));
429  break;
430  }
432  {
433  relationships.insert(std::make_pair(INTERFACE_INFER, WHOLE_APPLICATION));
434  break;
435  }
437  {
438  switch(GetStatus())
439  {
441  {
442  relationships.insert(std::make_pair(FUNCTION_CALL_TYPE_CLEANUP, SAME_FUNCTION));
443  break;
444  }
452  default:
453  break;
454  }
455  break;
456  }
457  default:
458  {
459  THROW_UNREACHABLE("");
460  }
461  }
462  return relationships;
463 }
464 
466 {
468 }
469 
471 {
472  THROW_ASSERT(parameters->isOption(OPT_soft_float) && parameters->getOption<bool>(OPT_soft_float),
473  "Floating-point lowering should not be executed");
474 
475  static const auto ff_already_propagated =
476  parameters->isOption(OPT_fp_format_propagate) && parameters->getOption<bool>(OPT_fp_format_propagate);
477  // Check if current function needs IO fp format interface (avoid check if fp format propagation has already been
478  // computed)
479  if(!ff_already_propagated && !_version->ieee_format())
480  {
481  const auto CG = AppM->CGetCallGraphManager()->CGetCallGraph();
482  InEdgeIterator ie, ie_end;
483  for(boost::tie(ie, ie_end) = boost::in_edges(_version->function_vertex, *CG); ie != ie_end; ie++)
484  {
485  if(static_cast<bool>(funcFF.count(ie->m_source)))
486  {
487  const auto& funcV = funcFF.at(ie->m_source);
488  if(funcV->ieee_format() || *(funcV->userRequired) != *(_version->userRequired))
489  {
490  // If a caller of current function uses a different float format, current function is not internal to the
491  // user specified float format
492  _version->internal = false;
493  break;
494  }
495  }
496  else
497  {
498  // If a caller of current function does not have a function version specified, it uses a standard float
499  // format for sure, thus current function is not internal
500  _version->internal = false;
501  break;
502  }
503  }
504  }
505  THROW_ASSERT(!_version->ieee_format() || _version->internal,
506  "A standard floating-point format function should be internal.");
507 
508 #ifndef NDEBUG
509  const auto fn_name = tree_helper::print_type(
510  TreeM, function_id, false, true, false, 0U,
511  var_pp_functorConstRef(new std_var_pp_functor(function_behavior->CGetBehavioralHelper())));
512 #endif
514  "-->Function " + fn_name + " implementing " + _version->ToString() + " floating-point format");
516  "---IO interface is " + STR((_version->ieee_format() || _version->internal) ? "not " : "") +
517  "necessary");
518 
519  const auto sl = GetPointerS<statement_list>(GET_NODE(fd->body));
520  bool modified = false;
521 
522  for(const auto& block : sl->list_of_bloc)
523  {
524  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Update recursively BB" + STR(block.first));
525  for(const auto& phi : block.second->CGetPhiList())
526  {
528  }
529 
530  // RecursiveExaminate could add statements to the statements list, thus it is necessary to iterate over a static
531  // copy of the initial statement list
532  for(const auto& stmt : block.second->CGetStmtList())
533  {
534  modified |= RecursiveExaminate(stmt, stmt, INTERFACE_TYPE_NONE);
535  }
536  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Updated recursively BB" + STR(block.first));
537  }
538 
539  // Fix hardware implemented function arguments
540  if(hwParam.size())
541  {
543  "Adding view-convert expressions to support hardware implemented FU call arguments");
544  for(const auto& ssa_uses : hwParam)
545  {
546  const auto ssa = ssa_uses.first;
547  const auto ssa_ridx = TreeM->GetTreeReindex(ssa->index);
548  const auto out_int = outputInterface.find(ssa);
549  std::vector<tree_nodeRef>* out_ssa =
550  out_int != outputInterface.end() ? &std::get<1>(out_int->second) : nullptr;
551  for(const auto& call_stmt_idx : ssa_uses.second)
552  {
553  const auto call_stmt = TreeM->CGetTreeReindex(call_stmt_idx);
554  const auto call_node = GetPointerS<const gimple_node>(GET_CONST_NODE(call_stmt));
555  const auto& call_bb = sl->list_of_bloc.at(call_node->bb_index);
557  "---View-convert for " + ssa->ToString() + " in BB" + STR(call_bb->number) + " " +
558  call_node->ToString());
559  // At this time ssa->type is still real_type, thus we can exploit that (it will be modified after)
560  const auto arg_vc =
561  tree_man->create_unary_operation(ssa->type, ssa_ridx, BUILTIN_SRCP, view_convert_expr_K);
562  const auto vc_stmt = tree_man->CreateGimpleAssign(ssa->type, tree_nodeRef(), tree_nodeRef(), arg_vc,
564  const auto vc_ssa = GetPointerS<gimple_assign>(GET_NODE(vc_stmt))->op0;
565  call_bb->PushBefore(vc_stmt, call_stmt, AppM);
566  TreeM->ReplaceTreeNode(call_stmt, ssa_ridx, vc_ssa);
567  if(out_ssa)
568  {
569  std::replace_if(
570  out_ssa->begin(), out_ssa->end(),
571  [&](const tree_nodeRef& t) { return GET_INDEX_CONST_NODE(t) == call_stmt_idx; }, vc_stmt);
572  }
573  }
574  }
575  modified = true;
576  hwParam.clear();
577  }
578 
579  // Fix hardware implemented function return values
580  if(hwReturn.size())
581  {
583  "Adding view-convert expressions to support hardware implemented FU call return values");
584  for(const auto& ssa : hwReturn)
585  {
586  const auto call_stmt = ssa->CGetDefStmt();
587  const auto def_node = GetPointerS<const gimple_node>(GET_CONST_NODE(call_stmt));
588  const auto call_bb = sl->list_of_bloc.at(def_node->bb_index);
590  "-->View-convert for " + ssa->ToString() + " in BB" + STR(call_bb->number) + " " +
591  def_node->ToString());
592  const auto ssa_ridx = TreeM->GetTreeReindex(ssa->index);
593  // Hardware calls are for sure dealing with standard IEEE formats only
594  const auto int_ret_type = tree_helper::Size(ssa->type) == 32 ? float32_type : float64_type;
595  const auto ret_vc =
596  tree_man->create_unary_operation(int_ret_type, ssa_ridx, BUILTIN_SRCP, view_convert_expr_K);
597  const auto vc_stmt = tree_man->CreateGimpleAssign(int_ret_type, tree_nodeRef(), tree_nodeRef(), ret_vc,
599  const auto vc_ssa = GetPointerS<const gimple_assign>(GET_CONST_NODE(vc_stmt))->op0;
601  "-->Added statement " + GET_CONST_NODE(vc_stmt)->ToString());
602  const auto if_info = inputInterface.find(ssa);
603  if(if_info != inputInterface.end())
604  {
605  const auto new_ssa = GetPointer<ssa_name>(GET_NODE(vc_ssa));
606  THROW_ASSERT(std::get<0>(if_info->second), "");
608  "---Input interface " + std::get<0>(if_info->second)->ToString() + " moved");
609  inputInterface.insert(std::make_pair(new_ssa, if_info->second));
610  inputInterface.erase(ssa);
611  }
612  const auto ssa_uses = ssa->CGetUseStmts();
613  for(const auto& stmt_use : ssa_uses)
614  {
616  "---Replace use - before: " + GET_CONST_NODE(stmt_use.first)->ToString());
617  TreeM->ReplaceTreeNode(stmt_use.first, ssa_ridx, vc_ssa);
619  "--- after: " + GET_CONST_NODE(stmt_use.first)->ToString());
620  }
621  call_bb->PushAfter(vc_stmt, call_stmt, AppM);
623  viewConvert.erase(ssa);
625  }
626  modified = true;
627  hwReturn.clear();
628  }
629 
630  // Design top function signatures must not be modified, thus a view-convert operation for real_type parameters and
631  // return value must be added inside the function body
632  if(isTopFunction &&
633  (!parameters->isOption(OPT_fp_format_interface) || !parameters->getOption<bool>(OPT_fp_format_interface)))
634  {
636  "Parameters binding " + STR(bindingCompleted ? "" : "partially ") + "completed on " +
637  STR(paramBinding.size()) + " arguments");
639 
640  const auto entry_bb = sl->list_of_bloc.at(bloc::ENTRY_BLOCK_ID);
641  const auto first_bb = sl->list_of_bloc.at(entry_bb->list_of_succ.front());
642  for(const auto& parm : paramBinding)
643  {
644  if(parm)
645  {
646  THROW_ASSERT(parm->get_kind() == ssa_name_K,
647  "Unexpected parameter node type (" + parm->get_kind_text() + ")");
648  const auto parmSSA = GetPointerS<ssa_name>(parm);
649  if(lowering_needed(parmSSA))
650  {
651  const auto parm_ridx = TreeM->CGetTreeReindex(parmSSA->index);
652  const auto parm_type = int_type_for(parmSSA->type, false);
654  "Lowering top function parameter type of " + parmSSA->ToString() + ": " +
655  GET_NODE(parmSSA->type)->ToString() + " -> " + GET_NODE(parm_type)->ToString());
656  tree_nodeRef vc_stmt;
657  if(GET_NODE(parm_type)->get_kind() == pointer_type_K)
658  {
659  vc_stmt = tree_man->CreateNopExpr(parm_ridx, parm_type, tree_nodeRef(), tree_nodeRef(), function_id);
660  }
661  else
662  {
663  const auto vc =
664  tree_man->create_unary_operation(parm_type, parm_ridx, BUILTIN_SRCP, view_convert_expr_K);
665  vc_stmt = tree_man->CreateGimpleAssign(parm_type, tree_nodeRef(), tree_nodeRef(), vc, function_id,
666  BUILTIN_SRCP);
667  if(!_version->ieee_format())
668  {
669  const auto ssa_ff = tree_helper::Size(parmSSA->type) == 32 ? float32FF : float64FF;
670  const auto ientry = inputInterface.insert(
671  {GetPointerS<ssa_name>(GET_CONST_NODE(GetPointerS<gimple_assign>(GET_NODE(vc_stmt))->op0)),
672  {ssa_ff, std::vector<unsigned int>()}});
673  THROW_ASSERT(ientry.second, "");
674  const auto oentry = outputInterface.find(parmSSA);
675  if(oentry != outputInterface.end())
676  {
677  const auto& oentry_list = std::get<1>(oentry->second);
678  auto& ientry_list = std::get<1>(ientry.first->second);
679  for(const auto& e : oentry_list)
680  {
681  ientry_list.push_back(e->index);
682  }
683  outputInterface.erase(oentry);
684  }
686  "---Input interface required for current parameter");
687  }
688  }
690  "---Lowering statement added to BB" + STR(first_bb->number) + ": " +
691  GET_NODE(vc_stmt)->ToString());
692  const auto lowered_parm = GetPointerS<gimple_assign>(GET_NODE(vc_stmt))->op0;
693  const auto parm_uses = parmSSA->CGetUseStmts();
694  for(const auto& stmt_uses : parm_uses)
695  {
696  TreeM->ReplaceTreeNode(stmt_uses.first, parm_ridx, lowered_parm);
697  }
698  first_bb->PushFront(vc_stmt, AppM);
699  viewConvert.erase(parmSSA);
700  modified = true;
701  }
702  }
703  }
704  paramBinding.clear();
705  for(const auto& ret_stmt : topReturn)
706  {
707  const auto gr = GetPointerS<gimple_return>(GET_NODE(ret_stmt));
708  const auto ret_ssa = GetPointerS<ssa_name>(GET_NODE(gr->op));
710  "Return value type restore added for variable " + ret_ssa->ToString());
711  const auto bb = sl->list_of_bloc.at(gr->bb_index);
712  tree_nodeRef vc_stmt;
713  if(GET_NODE(ret_ssa->type)->get_kind() == pointer_type_K)
714  {
715  vc_stmt = tree_man->CreateNopExpr(gr->op, ret_ssa->type, tree_nodeRef(), tree_nodeRef(), function_id);
716  }
717  else
718  {
719  const auto vc = tree_man->create_unary_operation(ret_ssa->type, gr->op, BUILTIN_SRCP, view_convert_expr_K);
720  vc_stmt = tree_man->CreateGimpleAssign(ret_ssa->type, tree_nodeRef(), tree_nodeRef(), vc, function_id,
721  BUILTIN_SRCP);
722  if(!_version->ieee_format())
723  {
724  const auto ssa_ff = tree_helper::Size(ret_ssa->type) == 32 ? float32FF : float64FF;
725  outputInterface.insert({ret_ssa, {ssa_ff, std::vector<tree_nodeRef>({vc_stmt})}});
727  "---Output interface required for current variable use");
728  }
729  }
730  const auto lowered_ret = GetPointerS<gimple_assign>(GET_NODE(vc_stmt))->op0;
731  bb->PushBefore(vc_stmt, ret_stmt, AppM);
732  TreeM->ReplaceTreeNode(ret_stmt, gr->op, lowered_ret);
733  }
734  modified |= topReturn.size();
736  }
737  else
738  {
739  // Else transform real type parameters and return value in unsigned integer type
740  const auto modified_signature = signature_lowering(fd);
741  if(modified_signature)
742  {
743  modified = true;
745  "Parameters binding " + STR(bindingCompleted ? "" : "partially ") + "completed on " +
746  STR(paramBinding.size()) + " arguments");
748  size_t idx;
749  for(idx = 0; idx < fd->list_of_args.size(); ++idx)
750  {
751  const auto& param = paramBinding.at(idx);
752  const auto& arg = fd->list_of_args.at(idx);
753  const auto pd = GetPointerS<const parm_decl>(GET_CONST_NODE(arg));
754  if(param)
755  {
756  THROW_ASSERT(param->get_kind() == ssa_name_K,
757  "Unexpected parameter node type (" + param->get_kind_text() + ")");
758  const auto parmSSA = GetPointerS<ssa_name>(param);
759 
760  if(GET_INDEX_NODE(pd->type) != GET_INDEX_NODE(parmSSA->type))
761  {
763  "Lowering type of " + parmSSA->ToString() + " bound to paremeter " + pd->ToString() +
764  ": " + GET_NODE(parmSSA->type)->ToString() + " -> " +
765  GET_NODE(pd->type)->ToString());
766  parmSSA->type = pd->type;
767 
768  // Remove ssa variable associated to function parameter to avoid multiple type replacement
769  viewConvert.erase(parmSSA);
770  }
771  }
772  else
773  {
775  "Missing binding for parameter " + pd->ToString());
776  }
777  }
778  paramBinding.clear();
780  }
781  }
782 
783  if(viewConvert.size())
784  {
786  "Lowering type for " + STR(viewConvert.size()) + " ssa variables");
788  for(const auto& ssa_var : viewConvert)
789  {
790  ssa_lowering(ssa_var.first, ssa_var.second);
791  }
792  modified = true;
793  viewConvert.clear();
795  }
796 
797  if(nopConvert.size())
798  {
800  "Lowering " + STR(nopConvert.size()) + " view-convert expressions to nop expressions");
802  for(const auto& vcStmt : nopConvert)
803  {
804  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Before lowering - " + GET_NODE(vcStmt)->ToString());
805  const auto ga = GetPointerS<gimple_assign>(GET_NODE(vcStmt));
806  THROW_ASSERT(ga, "");
807  const auto vc = GetPointerS<view_convert_expr>(GET_NODE(ga->op1));
808  THROW_ASSERT(vc, "");
809  THROW_ASSERT(GET_CONST_NODE(tree_helper::CGetType(vc->op))->get_kind() == integer_type_K,
810  "At this point " + GET_NODE(vc->op)->ToString() + " should be of integer type.");
811  const auto resType = tree_helper::CGetType(ga->op0);
812  THROW_ASSERT(GET_CONST_NODE(resType)->get_kind() == integer_type_K,
813  "Destination variable should of integer type (" + GET_CONST_NODE(resType)->get_kind_text() + ")");
814  const auto nop = tree_man->create_unary_operation(resType, vc->op, BUILTIN_SRCP, nop_expr_K);
815  TreeM->ReplaceTreeNode(vcStmt, ga->op1, nop);
816  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---After lowering - " + GET_NODE(vcStmt)->ToString());
817  }
818  modified = true;
819  nopConvert.clear();
821  }
822 
823  if(inputInterface.size())
824  {
826  "Generating input interface for " + STR(inputInterface.size()) + " variables");
828  for(auto& if_info : inputInterface)
829  {
830  const auto* SSA = if_info.first;
831  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Input interface for " + SSA->ToString());
832  const auto ssa = TreeM->GetTreeReindex(SSA->index);
833  auto& exclude = std::get<1>(if_info.second);
834  const auto oentry = outputInterface.find(if_info.first);
835  if(oentry != outputInterface.end())
836  {
837  const auto& oentry_list = std::get<1>(oentry->second);
838  std::transform(oentry_list.begin(), oentry_list.end(), std::back_inserter(exclude),
839  [&](const tree_nodeRef& tn) {
841  "---Skipping replacement for statement " + GET_NODE(tn)->ToString());
842  return tn->index;
843  });
844  outputInterface.erase(oentry);
845  }
846 
847  // Get ssa uses before renaming to avoid replacement in cast rename operations
848  const auto ssaUses = SSA->CGetUseStmts();
849  if(ssaUses.size() == exclude.size())
850  {
852  "---Input interface for " + SSA->ToString() + " has no users, skipping...");
853  continue;
854  }
855 
856  auto defStmt = SSA->CGetDefStmt();
857  const auto def = GetPointerS<gimple_node>(GET_NODE(defStmt));
858  blocRef bb;
859  if(def->get_kind() == gimple_assign_K)
860  {
861  THROW_ASSERT(sl->list_of_bloc.count(def->bb_index),
862  "BB " + STR(def->bb_index) + " not present in current function.");
863  bb = sl->list_of_bloc.at(def->bb_index);
865  "Input interface will be inserted in BB" + STR(bb->number));
866  }
867  else if(def->get_kind() == gimple_phi_K)
868  {
869  THROW_ASSERT(sl->list_of_bloc.count(def->bb_index),
870  "BB " + STR(def->bb_index) + " not present in current function.");
871  bb = sl->list_of_bloc.at(def->bb_index);
872  defStmt = nullptr;
874  "Input interface for phi will be inserted in BB" + STR(bb->number));
875  }
876  else
877  {
878  THROW_ASSERT(sl->list_of_bloc.at(BB_ENTRY)->list_of_succ.size() == 1,
879  "Multiple successors after entry basic block.");
880  const auto realEntryBBIdx = sl->list_of_bloc.at(BB_ENTRY)->list_of_succ.front();
881  bb = sl->list_of_bloc.at(realEntryBBIdx);
882  defStmt = nullptr;
884  "Input interface for parameter will be inserted in BB" + STR(bb->number));
885  }
886 
887  const auto convertedSSA =
888  generate_interface(bb, defStmt, ssa, std::get<0>(if_info.second), _version->userRequired);
889  const auto convertedSSA_type = tree_helper::CGetType(convertedSSA);
891  "-->Interface from " + std::get<0>(if_info.second)->ToString() + " to " +
892  _version->userRequired->ToString() + " generated output " +
893  GET_NODE(convertedSSA)->ToString());
894 
895  for(const auto& ssaUse : ssaUses)
896  {
897  const auto& useStmt = ssaUse.first;
898  if(std::find(exclude.begin(), exclude.end(), GET_INDEX_NODE(useStmt)) != exclude.end())
899  {
901  "---Skipping replacement for statement " + GET_NODE(useStmt)->ToString());
902  continue;
903  }
904  TreeM->ReplaceTreeNode(useStmt, ssa, convertedSSA);
905  const auto* ga = GetPointer<const gimple_assign>(GET_CONST_NODE(useStmt));
906  if(ga)
907  {
908  // Unary and binary expression have already been lowered to function calls
909  auto* te = GetPointer<ternary_expr>(GET_NODE(ga->op1));
910  if(te)
911  {
912  te->type = TreeM->GetTreeNode(convertedSSA_type->index);
913  }
914  }
916  "---Replaced in statement " + GET_NODE(useStmt)->ToString());
917  modified = true;
918  }
920  }
921  inputInterface.clear();
923  }
924 
925  if(outputInterface.size())
926  {
928  "Generating output interface for " + STR(outputInterface.size()) + " variables");
930  for(const auto& if_info : outputInterface)
931  {
932  const auto* SSA = if_info.first;
933  const auto ssa = TreeM->GetTreeReindex(SSA->index);
934  const auto& useStmts = std::get<1>(if_info.second);
935 
936  auto defStmt = SSA->CGetDefStmt();
937  const auto gn = GetPointerS<gimple_node>(GET_NODE(defStmt));
938  THROW_ASSERT(sl->list_of_bloc.count(gn->bb_index),
939  "BB" + STR(gn->bb_index) + " not present in current function.");
940  auto bb = sl->list_of_bloc.at(gn->bb_index);
941  if(gn->get_kind() == gimple_nop_K)
942  {
943  THROW_ASSERT(bb->number == BB_ENTRY, "Parameter definition should be associated to entry block");
944  THROW_ASSERT(bb->list_of_succ.size() == 1, "Multiple successors after entry basic block.");
945  THROW_ASSERT(sl->list_of_bloc.count(bb->list_of_succ.front()),
946  "BB " + STR(bb->list_of_succ.front()) + " not present in current function.");
947  defStmt = nullptr;
948  bb = sl->list_of_bloc.at(bb->list_of_succ.front());
949  }
951  "Output interface for " + SSA->ToString() + " will be inserted in BB" + STR(bb->number));
952 
953  const auto convertedSSA =
954  generate_interface(bb, defStmt, ssa, _version->userRequired, std::get<0>(if_info.second));
956  "Interface generated output " + GET_NODE(convertedSSA)->ToString());
957  for(const auto& stmt : useStmts)
958  {
959  TreeM->ReplaceTreeNode(stmt, ssa, convertedSSA);
961  "---Replaced in statement " + GET_NODE(stmt)->ToString());
962  modified = true;
963  }
964  }
965  outputInterface.clear();
967  }
969 
970  if(modified)
971  {
972  function_behavior->UpdateBBVersion();
974  }
976 }
977 
979 {
981  {
983  }
984  return tree_helper::IsRealType(ssa->type);
985 }
986 
988 {
990  {
992  }
993  if(!use_internal || _version->ieee_format())
994  {
995  return tree_helper::Size(type) == 32 ? float32_type : float64_type;
996  }
997  else
998  {
999  THROW_ASSERT(int_type, "Internal integer type should have been defined before.");
1000  return int_type;
1001  }
1002 }
1003 
1005 {
1006 #ifndef NDEBUG
1007  const auto f_name = tree_helper::print_type(TreeM, f_decl->index, false, true, false, 0U,
1009  AppM->CGetFunctionBehavior(f_decl->index)->CGetBehavioralHelper())));
1010 #endif
1011  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Analysing function signature " + f_name);
1013  bool changed_parm = false, changed_type = false;
1014  const auto decl_type = GET_NODE(f_decl->type);
1015  const auto is_ptr_type = decl_type->get_kind() == pointer_type_K;
1016  // Tree node decoupling is necessary when directly modifying a type node
1018  const auto dup_ft =
1019  tree_node_dup(remapping, AppM)
1020  .create_tree_node(is_ptr_type ? GET_NODE(GetPointerS<pointer_type>(decl_type)->ptd) : decl_type,
1022  const auto f_type = TreeM->CGetTreeReindex(dup_ft);
1023 
1024  tree_list* prms = nullptr;
1025  if(tree_helper::IsFunctionType(f_type))
1026  {
1027  const auto ft = GetPointerS<function_type>(GET_NODE(f_type));
1028  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Analysing return type " + GET_NODE(ft->retn)->ToString());
1029  if(tree_helper::IsRealType(ft->retn))
1030  {
1031  const auto int_ret = int_type_for(ft->retn, _version->internal);
1032  const auto ret_type = GetPointerS<const type_node>(GET_CONST_NODE(int_ret));
1034  "---Return type lowered to " + ret_type->ToString() + " " + STR(tree_helper::Size(int_ret)));
1035  ft->retn = int_ret;
1036  ft->algn = ret_type->algn;
1037  ft->qual = ret_type->qual;
1038  ft->size = ret_type->size;
1039  changed_type = true;
1040  }
1041  prms = ft->prms ? GetPointerS<tree_list>(GET_NODE(ft->prms)) : nullptr;
1042  }
1043 
1044  for(const auto& arg : f_decl->list_of_args)
1045  {
1046  const auto pd = GetPointerS<parm_decl>(GET_NODE(arg));
1047  const auto& parm_type = pd->type;
1049  "Analysing parameter " + pd->ToString() + " of type " + STR(parm_type));
1051  tree_helper::IsRealType(parm_type))
1052  {
1053  const auto int_parm_type = int_type_for(parm_type, _version->internal);
1054  const auto parm_int_type = GetPointerS<const type_node>(GET_CONST_NODE(int_parm_type));
1055  pd->algn = parm_int_type->algn;
1056  pd->argt = int_parm_type;
1057  pd->packed_flag = parm_int_type->packed_flag;
1058  pd->type = int_parm_type;
1059  if(prms)
1060  {
1061  prms->valu = int_parm_type;
1062  changed_type = true;
1063  }
1065  "---Parameter type lowered to " + STR(int_parm_type) + " " +
1066  STR(tree_helper::Size(int_parm_type)));
1067  changed_parm = true;
1068  }
1069  prms = prms ? (prms->chan ? GetPointerS<tree_list>(GET_NODE(prms->chan)) : nullptr) : nullptr;
1070  }
1072  if(changed_type)
1073  {
1074  // Replace function type reference when modifications have been applied
1075  f_decl->type = is_ptr_type ? tree_man->GetPointerType(f_type) : f_type;
1076  }
1077  return changed_parm || changed_type;
1078 }
1079 
1080 void soft_float_cg_ext::ssa_lowering(ssa_name* ssa, bool internal_type) const
1081 {
1082  THROW_ASSERT(lowering_needed(ssa), "Unexpected ssa type - " + ssa->ToString() + " " + STR(ssa->type));
1083  const auto vc_type = int_type_for(ssa->type, internal_type);
1084  THROW_ASSERT(vc_type, "");
1085  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Lowering " + ssa->ToString() + " type to " + STR(vc_type));
1086 
1087  const auto defStmt = ssa->CGetDefStmt();
1088  const auto def = GetPointer<gimple_assign>(GET_NODE(defStmt));
1089  if(def)
1090  {
1091  const auto ue = GetPointer<unary_expr>(GET_NODE(def->op1));
1092  if(ue)
1093  {
1094  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Definition statement before - " + def->ToString());
1095  if(ue->get_kind() == view_convert_expr_K)
1096  {
1097  const auto nop = tree_man->create_unary_operation(vc_type, ue->op, BUILTIN_SRCP, nop_expr_K);
1098  TreeM->ReplaceTreeNode(defStmt, def->op1, nop);
1099  }
1100  else if(ue->get_kind() == imagpart_expr_K || ue->get_kind() == realpart_expr_K)
1101  {
1102  const auto ssa_ridx = TreeM->CGetTreeReindex(ssa->index);
1103  const auto def_bb = GetPointerS<statement_list>(GET_NODE(fd->body))->list_of_bloc.at(def->bb_index);
1104  const auto vc = tree_man->create_unary_operation(vc_type, ssa_ridx, BUILTIN_SRCP, view_convert_expr_K);
1105  const auto vc_stmt =
1108  "---Inserting view-convert operation after complex part expression - " +
1109  GET_NODE(vc_stmt)->ToString());
1110  const auto lowered_ssa = GetPointerS<gimple_assign>(GET_NODE(vc_stmt))->op0;
1111 
1112  const auto ssa_uses = ssa->CGetUseStmts();
1113  for(const auto& stmt_uses : ssa_uses)
1114  {
1115  TreeM->ReplaceTreeNode(stmt_uses.first, ssa_ridx, lowered_ssa);
1116  }
1117  def_bb->PushAfter(vc_stmt, defStmt, AppM);
1118  return;
1119  }
1120  else
1121  {
1122  ue->type = vc_type;
1123  }
1124  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Definition statement after - " + def->ToString());
1125  }
1126  else
1127  {
1128  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Definition statement - " + def->ToString());
1129  }
1130  }
1131 
1132  ssa->type = vc_type;
1133  if(ssa->var && GET_NODE(ssa->var)->get_kind() != parm_decl_K)
1134  {
1135  const auto vd = GetPointer<var_decl>(GET_NODE(ssa->var));
1136  THROW_ASSERT(vd, "SSA name associated variable is espected to be a variable declaration " +
1137  GET_NODE(ssa->var)->get_kind_text() + " " + GET_NODE(ssa->var)->ToString());
1138  if(GET_INDEX_NODE(vd->type) != GET_INDEX_NODE(ssa->type))
1139  {
1141  "---Variable declaration before - " + vd->ToString() + " " + GET_NODE(vd->type)->ToString());
1142  const auto var_int_type = GetPointerS<type_node>(GET_NODE(vc_type));
1143  vd->algn = var_int_type->algn;
1144  vd->packed_flag = var_int_type->packed_flag;
1145  vd->type = vc_type;
1147  "---Variable declaration after - " + vd->ToString() + " " + GET_NODE(vd->type)->ToString());
1148  }
1149  else
1150  {
1152  "---Variable declaration - " + vd->ToString() + " " + GET_NODE(vd->type)->ToString());
1153  }
1154  }
1155 
1156  for(const auto& use_count : ssa->CGetUseStmts())
1157  {
1158  const auto* ga = GetPointer<const gimple_assign>(GET_CONST_NODE(use_count.first));
1159  if(ga)
1160  {
1161  // Unary and binary expression have already been lowered to function calls
1162  auto* te = GetPointer<ternary_expr>(GET_NODE(ga->op1));
1163  if(te)
1164  {
1165  te->type = vc_type;
1166  }
1167  }
1168  }
1169 }
1170 
1171 tree_nodeRef soft_float_cg_ext::cstCast(uint64_t bits, const FloatFormatRef& inFF, const FloatFormatRef& outFF) const
1172 {
1173  uint64_t Sign, Exp, Frac;
1174 
1175  Sign = bits >> (inFF->exp_bits + inFF->frac_bits);
1176  Exp = (bits >> (inFF->frac_bits)) & ((1ULL << inFF->exp_bits) - 1);
1177  Frac = bits & ((1ULL << inFF->frac_bits) - 1);
1178 
1179  uint64_t FExp, SFrac;
1180  bool ExpOverflow = false;
1181 
1182  const auto needed_bits = [](int i) -> auto
1183  {
1184  int lz;
1185  if(i > 0)
1186  {
1187  lz = 32 - __builtin_clz(static_cast<unsigned int>(i));
1188  }
1189  else
1190  {
1191  i = -i;
1192  lz = 32 - __builtin_clz(static_cast<unsigned int>(i)) + ((i & (i - 1)) != 0);
1193  }
1194  return static_cast<unsigned int>(lz);
1195  };
1196  const auto exp_bits_diff =
1197  inFF->exp_bits > outFF->exp_bits ? (inFF->exp_bits - outFF->exp_bits) : (outFF->exp_bits - inFF->exp_bits);
1198  const auto exp_type_size = std::max({static_cast<unsigned int>(inFF->exp_bits) + (exp_bits_diff == 1),
1199  static_cast<unsigned int>(outFF->exp_bits) + (exp_bits_diff == 1),
1200  needed_bits(inFF->exp_bias), needed_bits(outFF->exp_bias)});
1201 
1202  const auto biasDiff = inFF->exp_bias - outFF->exp_bias;
1203  const auto rangeDiff = ((1 << outFF->exp_bits) - !outFF->has_subnorm) - ((1 << inFF->exp_bits) - !inFF->has_subnorm);
1204  if((inFF->exp_bits != outFF->exp_bits) || (inFF->exp_bias != outFF->exp_bias))
1205  {
1206  FExp = Exp + static_cast<uint64_t>(biasDiff);
1207  bool ExpUnderflow = false;
1208  if(biasDiff < 0 || biasDiff > rangeDiff)
1209  {
1210  const auto expOverflow = (FExp >> outFF->exp_bits) & ((1ULL << (exp_type_size - outFF->exp_bits - 1)) - 1);
1211  ExpOverflow = expOverflow != 0ULL;
1212  ExpUnderflow = (FExp >> (exp_type_size - 1)) & 1;
1213  THROW_ASSERT((!ExpOverflow && !ExpUnderflow) || bits == 0,
1214  "Target FP format can not represent a program constant.");
1215  const auto ExExp = ExpUnderflow ? 0ULL : ((1ULL << outFF->exp_bits) - 1);
1216  FExp = FExp & ((1ULL << outFF->exp_bits) - 1);
1217  FExp = ExpOverflow ? ExExp : FExp;
1218  Frac = ExpUnderflow ? 0 : Frac;
1219  ExpOverflow = ExpOverflow ^ ExpUnderflow;
1220  }
1221 
1222  FExp = FExp & ((1ULL << outFF->exp_bits) - 1);
1223  const bool ExpNull = Exp == 0;
1224  const bool FracNull = Frac == 0;
1225  bool inputZero = ExpNull && FracNull;
1226  if(biasDiff < 0 || biasDiff > rangeDiff)
1227  {
1228  inputZero = inputZero || ExpUnderflow;
1229  }
1230  FExp = inputZero ? 0ULL : FExp;
1231  }
1232  else
1233  {
1234  if(inFF->has_subnorm && !outFF->has_subnorm)
1235  {
1236  const bool ExpNull = Exp == 0;
1237  Frac = ExpNull ? 0ULL : Frac;
1238  }
1239  FExp = Exp;
1240  }
1241 
1242  if(inFF->frac_bits > outFF->frac_bits)
1243  {
1244  const auto bits_diff = inFF->frac_bits - outFF->frac_bits;
1245 
1246  SFrac = Frac >> bits_diff;
1247 
1248  if(outFF->rounding_mode == FloatFormat::FPRounding_NearestEven)
1249  {
1250  const bool GuardBit = (Frac >> (bits_diff - 1)) & 1;
1251 
1252  bool LSB = 0;
1253  if(bits_diff > 1)
1254  {
1255  const bool RoundBit = (Frac >> (bits_diff - 2)) & 1;
1256  LSB = LSB | RoundBit;
1257  }
1258 
1259  if(bits_diff > 2)
1260  {
1261  const bool Sticky = (Frac & ((1ULL << (bits_diff - 2)) - 1)) != 0;
1262  LSB = LSB | Sticky;
1263  }
1264 
1265  const bool Round = GuardBit & LSB;
1266  SFrac = SFrac | static_cast<uint64_t>(Round);
1267  }
1268  }
1269  else if(inFF->frac_bits < outFF->frac_bits)
1270  {
1271  const auto bits_diff = outFF->frac_bits - inFF->frac_bits;
1272  SFrac = Frac << bits_diff;
1273  }
1274  else
1275  {
1276  SFrac = Frac;
1277  }
1278 
1279  bool out_nan = false;
1280  if(outFF->sign != bit_lattice::U && inFF->sign != outFF->sign)
1281  {
1282  if(inFF->sign == bit_lattice::U)
1283  {
1284  out_nan |= Sign != (outFF->sign == bit_lattice::ONE ? 1 : 0);
1285  }
1286  else
1287  {
1288  THROW_ERROR("Casting from fixed " + STR(inFF->sign == bit_lattice::ONE ? "negative" : "positive") +
1289  " type to fixed " + STR(outFF->sign == bit_lattice::ONE ? "negative" : "positive") +
1290  " type will always result in a static value.");
1291  return nullptr;
1292  }
1293  }
1294 
1295  if(inFF->exception_mode == FloatFormat::FPException_IEEE)
1296  {
1297  out_nan |= Exp == ((1ULL << inFF->exp_bits) - 1);
1298  }
1299  uint64_t RExp, NFrac, RFrac;
1300 
1301  RExp = out_nan ? ((1ULL << outFF->exp_bits) - 1) : FExp;
1302  RExp <<= outFF->frac_bits;
1303 
1304  if(biasDiff < 0 || biasDiff > rangeDiff)
1305  {
1306  out_nan |= ExpOverflow;
1307  }
1308 
1309  if(outFF->exception_mode == FloatFormat::FPException_IEEE)
1310  {
1311  if(inFF->exception_mode == FloatFormat::FPException_IEEE)
1312  {
1313  const auto in_nan = (Exp == ((1ULL << inFF->exp_bits) - 1)) && (Frac != 0);
1314  NFrac = in_nan ? ((1ULL << outFF->frac_bits) - 1) : 0;
1315  }
1316  else
1317  {
1318  NFrac = 0;
1319  }
1320  }
1321  else
1322  {
1323  NFrac = ((1ULL << outFF->frac_bits) - 1);
1324  }
1325 
1326  RFrac = out_nan ? NFrac : SFrac;
1327 
1328  uint64_t out_val = RExp | RFrac;
1329 
1330  if(outFF->sign == bit_lattice::U)
1331  {
1332  uint64_t FSign;
1333  if(inFF->sign != bit_lattice::U)
1334  {
1335  FSign = inFF->sign == bit_lattice::ONE ? (1ULL << (outFF->exp_bits + outFF->frac_bits)) : 0;
1336  }
1337  else
1338  {
1339  FSign = Sign << (outFF->exp_bits + outFF->frac_bits);
1340  }
1341  out_val |= FSign;
1342  }
1343 
1344  return TreeM->CreateUniqueIntegerCst(
1345  static_cast<int64_t>(out_val),
1346  tree_man->GetCustomIntegerType(static_cast<unsigned int>(static_cast<uint8_t>(outFF->sign == bit_lattice::U) +
1347  outFF->exp_bits + outFF->frac_bits),
1348  true));
1349 }
1350 
1351 #define FLOAT_CAST_FU_NAME "__float_cast"
1352 
1354  const FloatFormatRef inFF, const FloatFormatRef outFF) const
1355 {
1356  static const auto default_bool_type = tree_man->GetBooleanType();
1357  static const auto default_int_type = tree_man->GetSignedIntegerType();
1358 
1359 #if HAVE_ASSERTS
1360  const auto t_kind = GET_CONST_NODE(tree_helper::CGetType(ssa))->get_kind();
1361 #endif
1362  THROW_ASSERT(t_kind == integer_type_K,
1363  "Cast rename should be applied on integer variables only. " + tree_node::GetString(t_kind));
1364  THROW_ASSERT(inFF, "Interface input float format must be defined.");
1365  THROW_ASSERT(outFF, "Interface output float format must be defined.");
1366 
1367  const auto float_cast = TreeM->GetFunction(FLOAT_CAST_FU_NAME);
1368  THROW_ASSERT(float_cast, "The library miss this function " FLOAT_CAST_FU_NAME);
1369  const auto spec_suffix = inFF->ToString() + "_to_" + outFF->ToString();
1370  auto spec_function = TreeM->GetFunction(FLOAT_CAST_FU_NAME + spec_suffix);
1371  if(!spec_function)
1372  {
1374  "---Generating specialized version of " FLOAT_CAST_FU_NAME " (" + STR(float_cast->index) +
1375  ") with fp format " + spec_suffix);
1376  spec_function = tree_man->CloneFunction(float_cast, spec_suffix);
1377  THROW_ASSERT(spec_function, "Error cloning function " FLOAT_CAST_FU_NAME " (" + STR(float_cast->index) + ").");
1378  }
1379  const std::vector<tree_nodeRef> args = {
1380  ssa,
1381  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->exp_bits), default_int_type),
1382  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->frac_bits), default_int_type),
1383  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->exp_bias), default_int_type),
1384  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->rounding_mode), default_int_type),
1385  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->exception_mode), default_int_type),
1386  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->has_one), default_bool_type),
1387  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->has_subnorm), default_bool_type),
1388  TreeM->CreateUniqueIntegerCst(
1389  static_cast<long long>(inFF->sign == bit_lattice::U ? -1 : (inFF->sign == bit_lattice::ONE ? 1 : 0)),
1390  default_int_type),
1391  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->exp_bits), default_int_type),
1392  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->frac_bits), default_int_type),
1393  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->exp_bias), default_int_type),
1394  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->rounding_mode), default_int_type),
1395  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->exception_mode), default_int_type),
1396  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->has_one), default_bool_type),
1397  TreeM->CreateUniqueIntegerCst(static_cast<long long>(outFF->has_subnorm), default_bool_type),
1398  TreeM->CreateUniqueIntegerCst(
1399  static_cast<long long>(outFF->sign == bit_lattice::U ? -1 : (outFF->sign == bit_lattice::ONE ? 1 : 0)),
1400  default_int_type),
1401  };
1402  const auto float_cast_call = tree_man->CreateCallExpr(spec_function, args, BUILTIN_SRCP);
1403  const auto ret_type = tree_helper::GetFunctionReturnType(spec_function);
1404  const auto cast_stmt = tree_man->CreateGimpleAssign(ret_type, tree_nodeConstRef(), tree_nodeConstRef(),
1405  float_cast_call, function_id, BUILTIN_SRCP);
1406  if(stmt == nullptr)
1407  {
1408  bb->PushFront(cast_stmt, AppM);
1409  }
1410  else
1411  {
1412  bb->PushAfter(cast_stmt, stmt, AppM);
1413  }
1414  auto out_var = GetPointer<const gimple_assign>(GET_CONST_NODE(cast_stmt))->op0;
1415  const auto out_type =
1416  tree_man->GetCustomIntegerType(static_cast<unsigned int>(static_cast<uint8_t>(outFF->sign == bit_lattice::U) +
1417  outFF->exp_bits + outFF->frac_bits),
1418  true);
1419  if(!tree_helper::IsSameType(ret_type, out_type))
1420  {
1421  const auto nop_stmt =
1423  out_var = GetPointer<const gimple_assign>(GET_CONST_NODE(nop_stmt))->op0;
1424  bb->PushAfter(nop_stmt, cast_stmt, AppM);
1425  }
1426  if(inline_conversion)
1427  {
1429  }
1430 
1431  // Update functions float format map
1432  const auto called_func_vertex = AppM->CGetCallGraphManager()->GetVertex(spec_function->index);
1433  const auto calledFF = FunctionVersionRef(new FunctionVersion(called_func_vertex, inFF));
1434 #if HAVE_ASSERTS
1435  const auto res =
1436 #endif
1437  funcFF.insert(std::make_pair(called_func_vertex, calledFF));
1438  THROW_ASSERT(res.second || res.first->second->compare(*calledFF, true) == 0,
1439  "Same function registered with different formats: " + res.first->second->ToString() + " and " +
1440  calledFF->ToString() + " (" FLOAT_CAST_FU_NAME ")");
1441  return out_var;
1442 }
1443 
1444 tree_nodeRef soft_float_cg_ext::floatNegate(const tree_nodeRef& op, const FloatFormatRef& ff) const
1445 {
1446  if(ff->sign == bit_lattice::U)
1447  {
1448  const auto int_ff_type = tree_man->GetCustomIntegerType(1U + ff->exp_bits + ff->frac_bits, true);
1450  int_ff_type, op, TreeM->CreateUniqueIntegerCst(1LL << (ff->exp_bits + ff->frac_bits), int_ff_type),
1451  BUILTIN_SRCP, bit_xor_expr_K);
1452  }
1453  else
1454  {
1455  THROW_ERROR("Negate operation on fixed sign type will flatten all values.");
1456  return nullptr;
1457  }
1458 }
1459 
1460 tree_nodeRef soft_float_cg_ext::floatAbs(const tree_nodeRef& op, const FloatFormatRef& ff) const
1461 {
1462  if(ff->sign == bit_lattice::U)
1463  {
1464  const auto int_ff_type = tree_man->GetCustomIntegerType(1U + ff->exp_bits + ff->frac_bits, true);
1466  int_ff_type, op, TreeM->CreateUniqueIntegerCst((1LL << (ff->exp_bits + ff->frac_bits)) - 1, int_ff_type),
1467  BUILTIN_SRCP, bit_and_expr_K);
1468  }
1469  else if(ff->sign == bit_lattice::ONE)
1470  {
1471  // Fixed positive sign representation is always positive already
1472  return op;
1473  }
1474  else
1475  {
1476  THROW_ERROR("Negate operation on fixed negative sign type will flatten all values.");
1477  return nullptr;
1478  }
1479 }
1480 
1481 void soft_float_cg_ext::replaceWithCall(const FloatFormatRef& specFF, const std::string& fu_name,
1482  std::vector<tree_nodeRef> args, const tree_nodeRef& current_statement,
1483  const tree_nodeRef& current_tree_node, const std::string& current_srcp)
1484 {
1485  THROW_ASSERT(specFF, "FP format specialization missing");
1486 
1487  auto called_function = TreeM->GetFunction(fu_name);
1488  THROW_ASSERT(called_function, "The library miss this function " + fu_name);
1489  const auto spec_suffix = specFF->ToString();
1490  auto spec_function = TreeM->GetFunction(fu_name + spec_suffix);
1491  if(!spec_function)
1492  {
1494  "---Generating specialized version of " + fu_name + " (" + STR(called_function->index) +
1495  ") with fp format " + spec_suffix);
1496  spec_function = tree_man->CloneFunction(called_function, spec_suffix);
1497  THROW_ASSERT(spec_function, "Error cloning function " + fu_name + " (" + STR(called_function->index) + ").");
1498 
1499  auto& version_args = versioning_args[spec_function->index];
1500  static const auto default_bool_type = tree_man->GetBooleanType();
1501  static const auto default_int_type = tree_man->GetSignedIntegerType();
1502 
1503  version_args[0] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->exp_bits), default_int_type);
1504  version_args[1] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->frac_bits), default_int_type);
1505  version_args[2] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->exp_bias), default_int_type);
1506  version_args[3] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->rounding_mode), default_int_type);
1507  version_args[4] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->exception_mode), default_int_type);
1508  version_args[5] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->has_one), default_bool_type);
1509  version_args[6] = TreeM->CreateUniqueIntegerCst(static_cast<long long>(specFF->has_subnorm), default_bool_type);
1510  version_args[7] = TreeM->CreateUniqueIntegerCst(
1511  static_cast<long long>(specFF->sign == bit_lattice::U ? -1 : (specFF->sign == bit_lattice::ONE ? 1 : 0)),
1512  default_int_type);
1513  }
1514  THROW_ASSERT(static_cast<bool>(versioning_args.count(spec_function->index)),
1515  "Static arguments for specialization parameters of " + fu_name + spec_suffix + " (" +
1516  STR(spec_function->index) + ") where not specified.");
1517  std::copy(versioning_args.at(spec_function->index).begin(), versioning_args.at(spec_function->index).end(),
1518  std::back_inserter(args));
1519  called_function = spec_function;
1520  TreeM->ReplaceTreeNode(current_statement, current_tree_node,
1521  tree_man->CreateCallExpr(called_function, args, current_srcp));
1523  GET_INDEX_CONST_NODE(current_statement),
1525  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Added call point for " + STR(called_function->index));
1526 
1527  // Update functions float format map
1528  const auto called_func_vertex = AppM->CGetCallGraphManager()->GetVertex(called_function->index);
1529  const auto calledFF = FunctionVersionRef(new FunctionVersion(called_func_vertex, specFF));
1530 #if HAVE_ASSERTS
1531  const auto res =
1532 #endif
1533  funcFF.insert(std::make_pair(called_func_vertex, calledFF));
1534  THROW_ASSERT(res.second || res.first->second->compare(*calledFF, true) == 0,
1535  "Same function registered with different formats: " + res.first->second->ToString() + " and " +
1536  calledFF->ToString() + " (" + fu_name + ")");
1537 }
1538 
1539 bool soft_float_cg_ext::RecursiveExaminate(const tree_nodeRef& current_statement, const tree_nodeRef& current_tree_node,
1540  int type_interface)
1541 {
1542  THROW_ASSERT(current_tree_node->get_kind() == tree_reindex_K, "Node is not a tree reindex");
1543  THROW_ASSERT((type_interface & 3) == INTERFACE_TYPE_NONE || (type_interface & 3) == INTERFACE_TYPE_INPUT ||
1544  (type_interface & 3) == INTERFACE_TYPE_OUTPUT,
1545  "Required interface type must be unique (" + STR(type_interface) + ")");
1546  const auto curr_tn = GET_NODE(current_tree_node);
1548  "-->Update recursively (ti=" + STR(type_interface) + ") (" + STR(current_tree_node->index) + " " +
1549  curr_tn->get_kind_text() + ") " + STR(current_tree_node));
1550  const auto current_srcp = [curr_tn]() -> std::string {
1551  const auto srcp_tn = GetPointer<const srcp>(curr_tn);
1552  if(srcp_tn)
1553  {
1554  return srcp_tn->include_name + ":" + STR(srcp_tn->line_number) + ":" + STR(srcp_tn->column_number);
1555  }
1556  return "";
1557  }();
1558  bool modified = false;
1559  const auto is_internal_call = [&](const tree_nodeRef& fn) -> bool {
1560  static const auto mcpy_node = TreeM->GetFunction(MEMCPY);
1561  static const auto mset_node = TreeM->GetFunction(MEMSET);
1562  const auto fn_fd = GetPointerS<function_decl>(GET_NODE(fn));
1563  if(!fn_fd->body)
1564  {
1565  if(!_version->ieee_format() && tree_helper::print_function_name(TreeM, fn_fd) == BUILTIN_WAIT_CALL)
1566  {
1567  THROW_UNREACHABLE("Function pointers not supported from user defined floating point format functions");
1568  // TODO: maybe it could be possible to only warn the user here to be careful about the pointed function
1569  // definition and go on
1570  }
1571  return _version->ieee_format();
1572  }
1573  const auto fn_v = AppM->CGetCallGraphManager()->GetVertex(GET_INDEX_CONST_NODE(fn));
1574  const auto ff_it = funcFF.find(fn_v);
1575  if(ff_it != funcFF.end())
1576  {
1577  return ff_it->second->internal && _version->ieee_format() == ff_it->second->ieee_format();
1578  }
1579  else if(fn_fd->builtin_flag || fn_fd->index == mcpy_node->index || fn_fd->index == mset_node->index)
1580  {
1581  return _version->ieee_format();
1582  }
1583  THROW_UNREACHABLE("");
1584  return false;
1585  };
1586  const auto ExaminateFunctionCall = [&](tree_nodeRef fn) -> int {
1587  const auto ae = GetPointer<addr_expr>(GET_NODE(fn));
1588  if(ae)
1589  {
1590  fn = ae->op;
1591  const auto called_fd = GetPointerS<const function_decl>(GET_CONST_NODE(fn));
1592  ae->type = GET_CONST_NODE(called_fd->type)->get_kind() == pointer_type_K ?
1593  called_fd->type :
1594  tree_man->GetPointerType(called_fd->type);
1595  modified = true;
1596  }
1597  if(tree_helper::print_function_name(TreeM, GetPointerS<const function_decl>(GET_CONST_NODE(fn))) ==
1599  {
1600  if(_version->ieee_format())
1601  {
1602  return INTERFACE_TYPE_NONE;
1603  }
1604  THROW_UNREACHABLE("Function pointers not supported from user defined floating point format functions");
1605  // TODO: maybe it could be possible to only warn the user here to be careful about the pointed function
1606  // definition and go on
1607  }
1608 
1609  int type_i = is_internal_call(fn) ? INTERFACE_TYPE_NONE : INTERFACE_TYPE_OUTPUT;
1610  // Hardware implemented functions need arguments to still be real_type, thus it is necessary to add a view_convert
1611  // operation before
1612  if(AppM->get_tree_manager()->get_implementation_node(GET_INDEX_CONST_NODE(fn)) == 0)
1613  {
1614  type_i |= INTERFACE_TYPE_REAL;
1615  }
1616  return type_i;
1617  };
1618  switch(curr_tn->get_kind())
1619  {
1620  case call_expr_K:
1621  case aggr_init_expr_K:
1622  {
1623  const auto ce = GetPointerS<const call_expr>(curr_tn);
1624  type_interface = ExaminateFunctionCall(ce->fn);
1625  for(const auto& arg : ce->args)
1626  {
1627  RecursiveExaminate(current_statement, arg, type_interface);
1628  }
1629  break;
1630  }
1631  case gimple_call_K:
1632  {
1633  const auto ce = GetPointerS<const gimple_call>(curr_tn);
1634  type_interface = ExaminateFunctionCall(ce->fn);
1635  for(const auto& arg : ce->args)
1636  {
1637  RecursiveExaminate(current_statement, arg, type_interface);
1638  }
1639  break;
1640  }
1641  case gimple_phi_K:
1642  {
1643  const auto gp = GetPointerS<const gimple_phi>(curr_tn);
1644  RecursiveExaminate(current_statement, gp->res, type_interface);
1645  for(const auto& de : gp->CGetDefEdgesList())
1646  {
1647  RecursiveExaminate(current_statement, de.first, type_interface);
1648  }
1649  break;
1650  }
1651  case gimple_assign_K:
1652  {
1653  const auto ga = GetPointerS<const gimple_assign>(curr_tn);
1654  const auto rhs_type = GET_NODE(ga->op1)->get_kind();
1655  if(rhs_type == call_expr_K || rhs_type == aggr_init_expr_K)
1656  {
1657  const auto ce = GetPointerS<const call_expr>(GET_NODE(ga->op1));
1658  const auto fn = GetPointer<const addr_expr>(GET_CONST_NODE(ce->fn)) ?
1659  GetPointerS<const addr_expr>(GET_CONST_NODE(ce->fn))->op :
1660  ce->fn;
1661  const auto fname =
1662  tree_helper::print_function_name(TreeM, GetPointerS<const function_decl>(GET_CONST_NODE(fn)));
1663  bool is_f32 = false;
1664  const auto tf_fname = strip_fname(fname, &is_f32);
1665  if(supported_libm_calls.count(tf_fname))
1666  {
1668  "---Replacing libm call with templatized version");
1669  // libm function calls may be replaced with their templatized version if available, avoiding conversion
1670  AppM->GetCallGraphManager()->RemoveCallPoint(function_id, GET_INDEX_CONST_NODE(fn),
1671  GET_INDEX_CONST_NODE(current_statement));
1672  is_f32 |= !ce->args.empty() && tree_helper::Size(ce->args.front()) == 32;
1673  const auto specFF = _version->ieee_format() ? (is_f32 ? float32FF : float64FF) : _version->userRequired;
1674  replaceWithCall(specFF, "__" + tf_fname, ce->args, current_statement, ga->op1, current_srcp);
1675  RecursiveExaminate(current_statement, ga->op0, INTERFACE_TYPE_NONE);
1676  if(supported_libm_calls_inlined.count(tf_fname))
1677  {
1679  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call inlining required");
1680  }
1681  modified = true;
1682  }
1683  else
1684  {
1685  const auto type_i = [&]() {
1686  // Return values associated to non-internal calls need to be cast renamed to local float format
1687  int ti = is_internal_call(fn) ? type_interface : INTERFACE_TYPE_INPUT;
1688 
1689  // Hardware implemented functions need the return value to still be real_type, thus it is necessary to
1690  // add a view_convert operation after
1691  if(fname != BUILTIN_WAIT_CALL &&
1692  AppM->get_tree_manager()->get_implementation_node(GET_INDEX_CONST_NODE(fn)) == 0)
1693  {
1694  ti |= INTERFACE_TYPE_REAL;
1695  }
1696  return ti;
1697  }();
1698  RecursiveExaminate(current_statement, ga->op0, type_i);
1699  }
1700  }
1701  else if(tree_helper::IsLoad(current_statement, function_behavior->get_function_mem()))
1702  {
1703  // Values loaded from memory need to be cast renamed to local float format
1704  RecursiveExaminate(current_statement, ga->op0, INTERFACE_TYPE_INPUT);
1705  }
1706  else
1707  {
1708  RecursiveExaminate(current_statement, ga->op0, type_interface);
1709  }
1710  if(tree_helper::IsStore(current_statement, function_behavior->get_function_mem()))
1711  {
1712  // Values stored to memory need to be cast renamed before the store statement
1713  RecursiveExaminate(current_statement, ga->op1, INTERFACE_TYPE_OUTPUT);
1714  }
1715  else
1716  {
1717  RecursiveExaminate(current_statement, ga->op1, type_interface);
1718  }
1719  if(ga->predicate)
1720  {
1721  RecursiveExaminate(current_statement, ga->predicate, type_interface);
1722  }
1723  break;
1724  }
1725  case gimple_nop_K:
1726  {
1727  break;
1728  }
1729  case var_decl_K:
1730  case parm_decl_K:
1731  {
1732  break;
1733  }
1734  case ssa_name_K:
1735  {
1736  const auto SSA = GetPointerS<ssa_name>(curr_tn);
1737  if(lowering_needed(SSA))
1738  {
1739  // Real variables must all be converted to unsigned integers after softfloat lowering operations
1740  viewConvert.insert({SSA, type_interface == INTERFACE_TYPE_NONE});
1741  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Lowering required for current variable");
1742 
1743  if(type_interface & INTERFACE_TYPE_REAL)
1744  {
1745  if(GET_INDEX_CONST_NODE(SSA->CGetDefStmt()) == GET_INDEX_CONST_NODE(current_statement))
1746  {
1747  hwReturn.push_back(SSA);
1748  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Internal input interface required");
1749  }
1750  else
1751  {
1752  hwParam[SSA].insert(GET_INDEX_CONST_NODE(current_statement));
1753  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Internal output interface required");
1754  }
1755  }
1756  }
1757 
1758  // Search for ssa variables associated to input parameters
1759  if(!bindingCompleted)
1760  {
1761  const auto& args = fd->list_of_args;
1762  // If ssa_name references a parm_decl and is defined by a gimple_nop, it represents the formal function
1763  // parameter inside the function body
1764  if(SSA->var != nullptr && GET_CONST_NODE(SSA->var)->get_kind() == parm_decl_K &&
1765  GET_CONST_NODE(SSA->CGetDefStmt())->get_kind() == gimple_nop_K)
1766  {
1767  auto argIt = std::find_if(args.begin(), args.end(), [&](const tree_nodeRef& arg) {
1768  return GET_INDEX_CONST_NODE(arg) == GET_INDEX_CONST_NODE(SSA->var);
1769  });
1770  THROW_ASSERT(argIt != args.end(), "parm_decl associated with ssa_name not found in function parameters");
1771  const auto arg_pos = static_cast<size_t>(argIt - args.begin());
1772  THROW_ASSERT(arg_pos < args.size(), "Computed parameter position outside actual parameters number");
1773  paramBinding[arg_pos] = curr_tn;
1774  bindingCompleted = std::find(paramBinding.begin(), paramBinding.end(), nullptr) == paramBinding.end();
1776  "---Variable " + SSA->ToString() + " is defined from parameter " + STR(arg_pos));
1777  }
1778  }
1779 
1780  if(!_version->ieee_format() && tree_helper::IsRealType(SSA->type))
1781  {
1782  const auto ssa_ff = tree_helper::Size(SSA->type) == 32 ? float32FF : float64FF;
1783  if((!_version->internal &&
1784  std::find(paramBinding.begin(), paramBinding.end(), curr_tn) != paramBinding.end()) ||
1785  type_interface & INTERFACE_TYPE_INPUT)
1786  {
1788  "---Input interface required for current parameter");
1789  if(type_interface & INTERFACE_TYPE_OUTPUT)
1790  {
1791  // Considered ssa has been discovered to be a function parameter and is used in current statement as a
1792  // non-internal function argument, thus conversion can be avoided
1793  const auto iif = inputInterface.find(SSA);
1794  if(iif == inputInterface.end())
1795  {
1796  THROW_ASSERT(ssa_ff, "");
1797  inputInterface.insert(
1798  {SSA, {ssa_ff, std::vector<unsigned int>({GET_INDEX_CONST_NODE(current_statement)})}});
1799  }
1800  else
1801  {
1802  std::get<1>(iif->second).push_back(GET_INDEX_CONST_NODE(current_statement));
1803  }
1805  "---Skipping input interface for current parameter");
1806  break;
1807  }
1808  if(!static_cast<bool>(inputInterface.count(SSA)))
1809  {
1810  // Add current input SSA to the input cast rename list for all its uses if not already present
1811  THROW_ASSERT(ssa_ff, "");
1812  inputInterface.insert({SSA, {ssa_ff, std::vector<unsigned int>()}});
1813  }
1814  }
1815  else if(type_interface & INTERFACE_TYPE_OUTPUT)
1816  {
1817  const auto iif = inputInterface.find(SSA);
1818  if(iif != inputInterface.end())
1819  {
1820  std::get<1>(iif->second).push_back(GET_INDEX_CONST_NODE(current_statement));
1821  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Uninterfaced value forward required");
1822  }
1823  else
1824  {
1825  // Add current output SSA to the output cast rename list for its uses in current statement
1826  const auto oif = outputInterface.find(SSA);
1827  if(oif == outputInterface.end())
1828  {
1829  outputInterface.insert({SSA, {ssa_ff, std::vector<tree_nodeRef>({current_statement})}});
1830  }
1831  else
1832  {
1833  std::get<1>(oif->second).push_back(current_statement);
1834  }
1836  "---Output interface required for current variable use");
1837  }
1838  }
1839  }
1840 
1841  break;
1842  }
1843  case tree_list_K:
1844  {
1845  auto current = current_tree_node;
1846  while(current)
1847  {
1848  RecursiveExaminate(current_statement, GetPointerS<const tree_list>(GET_CONST_NODE(current))->valu,
1849  type_interface);
1850  current = GetPointerS<const tree_list>(GET_CONST_NODE(current))->chan;
1851  }
1852  break;
1853  }
1854  case CASE_UNARY_EXPRESSION:
1855  {
1856  const auto ue = GetPointerS<const unary_expr>(curr_tn);
1857  const auto& expr_type = ue->type;
1858  const auto op_expr_type = tree_helper::CGetType(ue->op);
1859  // Propagate recursion with INTERFACE_TYPE_NONE to avoid cast rename of internal variables (input parameters
1860  // and constant will be converted anyway)
1861  RecursiveExaminate(current_statement, ue->op, INTERFACE_TYPE_NONE);
1862  if(tree_helper::IsRealType(expr_type))
1863  {
1864  switch(curr_tn->get_kind())
1865  {
1866  case float_expr_K:
1867  {
1868  auto bitsize_in = tree_helper::Size(op_expr_type);
1869  if(bitsize_in < 32)
1870  {
1871  bitsize_in = 32;
1872  }
1873  else if(bitsize_in > 32 && bitsize_in < 64)
1874  {
1875  bitsize_in = 64;
1876  }
1877  auto bitsize_out = tree_helper::Size(expr_type);
1878  FloatFormatRef outFF;
1879  if(bitsize_out <= 32)
1880  {
1881  bitsize_out = 32;
1882  outFF = float32FF;
1883  }
1884  else if(bitsize_out > 32 && bitsize_out <= 64)
1885  {
1886  bitsize_out = 64;
1887  outFF = float64FF;
1888  }
1889  const auto bitsize_str_in = STR(bitsize_in);
1890  const auto bitsize_str_out = bitsize_out == 96 ? "x80" : STR(bitsize_out);
1891  if(!tree_helper::IsRealType(op_expr_type))
1892  {
1893  const auto is_unsigned = tree_helper::IsUnsignedIntegerType(op_expr_type);
1894  const auto fu_name = "__" + std::string(is_unsigned ? "u" : "") + "int" + bitsize_str_in +
1895  "_to_float" + bitsize_str_out;
1896  THROW_ASSERT(!_version->ieee_format() || outFF, "");
1897  replaceWithCall(_version->ieee_format() ? outFF : _version->userRequired, fu_name, {ue->op},
1898  current_statement, current_tree_node, current_srcp);
1899  if(inline_conversion)
1900  {
1902  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call inlining required");
1903  }
1904  modified = true;
1905  }
1906  break;
1907  }
1908  case view_convert_expr_K:
1909  {
1910  // BEAWARE: this view_convert is from integer to real type, thus it will be a def statement of a real
1911  // type ssa_name
1912  // def statements of real type ssa_name variables will be correctly replaced in the next
1913  // phase of this step
1914  break;
1915  }
1916  case abs_expr_K:
1917  {
1918  const auto float_size = tree_helper::Size(op_expr_type);
1919  THROW_ASSERT(float_size == 32 || float_size == 64,
1920  "Unhandled floating point format (size = " + STR(float_size) + ")");
1921  const auto ff =
1922  _version->ieee_format() ? (float_size == 32 ? float32FF : float64FF) : _version->userRequired;
1923  THROW_ASSERT(ff, "Float format should be defined here");
1924  const auto float_negate = floatAbs(ue->op, ff);
1925  TreeM->ReplaceTreeNode(current_statement, current_tree_node, float_negate);
1926  modified = true;
1927  break;
1928  }
1929  case negate_expr_K:
1930  {
1931  const auto float_size = tree_helper::Size(op_expr_type);
1932  THROW_ASSERT(float_size == 32 || float_size == 64,
1933  "Unhandled floating point format (size = " + STR(float_size) + ")");
1934  const auto ff =
1935  _version->ieee_format() ? (float_size == 32 ? float32FF : float64FF) : _version->userRequired;
1936  THROW_ASSERT(ff, "Float format should be defined here");
1937  const auto float_negate = floatNegate(ue->op, ff);
1938  TreeM->ReplaceTreeNode(current_statement, current_tree_node, float_negate);
1939  modified = true;
1940  break;
1941  }
1942  case nop_expr_K:
1943  {
1944  if(_version->ieee_format())
1945  {
1946  auto bitsize_in = tree_helper::Size(op_expr_type);
1947  auto bitsize_out = tree_helper::Size(expr_type);
1948  THROW_ASSERT(bitsize_in == 32 || bitsize_in == 64,
1949  "Unhandled input floating point format (size = " + STR(bitsize_in) + ")");
1950  THROW_ASSERT(bitsize_out == 32 || bitsize_out == 64,
1951  "Unhandled output floating point format (size = " + STR(bitsize_out) + ")");
1952  if(tree_helper::IsRealType(op_expr_type))
1953  {
1954  const auto fu_name = "__float" + STR(bitsize_in) + "_to_float" + STR(bitsize_out) + "_ieee";
1955  const auto inFF = bitsize_in == 32 ? float32FF : float64FF;
1956  const auto called_function = TreeM->GetFunction(fu_name);
1957  THROW_ASSERT(called_function, "The library miss this function " + fu_name);
1958  std::vector<tree_nodeRef> args = {
1959  ue->op,
1960  TreeM->CreateUniqueIntegerCst(static_cast<long long>(inFF->exception_mode),
1962  TreeM->CreateUniqueIntegerCst(inFF->has_subnorm, tree_man->GetBooleanType())};
1963  TreeM->ReplaceTreeNode(current_statement, current_tree_node,
1964  tree_man->CreateCallExpr(called_function, args, current_srcp));
1966  already_visited, AppM, function_id, called_function->index,
1970  "---Added call point for " + STR(called_function->index));
1971  if(inline_conversion)
1972  {
1974  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call inlining required");
1975  }
1976  }
1977  else
1978  {
1979  const auto vc_expr =
1980  tree_man->create_unary_operation(expr_type, ue->op, current_srcp, view_convert_expr_K);
1981  TreeM->ReplaceTreeNode(current_statement, current_tree_node, vc_expr);
1982  }
1983  modified = true;
1984  }
1985  else
1986  {
1987  THROW_UNREACHABLE("Operation not yet supported: function with user-defined floating point format "
1988  "should use a unique format type.");
1989  }
1990  break;
1991  }
1992  case indirect_ref_K:
1993  case imagpart_expr_K:
1994  case realpart_expr_K:
1995  case paren_expr_K:
1996  break;
1997  case addr_expr_K:
1998  case alignof_expr_K:
1999  case arrow_expr_K:
2000  case bit_not_expr_K:
2001  case buffer_ref_K:
2002  case card_expr_K:
2003  case cleanup_point_expr_K:
2004  case conj_expr_K:
2005  case convert_expr_K:
2006  case exit_expr_K:
2007  case fix_ceil_expr_K:
2008  case fix_floor_expr_K:
2009  case fix_round_expr_K:
2010  case fix_trunc_expr_K:
2011  case misaligned_indirect_ref_K:
2012  case loop_expr_K:
2013  case non_lvalue_expr_K:
2014  case reference_expr_K:
2015  case reinterpret_cast_expr_K:
2016  case sizeof_expr_K:
2017  case static_cast_expr_K:
2018  case throw_expr_K:
2019  case truth_not_expr_K:
2020  case unsave_expr_K:
2021  case va_arg_expr_K:
2022  case reduc_max_expr_K:
2023  case reduc_min_expr_K:
2024  case reduc_plus_expr_K:
2025  case vec_unpack_hi_expr_K:
2026  case vec_unpack_lo_expr_K:
2027  case vec_unpack_float_hi_expr_K:
2028  case vec_unpack_float_lo_expr_K:
2029  case binfo_K:
2030  case block_K:
2031  case call_expr_K:
2032  case aggr_init_expr_K:
2033  case case_label_expr_K:
2034  case constructor_K:
2035  case identifier_node_K:
2036  case ssa_name_K:
2037  case statement_list_K:
2038  case target_expr_K:
2039  case target_mem_ref_K:
2040  case target_mem_ref461_K:
2041  case tree_list_K:
2042  case tree_vec_K:
2043  case error_mark_K:
2044  case lut_expr_K:
2046  case CASE_CPP_NODES:
2047  case CASE_CST_NODES:
2048  case CASE_DECL_NODES:
2049  case CASE_FAKE_NODES:
2050  case CASE_GIMPLE_NODES:
2051  case CASE_PRAGMA_NODES:
2054  case CASE_TYPE_NODES:
2055  {
2056  THROW_ERROR("not yet supported soft float function: " + curr_tn->get_kind_text());
2057  break;
2058  }
2059  default:
2060  {
2061  THROW_UNREACHABLE("");
2062  }
2063  }
2064  }
2065  if(tree_helper::IsRealType(op_expr_type))
2066  {
2067  switch(curr_tn->get_kind())
2068  {
2069  case fix_trunc_expr_K:
2070  {
2071  const auto bitsize_in = tree_helper::Size(op_expr_type);
2072  const auto inFF = bitsize_in == 32 ? float32FF : (bitsize_in == 64 ? float64FF : nullptr);
2073  auto bitsize_out = tree_helper::Size(expr_type);
2074  if(bitsize_out < 32)
2075  {
2076  bitsize_out = 32;
2077  }
2078  else if(bitsize_out > 32 && bitsize_out < 64)
2079  {
2080  bitsize_out = 64;
2081  }
2082  const auto is_unsigned = tree_helper::IsUnsignedIntegerType(expr_type);
2083  const auto bitsize_str_in = bitsize_in == 96 ? "x80" : STR(bitsize_in);
2084  const auto bitsize_str_out = bitsize_out == 96 ? "x80" : STR(bitsize_out);
2085  const auto fu_name = "__float" + bitsize_str_in + "_to_" + (is_unsigned ? "u" : "") + "int" +
2086  bitsize_str_out + "_round_to_zero";
2087  replaceWithCall(_version->ieee_format() ? inFF : _version->userRequired, fu_name, {ue->op},
2088  current_statement, current_tree_node, current_srcp);
2089  if(inline_conversion)
2090  {
2092  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call inlining required");
2093  }
2094  modified = true;
2095  break;
2096  }
2097  case view_convert_expr_K:
2098  {
2099  // This view_convert is from real to integer type variable, thus needs to be stored in the type
2100  // conversion set of statements to be converted later if necessary
2101  nopConvert.push_back(current_statement);
2102  break;
2103  }
2104  case binfo_K:
2105  case block_K:
2106  case call_expr_K:
2107  case aggr_init_expr_K:
2108  case case_label_expr_K:
2109  case constructor_K:
2110  case identifier_node_K:
2111  case ssa_name_K:
2112  case statement_list_K:
2113  case target_expr_K:
2114  case target_mem_ref_K:
2115  case target_mem_ref461_K:
2116  case tree_list_K:
2117  case tree_vec_K:
2118  case lut_expr_K:
2120  case CASE_CPP_NODES:
2121  case CASE_CST_NODES:
2122  case CASE_DECL_NODES:
2123  case CASE_FAKE_NODES:
2124  case CASE_GIMPLE_NODES:
2125  case CASE_PRAGMA_NODES:
2128  case CASE_TYPE_NODES:
2129  case abs_expr_K:
2130  case addr_expr_K:
2131  case alignof_expr_K:
2132  case arrow_expr_K:
2133  case bit_not_expr_K:
2134  case buffer_ref_K:
2135  case card_expr_K:
2136  case cleanup_point_expr_K:
2137  case conj_expr_K:
2138  case convert_expr_K:
2139  case exit_expr_K:
2140  case fix_ceil_expr_K:
2141  case fix_floor_expr_K:
2142  case fix_round_expr_K:
2143  case float_expr_K:
2144  case imagpart_expr_K:
2145  case indirect_ref_K:
2146  case misaligned_indirect_ref_K:
2147  case loop_expr_K:
2148  case negate_expr_K:
2149  case non_lvalue_expr_K:
2150  case nop_expr_K:
2151  case paren_expr_K:
2152  case realpart_expr_K:
2153  case reference_expr_K:
2154  case reinterpret_cast_expr_K:
2155  case sizeof_expr_K:
2156  case static_cast_expr_K:
2157  case throw_expr_K:
2158  case truth_not_expr_K:
2159  case unsave_expr_K:
2160  case va_arg_expr_K:
2161  case reduc_max_expr_K:
2162  case reduc_min_expr_K:
2163  case reduc_plus_expr_K:
2164  case vec_unpack_hi_expr_K:
2165  case vec_unpack_lo_expr_K:
2166  case vec_unpack_float_hi_expr_K:
2167  case vec_unpack_float_lo_expr_K:
2168  case error_mark_K:
2169  break;
2170  default:
2171  {
2172  THROW_UNREACHABLE("");
2173  }
2174  }
2175  }
2176  break;
2177  }
2179  {
2180  const auto be = GetPointerS<binary_expr>(curr_tn);
2181  // Get operand type before recursive examination because floating point operands may be converted to unsigned
2182  // integer during during recursion
2183  const auto expr_type = tree_helper::CGetType(be->op0);
2184  // Propagate recursion with INTERFACE_TYPE_NONE to avoid cast rename of internal variables (input parameters
2185  // and constant will be converted anyway)
2186  RecursiveExaminate(current_statement, be->op0,
2187  (tree_helper::IsRealType(expr_type) &&
2188  (curr_tn->get_kind() == unordered_expr_K || curr_tn->get_kind() == ordered_expr_K ||
2189  curr_tn->get_kind() == complex_expr_K)) ?
2192  RecursiveExaminate(current_statement, be->op1,
2193  (tree_helper::IsRealType(expr_type) &&
2194  (curr_tn->get_kind() == unordered_expr_K || curr_tn->get_kind() == ordered_expr_K ||
2195  curr_tn->get_kind() == complex_expr_K)) ?
2198  if(tree_helper::IsRealType(expr_type))
2199  {
2200  bool add_call = true;
2201  std::string fu_suffix;
2202  switch(curr_tn->get_kind())
2203  {
2204  case mult_expr_K:
2205  {
2206  fu_suffix = "mul";
2207  break;
2208  }
2209  case plus_expr_K:
2210  {
2211  fu_suffix = "add";
2212  break;
2213  }
2214  case minus_expr_K:
2215  {
2216  fu_suffix = "sub";
2217  break;
2218  }
2219  case rdiv_expr_K:
2220  {
2221  fu_suffix = "div";
2222  const auto bitsize = tree_helper::Size(expr_type);
2223  if(bitsize == 32 || bitsize == 64)
2224  {
2225  THROW_ASSERT(parameters->isOption(OPT_hls_fpdiv), "a default is expected");
2226  if(parameters->getOption<std::string>(OPT_hls_fpdiv) == "SRT4")
2227  {
2228  fu_suffix = fu_suffix + "SRT4";
2229  }
2230  else if(parameters->getOption<std::string>(OPT_hls_fpdiv) == "G")
2231  {
2232  fu_suffix = fu_suffix + "G";
2233  }
2234  else if(parameters->getOption<std::string>(OPT_hls_fpdiv) == "SF")
2235  {
2236  // do nothing
2237  }
2238  else
2239  {
2240  THROW_ERROR("FP-Division algorithm not supported:" +
2241  parameters->getOption<std::string>(OPT_hls_fpdiv));
2242  }
2243  }
2244  break;
2245  }
2246  case gt_expr_K:
2247  {
2248  fu_suffix = "gt";
2249  break;
2250  }
2251  case ge_expr_K:
2252  {
2253  fu_suffix = "ge";
2254  break;
2255  }
2256  case lt_expr_K:
2257  {
2258  fu_suffix = "lt";
2259  break;
2260  }
2261  case le_expr_K:
2262  {
2263  fu_suffix = "le";
2264  break;
2265  }
2266  case eq_expr_K:
2267  {
2268  fu_suffix = "eq";
2269  break;
2270  }
2271  case ne_expr_K:
2272  case ltgt_expr_K:
2273  {
2274  fu_suffix = "ltgt_quiet";
2275  break;
2276  }
2277  case uneq_expr_K:
2278  case unge_expr_K:
2279  case ungt_expr_K:
2280  case unle_expr_K:
2281  case unlt_expr_K:
2282  {
2283  THROW_ERROR("Unsupported tree node " + curr_tn->get_kind_text());
2284  break;
2285  }
2286  case assert_expr_K:
2287  case bit_and_expr_K:
2288  case bit_ior_expr_K:
2289  case bit_xor_expr_K:
2290  case catch_expr_K:
2291  case ceil_div_expr_K:
2292  case ceil_mod_expr_K:
2293  case complex_expr_K:
2294  case compound_expr_K:
2295  case eh_filter_expr_K:
2296  case exact_div_expr_K:
2297  case fdesc_expr_K:
2298  case floor_div_expr_K:
2299  case floor_mod_expr_K:
2300  case goto_subroutine_K:
2301  case in_expr_K:
2302  case init_expr_K:
2303  case lrotate_expr_K:
2304  case lshift_expr_K:
2305  case lut_expr_K:
2306  case max_expr_K:
2307  case mem_ref_K:
2308  case min_expr_K:
2309  case modify_expr_K:
2310  case mult_highpart_expr_K:
2311  case ordered_expr_K:
2312  case pointer_plus_expr_K:
2313  case postdecrement_expr_K:
2314  case postincrement_expr_K:
2315  case predecrement_expr_K:
2316  case preincrement_expr_K:
2317  case range_expr_K:
2318  case round_div_expr_K:
2319  case round_mod_expr_K:
2320  case rrotate_expr_K:
2321  case rshift_expr_K:
2322  case set_le_expr_K:
2323  case trunc_div_expr_K:
2324  case trunc_mod_expr_K:
2325  case truth_and_expr_K:
2326  case truth_andif_expr_K:
2327  case truth_or_expr_K:
2328  case truth_orif_expr_K:
2329  case truth_xor_expr_K:
2330  case try_catch_expr_K:
2331  case try_finally_K:
2332  case unordered_expr_K:
2333  case widen_sum_expr_K:
2334  case widen_mult_expr_K:
2335  case with_size_expr_K:
2336  case vec_lshift_expr_K:
2337  case vec_rshift_expr_K:
2338  case widen_mult_hi_expr_K:
2339  case widen_mult_lo_expr_K:
2340  case vec_pack_trunc_expr_K:
2341  case vec_pack_sat_expr_K:
2342  case vec_pack_fix_trunc_expr_K:
2343  case vec_extracteven_expr_K:
2344  case vec_extractodd_expr_K:
2345  case vec_interleavehigh_expr_K:
2346  case vec_interleavelow_expr_K:
2347  case extract_bit_expr_K:
2348  case sat_plus_expr_K:
2349  case sat_minus_expr_K:
2350  case extractvalue_expr_K:
2351  case extractelement_expr_K:
2352  {
2353  add_call = false;
2354  break;
2355  }
2356  case binfo_K:
2357  case block_K:
2358  case call_expr_K:
2359  case aggr_init_expr_K:
2360  case case_label_expr_K:
2361  case constructor_K:
2362  case identifier_node_K:
2363  case ssa_name_K:
2364  case statement_list_K:
2365  case target_expr_K:
2366  case target_mem_ref_K:
2367  case target_mem_ref461_K:
2368  case tree_list_K:
2369  case tree_vec_K:
2370  case error_mark_K:
2371  case frem_expr_K:
2372  case CASE_CPP_NODES:
2373  case CASE_CST_NODES:
2374  case CASE_DECL_NODES:
2375  case CASE_FAKE_NODES:
2376  case CASE_GIMPLE_NODES:
2377  case CASE_PRAGMA_NODES:
2380  case CASE_TYPE_NODES:
2381  case CASE_UNARY_EXPRESSION:
2382  {
2383  break;
2384  }
2385  default:
2386  {
2387  THROW_UNREACHABLE("");
2388  }
2389  }
2390  if(add_call)
2391  {
2392  const auto bitsize = tree_helper::Size(expr_type);
2393  const auto opFF = bitsize == 32 ? float32FF : (bitsize == 64 ? float64FF : nullptr);
2394  const auto fu_name = "__float_" + fu_suffix;
2395  replaceWithCall(_version->ieee_format() ? opFF : _version->userRequired, fu_name, {be->op0, be->op1},
2396  current_statement, current_tree_node, current_srcp);
2397  if(inline_math)
2398  {
2400  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Call inlining required");
2401  }
2402  modified = true;
2403  }
2404  }
2405  else if(tree_helper::IsRealType(be->type))
2406  {
2407  if(curr_tn->get_kind() == mem_ref_K)
2408  {
2409  const auto mr = GetPointerS<mem_ref>(curr_tn);
2410  mr->type = tree_helper::Size(mr->type) == 32 ? float32_type : float64_type;
2411  }
2412  else
2413  {
2414  THROW_UNREACHABLE("Real type expression not handled: " + curr_tn->get_kind_text() + " " +
2415  curr_tn->ToString());
2416  }
2417  }
2418  else if(tree_helper::IsPointerType(current_tree_node) &&
2420  {
2421  if(curr_tn->get_kind() == mem_ref_K)
2422  {
2423  const auto mr = GetPointerS<mem_ref>(curr_tn);
2424  mr->type = int_type_for(mr->type, true);
2425  }
2426  else if(curr_tn->get_kind() == pointer_plus_expr_K)
2427  {
2428  const auto pp = GetPointerS<pointer_plus_expr>(curr_tn);
2429  pp->type = int_type_for(pp->type, true);
2430  }
2431  else
2432  {
2433  THROW_UNREACHABLE("Real pointer type expression not handled: " + curr_tn->get_kind_text() + " " +
2434  curr_tn->ToString());
2435  }
2436  }
2437  break;
2438  }
2440  {
2441  const auto te = GetPointerS<ternary_expr>(curr_tn);
2442  RecursiveExaminate(current_statement, te->op0, type_interface);
2443  if(te->op1)
2444  {
2445  RecursiveExaminate(current_statement, te->op1, type_interface);
2446  }
2447  if(te->op2)
2448  {
2449  RecursiveExaminate(current_statement, te->op2, type_interface);
2450  }
2451  break;
2452  }
2454  {
2455  const auto qe = GetPointerS<quaternary_expr>(curr_tn);
2456  RecursiveExaminate(current_statement, qe->op0, type_interface);
2457  if(qe->op1)
2458  {
2459  RecursiveExaminate(current_statement, qe->op1, type_interface);
2460  }
2461  if(qe->op2)
2462  {
2463  RecursiveExaminate(current_statement, qe->op2, type_interface);
2464  }
2465  if(qe->op3)
2466  {
2467  RecursiveExaminate(current_statement, qe->op3, type_interface);
2468  }
2469  break;
2470  }
2471  case lut_expr_K:
2472  {
2473  const auto le = GetPointerS<lut_expr>(curr_tn);
2474  RecursiveExaminate(current_statement, le->op0, type_interface);
2475  RecursiveExaminate(current_statement, le->op1, type_interface);
2476  if(le->op2)
2477  {
2478  RecursiveExaminate(current_statement, le->op2, type_interface);
2479  }
2480  if(le->op3)
2481  {
2482  RecursiveExaminate(current_statement, le->op3, type_interface);
2483  }
2484  if(le->op4)
2485  {
2486  RecursiveExaminate(current_statement, le->op4, type_interface);
2487  }
2488  if(le->op5)
2489  {
2490  RecursiveExaminate(current_statement, le->op5, type_interface);
2491  }
2492  if(le->op6)
2493  {
2494  RecursiveExaminate(current_statement, le->op6, type_interface);
2495  }
2496  if(le->op7)
2497  {
2498  RecursiveExaminate(current_statement, le->op7, type_interface);
2499  }
2500  if(le->op8)
2501  {
2502  RecursiveExaminate(current_statement, le->op8, type_interface);
2503  }
2504  break;
2505  }
2506  case constructor_K:
2507  {
2508  const auto co = GetPointerS<constructor>(curr_tn);
2509  for(const auto& idx_valu : co->list_of_idx_valu)
2510  {
2511  RecursiveExaminate(current_statement, idx_valu.second, type_interface);
2512  }
2513  break;
2514  }
2515  case gimple_cond_K:
2516  {
2517  const auto gc = GetPointerS<gimple_cond>(curr_tn);
2518  RecursiveExaminate(current_statement, gc->op0, type_interface);
2519  break;
2520  }
2521  case gimple_switch_K:
2522  {
2523  const auto se = GetPointerS<gimple_switch>(curr_tn);
2524  RecursiveExaminate(current_statement, se->op0, type_interface);
2525  break;
2526  }
2527  case gimple_multi_way_if_K:
2528  {
2529  const auto gmwi = GetPointerS<gimple_multi_way_if>(curr_tn);
2530  for(const auto& cond : gmwi->list_of_cond)
2531  {
2532  if(cond.first)
2533  {
2534  RecursiveExaminate(current_statement, cond.first, type_interface);
2535  }
2536  }
2537  break;
2538  }
2539  case gimple_return_K:
2540  {
2541  const auto re = GetPointerS<gimple_return>(curr_tn);
2542  if(re->op)
2543  {
2544  if(isTopFunction && GET_NODE(re->op)->get_kind() == ssa_name_K &&
2545  lowering_needed(GetPointerS<ssa_name>(GET_NODE(re->op))))
2546  {
2547  topReturn.push_back(current_statement);
2548  }
2549  RecursiveExaminate(current_statement, re->op,
2551  }
2552  break;
2553  }
2554  case gimple_for_K:
2555  {
2556  const auto gf = GetPointerS<const gimple_for>(curr_tn);
2557  RecursiveExaminate(current_statement, gf->op0, type_interface);
2558  RecursiveExaminate(current_statement, gf->op1, type_interface);
2559  RecursiveExaminate(current_statement, gf->op2, type_interface);
2560  break;
2561  }
2562  case gimple_while_K:
2563  {
2564  const auto gw = GetPointerS<gimple_while>(curr_tn);
2565  RecursiveExaminate(current_statement, gw->op0, type_interface);
2566  break;
2567  }
2568  case CASE_TYPE_NODES:
2569  case type_decl_K:
2570  {
2571  break;
2572  }
2573  case target_mem_ref_K:
2574  {
2575  const auto tmr = GetPointerS<target_mem_ref>(curr_tn);
2576  if(tmr->symbol)
2577  {
2578  RecursiveExaminate(current_statement, tmr->symbol, type_interface);
2579  }
2580  if(tmr->base)
2581  {
2582  RecursiveExaminate(current_statement, tmr->base, type_interface);
2583  }
2584  if(tmr->idx)
2585  {
2586  RecursiveExaminate(current_statement, tmr->idx, type_interface);
2587  }
2588  break;
2589  }
2590  case target_mem_ref461_K:
2591  {
2592  const auto tmr = GetPointerS<target_mem_ref461>(curr_tn);
2593  if(tmr->base)
2594  {
2595  RecursiveExaminate(current_statement, tmr->base, type_interface);
2596  }
2597  if(tmr->idx)
2598  {
2599  RecursiveExaminate(current_statement, tmr->idx, type_interface);
2600  }
2601  if(tmr->idx2)
2602  {
2603  RecursiveExaminate(current_statement, tmr->idx2, type_interface);
2604  }
2605  break;
2606  }
2607  case real_cst_K:
2608  {
2609  if(~type_interface & INTERFACE_TYPE_REAL)
2610  {
2611  const auto cst = GetPointerS<real_cst>(curr_tn);
2612  const auto bw = tree_helper::Size(current_tree_node);
2613  const auto fp_str =
2614  (cst->valx.front() == '-' && cst->valr.front() != cst->valx.front()) ? ("-" + cst->valr) : cst->valr;
2615  const auto cst_val = convert_fp_to_bits(fp_str, bw);
2616  tree_nodeRef int_cst;
2617  if(type_interface == INTERFACE_TYPE_OUTPUT || _version->ieee_format())
2618  {
2619  int_cst = TreeM->CreateUniqueIntegerCst(static_cast<long long>(cst_val),
2620  tree_man->GetCustomIntegerType(bw, true));
2621  }
2622  else
2623  {
2624  const auto inFF = bw == 32 ? float32FF : float64FF;
2625  int_cst = cstCast(cst_val, inFF, _version->userRequired);
2626  }
2627 
2628  // Perform static constant value cast and replace real type constant with converted unsigned integer type
2629  // constant
2630  TreeM->ReplaceTreeNode(current_statement, current_tree_node, int_cst);
2631  modified = true;
2633  "---Real type constant " + curr_tn->ToString() + " converted to " +
2634  GET_NODE(int_cst)->ToString());
2635  }
2636  break;
2637  }
2638  case integer_cst_K:
2639  // {
2640  // const auto cst_val = tree_helper::GetConstValue(curr_tn);
2641  // if(tree_helper::IsPointerType(curr_tn))
2642  // {
2643  // const auto ptd_type = tree_helper::CGetPointedType(curr_tn);
2644  // if(tree_helper::IsRealType(ptd_type))
2645  // {
2646  // const auto int_ptr_cst = TreeM->CreateUniqueIntegerCst(cst_val, tree_helper::Size(ptd_type) == 32
2647  // ? float32_ptr_type : float64_ptr_type); TreeM->ReplaceTreeNode(current_statement,
2648  // current_tree_node, int_ptr_cst); INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Real
2649  // pointer type constant " + curr_tn->ToString() + " converted to " +
2650  // GET_NODE(int_ptr_cst)->ToString());
2651  // }
2652  // }
2653  // break;
2654  // }
2655  case complex_cst_K:
2656  case string_cst_K:
2657  case field_decl_K:
2658  case function_decl_K:
2659  case label_decl_K:
2660  case result_decl_K:
2661  case vector_cst_K:
2662  case void_cst_K:
2663  case tree_vec_K:
2664  case case_label_expr_K:
2665  case gimple_label_K:
2666  case gimple_asm_K:
2667  case gimple_goto_K:
2668  case gimple_pragma_K:
2669  case CASE_PRAGMA_NODES:
2670  break;
2671  case binfo_K:
2672  case block_K:
2673  case const_decl_K:
2674  case CASE_CPP_NODES:
2675  case gimple_bind_K:
2676  case gimple_predict_K:
2677  case gimple_resx_K:
2678  case identifier_node_K:
2679  case last_tree_K:
2680  case namespace_decl_K:
2681  case none_K:
2682  case placeholder_expr_K:
2683  case statement_list_K:
2684  case translation_unit_decl_K:
2685  case using_decl_K:
2686  case template_decl_K:
2687  case tree_reindex_K:
2688  case target_expr_K:
2689  case error_mark_K:
2690  {
2691  THROW_ERROR_CODE(NODE_NOT_YET_SUPPORTED_EC, "Not supported node: " + std::string(curr_tn->get_kind_text()));
2692  break;
2693  }
2694  default:
2695  {
2696  THROW_UNREACHABLE("");
2697  }
2698  }
2700  "<--Updated recursively (" + STR(current_tree_node->index) + ") " + STR(current_tree_node));
2701  return modified;
2702 }
2703 
2704 FloatFormat::FloatFormat(uint8_t _exp_bits, uint8_t _frac_bits, int32_t _exp_bias, FPRounding _rounding_mode,
2705  FPException _exception_mode, bool _has_one, bool _has_subnorm, bit_lattice _sign)
2706  : exp_bits(_exp_bits),
2707  frac_bits(_frac_bits),
2708  exp_bias(_exp_bias),
2709  rounding_mode(_rounding_mode),
2710  exception_mode(_exception_mode),
2711  has_one(_has_one),
2712  has_subnorm(_has_subnorm),
2713  sign(_sign)
2714 {
2715 }
2716 
2717 bool FloatFormat::operator==(const FloatFormat& other) const
2718 {
2720  std::tie(other.exp_bits, other.frac_bits, other.exp_bias, other.rounding_mode, other.exception_mode,
2721  other.has_one, other.has_subnorm, other.sign);
2722 }
2723 
2724 bool FloatFormat::operator!=(const FloatFormat& other) const
2725 {
2727  std::tie(other.exp_bits, other.frac_bits, other.exp_bias, other.rounding_mode, other.exception_mode,
2728  other.has_one, other.has_subnorm, other.sign);
2729 }
2730 
2732 {
2733  return ((exp_bits == 8 && frac_bits == 23 && exp_bias == -127) ||
2734  (exp_bits == 11 && frac_bits == 52 && exp_bias == -1023)) &&
2736  sign == bit_lattice::U);
2737 }
2738 
2739 std::string FloatFormat::ToString() const
2740 {
2741  std::stringstream ss;
2742  ss << "e" << +exp_bits;
2743  ss << "m" << +frac_bits;
2744  ss << "b" << (exp_bias < 0 ? "_" : "");
2745  ss << std::abs(exp_bias);
2746  switch(rounding_mode)
2747  {
2749  ss << "n";
2750  break;
2751  case FPRounding_Truncate:
2752  ss << "t";
2753  default:
2754  break;
2755  }
2756  switch(exception_mode)
2757  {
2758  case FPException_IEEE:
2759  ss << "i";
2760  break;
2762  ss << "a";
2763  break;
2764  case FPException_Overflow:
2765  ss << "o";
2766  break;
2767  default:
2768  break;
2769  }
2770  if(has_one)
2771  {
2772  ss << "h";
2773  }
2774  if(has_subnorm)
2775  {
2776  ss << "s";
2777  }
2778  switch(sign)
2779  {
2780  case bit_lattice::ONE:
2781  ss << "1";
2782  break;
2783  case bit_lattice::ZERO:
2784  ss << "0";
2785  break;
2786  case bit_lattice::U:
2787  case bit_lattice::X:
2788  default:
2789  break;
2790  }
2791  return ss.str();
2792 }
2793 
2794 #define FP_FORMAT_EXP 1
2795 #define FP_FORMAT_SIG 2
2796 #define FP_FORMAT_BIAS 3
2797 #define FP_FORMAT_RND 4
2798 #define FP_FORMAT_EXC 5
2799 #define FP_FORMAT_SPEC 6
2800 #define FP_FORMAT_SIGN 7
2801 FloatFormatRef FloatFormat::FromString(std::string ff_str)
2802 {
2803  std::replace(ff_str.begin(), ff_str.end(), '_', '-');
2804  static const std::regex fp_format("^e(\\d+)m(\\d+)b([_-]?\\d+)(\\D)(\\D)(\\D*)(\\d?)$");
2805  std::cmatch what;
2806  if(std::regex_search(ff_str.data(), what, fp_format))
2807  {
2808  const auto e = std::stoi(std::string(
2809  what[FP_FORMAT_EXP].first, static_cast<size_t>(what[FP_FORMAT_EXP].second - what[FP_FORMAT_EXP].first)));
2810  const auto m = std::stoi(std::string(
2811  what[FP_FORMAT_SIG].first, static_cast<size_t>(what[FP_FORMAT_SIG].second - what[FP_FORMAT_SIG].first)));
2812  const auto b = std::stoi(std::string(
2813  what[FP_FORMAT_BIAS].first, static_cast<size_t>(what[FP_FORMAT_BIAS].second - what[FP_FORMAT_BIAS].first)));
2814  FloatFormatRef ff(new FloatFormat(static_cast<uint8_t>(e), static_cast<uint8_t>(m), b));
2815  switch(*what[FP_FORMAT_RND].first)
2816  {
2817  case 't':
2818  ff->rounding_mode = FPRounding_Truncate;
2819  break;
2820  case 'n':
2821  ff->rounding_mode = FPRounding_NearestEven;
2822  break;
2823  default:
2824  break;
2825  }
2826  switch(*what[FP_FORMAT_EXC].first)
2827  {
2828  case 'i':
2829  ff->exception_mode = FPException_IEEE;
2830  break;
2831  case 'a':
2832  ff->exception_mode = FPException_Saturation;
2833  break;
2834  case 'o':
2835  ff->exception_mode = FPException_Overflow;
2836  break;
2837  default:
2838  break;
2839  }
2840  const auto spec = std::string(what[FP_FORMAT_SPEC].first,
2841  static_cast<size_t>(what[FP_FORMAT_SPEC].second - what[FP_FORMAT_SPEC].first));
2842  for(const auto& s : spec)
2843  {
2844  switch(s)
2845  {
2846  case 'h':
2847  ff->has_one = true;
2848  break;
2849  case 's':
2850  ff->has_subnorm = true;
2851  break;
2852  default:
2853  break;
2854  }
2855  }
2856  if(what[FP_FORMAT_SIGN].second - what[FP_FORMAT_SIGN].first)
2857  {
2858  const auto sign = static_cast<bool>(std::stoi(std::string(what[FP_FORMAT_SIGN].first, 1)));
2859  ff->sign = sign ? bit_lattice::ONE : bit_lattice::ZERO;
2860  }
2861  return ff;
2862  }
2863  return nullptr;
2864 }
2865 
2866 FunctionVersion::FunctionVersion() : function_vertex(nullptr), userRequired(nullptr), internal(true)
2867 {
2868 }
2869 
2870 FunctionVersion::FunctionVersion(CallGraph::vertex_descriptor func_v, const FloatFormatRef& userFormat)
2871  : function_vertex(func_v), userRequired(userFormat), internal(true)
2872 {
2873 }
2874 
2877  userRequired(other.ieee_format() ? nullptr : new FloatFormat(*other.userRequired)),
2878  internal(other.internal)
2879 {
2880 }
2881 
2883 
2884 int FunctionVersion::compare(const FunctionVersion& other, bool format_only) const
2885 {
2886  return ((function_vertex != other.function_vertex || internal != other.internal) && !format_only) ||
2887  !((userRequired == nullptr && other.userRequired == nullptr) ||
2888  (userRequired != nullptr && other.userRequired != nullptr && *userRequired == *other.userRequired));
2889 }
2890 
2892 {
2893  return compare(other) == 0;
2894 }
2895 
2897 {
2898  return compare(other) != 0;
2899 }
2900 
2902 {
2903  return userRequired == nullptr /*|| userRequired->ieee_format()*/;
2904 }
2905 
2906 std::string FunctionVersion::ToString() const
2907 {
2908  return STR(function_vertex) + (internal ? "_internal_" : "") + (userRequired ? userRequired->ToString() : "");
2909 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
static bool IsSameType(const tree_nodeConstRef &tn0, const tree_nodeConstRef &tn1)
Given two nodes tells if they have same base type (const is not considered: const double == double) ...
static bool IsStore(const tree_nodeConstRef &tn, const CustomOrderedSet< unsigned int > &fun_mem_data)
Return true if the tree node is a gimple_assign writing something which will be allocated in memory...
static bool lowering_needed(const ssa_name *ssa)
#define FP_FORMAT_EXC
tree_nodeRef generate_interface(const blocRef &bb, tree_nodeRef stmt, const tree_nodeRef &ssa, FloatFormatRef inFF, FloatFormatRef outFF) const
Generate necessary statements to convert ssa variable from inFF to outFF and insert them after stmt i...
static std::string strip_fname(std::string fname, bool *single_prec=nullptr)
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
const TreeNodeMap< size_t > & CGetUseStmts() const
Return the use stmts.
Definition: tree_node.cpp:1343
Step does not exits.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
TVMValue param[3]
const tree_nodeRef CGetDefStmt() const
Return the def stmt (checking that is unique)
Definition: tree_node.cpp:1256
tree_nodeRef floatNegate(const tree_nodeRef &op, const FloatFormatRef &ff) const
Generate float negate operation based on given floating-point format.
#define MEMCPY
constant string identifying the operation performed when two objects are memcopied.
Definition: op_graph.hpp:310
File containing functions and utilities to support the printing of debug messagges.
static tree_nodeRef float64_type
std::string ToString() const
Print this node as string in gimple format.
CustomMap< ssa_name *, std::set< unsigned int > > hwParam
Hardware implemented functions need parameters specified as real_type, thus it is necessary to add a ...
Step successfully executed.
#define CASE_BINARY_EXPRESSION
This macro collects all case labels for binary_expr objects.
Definition: tree_node.hpp:463
std::vector< tree_nodeRef > paramBinding
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
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.
#define FP_FORMAT_SIGN
bool operator!=(const FunctionVersion &other) const
Definition of the class representing a generic C application.
const int output_level
The output level.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
#define CASE_DECL_NODES
NOTE that cast_expr is a unary expression but it could not be included in the CASE_UNARY_EXPRESSION b...
Definition: tree_node.hpp:672
static std::string print_type(const tree_managerConstRef &TM, unsigned int type, bool global=false, bool print_qualifiers=false, bool print_storage=false, unsigned int var=0, const var_pp_functorConstRef &vppf=var_pp_functorConstRef(), const std::string &prefix="", const std::string &tail="")
Print a type and its variable in case var is not zero.
Step successfully executed but without any IR change.
const CallGraph::vertex_descriptor function_vertex
CustomMap< ssa_name *, std::tuple< FloatFormatRef, std::vector< unsigned int > > > inputInterface
SSA variable which requires cast renaming from standard to user-defined float format in all but given...
static bool inline_conversion
RelationshipType
The relationship type.
struct definition of the function_decl tree node.
Definition: tree_node.hpp:2759
bool signature_lowering(function_decl *f_decl) const
Source must be executed to satisfy target.
CustomMap< ssa_name *, bool > viewConvert
DesignFlowStep_Status InternalExec() override
Fixes the var_decl duplication.
static tree_nodeRef float32_ptr_type
tree_nodeRef var
var is the variable being referenced (macro SSA_NAME_VAR).
Definition: tree_node.hpp:4543
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
Definition: tree_node.cpp:120
static const std::set< std::string > libm_func
List of low level implementation libm functions.
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
boost::graph_traits< graph >::in_edge_iterator InEdgeIterator
in_edge_iterator definition.
Definition: graph.hpp:1310
exceptions managed by PandA
tree_nodeRef CloneFunction(const tree_nodeRef &tn, const std::string &funNameSuffix)
CloneFunction duplicates a function.
bit_lattice sign
tree_nodeRef create_binary_operation(const tree_nodeConstRef &type, const tree_nodeRef &op0, const tree_nodeRef &op1, const std::string &srcp, enum kind operation_kind) const
Function used to create a binary expression.
tree_nodeRef GetSignedIntegerType() const
Function that creates a integer type if it is not already present, otherwise it returns the one that ...
#define BUILTIN_WAIT_CALL
constant defining the builtin wait call intrinsic function
Definition: op_graph.hpp:358
bool RecursiveExaminate(const tree_nodeRef &current_statement, const tree_nodeRef &current_tree_node, int castRename)
Recursive examine tree node.
#define FP_FORMAT_EXP
#define GET_INDEX_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:361
void ssa_lowering(ssa_name *ssa, bool internal_type) const
#define FP_FORMAT_BIAS
static std::string print_function_name(const tree_managerConstRef &TM, const function_decl *fd)
Return the name of the function in a string.
This class provides methods to build a basic blocks graph.
#define abs(x)
Definition: main.c:3
Node not yet supported.
Definition: exceptions.hpp:323
Data structure describing a basic block at tree level.
FloatFormat(uint8_t _exp_bits, uint8_t _frac_bits, int32_t _exp_bias, FPRounding _rounding_mode=FPRounding_NearestEven, FPException _exception_mode=FPException_IEEE, bool _has_one=true, bool _has_subnorm=false, bit_lattice _sign=bit_lattice::U)
unsigned int bb_version
The version of the basic block intermediate representation on which this step has been applied...
static CustomMap< CallGraph::vertex_descriptor, FunctionVersionRef > funcFF
Floating-point function version map.
redefinition of map to manage ordered/unordered structures
tree_nodeRef create_unary_operation(const tree_nodeConstRef &type, const tree_nodeRef &op, const std::string &srcp, enum kind operation_kind) const
EXPRESSION_TREE_NODES.
FPException exception_mode
tree_nodeRef CreateGimpleAssign(const tree_nodeConstRef &type, const tree_nodeConstRef &min, const tree_nodeConstRef &max, const tree_nodeRef &op, unsigned int function_decl_nid, const std::string &srcp) const
Create gimple assignment.
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
bool operator==(const FloatFormat &other) const
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
void replaceWithCall(const FloatFormatRef &specFF, const std::string &fu_name, std::vector< tree_nodeRef > args, const tree_nodeRef &current_statement, const tree_nodeRef &current_tree_node, const std::string &current_scrp)
Replace current_tree_node with a call_expr to fu_name function specialized with specFF fp format in c...
#define max
Definition: backprop.h:17
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
static void addCallPointAndExpand(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type, int DL)
static bool IsUnsignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of unsigned integer type.
#define MEMSET
constant string identifying the operation performed when two objects are memsetted.
Definition: op_graph.hpp:320
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
Standard functor that returns the name of a variable.
soft_float_cg_ext(const ParameterConstRef _parameters, const application_managerRef AppM, unsigned int _function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
Base class for step of design flow.
CustomMap< ssa_name *, std::tuple< FloatFormatRef, std::vector< tree_nodeRef > > > outputInterface
SSA variable which requires cast renaming from user-defined to standard float format in given stateme...
static void RequestCallOpt(const tree_nodeConstRef &call_stmt, unsigned int caller_id, FunctionOptType opt)
Request optimization for given call statement.
tree_nodeRef GetPointerType(const tree_nodeConstRef &ptd, unsigned long long algn=0) const
Function that creates a pointer type if it is not already present, otherwise it returns the one that ...
tree_nodeRef floatAbs(const tree_nodeRef &op, const FloatFormatRef &ff) const
Generate float absolute value operation based on given floating-point format.
#define FP_FORMAT_SPEC
#define CASE_QUATERNARY_EXPRESSION
This macro collects all case labels for quaternary_expr objects.
Definition: tree_node.hpp:574
#define CASE_UNARY_EXPRESSION
This macro collects all case labels for unary_expr objects.
Definition: tree_node.hpp:371
unsigned int create_tree_node(const tree_nodeRef &tn, int mode=tree_node_dup_mode::DEFAULT)
tree_node visitors
FloatFormatRef userRequired
static tree_nodeRef float64_ptr_type
int compare(const FunctionVersion &other, bool format_only=false) const
std::string ToString() const
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
static bool IsFunctionType(const tree_nodeConstRef &type)
Return true if the treenode is of type function type.
bool ieee_format() const
Classes to describe design flow graph.
tree_nodeRef body
body field is the saved representation of the body of the entire function.
Definition: tree_node.hpp:2870
~soft_float_cg_ext() override
Destructor.
static const FloatFormatRef float32FF(new FloatFormat(8, 23, -127))
static const FloatFormatRef float64FF(new FloatFormat(11, 52, -1023))
#define FP_FORMAT_SIG
#define BB_ENTRY
constant identifying the basic block node of type entry
tree_nodeRef chan
purp is the TREE_CHAIN field: tree_list nodes are made into lists by chaining through the TREE_CHAIN ...
Definition: tree_node.hpp:5269
tree_nodeRef int_type_for(const tree_nodeRef &type, bool use_internal) const
#define FLOAT_CAST_FU_NAME
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
FPRounding rounding_mode
refcount< const tree_node > tree_nodeConstRef
Definition: tree_node.hpp:213
DesignFlowStep_Status GetStatus() const
Return the status of this design step.
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
bit_lattice
Definition: bit_lattice.hpp:60
DesignFlowStep_Status
The status of a step.
#define FP_FORMAT_RND
CustomUnorderedSet< unsigned int > already_visited
Already visited tree node (used to avoid infinite recursion)
Call graph hierarchy.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
tree_nodeRef cstCast(uint64_t in, const FloatFormatRef &inFF, const FloatFormatRef &outFF) const
Cast real type constant from inFF to outFF format.
Wrapper of design_flow.
std::vector< tree_nodeRef > topReturn
Step that extends the call graph with the soft-float calls where appropriate.
bool ieee_format() const
tree_nodeRef GetBooleanType() const
Function that creates a boolean type if it is not already present, otherwise it returns the one that ...
This struct specifies the block node.
Definition: tree_node.hpp:1820
#define CASE_TYPE_NODES
This macro collects all case labels for type objects.
Definition: tree_node.hpp:581
This file collects some utility functions.
std::vector< tree_nodeRef > list_of_args
args field holds a chain of parm_decl nodes for the arguments.
Definition: tree_node.hpp:2841
static const std::set< std::string > supported_libm_calls
tree_nodeRef GetCustomIntegerType(unsigned long long prec, bool unsigned_p) const
create an integer type starting from a given prec
static tree_nodeRef float32_type
const tree_managerRef TreeM
Tree manager.
std::vector< tree_nodeRef > nopConvert
tree_nodeRef CreateCallExpr(const tree_nodeConstRef &called_function, const std::vector< tree_nodeRef > &args, const std::string &srcp) const
Create a call_expr.
#define BUILTIN_SRCP
const unsigned int function_id
The index of the function to be analyzed.
#define CASE_CST_NODES
This macro collects all case labels for cast nodes.
Definition: tree_node.hpp:689
const application_managerRef AppM
The application manager.
This struct specifies the tree_list node.
Definition: tree_node.hpp:5255
static const std::set< std::string > supported_libm_calls_inlined
Class specification of the tree_reindex support class.
static const unsigned int ENTRY_BLOCK_ID
constant identifying the entry basic block
bool operator==(const FunctionVersion &other) const
#define CASE_FAKE_NODES
This macro collects all case labels for fake or empty nodes.
Definition: tree_node.hpp:635
std::string ToString() const
FunctionVersionRef _version
T * GetPointer(const refcount< U > &t)
Template function used to hide dynamic_cast The template parameter T represents a type of an object h...
Definition: refcount.hpp:237
std::vector< ssa_name * > hwReturn
Hardware implemented functions return values as real_type, thus a view_convert is necessary...
Class specification of the basic_block structure.
static FloatFormatRef FromString(std::string ff_str)
Data structures used in operations graph.
tree_nodeRef CreateNopExpr(const tree_nodeConstRef &operand, const tree_nodeConstRef &type, const tree_nodeConstRef &min, const tree_nodeConstRef &max, unsigned int function_decl_nid) const
Create a nop_expr to perform a conversion.
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
#define THROW_ERROR_CODE(code, str_expr)
helper function used to throw an error with a code error
Definition: exceptions.hpp:266
tree_nodeRef type
type field holds the data type of the object, when relevant.
Definition: tree_node.hpp:907
static tree_nodeConstRef CGetPointedType(const tree_nodeConstRef &pointer)
Return the pointed type of a pointer object.
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.
#define CASE_CPP_NODES
This macro collects all case labels for cpp nodes.
Definition: tree_node.hpp:644
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
tree_nodeRef valu
purp is the TREE_VALUE field which stores the elements of the list.
Definition: tree_node.hpp:5266
refcount< tree_node > tree_nodeRef
RefCount type definition of the tree_node class structure.
Definition: tree_node.hpp:212
tree node duplication class.
This struct specifies the ssa_name node.
Definition: tree_node.hpp:4523
Wrapper to call graph.
uint32_t sign
absl::node_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMapStable
Definition: custom_map.hpp:152
#define CASE_GIMPLE_NODES
This macro collects all cases labels for gimple nodes.
Definition: tree_node.hpp:700
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
tree_nodeRef type
starting from GCC 4.7.2 ssa_name has a type
Definition: tree_node.hpp:4540
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
refcount< const var_pp_functor > var_pp_functorConstRef
bool operator!=(const FloatFormat &other) const
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
static CustomMap< unsigned int, std::array< tree_nodeRef, 8 > > versioning_args
Static arguments list to feed specialization parameters of versioned functions.
Step is symbolic and it has already been marked.
static bool IsLoad(const tree_nodeConstRef &tn, const CustomOrderedSet< unsigned int > &fun_mem_data)
Return true if the tree node is a gimple_assign reading something which will be allocated in memory...
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
#define CASE_TERNARY_EXPRESSION
This macro collects all case labels for ternary_expr objects.
Definition: tree_node.hpp:550
const tree_manipulationRef tree_man
tree manipulation
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
unsigned long long convert_fp_to_bits(std::string num, unsigned long long precision)
convert a real number stored in a string into bits with a given precision
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
int sl
Definition: adpcm.c:105
Step not yet executed.
#define CASE_PRAGMA_NODES
This macro collects all case labels for pragma objects.
Definition: tree_node.hpp:610
#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:52 for PandA-2024.02 by doxygen 1.8.13