64 static std::string unique_name(
const std::string &name,
const std::string &args) {
65 if (name ==
"operator+") {
66 return "op_add_" + args;
67 }
else if (name ==
"operator-") {
68 if (args.size() == 1) {
69 return "op_neg_" + args;
71 return "op_sub_" + args;
73 }
else if (name ==
"operator*") {
74 return "op_mul_" + args;
75 }
else if (name ==
"operator/") {
76 return "op_div_" + args;
77 }
else if (name ==
"operator//") {
78 return "op_int_div_" + args;
79 }
else if (name ==
"operator%") {
80 return "op_mod_" + args;
81 }
else if (name ==
"operator**") {
82 return "op_pow_" + args;
83 }
else if (name ==
"operator<<") {
84 return "op_shl_" + args;
85 }
else if (name ==
"operator>>") {
86 return "op_sra_" + args;
87 }
else if (name ==
"operator>>>") {
88 return "op_srl_" + args;
89 }
else if (name ==
"operator==") {
90 return "op_eq_" + args;
91 }
else if (name ==
"operator!=") {
92 return "op_ne_" + args;
93 }
else if (name ==
"operator>=") {
94 return "op_ge_" + args;
95 }
else if (name ==
"operator>") {
96 return "op_gt_" + args;
97 }
else if (name ==
"operator<=") {
98 return "op_le_" + args;
99 }
else if (name ==
"operator<") {
100 return "op_lt_" + args;
101 }
else if (name ==
"operator~") {
102 return "op_binv_" + args;
103 }
else if (name ==
"operator&") {
104 return "op_band_" + args;
105 }
else if (name ==
"operator^") {
106 return "op_bxor_" + args;
107 }
else if (name ==
"operator|") {
108 return "op_bor_" + args;
109 }
else if (name ==
"operator!") {
110 return "op_linv_" + args;
111 }
else if (name ==
"operator&&") {
112 return "op_land_" + args;
113 }
else if (name ==
"operator^^") {
114 return "op_lxor_" + args;
115 }
else if (name ==
"operator||") {
116 return "op_lor_" + args;
117 }
else if (name ==
"operator?:") {
118 return "op_tcnd_" + args;
120 return "fn_" + name +
"_" + args;
129 Function(
const std::string &name,
const std::string &args)
130 : cpp_name(unique_name(name, args)), cqasm_name(name), cqasm_args(args)
144 std::vector<Function> funcs;
149 std::ofstream header;
154 std::ofstream source;
159 void generate_register_function() {
165 void register_into(resolver::FunctionTable &table); 172 void register_into(resolver::FunctionTable &table) { 174 for (
const auto &func : funcs) {
175 source <<
" table.add(";
176 source <<
"\"" << func.cqasm_name <<
"\", ";
177 source <<
"types::from_spec(\"" << func.cqasm_args <<
"\"), ";
178 source << func.cpp_name;
179 source <<
");" << std::endl;
181 source << std::endl <<
"}" << std::endl;
189 void generate_impl_header(
const Function &func) {
190 auto proto =
"values::Value " + func.
cpp_name +
"(const values::Values &v)";
191 header << proto <<
";" << std::endl;
192 source << std::endl << proto <<
" {" << std::endl;
193 funcs.push_back(func);
203 void generate_const_impl_header(
const Function &func) {
204 generate_impl_header(func);
205 source <<
" values::check_const(v);" << std::endl;
208 source <<
" auto " << (char)(
'a' + index) <<
" = v[" << index <<
"]";
210 case 'b': source <<
"->as_const_bool()->value";
break;
211 case 'a': source <<
"->as_const_axis()->value";
break;
212 case 'i': source <<
"->as_const_int()->value";
break;
213 case 'r': source <<
"->as_const_real()->value";
break;
214 case 'c': source <<
"->as_const_complex()->value";
break;
215 case 'm': source <<
"->as_const_real_matrix()->value";
break;
217 case 'n': source <<
"->as_const_complex_matrix()->value";
break;
218 case 's': source <<
"->as_const_string()->value";
break;
219 case 'j': source <<
"->as_const_json()->value";
break;
221 source <<
";" << std::endl;
242 void generate_impl_footer(
const std::string &return_expr,
char return_type) {
243 source <<
" return tree::make<values::";
244 switch (return_type) {
245 case 'b': source <<
"ConstBool";
break;
246 case 'a': source <<
"ConstAxis";
break;
247 case 'i': source <<
"ConstInt";
break;
248 case 'r': source <<
"ConstReal";
break;
249 case 'c': source <<
"ConstComplex";
break;
250 case 'm': source <<
"ConstRealMatrix";
break;
251 case 'n': source <<
"ConstComplexMatrix";
break;
252 case 's': source <<
"ConstString";
break;
253 case 'j': source <<
"ConstJson";
break;
254 case 'Q': source <<
"QubitRefs";
break;
255 case 'B': source <<
"BitRefs";
break;
256 default:
throw std::invalid_argument(
"unknown type code");
258 source <<
">(" << return_expr <<
");" << std::endl;
259 source <<
"}" << std::endl;
274 const std::string &name,
275 const char return_type,
276 const std::string &arg_types,
277 const std::string &impl
279 generate_const_impl_header(
Function(name, arg_types));
280 generate_impl_footer(impl, return_type);
287 const std::string &header_filename,
288 const std::string &source_filename
291 header(header_filename),
292 source(source_filename)
295 if (!header.is_open()) {
296 throw std::runtime_error(
"failed to open header file");
298 if (!source.is_open()) {
299 throw std::runtime_error(
"failed to open source file");
303 auto pos = header_filename.rfind(
'/');
304 auto header_name = (pos == header_filename.npos) ? header_filename : header_filename.substr(pos + 1);
312 #include "cqasm-v1-resolver.hpp" 316 namespace functions { 325 #include ")" << header_name << R"(" 333 namespace functions { 339 static int64_t div_floor(int64_t a, int64_t b) { 342 // Correct division result downwards if up-rounding happened, 343 // (for non-zero remainder of sign different than the divisor). 344 int64_t corr = (rem != 0 && ((rem < 0) != (b < 0))); 351 static int64_t mod_floor(int64_t a, int64_t b) { 353 if (rem != 0 && ((rem < 0) != (b < 0))) { 366 generate_register_function(); 368 } // namespace functions 383 int main(
int argc,
char *argv[]) {
387 std::cerr <<
"Usage: func-gen <header.hpp> <source.cpp" << std::endl;
396 generator.generate_const_scalar_op(
"operator+",
'r',
"rr",
"a + b");
397 generator.generate_const_scalar_op(
"operator+",
'i',
"ii",
"a + b");
398 generator.generate_const_scalar_op(
"operator+",
's',
"ss",
"a + b");
399 generator.generate_const_scalar_op(
"operator-",
'c',
"cc",
"a - b");
400 generator.generate_const_scalar_op(
"operator-",
'r',
"rr",
"a - b");
401 generator.generate_const_scalar_op(
"operator-",
'i',
"ii",
"a - b");
402 generator.generate_const_scalar_op(
"operator-",
'c',
"c",
"-a");
403 generator.generate_const_scalar_op(
"operator-",
'r',
"r",
"-a");
404 generator.generate_const_scalar_op(
"operator-",
'i',
"i",
"-a");
405 generator.generate_const_scalar_op(
"operator*",
'c',
"cc",
"a * b");
406 generator.generate_const_scalar_op(
"operator*",
'r',
"rr",
"a * b");
407 generator.generate_const_scalar_op(
"operator*",
'i',
"ii",
"a * b");
408 generator.generate_const_scalar_op(
"operator/",
'c',
"cc",
"a / b");
409 generator.generate_const_scalar_op(
"operator/",
'r',
"rr",
"a / b");
410 generator.generate_const_scalar_op(
"operator//",
'i',
"ii",
"div_floor(a, b)");
411 generator.generate_const_scalar_op(
"operator%",
'i',
"ii",
"mod_floor(a, b)");
412 generator.generate_const_scalar_op(
"operator**",
'c',
"cc",
"std::pow(a, b)");
413 generator.generate_const_scalar_op(
"operator**",
'r',
"rr",
"std::pow(a, b)");
416 generator.generate_const_scalar_op(
"operator==",
'b',
"cc",
"a == b");
417 generator.generate_const_scalar_op(
"operator!=",
'b',
"cc",
"a != b");
418 for (
const char *type : {
"rr",
"ii",
"bb"}) {
419 generator.generate_const_scalar_op(
"operator==",
'b', type,
"a == b");
420 generator.generate_const_scalar_op(
"operator!=",
'b', type,
"a != b");
421 generator.generate_const_scalar_op(
"operator>=",
'b', type,
"a >= b");
422 generator.generate_const_scalar_op(
"operator>",
'b', type,
"a > b");
423 generator.generate_const_scalar_op(
"operator<=",
'b', type,
"a <= b");
424 generator.generate_const_scalar_op(
"operator<",
'b', type,
"a < b");
428 generator.generate_const_scalar_op(
"operator~",
'i',
"i",
"~a");
429 generator.generate_const_scalar_op(
"operator&",
'i',
"ii",
"a & b");
430 generator.generate_const_scalar_op(
"operator^",
'i',
"ii",
"a ^ b");
431 generator.generate_const_scalar_op(
"operator|",
'i',
"ii",
"a | b");
432 generator.generate_const_scalar_op(
"operator<<",
'i',
"ii",
"a << b");
433 generator.generate_const_scalar_op(
"operator>>",
'i',
"ii",
"a >> b");
434 generator.generate_const_scalar_op(
"operator>>>",
'i',
"ii",
"(int64_t)(((uint64_t)a) >> b)");
437 generator.generate_const_scalar_op(
"operator!",
'b',
"b",
"!a");
438 generator.generate_const_scalar_op(
"operator&&",
'b',
"bb",
"a && b");
439 generator.generate_const_scalar_op(
"operator^^",
'b',
"bb",
"!a ^ !b");
440 generator.generate_const_scalar_op(
"operator||",
'b',
"bb",
"a || b");
443 for (
const char *type : {
"bcc",
"brr",
"bii",
"bbb"}) {
444 generator.generate_const_scalar_op(
"operator?:", type[1], type,
"a ? b : c");
449 for (
const char *type : {
"c",
"r"}) {
450 generator.generate_const_scalar_op(
"sqrt", type[0], type,
"std::sqrt(a)");
451 generator.generate_const_scalar_op(
"exp", type[0], type,
"std::exp(a)");
452 generator.generate_const_scalar_op(
"log", type[0], type,
"std::log(a)");
453 for (
const char *prefix : {
"",
"a"}) {
454 for (
const char *suffix : {
"",
"h"}) {
455 for (
const char *func : {
"sin",
"cos",
"tan"}) {
456 std::ostringstream ss;
457 ss << prefix << func << suffix;
458 generator.generate_const_scalar_op(
459 ss.str(), type[0], type,
"std::" + ss.str() +
"(a)");
466 generator.generate_const_scalar_op(
"abs",
'r',
"r",
"std::abs(a)");
467 generator.generate_const_scalar_op(
"abs",
'i',
"i",
"std::abs(a)");
470 generator.generate_const_scalar_op(
"complex",
'c',
"rr",
"primitives::Complex(a, b)");
471 generator.generate_const_scalar_op(
"polar",
'c',
"rr",
"std::polar<double>(a, b)");
472 generator.generate_const_scalar_op(
"real",
'r',
"c",
"std::real<double>(a)");
473 generator.generate_const_scalar_op(
"imag",
'r',
"c",
"std::imag<double>(a)");
474 generator.generate_const_scalar_op(
"arg",
'r',
"c",
"std::arg<double>(a)");
475 generator.generate_const_scalar_op(
"norm",
'r',
"c",
"std::norm<double>(a)");
476 generator.generate_const_scalar_op(
"conj",
'c',
"c",
"std::conj<double>(a)");
void generate_const_scalar_op(const std::string &name, const char return_type, const std::string &arg_types, const std::string &impl)
Generates a basic constant scalar function, such as integer addition for instance.
Generator(const std::string &header_filename, const std::string &source_filename)
Constructs a generator for the function table.
Represents a previously generated function, to be added in the register function once it is generated...
const std::string cqasm_name
Name of the function as exposed to cQASM.
Function(const std::string &name, const std::string &args)
Constructs a normal function.
int main(int argc, char *argv[])
Entry point.
const std::string cpp_name
Name of the function implementation as generated in the C++ file.
const std::string cqasm_args
Argument type spec for overload resolution, type checking, and type promotion.
Namespace for the func-gen program.
~Generator()
Finishes writing the header & source file, then destroys the generator.