+2018-05-04 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * brig/brig-lang.c: Add support for whole program
+ optimizations by marking the kernels externally visible.
+ * brig/brigfrontend/brig-branch-inst-handler.cc: See above.
+ * brig/brigfrontend/brig-function-handler.cc: See above.
+ * brig/brigfrontend/brig-function.cc: See above.
+ * brig/brigfrontend/brig-to-generic.cc: See above.
+ * brig/brigfrontend/brig-to-generic.h: See above.
+ * brig/brigfrontend/brig-variable-handler.h: See above.
+
2018-01-03 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
-/* This file is based on Go frontent'd go-lang.c and gogo-tree.cc. */
+/* This file is based on Go frontend's go-lang.c and gogo-tree.cc. */
/* If -v set. */
/* If we set this to one, the whole program optimizations internalize
all global variables, making them invisible to the dyn loader (and
thus the HSA runtime implementation). */
- opts->x_flag_whole_program = 0;
+ opts->x_flag_whole_program = 1;
/* The builtin math functions should not set errno. */
opts->x_flag_errno_math = 0;
}
m_parent.m_cf->m_called_functions.push_back (func_ref);
+ if (DECL_EXTERNAL (func_ref))
+ m_parent.add_decl_call (call);
return base->byteCount;
}
DECL_RESULT (fndecl) = resdecl;
DECL_CONTEXT (resdecl) = fndecl;
DECL_EXTERNAL (fndecl) = 0;
+
+ /* Aggressive inlining to the kernel function is usually a good
+ idea with offlined functionality to enchance SIMD execution on
+ GPUs and vector units. */
+
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("flatten"), NULL,
+ DECL_ATTRIBUTES (fndecl));
}
else
{
vec_safe_push (args, ptr_type_node);
vec_safe_push (args, ptr_type_node);
+ vec_safe_push (args, ptr_type_node);
+ vec_safe_push (args, ptr_type_node);
fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, name_identifier,
build_function_type_vec (ret_type, args));
DECL_SAVED_TREE (fndecl) = bind_expr;
- /* Try to preserve the functions across IPA. */
- DECL_PRESERVE_P (fndecl) = 1;
- TREE_SIDE_EFFECTS (fndecl) = 1;
-
- TREE_ADDRESSABLE (fndecl) = 1;
+ set_externally_visible (fndecl);
if (base->kind == BRIG_KIND_DIRECTIVE_FUNCTION)
{
- TREE_STATIC (fndecl) = 1;
+ TREE_STATIC (fndecl) = 0;
TREE_PUBLIC (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
}
else if (base->kind == BRIG_KIND_DIRECTIVE_KERNEL)
{
- TREE_STATIC (fndecl) = 1;
+ TREE_STATIC (fndecl) = 0;
TREE_PUBLIC (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 0;
+ set_externally_visible (fndecl);
}
else if (base->kind == BRIG_KIND_DIRECTIVE_SIGNATURE)
{
m_parent.add_function_decl (func_name, fndecl);
m_parent.append_global (fndecl);
+
if (!is_definition)
- return bytes_consumed;
+ {
+ DECL_EXTERNAL (fndecl) = 1;
+ return bytes_consumed;
+ }
m_parent.start_function (fndecl);
tree bind_expr = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, NULL);
- TREE_STATIC (launcher) = 0;
+ TREE_STATIC (launcher) = 1;
TREE_PUBLIC (launcher) = 1;
DECL_SAVED_TREE (launcher) = bind_expr;
emit_metadata (stmt_list);
+ set_externally_visible (launcher);
+
return launcher;
}
#include "cgraph.h"
#include "dumpfile.h"
#include "tree-pretty-print.h"
+#include "attribs.h"
extern int gccbrig_verbose;
tree var_addr = build1 (ADDR_EXPR, ptype, var_decl);
DECL_INITIAL (host_def_var) = var_addr;
- TREE_PUBLIC (host_def_var) = 0;
+ TREE_PUBLIC (host_def_var) = 1;
+
+ set_externally_visible (host_def_var);
}
/* Adds an indirection pointer for a potential host-defined program scope
TREE_ADDRESSABLE (ptr_var) = 1;
TREE_STATIC (ptr_var) = 1;
+ set_externally_visible (ptr_var);
+
append_global (ptr_var);
m_global_variables[var_name] = ptr_var;
}
+void
+brig_to_generic::add_decl_call (tree call)
+{
+ m_decl_call.push_back (call);
+}
+
/* Produce a "mangled name" for the given brig function or kernel.
The mangling is used to make unique global symbol name in case of
module scope functions. Program scope functions are not mangled
m_cf->finish ();
m_cf->emit_metadata (stmts);
dump_function (m_dump_file, m_cf);
- gimplify_function_tree (m_cf->m_func_decl);
- cgraph_node::finalize_function (m_cf->m_func_decl, true);
}
else
/* Emit the kernel only at the very end so we can analyze the total
void
brig_to_generic::write_globals ()
{
+
+ /* Replace calls to declarations with calls to definitions. Otherwise
+ inlining will fail to find the definition to inline from. */
+
+ for (size_t i = 0; i < m_decl_call.size(); ++i)
+ {
+ tree decl_call = m_decl_call.at(i);
+ tree func_decl = get_callee_fndecl (decl_call);
+ brig_function *brig_function = get_finished_function (func_decl);
+
+ if (brig_function && brig_function->m_func_decl
+ && DECL_EXTERNAL (brig_function->m_func_decl) == 0
+ && brig_function->m_func_decl != func_decl)
+ {
+
+ decl_call = CALL_EXPR_FN (decl_call);
+ STRIP_NOPS (decl_call);
+ if (TREE_CODE (decl_call) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (decl_call, 0)) == FUNCTION_DECL)
+ TREE_OPERAND (decl_call, 0) = brig_function->m_func_decl;
+ }
+ }
+
+ for (std::map<std::string, brig_function *>::iterator i
+ = m_finished_functions.begin(), e = m_finished_functions.end();
+ i != e; ++i)
+ {
+ brig_function *brig_f = (*i).second;
+ if (brig_f->m_is_kernel)
+ continue;
+
+ /* Finalize only at this point to allow the cgraph analysis to
+ see definitions to calls to later functions. */
+ gimplify_function_tree (brig_f->m_func_decl);
+ cgraph_node::finalize_function (brig_f->m_func_decl, true);
+ }
+
/* Now that the whole BRIG module has been processed, build a launcher
and a metadata section for each built kernel. */
for (size_t i = 0; i < m_kernels.size (); ++i)
append_global (launcher);
+ if (m_dump_file)
+ {
+ std::string kern_name = f->m_name.substr (1);
+ fprintf (m_dump_file, "\n;; Function %s", kern_name.c_str());
+ fprintf (m_dump_file, "\n;; enabled by -%s\n\n",
+ dump_flag_name (TDI_original));
+ print_generic_decl (m_dump_file, launcher, 0);
+ print_generic_expr (m_dump_file, DECL_SAVED_TREE (launcher), 0);
+ fprintf (m_dump_file, "\n");
+ }
+
gimplify_function_tree (launcher);
cgraph_node::finalize_function (launcher, true);
pop_cfun ();
* BITS_PER_UNIT, true);
}
+/* Set the declaration externally visible so it won't get removed by
+ whole program optimizations. */
+
+void
+set_externally_visible (tree decl)
+{
+ if (!lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
+ DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("externally_visible"),
+ NULL, DECL_ATTRIBUTES (decl));
+}
+
+void
+set_inline (tree decl)
+{
+ if (!lookup_attribute ("inline", DECL_ATTRIBUTES (decl)))
+ DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("inline"),
+ NULL, DECL_ATTRIBUTES (decl));
+}
+
void
dump_function (FILE *dump_file, brig_function *f)
{
tree global_variable (const std::string &name) const;
void add_global_variable (const std::string &name, tree var_decl);
void add_host_def_var_ptr (const std::string &name, tree var_decl);
+ void add_decl_call (tree call);
void start_function (tree f);
void finish_function ();
label_index m_global_variables;
+ /* Calls to declarations to be fixed in the end of processing to call
+ defs instead. */
+ std::vector<tree> m_decl_call;
+
/* The size of each private variable, including the alignment padding. */
std::map<std::string, size_t> m_private_data_sizes;
tree get_unsigned_int_type (tree type);
tree get_scalar_unsigned_int_type (tree type);
+void set_externally_visible (tree decl);
+
+void set_inline (tree decl);
void dump_function (FILE *dump_file, brig_function *f);
#include "brig-util.h"
#include "print-tree.h"
#include "diagnostic-core.h"
+#include "brig-to-generic.h"
tree
brig_directive_variable_handler::build_variable
so we can get their address from the Runtime API. */
DECL_CONTEXT (var_decl) = NULL_TREE;
TREE_STATIC (var_decl) = 1;
+ TREE_PUBLIC (var_decl) = 1;
+ set_externally_visible (var_decl);
m_parent.add_global_variable (var_name, var_decl);
}
}