69 #define PARAMETER_INLINE_MAX_COST "inline-max-cost" 70 #define DEAFULT_MAX_INLINE_CONST 60 80 {call_expr_K, 8}, {mult_expr_K, 3}, {widen_mult_expr_K, 3}, {widen_mult_hi_expr_K, 3},
81 {widen_mult_lo_expr_K, 3}, {trunc_div_expr_K, 3}, {exact_div_expr_K, 3}, {round_div_expr_K, 3},
82 {ceil_div_expr_K, 3}, {floor_div_expr_K, 3}, {trunc_mod_expr_K, 3}, {round_mod_expr_K, 3},
83 {ceil_mod_expr_K, 3}, {floor_mod_expr_K, 3}, {view_convert_expr_K, 0}, {convert_expr_K, 0},
84 {nop_expr_K, 0}, {ssa_name_K, 0}, {addr_expr_K, 0}, {bit_ior_concat_expr_K, 0},
85 {extract_bit_expr_K, 0}};
87 static std::string
__arg_suffix(
const std::vector<tree_nodeRef>& tns)
89 std::stringstream suffix;
90 for(
const auto& tn : tns)
101 const auto hash = std::hash<std::string>{}(suffix.str());
102 suffix.str(std::string());
103 suffix <<
"_" << std::hex << hash;
108 unsigned int _function_id,
const DesignFlowManagerConstRef _design_flow_manager)
120 switch(relationship_type)
124 relationships.insert(std::make_pair(COMPLETE_BB_GRAPH,
SAME_FUNCTION));
127 relationships.insert(std::make_pair(FUNCTION_CALL_TYPE_CLEANUP,
SAME_FUNCTION));
138 if(!
parameters->getOption<
int>(OPT_gcc_openmp_simd))
140 relationships.insert(std::make_pair(BIT_VALUE,
SAME_FUNCTION));
142 relationships.insert(std::make_pair(COMPLETE_BB_GRAPH,
SAME_FUNCTION));
143 relationships.insert(std::make_pair(DETERMINE_MEMORY_ACCESSES,
SAME_FUNCTION));
152 return relationships;
159 if(
AppM->CGetFunctionBehavior(id_bb.first)->GetBBVersion() != id_bb.second)
171 const auto TM =
AppM->get_tree_manager();
176 if(
parameters->isOption(OPT_inline_functions))
179 for(
const auto& fname_cond : fnames)
182 const auto& fname = toks.at(0);
183 const auto fnode = TM->GetFunction(fname);
187 inline_set.insert(fnode->index);
189 "Required " +
STR((!(toks.size() > 1) || toks.at(1) ==
"1") ?
"always" :
"never") +
190 " inline for function " + fname);
200 const auto fnode = TM->GetFunction(defaultInlineFunction);
206 const auto HLSMgr = GetPointer<HLS_manager>(
AppM);
207 for(
const auto& [symbol, arch] : *HLSMgr->module_arch)
209 THROW_ASSERT(arch,
"Expected initialized architecture for function " + symbol);
210 const auto inline_attr = arch->attrs.find(FunctionArchitecture::func_inline);
211 if(inline_attr != arch->attrs.end())
213 const auto fnode = TM->GetFunction(symbol);
216 if(inline_attr->second ==
"self")
221 else if(inline_attr->second ==
"off")
226 else if(inline_attr->second ==
"recursive")
234 "Required inline (" + inline_attr->second +
") function not found: " + symbol);
246 "Function call optimization should not be executed");
247 if(GetPointer<const HLS_manager>(
AppM) && GetPointer<const HLS_manager>(
AppM)->get_HLS(
function_id) &&
251 "---Function already scheduled, inlining is not possible any more");
255 const auto TM =
AppM->get_tree_manager();
256 const auto fnode = TM->CGetTreeReindex(
function_id);
257 const auto fd = GetPointerS<function_decl>(
GET_NODE(fnode));
259 const auto sl = GetPointerS<statement_list>(
GET_NODE(fd->body));
260 bool modified =
false;
267 for(
const auto& stmt_opt : opt_stmts->second)
269 const auto& stmt_id = std::get<0>(stmt_opt);
270 const auto& opt_type = std::get<1>(stmt_opt);
271 const auto stmt = TM->CGetTreeReindex(stmt_id);
274 const auto gn = GetPointerS<const gimple_node>(
GET_CONST_NODE(stmt));
275 const auto bb_it =
sl->list_of_bloc.find(gn->bb_index);
276 if(gn->bb_index != 0 && bb_it !=
sl->list_of_bloc.end())
278 const auto& bb = bb_it->second;
279 if(std::find_if(bb->CGetStmtList().cbegin(), bb->CGetStmtList().cend(), [&](
const tree_nodeRef& tn) {
281 }) != bb->CGetStmtList().cend())
283 if(!
AppM->ApplyNewTransformation())
286 "---Max transformations reached, skipping function inlining...");
301 const auto version_suffix = [&]() -> std::string {
303 if(call_stmt->get_kind() == gimple_call_K)
305 const auto gc = GetPointerS<const gimple_call>(call_stmt);
308 else if(call_stmt->get_kind() == gimple_assign_K)
310 const auto ga = GetPointerS<const gimple_assign>(call_stmt);
311 const auto ce = GetPointer<const call_expr>(
GET_CONST_NODE(ga->op1));
314 THROW_UNREACHABLE(
"Unsupported call statement: " + call_stmt->get_kind_text() +
" " +
334 "Statement " +
STR(stmt_id) +
" was not present in BB" +
STR(bb->number));
340 "BB" +
STR(gn->bb_index) +
" was not found in current function");
346 "Statement " +
STR(stmt_id) +
" was not in tree manager");
354 if(
parameters->isOption(OPT_top_design_name) &&
358 "Current function is marked as top RTL design, skipping...");
366 const auto CGM =
AppM->CGetCallGraphManager();
367 const auto CG = CGM->CGetCallGraph();
368 const auto function_v = CGM->GetVertex(
function_id);
369 const auto call_count = [&]() ->
size_t {
370 size_t call_points = 0u;
371 BOOST_FOREACH(
EdgeDescriptor ie, boost::in_edges(function_v, *CG))
373 const auto caller_info = CG->CGetFunctionEdgeInfo(ie);
374 call_points +=
static_cast<size_t>(caller_info->direct_call_points.size());
375 call_points +=
static_cast<size_t>(caller_info->indirect_call_points.size());
376 call_points +=
static_cast<size_t>(caller_info->function_addresses.size());
383 bool has_simd =
false;
385 const auto omp_simd_enabled =
parameters->getOption<
int>(OPT_gcc_openmp_simd);
386 has_simd &= omp_simd_enabled;
398 "Current function has OpenMP SIMD constructs, inlining postponed");
402 BOOST_FOREACH(
EdgeDescriptor ie, boost::in_edges(function_v, *CG))
404 const auto caller_id = CGM->get_function(ie.m_source);
405 caller_bb.insert(std::make_pair(caller_id,
AppM->CGetFunctionBehavior(caller_id)->GetBBVersion()));
407 "Analysing call points from " +
409 GetPointerS<const function_decl>(TM->CGetTreeNode(caller_id))));
411 const auto caller_node = TM->CGetTreeNode(caller_id);
412 THROW_ASSERT(caller_node->get_kind() == function_decl_K,
"");
413 const auto caller_fd = GetPointerS<const function_decl>(caller_node);
415 const auto caller_sl = GetPointerS<const statement_list>(
GET_CONST_NODE(caller_fd->body));
422 "<--Caller has OpenMP SIMD constructs, analysis postponed");
426 const auto caller_info = CG->CGetFunctionEdgeInfo(ie);
427 bool all_inlined =
true;
428 for(
const auto& call_id : caller_info->direct_call_points)
430 const auto call_stmt = TM->CGetTreeNode(call_id);
432 "Analysing direct call point " +
STR(call_stmt));
433 const auto call_gn = GetPointerS<const gimple_node>(call_stmt);
434 if(call_gn->vdef || call_gn->vuses.size() || call_gn->vovers.size())
439 "---Call statement carries alias dependencies, skipping...");
444 if(!omp_simd_enabled || loop_count == 0)
446 const auto is_unique_bb_call = [&]() ->
bool {
447 THROW_ASSERT(caller_sl->list_of_bloc.count(call_gn->bb_index),
448 "BB" +
STR(call_gn->bb_index) +
" not found in function " +
450 const auto bb = caller_sl->list_of_bloc.at(call_gn->bb_index);
451 for(
const auto& tn : bb->CGetStmtList())
453 if(tn->index != call_gn->index &&
457 ->get_kind() == call_expr_K)))
464 if(is_unique_bb_call || loop_count == 0)
470 "Low body cost function") +
471 ", inlining required");
477 "---BB" +
STR(call_gn->bb_index) +
" from function " +
479 " has multiple call points, skipping...");
486 "---Inlining of functions with internal loops disabled with OpenMP, skipping...");
489 const auto all_const_args =
HasConstantArgs(TM->CGetTreeReindex(call_id));
490 if(all_const_args && loop_count == 0)
494 "---Current call has all constant arguments, versioning required");
505 "Analysed call points from " +
507 GetPointerS<const function_decl>(TM->CGetTreeNode(caller_id))));
514 "Current function has zero call points, skipping analysis...");
531 bool is_call = stmt_kind == gimple_call_K;
532 if(stmt_kind == gimple_assign_K)
534 const auto rhs = GetPointerS<const gimple_assign>(
GET_CONST_NODE(call_stmt))->op1;
536 is_call |= rhs_kind == call_expr_K || rhs_kind == aggr_init_expr_K;
539 THROW_ASSERT(is_call,
"Statement does not contain a call");
545 const auto all_constant = [](
const std::vector<tree_nodeRef>& tns) {
546 for(
const auto& tn : tns)
556 if(call_kind == gimple_call_K)
558 const auto gc = GetPointerS<const gimple_call>(
GET_CONST_NODE(call_stmt));
559 return all_constant(gc->args);
561 else if(call_kind == gimple_assign_K)
563 const auto ga = GetPointerS<const gimple_assign>(
GET_CONST_NODE(call_stmt));
565 const auto ce = GetPointerS<const call_expr>(
GET_CONST_NODE(ga->op1));
566 return all_constant(ce->args);
574 size_t total_cost = 0;
578 for(
const auto& stmt_rdx : bb.second->CGetStmtList())
581 if(stmt->get_kind() == gimple_assign_K)
583 const auto ga = GetPointerS<const gimple_assign>(stmt);
585 const auto op_cost =
op_costs.find(op_kind);
588 total_cost += op_cost->second;
592 if(op_kind == lshift_expr_K || op_kind == rshift_expr_K || op_kind == bit_and_expr_K ||
593 op_kind == bit_ior_expr_K)
603 else if(stmt->get_kind() == gimple_cond_K || stmt->get_kind() == gimple_call_K)
607 else if(stmt->get_kind() == gimple_multi_way_if_K)
609 const auto mw = GetPointerS<const gimple_multi_way_if>(stmt);
610 total_cost += mw->list_of_cond.size() * 8ULL;
612 else if(stmt->get_kind() == gimple_asm_K)
614 const auto ga = GetPointerS<const gimple_asm>(stmt);
615 total_cost += ga->str.size() / 5;
617 else if(stmt->get_kind() == gimple_pragma_K)
619 const auto gp = GetPointerS<const gimple_pragma>(stmt);
620 if(gp->scope && GetPointer<const omp_pragma>(
GET_CONST_NODE(gp->scope)))
622 const auto sp = GetPointer<const omp_simd_pragma>(
GET_CONST_NODE(gp->directive));
644 inverse_vertex_map.insert(
651 const auto& curr_bbi = curr_bb_pair.first;
652 const auto& curr_bb = curr_bb_pair.second;
653 for(
const auto& lop : curr_bb->list_of_pred)
655 THROW_ASSERT(static_cast<bool>(inverse_vertex_map.count(lop)),
656 "BB" +
STR(lop) +
" (successor of BB" +
STR(curr_bbi) +
") does not exist");
657 bb_graphs_collection->AddEdge(inverse_vertex_map.at(lop), inverse_vertex_map.at(curr_bbi),
CFG_SELECTOR);
660 for(
const auto& los : curr_bb->list_of_succ)
664 bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bbi), inverse_vertex_map.at(los),
CFG_SELECTOR);
668 if(curr_bb->list_of_succ.empty())
670 bb_graphs_collection->AddEdge(inverse_vertex_map.at(curr_bbi), inverse_vertex_map.at(
bloc::EXIT_BLOCK_ID),
676 std::map<size_t, UnorderedSetStdStable<vertex>> sccs;
678 size_t loop_count = 0;
679 for(
const auto& scc : sccs)
681 if(scc.second.size() > 1)
687 const auto bb_v = *scc.second.begin();
689 if(std::find(bb->list_of_succ.begin(), bb->list_of_succ.end(), bb->number) != bb->list_of_succ.end())
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static const std::set< std::string > inlinedFunctionByDefault
File containing functions and utilities to support the printing of debug messagges.
Step successfully executed.
static bool IsConstant(const tree_nodeConstRef &node)
Return if a tree node is a constant object.
Definition of the node_info object for the basic_block graph.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
This struct specifies the statement_list node.
#define PARAMETER_INLINE_MAX_COST
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.
std::string GetName() const override
Return the name of this design step.
void GetStronglyConnectedComponents(std::map< size_t, UnorderedSetStdStable< boost::graph_traits< graphs_collection >::vertex_descriptor >> &strongly_connected_components) const
Compute the strongly connected components of the graph.
RelationshipType
The relationship type.
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
static CustomSet< unsigned int > never_inline
Set of never inlined functions.
static std::string GetString(const enum kind k)
Given a kind, return the corresponding string.
unsigned int InlineFunctionCall(const tree_nodeRef &call_node, const tree_nodeRef &caller_node)
Execute function call inlining of given call statement (call graph must be recomputed after inlining)...
CustomOrderedMap< T, U > CustomMap
std::map< unsigned int, blocRef > list_of_bloc
list_of_bloc field is the list of basic block. If this field is null then the list_of_stmt field is n...
static const unsigned int EXIT_BLOCK_ID
constant identifying the exit basic block
This class provides methods to build a basic blocks graph.
Data structure describing a basic block at tree level.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
static std::string GetMangledFunctionName(const function_decl *fd)
Return the mangled function name.
#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
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
CustomMap< unsigned int, unsigned int > caller_bb
static void RequestCallOpt(const tree_nodeConstRef &call_stmt, unsigned int caller_id, FunctionOptType opt)
Request optimization for given call statement.
Class used to describe a particular graph with basic blocks as nodes.
DesignFlowStep_Status InternalExec() override
Computes the operations CFG graph data structure.
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.
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
static CustomSet< unsigned int > always_inline
Set of always inlined functions.
Information associated with the whole basic-block graph.
static std::string __arg_suffix(const std::vector< tree_nodeRef > &tns)
Classes to describe design flow graph.
Target must be reexecuted.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
#define GET_CONST_NODE(t)
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.
DesignFlowStep_Status
The status of a step.
Class defining some useful functions to create tree nodes and to manipulate the tree manager...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
static bool has_omp_simd(const statement_list *sl)
Check if omp simd pragmas are present in given statement list.
This struct specifies the block node.
This file collects some utility functions.
const unsigned int function_id
The index of the function to be analyzed.
size_t compute_cost(const statement_list *body, bool &has_simd)
Compute function body cost based on statements' types.
const application_managerRef AppM
The application manager.
bool VersionFunctionCall(const tree_nodeRef &call_node, const tree_nodeRef &caller_node, const std::string &version_suffix)
Perform function call versioning.
Class specification of the tree_reindex support class.
static const unsigned int ENTRY_BLOCK_ID
constant identifying the entry basic block
Class specification of the basic_block structure.
const BBNodeInfoConstRef CGetBBNodeInfo(const vertex node) const
Return the info associated with a basic block.
static bool HasConstantArgs(const tree_nodeConstRef &call_stmt)
Check if given call statement performs a call with all constant arguments.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
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.
FunctionCallOpt(const ParameterConstRef Param, const application_managerRef AppM, unsigned int function_id, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
#define DEAFULT_MAX_INLINE_CONST
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
static size_t inline_max_cost
int debug_level
The debug level.
static CustomMap< unsigned int, CustomSet< std::tuple< unsigned int, FunctionOptType > > > opt_call
#define GET_INDEX_CONST_NODE(t)
#define CFG_SELECTOR
Control flow graph edge selector.
Data structure definition for high-level synthesis flow.
refcount< BBGraphInfo > BBGraphInfoRef
refcount definition of the class
static CustomUnorderedMap< kind, size_t > op_costs
This class creates a layer to add nodes and to manipulate the tree_nodes manager. ...
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
~FunctionCallOpt() override
Destructor.
const FunctionBehaviorRef function_behavior
The function behavior of the function to be analyzed.
size_t detect_loops(const statement_list *body) const
Check if given function body has loops.
This structure defines graphs where nodes are basic_blocks.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...