make_tt.h
Go to the documentation of this file.
1 // to be #include'd within runtime::ttg namespace
2 
3 #ifndef TTG_MAKE_TT_H
4 #define TTG_MAKE_TT_H
5 
6 
7 // Class to wrap a callable with signature
8 //
9 // case 1 (keyT != void): returnT op(auto&& key, input_valuesT&&..., std::tuple<output_terminalsT...>&)
10 // case 2 (keyT == void): returnT op(input_valuesT&&..., std::tuple<output_terminalsT...>&)
11 //
12 // returnT is void for funcT = synchronous (ordinary) function and the appropriate return type for funcT=coroutine
13 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
14  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
15  typename keyT, typename output_terminalsT, typename... input_valuesT>
17  : public TT<
18  keyT, output_terminalsT,
19  CallableWrapTT<funcT, returnT, funcT_receives_input_tuple, funcT_receives_outterm_tuple, space, keyT, output_terminalsT, input_valuesT...>,
20  ttg::typelist<input_valuesT...>> {
21  using baseT = typename CallableWrapTT::ttT;
22 
23  using input_values_tuple_type = typename baseT::input_values_tuple_type;
24  using input_refs_tuple_type = typename baseT::input_refs_tuple_type;
25  using input_edges_type = typename baseT::input_edges_type;
26  using output_edges_type = typename baseT::output_edges_type;
27 
28  using noref_funcT = std::remove_reference_t<funcT>;
29  std::conditional_t<std::is_function_v<noref_funcT>, std::add_pointer_t<noref_funcT>, noref_funcT> func;
30 
31  using op_return_type =
32 #ifdef TTG_HAVE_COROUTINE
33  std::conditional_t<std::is_same_v<returnT, ttg::resumable_task>,
35 #ifdef TTG_HAVE_DEVICE
36  std::conditional_t<std::is_same_v<returnT, ttg::device::Task>,
37  ttg::device::Task::base_type,
38  void>
39 #else // TTG_HAVE_DEVICE
40  void
41 #endif // TTG_HAVE_DEVICE
42  >;
43 #else // TTG_HAVE_COROUTINE
44  void;
45 #endif // TTG_HAVE_COROUTINE
46 
47 public:
48  static constexpr bool have_cuda_op = (space == ttg::ExecutionSpace::CUDA);
49  static constexpr bool have_hip_op = (space == ttg::ExecutionSpace::HIP);
50  static constexpr bool have_level_zero_op = (space == ttg::ExecutionSpace::L0);
51 
52 protected:
53 
54  template<typename ReturnT>
55  auto process_return(ReturnT&& ret, output_terminalsT &out) {
56  static_assert(std::is_same_v<std::remove_reference_t<decltype(ret)>, returnT>,
57  "CallableWrapTT<funcT,returnT,...>: returnT does not match the actual return type of funcT");
58  if constexpr (!std::is_void_v<returnT>) { // protect from compiling for void returnT
59 #ifdef TTG_HAVE_COROUTINE
60  if constexpr (std::is_same_v<returnT, ttg::resumable_task>) {
62  // if task completed destroy it
63  if (ret.completed()) {
64  ret.destroy();
65  } else { // if task is suspended return the coroutine promise ptr
66  coro_handle = ret;
67  }
68  return coro_handle;
69  } else
70 #ifdef TTG_HAVE_DEVICE
71  if constexpr (std::is_same_v<returnT, ttg::device::Task>) {
72  ttg::device::Task::base_type coro_handle = ret;
73  return coro_handle;
74  }
75 #else // TTG_HAVE_DEVICE
76  ttg::abort(); // should not happen
77 #endif // TTG_HAVE_DEVICE
78  if constexpr (!(std::is_same_v<returnT, ttg::resumable_task>
79 #ifdef TTG_HAVE_DEVICE
80  || std::is_same_v<returnT, ttg::device::Task>
81 #endif // TTG_HAVE_DEVICE
82  ))
83 #endif
84  {
85  static_assert(std::tuple_size_v<std::remove_reference_t<decltype(out)>> == 1,
86  "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
87  "value only if there is only 1 out terminal");
88  static_assert(std::tuple_size_v<returnT> <= 2,
89  "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
90  "value only if it is a plain value (then sent with null key), a tuple-like containing a single "
91  "key (hence value is void), or a tuple-like containing a key and a value");
92  if constexpr (std::tuple_size_v<returnT> == 0)
93  std::get<0>(out).sendv(std::move(ret));
94  else if constexpr (std::tuple_size_v<returnT> == 1)
95  std::get<0>(out).sendk(std::move(std::get<0>(ret)));
96  else if constexpr (std::tuple_size_v<returnT> == 2)
97  std::get<0>(out).send(std::move(std::get<0>(ret)), std::move(std::get<1>(ret)));
98  return;
99  }
100  }
101  }
102 
104  template <typename Key, typename Tuple, std::size_t... S>
105  auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
106  using func_args_t = ttg::meta::tuple_concat_t<std::tuple<const Key &>, input_refs_tuple_type, output_edges_type>;
107  auto invoke_func_handle_ret = [&](auto&&... args){
108  if constexpr (std::is_void_v<returnT>) {
109  func(std::forward<Key>(key), std::forward<decltype(args)>(args)...);
110  } else {
111  return process_return(func(std::forward<Key>(key), std::forward<decltype(args)>(args)...), out);
112  }
113  };
114  auto unpack_input_tuple_if_needed = [&](auto&&... args){
115  if constexpr (funcT_receives_input_tuple) {
116  return invoke_func_handle_ret(std::forward<Tuple>(args_tuple), std::forward<decltype(args)>(args)...);
117  } else {
118  return invoke_func_handle_ret(baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))...,
119  std::forward<decltype(args)>(args)...);
120  }
121  };
122 
123  if constexpr (funcT_receives_outterm_tuple) {
124  return unpack_input_tuple_if_needed(out);
125  } else {
126  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
127  this->set_outputs_tls_ptr();
128  // make sure the output tls is reset
129  auto _ = ttg::detail::scope_exit(
130  [this, old_output_tls_ptr](){
131  this->set_outputs_tls_ptr(old_output_tls_ptr);
132  });
133  return unpack_input_tuple_if_needed();
134  }
135  }
136 
137  template <typename Tuple, std::size_t... S>
138  auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
140 
141  auto invoke_func_handle_ret = [&](auto&&... args){
142  if constexpr (std::is_void_v<returnT>) {
143  func(std::forward<decltype(args)>(args)...);
144  } else {
145  return process_return(func(std::forward<decltype(args)>(args)...), out);
146  }
147  };
148  auto unpack_input_tuple_if_needed = [&](auto&& fn, auto&&... args){
149  if constexpr (funcT_receives_input_tuple) {
150  return fn(std::forward<Tuple>(args_tuple), std::forward<decltype(args)>(args)...);
151  } else {
152  return fn(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))...,
153  std::forward<decltype(args)>(args)...);
154  }
155  };
156 
157  if constexpr (funcT_receives_outterm_tuple) {
158  return unpack_input_tuple_if_needed(invoke_func_handle_ret, out);
159  } else {
160  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
161  this->set_outputs_tls_ptr();
162  // make sure the output tls is reset
163  auto _ = ttg::detail::scope_exit(
164  [this, old_output_tls_ptr](){
165  this->set_outputs_tls_ptr(old_output_tls_ptr);
166  });
167  return unpack_input_tuple_if_needed(invoke_func_handle_ret);
168  }
169  }
170 
171  template <typename Key>
172  auto call_func(Key &&key, output_terminalsT &out) {
173  auto invoke_func_handle_ret = [&](auto&&... args){
174  if constexpr (std::is_void_v<returnT>) {
175  func(std::forward<Key>(key), std::forward<decltype(args)>(args)...);
176  } else {
177  return process_return(func(std::forward<Key>(key), std::forward<decltype(args)>(args)...), out);
178  }
179  };
180 
181  auto invoke_func_empty_tuple = [&](auto&&... args){
182  if constexpr(funcT_receives_input_tuple) {
183  invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
184  } else {
185  invoke_func_handle_ret(std::forward<decltype(args)>(args)...);
186  }
187  };
188 
189  if constexpr (funcT_receives_outterm_tuple) {
190  invoke_func_handle_ret(out);
191  } else {
192  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
193  this->set_outputs_tls_ptr();
194  // make sure the output tls is reset
195  auto _ = ttg::detail::scope_exit(
196  [this, old_output_tls_ptr](){
197  this->set_outputs_tls_ptr(old_output_tls_ptr);
198  });
199  return invoke_func_handle_ret();
200  }
201  }
202 
203  template <typename OutputTerminals>
204  auto call_func(OutputTerminals &out) {
205 
206  auto invoke_func_handle_ret = [&](auto&&... args){
207  if constexpr (std::is_void_v<returnT>) {
208  func(std::forward<decltype(args)>(args)...);
209  } else {
210  return process_return(func(std::forward<decltype(args)>(args)...), out);
211  }
212  };
213 
214  auto invoke_func_empty_tuple = [&](auto&&... args){
215  if constexpr(funcT_receives_input_tuple) {
216  invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
217  } else {
218  invoke_func_handle_ret(std::forward<decltype(args)>(args)...);
219  }
220  };
221 
222  if constexpr (funcT_receives_outterm_tuple) {
223  return invoke_func_empty_tuple(out);
224  } else {
225  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
226  this->set_outputs_tls_ptr();
227  // make sure the output tls is reset
228  auto _ = ttg::detail::scope_exit(
229  [this, old_output_tls_ptr](){
230  this->set_outputs_tls_ptr(old_output_tls_ptr);
231  });
232  return invoke_func_empty_tuple();
233  }
234  }
235 
236  template <typename Tuple, std::size_t... I>
237  static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence<I...>) {
238  return std::array<ttg::TerminalBase *, sizeof...(I)>{
239  {static_cast<ttg::TerminalBase *>(&std::get<I>(output_terminals))...}};
240  }
241 
242  public:
243  template <typename funcT_>
244  CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges,
245  const std::string &name, const std::vector<std::string> &innames,
246  const std::vector<std::string> &outnames)
247  : baseT(inedges, outedges, name, innames, outnames), func(std::forward<funcT_>(f)) {}
248 
249  template <typename funcT_>
250  CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector<std::string> &innames,
251  const std::vector<std::string> &outnames)
252  : baseT(name, innames, outnames), func(std::forward<funcT_>(f)) {}
253 
254  template <typename Key, typename ArgsTuple>
255  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
256  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && !ttg::meta::is_void_v<Key>,
257  op_return_type>
258  op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) {
259  assert(&out == &baseT::get_output_terminals());
260  return call_func(std::forward<Key>(key), std::forward<ArgsTuple>(args_tuple), out,
261  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
262  };
263 
264  template <typename ArgsTuple, typename Key = keyT>
265  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
266  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && ttg::meta::is_void_v<Key>,
267  op_return_type>
268  op(ArgsTuple &&args_tuple, output_terminalsT &out) {
269  assert(&out == &baseT::get_output_terminals());
270  return call_func(std::forward<ArgsTuple>(args_tuple), out,
271  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
272  };
273 
274  template <typename Key, typename ArgsTuple = input_refs_tuple_type>
275  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && !ttg::meta::is_void_v<Key>, op_return_type> op(
276  Key &&key, output_terminalsT &out) {
277  assert(&out == &baseT::get_output_terminals());
278  return call_func(std::forward<Key>(key), out);
279  };
280 
281  template <typename Key = keyT, typename ArgsTuple = input_refs_tuple_type>
282  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && ttg::meta::is_void_v<Key>, op_return_type> op(
283  output_terminalsT &out) {
284  assert(&out == &baseT::get_output_terminals());
285  return call_func(out);
286  };
287 };
288 
289 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
290  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
291  typename keyT, typename output_terminalsT, typename input_values_typelistT>
293 
294 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
295  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
296  typename keyT, typename output_terminalsT, typename... input_valuesT>
297 struct CallableWrapTTAsTypelist<funcT, returnT, funcT_receives_input_tuple,
298  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
299  std::tuple<input_valuesT...>> {
300  using type = CallableWrapTT<funcT, returnT, funcT_receives_input_tuple,
301  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
302  std::remove_reference_t<input_valuesT>...>;
303 };
304 
305 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
306  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
307  typename keyT, typename output_terminalsT, typename... input_valuesT>
308 struct CallableWrapTTAsTypelist<funcT, returnT, funcT_receives_input_tuple,
309  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
310  ttg::meta::typelist<input_valuesT...>> {
311  using type = CallableWrapTT<funcT, returnT, funcT_receives_input_tuple,
312  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
313  std::remove_reference_t<input_valuesT>...>;
314 };
315 
316 // clang-format off
342 // clang-format on
343 template <ttg::ExecutionSpace space,
344  typename keyT = void,
345  typename funcT,
346  typename... input_edge_valuesT,
347  typename... output_edgesT>
348 auto make_tt_tpl(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
349  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
350  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT),
351  "input"),
352  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT),
353  "output")) {
354  // ensure input types do not contain Void
355  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
356  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
357 
358  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
359 
360  // list of base datum types (T or const T)
362 
363  // gross list of candidate argument types
364  using gross_candidate_func_args_t = ttg::meta::typelist<
367  std::tuple<std::add_lvalue_reference_t<typename ttg::Edge<keyT, input_edge_valuesT>::value_type>...>>,
369 
370  // net list of candidate argument types excludes the empty typelists for void arguments
371  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
372 
373  // compute list of argument types with which func can be invoked
374  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
375  using return_type_typelist_and_gross_func_args_t =
376  decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{}));
377  using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
378  using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
379  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
380  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
381  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
382  "ttd::make_tt_tpl(func, inedges, ...): could not detect how to invoke generic callable func, either "
383  "the signature of func "
384  "is faulty, or inedges does match the expected list of types, or both");
385 
386  // net argument typelist
387  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
388  constexpr auto num_args = std::tuple_size_v<func_args_t>;
389 
390  // if given task id, make sure it's passed via const lvalue ref
391  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
392  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
393  constexpr bool TASK_ID_PASSED_AS_NONREF =
394  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
395  static_assert(
396  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
397  "ttg::make_tt_tpl(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
398 
399  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
400  constexpr bool have_outterm_tuple =
401  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
403  gross_func_args_t>;
404  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
405  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, true, func_args_t> : true;
406  static_assert(
407  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
408  "ttd::make_tt_tpl(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
409 
410  static_assert(num_args == 3 - (void_key ? 1 : 0) - (have_outterm_tuple ? 0 : 1),
411  "ttg::make_tt_tpl(func, ...): func takes wrong number of arguments (2, or 1, if keyT=void + optional "
412  "tuple of output terminals)");
413 
414  // 2. input_args_t = {input_valuesT&&...}
415  using nondecayed_input_args_t = std::tuple_element_t<void_key ? 0 : 1, func_args_t>;
416  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
417  !ttg::meta::is_any_nonconst_lvalue_reference_v<nondecayed_input_args_t>;
418  static_assert(
419  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
420  "ttg::make_tt_tpl(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
421  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
422  using input_args_t = std::decay_t<nondecayed_input_args_t>;
423  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
424  using wrapT = typename CallableWrapTTAsTypelist<funcT, func_return_t, true, have_outterm_tuple, space, keyT,
425  output_terminals_type, input_args_t>::type;
426  static_assert(std::is_same_v<decayed_input_args_t, std::tuple<input_edge_valuesT...>>,
427  "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func");
428 
429  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
430 }
431 
432 template <typename keyT = void,
433  typename funcT,
434  typename... input_edge_valuesT,
435  typename... output_edgesT>
436 auto make_tt_tpl(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
437  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
438  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT),
439  "input"),
440  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT),
441  "output"))
442 {
443  return make_tt_tpl<ttg::ExecutionSpace::Host, keyT>(
444  std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
445 }
446 // clang-format off
492 // clang-format on
493 template <ttg::ExecutionSpace space,
494  typename keyT = void, typename funcT,
495  typename... input_edge_valuesT, typename... output_edgesT>
496 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
497  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
498  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
499  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
500  // ensure input types do not contain Void
501  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
502 
503  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
504 
505  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
506 
507  // list of base datum types (T or const T)
509 
510  // gross list of candidate argument types
511  using gross_candidate_func_args_t = ttg::meta::typelist<
515 
516  // net list of candidate argument types excludes the empty typelists for void arguments
517  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
518 
519  // gross argument typelist for invoking func, can include void for optional args
520  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
521  using return_type_typelist_and_gross_func_args_t =
522  decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{}));
523  using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
524  using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
525  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
526  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
527  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
528  "ttd::make_tt(func, inedges, ...): could not detect how to invoke generic callable func, either the "
529  "signature of func "
530  "is faulty, or inedges does match the expected list of types, or both");
531 
532  // net argument typelist
533  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
534  constexpr auto num_args = std::tuple_size_v<func_args_t>;
535 
536  // if given task id, make sure it's passed via const lvalue ref
537  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
538  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
539  constexpr bool TASK_ID_PASSED_AS_NONREF =
540  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
541  static_assert(
542  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
543  "ttg::make_tt(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
544 
545  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
546  constexpr bool have_outterm_tuple =
547  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
548  : ttg::meta::probe_last_v<ttg::meta::decays_to_output_terminal_tuple, false, gross_func_args_t>;
549  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
550  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, false, func_args_t> : true;
551  static_assert(
552  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
553  "ttg::make_tt(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
554 
555  // TT needs actual types of arguments to func ... extract them and pass to CallableWrapTT
556  using input_edge_value_types = ttg::meta::typelist<std::decay_t<input_edge_valuesT>...>;
557  // input_args_t = {input_valuesT&&...}
558  using input_args_t = typename ttg::meta::take_first_n<
559  typename ttg::meta::drop_first_n<func_args_t, std::size_t(void_key ? 0 : 1)>::type,
560  std::tuple_size_v<func_args_t> - (void_key ? 0 : 1) - (have_outterm_tuple ? 1 : 0)>::type;
561  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
562  !ttg::meta::is_any_nonconst_lvalue_reference_v<input_args_t>;
563  static_assert(
564  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
565  "ttg::make_tt(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
566  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
567  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
568  // 3. full_input_args_t = edge-types with non-void types replaced by input_args_t
569  using full_input_args_t = ttg::meta::replace_nonvoid_t<input_edge_value_types, input_args_t>;
570  using wrapT = typename CallableWrapTTAsTypelist<funcT, func_return_t, false, have_outterm_tuple, space, keyT,
571  output_terminals_type, full_input_args_t>::type;
572 
573  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
574 }
575 
576 template <typename keyT = void, typename funcT,
577  typename... input_edge_valuesT, typename... output_edgesT>
578 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
579  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
580  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
581  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
582  return make_tt<ttg::ExecutionSpace::Host, keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
583 }
584 
585 template <typename keyT, typename funcT, typename... input_valuesT, typename... output_edgesT>
586 [[deprecated("use make_tt_tpl instead")]] inline auto wrapt(
587  funcT &&func, const std::tuple<ttg::Edge<keyT, input_valuesT>...> &inedges,
588  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
589  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_valuesT), "input"),
590  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
591  return make_tt_tpl<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
592 }
593 
594 template <typename keyT, typename funcT, typename... input_edge_valuesT, typename... output_edgesT>
595 [[deprecated("use make_tt instead")]] auto wrap(
596  funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges,
597  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
598  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
599  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
600  return make_tt<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
601 }
602 
603 #endif // TTG_MAKE_TT_H
CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:250
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&ttg::meta::is_void_v< Key >, op_return_type > op(output_terminalsT &out)
Definition: make_tt.h:282
auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:105
auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:138
auto call_func(Key &&key, output_terminalsT &out)
Definition: make_tt.h:172
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< input_refs_tuple_type > &&ttg::meta::is_void_v< Key >, op_return_type > op(ArgsTuple &&args_tuple, output_terminalsT &out)
Definition: make_tt.h:268
auto call_func(OutputTerminals &out)
Definition: make_tt.h:204
static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence< I... >)
Definition: make_tt.h:237
static constexpr bool have_level_zero_op
Definition: make_tt.h:50
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< input_refs_tuple_type > &&!ttg::meta::is_void_v< Key >, op_return_type > op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out)
Definition: make_tt.h:258
auto process_return(ReturnT &&ret, output_terminalsT &out)
Definition: make_tt.h:55
CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:244
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&!ttg::meta::is_void_v< Key >, op_return_type > op(Key &&key, output_terminalsT &out)
Definition: make_tt.h:275
static constexpr bool have_hip_op
Definition: make_tt.h:49
static constexpr bool have_cuda_op
Definition: make_tt.h:48
Edge is used to connect In and Out terminals.
Definition: edge.h:25
#define TTG_HAVE_DEVICE
Definition: config.in.h:33
auto wrap(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges, const std::tuple< output_edgesT... > &outedges, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Definition: make_tt.h:595
auto make_tt_tpl(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges=std::tuple<>{}, const std::tuple< output_edgesT... > &outedges=std::tuple<>{}, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Factory function to assist in wrapping a callable with signature.
Definition: make_tt.h:348
auto make_tt(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges=std::tuple<>{}, const std::tuple< output_edgesT... > &outedges=std::tuple<>{}, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Factory function to assist in wrapping a callable with signature.
Definition: make_tt.h:496
auto wrapt(funcT &&func, const std::tuple< ttg::Edge< keyT, input_valuesT >... > &inedges, const std::tuple< output_edgesT... > &outedges, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Definition: make_tt.h:586
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition: span.h:492
typename make_index_sequence_t< I... >::type make_index_sequence
constexpr bool probe_last_v
Definition: meta.h:120
auto compute_arg_binding_types(Func &func, typelist< Typelists... > argument_type_lists)
Definition: callable.h:154
typename tuple_concat< TupleTs... >::type tuple_concat_t
Definition: meta.h:60
typename candidate_argument_bindings< T >::type candidate_argument_bindings_t
Definition: callable.h:221
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8
ExecutionSpace
denotes task execution space
Definition: execution.h:17
void abort()
Aborts the TTG program using the default backend's ttg_abort method.
Definition: run.h:62
meta::typelist< Ts... > typelist
Definition: typelist.h:81
TTG_CXX_COROUTINE_NAMESPACE::coroutine_handle< Promise > coroutine_handle
Definition: coroutine.h:24
drops N elements from the front
Definition: meta.h:349
take first N elements of a type list
Definition: meta.h:373
A container for types.
Definition: typelist.h:24