1 /*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <string>
22 #include <fstream>
23 #include <iface.h>
24 #include <default_params.h>
25
26 using namespace std;
27 using namespace libint2;
28
29 namespace {
30 const char mh_name[] = "libint2.h";
31 const char th_name[] = "libint2_types.h";
32 const char ph_name[] = "libint2_params.h";
33 const char ih_name[] = "libint2_iface.h";
34 const char ii_name[] = "libint2_iface_internal.h";
35 const char si_name[] = "libint2_static_init.cc";
36 const char sc_name[] = "libint2_static_cleanup.cc";
37 const char li_name[] = "libint2_init.cc";
38
header_guard_open(std::ostream & os,const std::string & label)39 inline void header_guard_open(std::ostream& os, const std::string& label) {
40 os << "#ifndef _libint2_" << label << "_h_" << endl
41 << "#define _libint2_" << label << "_h_" << endl << endl;
42 }
header_guard_close(std::ostream & os)43 inline void header_guard_close(std::ostream& os) {
44 os << "#endif" << endl << endl;
45 }
46
47 };
48
Libint2Iface(const SafePtr<CompilationParameters> & cparams,const SafePtr<CodeContext> & ctext)49 Libint2Iface::Libint2Iface(const SafePtr<CompilationParameters>& cparams,
50 const SafePtr<CodeContext>& ctext) :
51 null_str_(""), oss_(), cparams_(cparams), ctext_(ctext),
52 th_((cparams_->source_directory() + th_name).c_str()),
53 ph_((cparams_->source_directory() + ph_name).c_str()),
54 ih_((cparams_->source_directory() + ih_name).c_str()),
55 ii_((cparams_->source_directory() + ii_name).c_str()),
56 si_((cparams_->source_directory() + si_name).c_str()),
57 sc_((cparams_->source_directory() + sc_name).c_str()),
58 li_((cparams_->source_directory() + li_name).c_str())
59 {
60 th_ << ctext_->copyright();
61 ph_ << ctext_->copyright();
62 ih_ << ctext_->copyright();
63 ii_ << ctext_->copyright();
64 si_ << ctext_->copyright();
65 sc_ << ctext_->copyright();
66 li_ << ctext_->copyright();
67
68 header_guard_open(th_,"libint2types");
69 header_guard_open(ph_,"libint2params");
70 header_guard_open(ih_,"libint2iface");
71 header_guard_open(ii_,"libint2ifaceint");
72
73 ph_ << macro_define("API_PREFIX", cparams_->api_prefix());
74 ph_ << macro_define("MAX_VECLEN", cparams_->max_vector_length());
75 ph_ << macro_define("ALIGN_SIZE", cparams_->align_size());
76 if (cparams_->count_flops())
77 ph_ << macro_define("FLOP_COUNT",1);
78 if (cparams_->profile())
79 ph_ << macro_define("PROFILE",1);
80 if (cparams_->accumulate_targets())
81 ph_ << macro_define("ACCUM_INTS",1);
82 const std::string realtype(cparams_->realtype());
83 {
84 // does LIBINT_USER_DEFINED_REAL need extra include statements?
85 #ifdef LIBINT_USER_DEFINED_REAL_INCLUDES
86 ph_ << LIBINT_USER_DEFINED_REAL_INCLUDES << std::endl;
87 #endif
88 ph_ << macro_define("REALTYPE", realtype);
89 }
90 if (cparams_->contracted_targets())
91 ph_ << macro_define("CONTRACTED_INTS",1);
92
93 ih_ << "#ifdef __cplusplus\n# include <cstddef>\n#else\n# include <stddef.h>\n#endif" << endl
94 << ctext_->code_prefix();
95
96 oss_.str(null_str_);
97 oss_ << ctext_->std_header() << "#include <" << ih_name << ">" << endl
98 << "#include <" << ii_name << ">" << endl
99 << "#include <cstddef>" << endl
100 << "#include <cassert>" << endl
101 << "#include <cstdlib>" << endl
102 << ctext_->code_prefix();
103 std::string pfix = oss_.str();
104 si_ << pfix;
105 sc_ << pfix;
106 li_ << "#include <libint2/util/memory.h>" << endl << pfix; // moved from libint2.h to here
107
108 // print out declarations for the array of pointers to evaluator functions
109 LibraryTaskManager& taskmgr = LibraryTaskManager::Instance();
110 typedef LibraryTaskManager::TasksCIter tciter;
111 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t) {
112 const std::string& tlabel = t->label();
113 const unsigned int nbf = cparams_->num_bf(tlabel);
114
115 ostringstream oss;
116 oss << "void (*" << ctext->label_to_name(cparams->api_prefix()) << "libint2_build_" << tlabel;
117 for(unsigned int c=0; c<nbf; ++c) {
118 const unsigned int lmax = const_cast<const CompilationParameters*>(cparams_.get())->max_am(tlabel, c);
119 oss << "[" << lmax+1 << "]";
120 std::cout << "task=" << tlabel << " center=" << c << " lmax=" << lmax << std::endl;
121 }
122 oss << ")(" << ctext_->const_modifier() << ctext_->inteval_type_name(tlabel) << "*);" << endl;
123 ih_ << "extern " << oss.str();
124 si_ << oss.str();
125 }
126
127 // Declare library constructor/destructor
128 oss_.str(null_str_);
129 oss_ << ctext_->type_name<void>() << " "
130 << ctext_->label_to_name(cparams->api_prefix() + "libint2_static_init") << "()";
131 std::string si_fdec(oss_.str());
132
133 oss_.str(null_str_);
134 oss_ << ctext_->type_name<void>() << " "
135 << ctext_->label_to_name(cparams->api_prefix() + "libint2_static_cleanup") << "()";
136 std::string sc_fdec(oss_.str());
137
138 ih_ << si_fdec << ctext_->end_of_stat() << endl;
139 ih_ << sc_fdec << ctext_->end_of_stat() << endl;
140
141 // Declare evaluator constructor/destructor (specific to the type of computation)
142 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t) {
143 const std::string& tlabel = t->label();
144
145 oss_.str(null_str_);
146 oss_ << ctext_->type_name<void>() << " "
147 << ctext_->label_to_name(cparams->api_prefix() + "libint2_init_" + tlabel)
148 << "(" << ctext_->inteval_type_name(tlabel)
149 << "* inteval, int max_am, void* buf)";
150 std::string li_fdec(oss_.str());
151 li_decls_.push_back(li_fdec);
152
153 oss_.str(null_str_);
154 oss_ << ctext_->type_name<size_t>() << " "
155 << ctext_->label_to_name(cparams->api_prefix() + "libint2_need_memory_" + tlabel)
156 << "(int max_am)";
157 std::string lm_fdec(oss_.str());
158 lm_decls_.push_back(lm_fdec);
159
160 oss_.str(null_str_);
161 oss_ << ctext_->type_name<void>() << " "
162 << ctext_->label_to_name(cparams->api_prefix() + "libint2_cleanup_" + tlabel)
163 << "(" << ctext_->inteval_type_name(tlabel) << "* inteval)";
164 std::string lc_fdec(oss_.str());
165 lc_decls_.push_back(lc_fdec);
166
167 ih_ << li_fdec << ctext_->end_of_stat() << endl;
168 ih_ << lm_fdec << ctext_->end_of_stat() << endl;
169 ih_ << lc_fdec << ctext_->end_of_stat() << endl;
170 }
171
172 // if counting flops, need additional initializer function
173 if (cparams_->count_flops()) {
174 oss_.str(null_str_);
175 oss_ << "#ifdef __cplusplus\n#ifdef LIBINT2_FLOP_COUNT\nextern \"C++\" template <typename EvalType> void "
176 << ctext_->label_to_name(cparams->api_prefix() + "libint2_init_flopcounter")
177 << "(EvalType* inteval_vector, int inteval_vector_size)"
178 << ctext_->open_block();
179 // TODO convert to ForLoop object
180 oss_ << "for(int v=1; v!=inteval_vector_size; ++v)"
181 << ctext_->open_block()
182 << ctext_->assign("inteval_vector[v].nflops", "inteval_vector[0].nflops")
183 << ctext_->close_block()
184 << ctext_->close_block();
185 oss_ << "#endif\n#endif\n";
186
187 lf_decl_ = oss_.str();
188 ih_ << lf_decl_ << ctext_->end_of_stat() << endl;
189 }
190
191 ih_ << ctext_->code_postfix() << endl;
192
193 si_ << si_fdec << ctext_->open_block();
194 sc_ << sc_fdec << ctext_->open_block();
195
196 }
197
~Libint2Iface()198 Libint2Iface::~Libint2Iface()
199 {
200 // For each task, print out defines for stack dimensions
201 LibraryTaskManager& taskmgr = LibraryTaskManager::Instance();
202 typedef LibraryTaskManager::TasksCIter tciter;
203 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t) {
204 SafePtr<TaskParameters> tparams = t->params();
205 const std::string& tlabel = t->label();
206 ph_ << macro_define(tlabel,"NUM_TARGETS",tparams->max_ntarget());
207 const unsigned int max_am = tparams->max_am();
208 for(unsigned int am=0; am<=max_am; ++am) {
209 { std::ostringstream oss; oss << "MAX_STACK_SIZE_" << am;
210 ph_ << macro_define(tlabel,oss.str(),tparams->max_stack_size(am)); }
211 { std::ostringstream oss; oss << "MAX_VECTOR_STACK_SIZE_" << am;
212 const unsigned int max_vector_stack_size = tparams->max_vector_stack_size(am);
213 ph_ << macro_define(tlabel,oss.str(),max_vector_stack_size); }
214 { std::ostringstream oss; oss << "MAX_HRR_HSRANK_" << am;
215 ph_ << macro_define(tlabel,oss.str(),tparams->max_hrr_hsrank(am)); }
216 { std::ostringstream oss; oss << "MAX_HRR_LSRANK_" << am;
217 ph_ << macro_define(tlabel,oss.str(),tparams->max_hrr_lsrank(am)); }
218 }
219 }
220
221 // For each task, generate the evaluator type
222 th_ << "#include <libint2/util/vector.h>" << std::endl;
223 th_ << "#include <libint2/util/intrinsic_operations.h>" << std::endl;
224 th_ << "#include <libint2/util/timer.h>" << std::endl; // in case LIBINT2_PROFILE is on
225 generate_inteval_type(th_);
226
227 // libint2_iface.h needs macros to help forming prefixed names in API
228 ih_ << ctext_->comment("Use LIBINT2_PREFIXED_NAME(fncname) to form properly prefixed function name from LIBINT2 API") << std::endl;
229 ih_ << "#define LIBINT2_PREFIXED_NAME(name) __libint2_prefixed_name__(LIBINT2_API_PREFIX,name)" << std::endl;
230 ih_ << "#define __libint2_prefixed_name__(prefix,name) __prescanned_prefixed_name__(prefix,name)" << std::endl;
231 ih_ << "#define __prescanned_prefixed_name__(prefix,name) prefix##name" << std::endl;
232 // also need macros to test what's in the evaluator
233 ih_ << ctext_->comment("Use LIBINT2_PREFIXED_NAME(fncname) to form properly prefixed function name from LIBINT2 API") << std::endl;
234 ih_ << "#define LIBINT2_DEFINED(taskname,symbol) __prescanned_libint2_defined__(taskname,symbol)" << std::endl;
235 if (cparams_->single_evaltype())
236 ih_ << "#define __prescanned_libint2_defined__(taskname,symbol) LIBINT2_DEFINED_##symbol" << std::endl << std::endl;
237 else
238 ih_ << "#define __prescanned_libint2_defined__(taskname,symbol) LIBINT2_DEFINED_##symbol##_##taskname" << std::endl << std::endl;
239
240
241
242 header_guard_close(th_);
243 header_guard_close(ph_);
244 header_guard_close(ih_);
245 header_guard_close(ii_);
246
247 std::ostringstream oss;
248 oss << ctext_->close_block() << ctext_->code_postfix() << endl << endl;
249 std::string pfix = oss.str();
250
251 si_ << pfix;
252 sc_ << pfix;
253
254 // Define Libint_t constructor/destructor (specific to the type of computation)
255 {
256 unsigned int i = 0;
257 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t,++i) {
258 const std::string& tlabel = t->label();
259
260 li_ << lm_decls_[i] << ctext_->open_block();
261 const unsigned int max_am = t->params()->max_am();
262 for(unsigned int am=0; am<=max_am; ++am) {
263 std::string ss, vss, hsr, lsr;
264 { std::ostringstream oss;
265 oss << "MAX_STACK_SIZE_" << am; ss = oss.str(); }
266 { std::ostringstream oss;
267 oss << "MAX_VECTOR_STACK_SIZE_" << am; vss = oss.str(); }
268 { std::ostringstream oss;
269 oss << "MAX_HRR_HSRANK_" << am; hsr = oss.str(); }
270 { std::ostringstream oss;
271 oss << "MAX_HRR_LSRANK_" << am; lsr = oss.str(); }
272
273 li_ << "assert(max_am <= " << max_am << ");" << std::endl;
274
275 li_ << "if (max_am == " << am << ") return " << macro(tlabel,ss) << " * " << macro("MAX_VECLEN") << " + "
276 << macro(tlabel,vss) << " * " << macro("MAX_VECLEN") << " * ("
277 << macro(tlabel,hsr) << " > " << macro(tlabel,lsr) << " ? "
278 << macro(tlabel,hsr) << " : " << macro(tlabel,lsr) << ");" << std::endl;
279 }
280 li_ << "return 0; // unreachable" << std::endl;
281 li_ << ctext_->close_block();
282 }
283
284 i = 0;
285 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t,++i) {
286 const std::string& tlabel = t->label();
287
288 li_ << li_decls_[i] << ctext_->open_block();
289 li_ << "if (buf != 0) inteval->stack = reinterpret_cast<LIBINT2_REALTYPE*>(buf);" << std::endl << "else " << std::endl;
290 {
291 std::string tmp = ctext_->label_to_name(cparams_->api_prefix() + "libint2_need_memory_" + tlabel) + "(max_am)";
292
293 // no posix_memalign? use new, with default alignment
294 li_ << ctext_->assign("inteval->stack",std::string("libint2::malloc<LIBINT2_REALTYPE>(") + tmp + std::string(")"));
295
296 }
297
298 const unsigned int max_am = t->params()->max_am();
299 for(unsigned int am=0; am<=max_am; ++am) {
300 std::string ss;
301 { std::ostringstream oss;
302 oss << "MAX_STACK_SIZE_" << am; ss = oss.str(); }
303
304 li_ << "assert(max_am <= " << max_am << ");" << std::endl;
305 li_ << "if (max_am == " << am << ")" << std::endl;
306 std::string vstack_ptr("inteval->stack + ");
307 vstack_ptr += macro(tlabel,ss);
308 vstack_ptr += " * ";
309 vstack_ptr += macro("MAX_VECLEN");
310 li_ << ctext_->assign("inteval->vstack",vstack_ptr);
311 }
312
313 if (cparams_->count_flops()) {
314 // allocate the counter and set it to zero
315 li_ << "inteval->nflops = new " << macro("UINT_LEAST64") << ";" << endl;
316 li_ << "inteval->nflops[0] = 0;" << endl;
317 }
318 if (cparams_->profile()) { // zero out the timers
319 li_ << ctext_->macro_if("LIBINT2_CPLUSPLUS_STD >= 2011");
320 li_ << "inteval->timers = new libint2::Timers<2>;" << endl;
321 li_ << "inteval->timers->clear();" << endl;
322 li_ << ctext_->macro_endif(); // >= C++11
323 }
324 li_ << ctext_->close_block();
325 }
326
327 i = 0;
328 for(tciter t=taskmgr.first(); t!=taskmgr.plast(); ++t,++i) {
329 li_ << lc_decls_[i] << ctext_->open_block();
330
331 li_ << "free(inteval->stack);\n";
332 li_ << ctext_->assign("inteval->stack","0");
333 li_ << ctext_->assign("inteval->vstack","0");
334 if (cparams_->count_flops()) {
335 // free the counter and set the pointer to zero
336 li_ << "delete inteval->nflops;" << endl;
337 li_ << "inteval->nflops = 0;" << endl;
338 }
339 if (cparams_->profile()) {
340 li_ << ctext_->macro_if("LIBINT2_CPLUSPLUS_STD >= 2011");
341 li_ << "delete inteval->timers;" << endl;
342 li_ << "inteval->timers = 0;" << endl;
343 li_ << ctext_->macro_endif(); // >= C++11
344 }
345 li_ << ctext_->close_block();
346 }
347 }
348
349 li_ << ctext_->code_postfix() << std::endl << std::endl;
350
351 th_.close();
352 ph_.close();
353 ih_.close();
354 ii_.close();
355 si_.close();
356 sc_.close();
357 li_.close();
358 }
359
360 namespace libint2 {
361
362 /// Parses the symbol if it is composed of a prefix followed by a number.
363 class Parser_prefixN {
364
365 public:
Parser_prefixN(const std::string & symbol)366 Parser_prefixN(const std::string& symbol) :
367 match_(false), N_(0) {
368
369 std::string N_str;
370 bool minus = false;
371
372 auto prefix_rbegin = symbol.rbegin();
373 for(auto ri = symbol.rbegin(); ri != symbol.rend(); ++ri) {
374 if (isdigit(*ri)) {
375 match_ = true;
376 N_str.insert(0, 1, *ri);
377 }
378 else { // no more digits? check for a minus sign
379 prefix_rbegin = ri;
380 if (*ri == '_') {
381 std::string token("_");
382 ++ri;
383 for(int i=0; i<6 && ri != symbol.rend(); ++ri, ++i) {
384 token.push_back(*ri);
385 }
386 if (token == "_sunim_") { // minus reversed
387 minus = true;
388 prefix_rbegin = ri;
389 }
390 }
391 break;
392 }
393 }
394
395 if (match_) {
396
397 N_ = atoi(N_str.c_str());
398 if (minus)
399 N_ *= -1;
400
401 prefix_ = std::string(prefix_rbegin, symbol.rend());
402 std::reverse(prefix_.begin(), prefix_.end());
403 }
404 }
405
406 /// returns true if the pattern matched
match() const407 bool match() const { return match_; }
408 /// returns N (only valid if match()==true)
N() const409 int N() const { return N_; }
410 /// returns prefix (only valid if match()==true)
prefix() const411 const std::string& prefix() const { return prefix_; }
412
413 private:
414 bool match_;
415 std::string prefix_;
416 int N_;
417
418 };
419 }
420
421 void
generate_inteval_type(std::ostream & os)422 Libint2Iface::generate_inteval_type(std::ostream& os)
423 {
424 LibraryTaskManager& taskmgr = LibraryTaskManager::Instance();
425
426 //
427 // If need to generate single type for all tasks, take a union of all symbols
428 // else process each task separately
429 //
430 typedef LibraryTaskManager::TasksCIter tciter;
431 const tciter tend = cparams_->single_evaltype() ? taskmgr.first()+1 : taskmgr.plast();
432 for(tciter t=taskmgr.first(); t!=tend; ++t) {
433 const SafePtr<TaskExternSymbols> tsymbols = t->symbols();
434
435 // Prologue
436 os << "typedef struct {" << std::endl;
437
438 //
439 // Declare external symbols
440 //
441 typedef TaskExternSymbols::SymbolList SymbolList;
442 std::string tlabel;
443 SymbolList symbols;
444 if (cparams_->single_evaltype()) {
445 TaskExternSymbols composite_symbols;
446 const tciter tend = taskmgr.plast();
447 for(tciter t=taskmgr.first(); t!=tend; ++t) {
448 const SafePtr<TaskExternSymbols> tsymbols = t->symbols();
449 composite_symbols.add(tsymbols->symbols());
450 }
451 symbols = composite_symbols.symbols();
452 tlabel = "";
453 }
454 else {
455 symbols = tsymbols->symbols();
456 tlabel = t->label();
457 }
458
459 // Spend some effort to ensure reasonable ordering/grouping of symbols in the list, e.g.
460 // all symbols of form PrefixIndex (e.g. crazyprefixN) will be grouped together in the order of increasing Index.
461 SymbolList ordered_symbols;
462 // 1) convert all symbols to valid code
463 // 2) then scan for symbols matching pattern prefixN, for each prefix determine range of N
464 std::map<std::string,std::pair<int,int> > prefix_symbols;
465 for(auto s : symbols) {
466 Parser_prefixN parser(ctext_->label_to_name(s));
467 if (parser.match()) {
468 if (prefix_symbols.find(parser.prefix()) == prefix_symbols.end()) {
469 prefix_symbols[parser.prefix()] = std::make_pair(parser.N(), parser.N());
470 }
471 else {
472 const int N = parser.N();
473 auto Nlimits = prefix_symbols[parser.prefix()];
474 if (N < Nlimits.first) Nlimits.first = N;
475 if (N > Nlimits.second) Nlimits.second = N;
476 prefix_symbols[parser.prefix()] = Nlimits;
477 }
478 }
479 }
480
481 // 3) for each prefix iterate over the corresponding range, and add the matching symbols in the same order
482 for(auto pi=prefix_symbols.begin(); pi!=prefix_symbols.end(); ++pi) {
483 auto prefix = pi->first;
484 auto Nlimits = pi->second;
485 for(int N=Nlimits.first; N<=Nlimits.second; ++N) {
486 std::ostringstream oss; oss << prefix << (N<0 ? "-" : "") << abs(N);
487 std::string code_symbol = ctext_->label_to_name(oss.str());
488 for(auto v : symbols) {
489 if (code_symbol == ctext_->label_to_name(v)) {
490 ordered_symbols.push_back(code_symbol);
491 }
492 }
493 }
494 }
495 // 4) the rest of symbols can appear in any order
496 // in practice, the order is lexicographic, hence xyz components are automatically ordered x,y,z
497 for(auto s : symbols) {
498 if (std::find(ordered_symbols.begin(), ordered_symbols.end(), ctext_->label_to_name(s)) == ordered_symbols.end())
499 ordered_symbols.push_back(s);
500 }
501
502 // now dump all symbols into the evaluator data type definition
503 for(auto s=ordered_symbols.begin(); s!=ordered_symbols.end(); ++s) {
504 // for each extrnal symbol #define a macro
505 std::string tmplabel("DEFINED_"); tmplabel += ctext_->label_to_name(*s);
506 os << macro_define(tlabel,tmplabel,1);
507 // all symbols are doubles
508 os << var_declare_v<double>(*s);
509 }
510
511 // Declare members common to all evaluators
512 os << ctext_->comment("Scratch buffer to hold intermediates") << std::endl;
513 os << ctext_->declare(ctext_->mutable_modifier() + ctext_->type_name<double*>(),std::string("stack"));
514
515 os << ctext_->comment("Buffer to hold vector intermediates. Only used by set-level RR code if it is vectorized linewise") << std::endl;
516 os << ctext_->declare(ctext_->mutable_modifier() + ctext_->type_name<double*>(),std::string("vstack"));
517
518 os << ctext_->comment("On completion, this contains pointers to computed targets") << std::endl;
519 if (cparams_->single_evaltype()) {
520 // figure out the maximum number of targets
521 unsigned int max_ntargets = 0;
522 const tciter tend = taskmgr.plast();
523 for(tciter t=taskmgr.first(); t!=tend; ++t) {
524 SafePtr<TaskParameters> tparams = t->params();
525 max_ntargets = std::max(max_ntargets,tparams->max_ntarget());
526 }
527 ostringstream oss;
528 oss << max_ntargets;
529 os << ctext_->declare_v(ctext_->mutable_modifier() + ctext_->type_name<double*>(),std::string("targets"),oss.str());
530 }
531 else {
532 os << ctext_->declare_v(ctext_->mutable_modifier() + ctext_->type_name<double*>(),std::string("targets"),macro(tlabel,"NUM_TARGETS"));
533 }
534
535 os << ctext_->comment("Actual vector length. Not to exceed MAX_VECLEN! If MAX_VECLEN is 1 then veclen is not used") << std::endl;
536 os << ctext_->declare(ctext_->type_name<int>(),std::string("veclen"));
537
538 os << ctext_->macro_if(macro("FLOP_COUNT"));
539 os << ctext_->comment("FLOP counter. Libint must be configured with --enable-flop-counter to allow FLOP counting. It is user's reponsibility to set zero nflops before computing integrals.") << std::endl;
540 os << ctext_->declare(ctext_->mutable_modifier() + macro("UINT_LEAST64*"),std::string("nflops"));
541 os << ctext_->macro_endif();
542
543 os << ctext_->macro_if(macro("PROFILE"));
544 os << ctext_->macro_if("LIBINT2_CPLUSPLUS_STD >= 2011");
545 os << ctext_->comment("profiling timers. Libint must be configured with --enable-profile to allow profiling.") << std::endl;
546 os << "#ifdef __cplusplus" << std::endl
547 << ctext_->declare(ctext_->mutable_modifier() + "libint2::Timers<2>*",std::string("timers")) // 1 timer for HRR and 1 timer for VRR
548 << "#else // timers are not accessible from C" << std::endl
549 << " void* timers;" << std::endl
550 << "#endif" << std::endl;
551 os << ctext_->macro_endif(); // >= C++11
552 os << ctext_->macro_endif();
553
554 os << ctext_->macro_if(macro("ACCUM_INTS"));
555 os << ctext_->comment("If libint was configured with --enable-accum-ints then the target integrals are accumulated. To zero out the targets automatically before the computation, set this to nonzero.") << std::endl;
556 os << ctext_->declare(ctext_->type_name<int>(),std::string("zero_out_targets"));
557 os << ctext_->macro_endif();
558
559 os << ctext_->macro_if(macro("CONTRACTED_INTS"));
560 os << ctext_->comment("If libint was configured with --enable-contracted-ints then contracted integrals are supported. Set this parameter to the total number of primitive combinations.") << std::endl;
561 os << ctext_->declare(ctext_->type_name<int>(),std::string("contrdepth"));
562 os << ctext_->macro_endif();
563
564 // Epilogue
565 os << "} " << ctext_->inteval_type_name(tlabel) << ctext_->end_of_stat() << std::endl;
566
567 }
568
569 // If generating single evaluator type, create aliases from the specialized types to the actual type
570 if (cparams_->single_evaltype()) {
571 const tciter tend = taskmgr.plast();
572 for(tciter t=taskmgr.first(); t!=tend; ++t) {
573 const std::string& tlabel = t->label();
574 os << "typedef "
575 << ctext_->inteval_gen_type_name() << " "
576 << ctext_->inteval_spec_type_name(tlabel)
577 << ctext_->end_of_stat() << std::endl;
578 }
579 }
580
581 }
582