From 5da63dde25bad77abdf665b16ab54d361b5317f4 Mon Sep 17 00:00:00 2001 From: Sam Yates <yates@cscs.ch> Date: Fri, 20 Jul 2018 17:08:36 +0200 Subject: [PATCH] Refactor modccutil.hpp (#542) Fixes #139. * Split colours and `pprintf(...)` into `io/pprintf.hpp` header. * Remove generic `to_string()` function, replacing its very occasional usage with `pprintf`. * Move block pretty printing into own .cpp file; this is the only place that the vector ostream printer was used. * Remove `enum_hash`, as not needed with C++14. * Move `is_in` utility function to `util.hpp`. * Remove old SIMD printer backend code. --- modcc/CMakeLists.txt | 1 + modcc/blocks.cpp | 79 +++++++++++ modcc/blocks.hpp | 61 ++------- modcc/expression.hpp | 3 +- modcc/functionexpander.cpp | 1 - modcc/functioninliner.cpp | 1 - modcc/io/pprintf.hpp | 82 +++++++++++ modcc/lexer.cpp | 2 +- modcc/memop.hpp | 3 +- modcc/modcc.cpp | 8 +- modcc/modccutil.hpp | 161 ---------------------- modcc/parser.cpp | 14 +- modcc/printer/backends/avx2.hpp | 221 ------------------------------ modcc/printer/backends/avx512.hpp | 162 ---------------------- modcc/printer/backends/base.hpp | 93 ------------- modcc/printer/backends/simd.hpp | 4 - modcc/printer/printerutil.cpp | 2 +- modcc/scope.hpp | 5 +- modcc/util.hpp | 40 ++++++ modcc/visitor.hpp | 1 - test/unit-modcc/common.hpp | 1 - test/unit-modcc/expr_expand.cpp | 12 +- test/unit-modcc/test_parser.cpp | 1 - test/unit-modcc/test_symdiff.cpp | 1 - test/unit-modcc/test_visitors.cpp | 1 - 25 files changed, 238 insertions(+), 722 deletions(-) create mode 100644 modcc/blocks.cpp create mode 100644 modcc/io/pprintf.hpp delete mode 100644 modcc/modccutil.hpp delete mode 100644 modcc/printer/backends/avx2.hpp delete mode 100644 modcc/printer/backends/avx512.hpp delete mode 100644 modcc/printer/backends/base.hpp delete mode 100644 modcc/printer/backends/simd.hpp create mode 100644 modcc/util.hpp diff --git a/modcc/CMakeLists.txt b/modcc/CMakeLists.txt index 23c0f924..6c4d9201 100644 --- a/modcc/CMakeLists.txt +++ b/modcc/CMakeLists.txt @@ -4,6 +4,7 @@ set(libmodcc_sources astmanip.cpp + blocks.cpp errorvisitor.cpp expression.cpp functionexpander.cpp diff --git a/modcc/blocks.cpp b/modcc/blocks.cpp new file mode 100644 index 00000000..bc9d57ec --- /dev/null +++ b/modcc/blocks.cpp @@ -0,0 +1,79 @@ +#include <string> +#include <vector> + +#include "blocks.hpp" +#include "io/pprintf.hpp" +#include "io/ostream_wrappers.hpp" + +// Pretty-printers for block info. + +using namespace io; + +template <typename T> +std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) { + separator s("[", " "); + for (auto& x: v) os << s << x; + os << ']'; + + return os; +} + +std::ostream& operator<<(std::ostream& os, Id const& V) { + if(V.units.size()) + os << "(" << V.token << "," << V.value << "," << V.units << ")"; + else + os << "(" << V.token << "," << V.value << ",)"; + + return os; +} + +std::ostream& operator<<(std::ostream& os, UnitsBlock::units_pair const& p) { + return os << "(" << p.first << ", " << p.second << ")"; +} + +std::ostream& operator<<(std::ostream& os, IonDep const& I) { + return os << "(" << I.name << ": read " << I.read << " write " << I.write << ")"; +} + +std::ostream& operator<<(std::ostream& os, moduleKind const& k) { + return os << (k==moduleKind::density ? "density" : "point process"); +} + +std::ostream& operator<<(std::ostream& os, NeuronBlock const& N) { + os << blue("NeuronBlock") << std::endl; + os << " kind : " << N.kind << std::endl; + os << " name : " << N.name << std::endl; + os << " threadsafe : " << (N.threadsafe ? "yes" : "no") << std::endl; + os << " ranges : " << N.ranges << std::endl; + os << " globals : " << N.globals << std::endl; + os << " ions : " << N.ions << std::endl; + + return os; +} + +std::ostream& operator<<(std::ostream& os, StateBlock const& B) { + os << blue("StateBlock") << std::endl; + return os << " variables : " << B.state_variables << std::endl; + +} + +std::ostream& operator<<(std::ostream& os, UnitsBlock const& U) { + os << blue("UnitsBlock") << std::endl; + os << " aliases : " << U.unit_aliases << std::endl; + + return os; +} + +std::ostream& operator<<(std::ostream& os, ParameterBlock const& P) { + os << blue("ParameterBlock") << std::endl; + os << " parameters : " << P.parameters << std::endl; + + return os; +} + +std::ostream& operator<<(std::ostream& os, AssignedBlock const& A) { + os << blue("AssignedBlock") << std::endl; + os << " parameters : " << A.parameters << std::endl; + + return os; +} diff --git a/modcc/blocks.hpp b/modcc/blocks.hpp index ad31932e..9ba8c657 100644 --- a/modcc/blocks.hpp +++ b/modcc/blocks.hpp @@ -1,13 +1,13 @@ #pragma once #include <algorithm> +#include <iosfwd> #include <string> #include <vector> #include "identifier.hpp" #include "location.hpp" #include "token.hpp" -#include "modccutil.hpp" // describes a relationship with an ion channel struct IonDep { @@ -152,62 +152,21 @@ struct AssignedBlock { //////////////////////////////////////////////// // helpers for pretty printing block information //////////////////////////////////////////////// -inline std::ostream& operator<< (std::ostream& os, Id const& V) { - if(V.units.size()) - os << "(" << V.token << "," << V.value << "," << V.units << ")"; - else - os << "(" << V.token << "," << V.value << ",)"; - return os; -} +std::ostream& operator<<(std::ostream& os, Id const& V); -inline std::ostream& operator<< (std::ostream& os, UnitsBlock::units_pair const& p) { - return os << "(" << p.first << ", " << p.second << ")"; -} +std::ostream& operator<<(std::ostream& os, UnitsBlock::units_pair const& p); -inline std::ostream& operator<< (std::ostream& os, IonDep const& I) { - return os << "(" << I.name << ": read " << I.read << " write " << I.write << ")"; -} +std::ostream& operator<<(std::ostream& os, IonDep const& I); -inline std::ostream& operator<< (std::ostream& os, moduleKind const& k) { - return os << (k==moduleKind::density ? "density" : "point process"); -} +std::ostream& operator<<(std::ostream& os, moduleKind const& k); -inline std::ostream& operator<< (std::ostream& os, NeuronBlock const& N) { - os << blue("NeuronBlock") << std::endl; - os << " kind : " << N.kind << std::endl; - os << " name : " << N.name << std::endl; - os << " threadsafe : " << (N.threadsafe ? "yes" : "no") << std::endl; - os << " ranges : " << N.ranges << std::endl; - os << " globals : " << N.globals << std::endl; - os << " ions : " << N.ions << std::endl; +std::ostream& operator<<(std::ostream& os, NeuronBlock const& N); - return os; -} +std::ostream& operator<<(std::ostream& os, StateBlock const& B); -inline std::ostream& operator<< (std::ostream& os, StateBlock const& B) { - os << blue("StateBlock") << std::endl; - return os << " variables : " << B.state_variables << std::endl; +std::ostream& operator<<(std::ostream& os, UnitsBlock const& U); -} +std::ostream& operator<<(std::ostream& os, ParameterBlock const& P); -inline std::ostream& operator<< (std::ostream& os, UnitsBlock const& U) { - os << blue("UnitsBlock") << std::endl; - os << " aliases : " << U.unit_aliases << std::endl; - - return os; -} - -inline std::ostream& operator<< (std::ostream& os, ParameterBlock const& P) { - os << blue("ParameterBlock") << std::endl; - os << " parameters : " << P.parameters << std::endl; - - return os; -} - -inline std::ostream& operator<< (std::ostream& os, AssignedBlock const& A) { - os << blue("AssignedBlock") << std::endl; - os << " parameters : " << A.parameters << std::endl; - - return os; -} +std::ostream& operator<<(std::ostream& os, AssignedBlock const& A); diff --git a/modcc/expression.hpp b/modcc/expression.hpp index dd018629..1b793591 100644 --- a/modcc/expression.hpp +++ b/modcc/expression.hpp @@ -11,7 +11,8 @@ #include "identifier.hpp" #include "memop.hpp" #include "scope.hpp" -#include "modccutil.hpp" + +#include "io/pprintf.hpp" class Visitor; diff --git a/modcc/functionexpander.cpp b/modcc/functionexpander.cpp index aedf9f16..a6b44330 100644 --- a/modcc/functionexpander.cpp +++ b/modcc/functionexpander.cpp @@ -4,7 +4,6 @@ #include "astmanip.hpp" #include "error.hpp" #include "functionexpander.hpp" -#include "modccutil.hpp" expression_ptr insert_unique_local_assignment(expr_list_type& stmts, Expression* e) { auto exprs = make_unique_local_assign(e->scope(), e); diff --git a/modcc/functioninliner.cpp b/modcc/functioninliner.cpp index a652c60a..da5dd5eb 100644 --- a/modcc/functioninliner.cpp +++ b/modcc/functioninliner.cpp @@ -2,7 +2,6 @@ #include "error.hpp" #include "functioninliner.hpp" -#include "modccutil.hpp" #include "errorvisitor.hpp" expression_ptr inline_function_call(Expression* e) diff --git a/modcc/io/pprintf.hpp b/modcc/io/pprintf.hpp new file mode 100644 index 00000000..474b84ce --- /dev/null +++ b/modcc/io/pprintf.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include <sstream> +#include <string> + +//'\e[1;31m' # Red +//'\e[1;32m' # Green +//'\e[1;33m' # Yellow +//'\e[1;34m' # Blue +//'\e[1;35m' # Purple +//'\e[1;36m' # Cyan +//'\e[1;37m' # White +enum class stringColor {white, red, green, blue, yellow, purple, cyan}; + +inline std::string colorize(std::string const& s, stringColor c) { + switch(c) { + case stringColor::white : + return "\033[1;37m" + s + "\033[0m"; + case stringColor::red : + return "\033[1;31m" + s + "\033[0m"; + case stringColor::green : + return "\033[1;32m" + s + "\033[0m"; + case stringColor::blue : + return "\033[1;34m" + s + "\033[0m"; + case stringColor::yellow: + return "\033[1;33m" + s + "\033[0m"; + case stringColor::purple: + return "\033[1;35m" + s + "\033[0m"; + case stringColor::cyan : + return "\033[1;36m" + s + "\033[0m"; + } + return s; +} + +// helpers for inline printing +inline std::string red(std::string const& s) { + return colorize(s, stringColor::red); +} +inline std::string green(std::string const& s) { + return colorize(s, stringColor::green); +} +inline std::string yellow(std::string const& s) { + return colorize(s, stringColor::yellow); +} +inline std::string blue(std::string const& s) { + return colorize(s, stringColor::blue); +} +inline std::string purple(std::string const& s) { + return colorize(s, stringColor::purple); +} +inline std::string cyan(std::string const& s) { + return colorize(s, stringColor::cyan); +} +inline std::string white(std::string const& s) { + return colorize(s, stringColor::white); +} + +// variadic printf for easy error messages + +inline std::string pprintf(const char* s) { + return s; +} + +template <typename T, typename ... Args> +std::string pprintf(const char *s, T value, Args... args) { + std::string errstring; + while(*s) { + if(*s == '%' && s[1]!='%') { + std::stringstream str; + str << value; + errstring += str.str(); + errstring += pprintf(++s, args...); + return errstring; + } + else { + errstring += *s; + ++s; + } + } + return errstring; +} + diff --git a/modcc/lexer.cpp b/modcc/lexer.cpp index 48a4e426..a2bb90af 100644 --- a/modcc/lexer.cpp +++ b/modcc/lexer.cpp @@ -4,7 +4,7 @@ #include <string> #include "lexer.hpp" -#include "modccutil.hpp" +#include "io/pprintf.hpp" // helpers for identifying character types inline bool in_range(char c, char first, char last) { diff --git a/modcc/memop.hpp b/modcc/memop.hpp index e962a785..48232ae4 100644 --- a/modcc/memop.hpp +++ b/modcc/memop.hpp @@ -1,7 +1,8 @@ #pragma once -#include "modccutil.hpp" +#include "io/pprintf.hpp" #include "lexer.hpp" +#include "util.hpp" /// Defines a memory operation that is to performed by an APIMethod. /// Kernels can read/write global state via an index, e.g. diff --git a/modcc/modcc.cpp b/modcc/modcc.cpp index 13dd6003..06556f1a 100644 --- a/modcc/modcc.cpp +++ b/modcc/modcc.cpp @@ -12,12 +12,12 @@ #include "printer/printeropt.hpp" #include "printer/simd.hpp" -#include "modccutil.hpp" #include "module.hpp" #include "parser.hpp" #include "perfvisitor.hpp" #include "io/bulkio.hpp" +#include "io/pprintf.hpp" using std::cout; using std::cerr; @@ -68,7 +68,7 @@ struct Options { std::string modulename; bool verbose = true; bool analysis = false; - std::unordered_set<targetKind, enum_hash> targets; + std::unordered_set<targetKind> targets; }; // Helper for formatting tabulated output (option reporting). @@ -218,7 +218,7 @@ int main(int argc, char **argv) { } } catch(TCLAP::ArgException &e) { - return report_error(e.error()+" for argument "+to_string(e.argId())); + return report_error(pprintf("% for argument %", e.error(), e.argId())); } try { @@ -312,7 +312,7 @@ int main(int argc, char **argv) { return report_error(e.what()); } catch (compiler_exception& e) { - return report_ice(e.what()+std::string(" @ ")+to_string(e.location())); + return report_ice(pprintf("% @ %", e.what(), e.location())); } catch (std::exception& e) { return report_ice(e.what()); diff --git a/modcc/modccutil.hpp b/modcc/modccutil.hpp deleted file mode 100644 index 58dc7d1a..00000000 --- a/modcc/modccutil.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include <exception> -#include <memory> -#include <sstream> -#include <vector> -#include <initializer_list> - -namespace impl { - template <typename C, typename V> - struct has_count_method { - template <typename T, typename U> - static decltype(std::declval<T>().count(std::declval<U>()), std::true_type{}) test(int); - template <typename T, typename U> - static std::false_type test(...); - - using type = decltype(test<C, V>(0)); - }; - - template <typename X, typename C> - bool is_in(const X& x, const C& c, std::false_type) { - for (const auto& y: c) { - if (y==x) return true; - } - return false; - } - - template <typename X, typename C> - bool is_in(const X& x, const C& c, std::true_type) { - return !!c.count(x); - } -} - -template <typename X, typename C> -bool is_in(const X& x, const C& c) { - return impl::is_in(x, c, typename impl::has_count_method<C,X>::type{}); -} - -template <typename X> -bool is_in(const X& x, const std::initializer_list<X>& c) { - return impl::is_in(x, c, std::false_type{}); -} - -struct enum_hash { - template <typename E, typename V = typename std::underlying_type<E>::type> - std::size_t operator()(E e) const noexcept { - return std::hash<V>{}(static_cast<V>(e)); - } -}; - -inline std::string pprintf(const char *s) { - std::string errstring; - while(*s) { - if(*s == '%' && s[1]!='%') { - // instead of throwing an exception, replace with ?? - //throw std::runtime_error("pprintf: the number of arguments did not match the format "); - errstring += "<?>"; - } - else { - errstring += *s; - } - ++s; - } - return errstring; -} - -// variadic printf for easy error messages -template <typename T, typename ... Args> -std::string pprintf(const char *s, T value, Args... args) { - std::string errstring; - while(*s) { - if(*s == '%' && s[1]!='%') { - std::stringstream str; - str << value; - errstring += str.str(); - errstring += pprintf(++s, args...); - return errstring; - } - else { - errstring += *s; - ++s; - } - } - return errstring; -} - -template <typename T> -std::string to_string(T val) { - std::stringstream str; - str << val; - return str.str(); -} - -//'\e[1;31m' # Red -//'\e[1;32m' # Green -//'\e[1;33m' # Yellow -//'\e[1;34m' # Blue -//'\e[1;35m' # Purple -//'\e[1;36m' # Cyan -//'\e[1;37m' # White -enum class stringColor {white, red, green, blue, yellow, purple, cyan}; - -#define COLOR_PRINTING -#ifdef COLOR_PRINTING -inline std::string colorize(std::string const& s, stringColor c) { - switch(c) { - case stringColor::white : - return "\033[1;37m" + s + "\033[0m"; - case stringColor::red : - return "\033[1;31m" + s + "\033[0m"; - case stringColor::green : - return "\033[1;32m" + s + "\033[0m"; - case stringColor::blue : - return "\033[1;34m" + s + "\033[0m"; - case stringColor::yellow: - return "\033[1;33m" + s + "\033[0m"; - case stringColor::purple: - return "\033[1;35m" + s + "\033[0m"; - case stringColor::cyan : - return "\033[1;36m" + s + "\033[0m"; - } - return s; -} -#else -inline std::string colorize(std::string const& s, stringColor c) { - return s; -} -#endif - -// helpers for inline printing -inline std::string red(std::string const& s) { - return colorize(s, stringColor::red); -} -inline std::string green(std::string const& s) { - return colorize(s, stringColor::green); -} -inline std::string yellow(std::string const& s) { - return colorize(s, stringColor::yellow); -} -inline std::string blue(std::string const& s) { - return colorize(s, stringColor::blue); -} -inline std::string purple(std::string const& s) { - return colorize(s, stringColor::purple); -} -inline std::string cyan(std::string const& s) { - return colorize(s, stringColor::cyan); -} -inline std::string white(std::string const& s) { - return colorize(s, stringColor::white); -} - -template <typename T> -std::ostream& operator<< (std::ostream& os, std::vector<T> const& V) { - os << "["; - for(auto it = V.begin(); it!=V.end(); ++it) { // ugly loop, pretty printing - os << *it << (it==V.end()-1 ? "" : " "); - } - return os << "]"; -} - diff --git a/modcc/parser.cpp b/modcc/parser.cpp index d912a441..6ce9258b 100644 --- a/modcc/parser.cpp +++ b/modcc/parser.cpp @@ -4,7 +4,9 @@ #include "parser.hpp" #include "perfvisitor.hpp" #include "token.hpp" -#include "modccutil.hpp" +#include "util.hpp" + +#include "io/pprintf.hpp" // specialize on const char* for lazy evaluation of compile time strings bool Parser::expect(tok tok, const char* str) { @@ -1545,9 +1547,8 @@ expression_ptr Parser::parse_block(bool is_nested) { } if(token_.type != tok::rbrace) { - error("could not find closing '" + yellow("}") - + "' for else statement that started at " - + ::to_string(block_location)); + error(pprintf("could not find closing '%' for else statement that started at ", + yellow("}"), block_location)); return nullptr; } get_token(); // consume closing '}' @@ -1582,9 +1583,8 @@ expression_ptr Parser::parse_initial() { } if(token_.type != tok::rbrace) { - error("could not find closing '" + yellow("}") - + "' for else statement that started at " - + ::to_string(block_location)); + error(pprintf("could not find closing '%' for else statement that started at ", + yellow("}"), block_location)); return nullptr; } get_token(); // consume closing '}' diff --git a/modcc/printer/backends/avx2.hpp b/modcc/printer/backends/avx2.hpp deleted file mode 100644 index d72f48ea..00000000 --- a/modcc/printer/backends/avx2.hpp +++ /dev/null @@ -1,221 +0,0 @@ -// -// AVX2 backend -// - -#pragma once - -#include "backends/base.hpp" -#include "util/compat.hpp" - -namespace modcc { - -// Specialize for the different architectures -template<> -struct simd_intrinsics<simdKind::avx2> { - static bool has_scatter() { - return false; - } - - static bool has_gather() { - return true; - } - - static std::string emit_headers() { - /* - std::string ret = "#include <immintrin.h>"; - ret += "\n#include <backends/multicore/intrin.hpp>"; - if (!compat::using_intel_compiler()) { - ret += "\n#include <backends/multicore/intrin.hpp>"; - } - return ret; - */ - - return - "#include <immintrin.h>\n" - "#include <backends/multicore/intrin.hpp>"; - } - - static std::string emit_simd_width() { - return "256"; - } - - static std::string emit_value_type() { - return "__m256d"; - } - - static std::string emit_index_type() { - return "__m128i"; - } - - template<typename T1, typename T2> - static void emit_binary_op(TextBuffer& tb, tok op, - const T1& arg1, const T2& arg2) { - switch (op) { - case tok::plus: - tb << "_mm256_add_pd("; - break; - case tok::minus: - tb << "_mm256_sub_pd("; - break; - case tok::times: - tb << "_mm256_mul_pd("; - break; - case tok::divide: - tb << "_mm256_div_pd("; - break; - case tok::max: - tb << "_mm256_max_pd("; - break; - case tok::min: - tb << "arb::multicore::arb_mm256_min_pd("; - break; - default: - throw std::invalid_argument("Unable to generate avx2 for binary operator " + token_map[op]); - } - - emit_operands(tb, arg_emitter(arg1), arg_emitter(arg2)); - tb << ")"; - } - - template<typename T> - static void emit_unary_op(TextBuffer& tb, tok op, const T& arg) { - switch (op) { - case tok::minus: - tb << "_mm256_sub_pd(_mm256_set1_pd(0), "; - break; - case tok::exp: - if (compat::using_intel_compiler()) { - tb << "_mm256_exp_pd("; - } - else { - tb << "arb::multicore::arb_mm256_exp_pd("; - } - break; - case tok::log: - if (compat::using_intel_compiler()) { - tb << "_mm256_log_pd("; - } - else { - tb << "arb::multicore::arb_mm256_log_pd("; - } - break; - case tok::abs: - tb << "arb::multicore::arb_mm256_abs_pd("; - break; - case tok::exprelr: - tb << "arb::multicore::arb_mm256_exprelr_pd("; - break; - default: - throw std::invalid_argument("Unable to generate avx2 for unary operator " + token_map[op]); - } - - emit_operands(tb, arg_emitter(arg)); - tb << ")"; - } - - template<typename B, typename E> - static void emit_pow(TextBuffer& tb, const B& base, const E& exp) { - if (compat::using_intel_compiler()) { - tb << "_mm256_pow_pd("; - } - else { - tb << "arb::multicore::arb_mm256_pow_pd("; - } - - emit_operands(tb, arg_emitter(base), arg_emitter(exp)); - tb << ")"; - } - - template<typename A, typename V> - static void emit_store_unaligned(TextBuffer& tb, const A& addr, - const V& value) { - tb << "_mm256_storeu_pd("; - emit_operands(tb, arg_emitter(addr), arg_emitter(value)); - tb << ")"; - } - - template<typename A> - static void emit_load_unaligned(TextBuffer& tb, const A& addr) { - tb << "_mm256_loadu_pd("; - emit_operands(tb, arg_emitter(addr)); - tb << ")"; - } - - template<typename A> - static void emit_load_index(TextBuffer& tb, const A& addr) { - tb << "_mm_lddqu_si128("; - emit_operands(tb, arg_emitter(addr)); - tb << ")"; - } - - template<typename A, typename I, typename V, typename S> - static void emit_scatter(TextBuffer& tb, const A& addr, - const I& index, const V& value, const S& scale) { - // no support of scatter in AVX2, so revert to simple scalar updates - std::string scalar_index_ptr = varprefix + std::to_string(varcnt++); - std::string scalar_value_ptr = varprefix + std::to_string(varcnt++); - - tb.end_line("{"); - tb.increase_indentation(); - - // FIXME: should probably read "index_type*" - tb.add_gutter(); - tb << "int* " << scalar_index_ptr - << " = (int*) &" << index; - tb.end_line(";"); - - tb.add_gutter(); - tb << "value_type* " << scalar_value_ptr - << " = (value_type*) &" << value; - tb.end_line(";"); - - tb.add_line("for (int k_ = 0; k_ < simd_width; ++k_) {"); - tb.increase_indentation(); - tb.add_gutter(); - tb << addr << "[" << scalar_index_ptr << "[k_]] = " - << scalar_value_ptr << "[k_]"; - tb.end_line(";"); - - tb.decrease_indentation(); - tb.add_line("}"); - - tb.decrease_indentation(); - tb.add_gutter(); - tb << "}"; - } - - template<typename A, typename I, typename S> - static void emit_gather(TextBuffer& tb, const A& addr, - const I& index, const S& scale) { - tb << "_mm256_i32gather_pd("; - emit_operands(tb, arg_emitter(addr), arg_emitter(index), - arg_emitter(scale)); - tb << ")"; - } - - // In avx2 require 4-wide gather of i32 indices. - template<typename A, typename I, typename S> - static void emit_gather_index(TextBuffer& tb, const A& addr, - const I& index, const S& scale) { - tb << "_mm_i32gather_epi32("; - emit_operands(tb, arg_emitter(addr), arg_emitter(index), - arg_emitter(scale)); - tb << ")"; - } - - template<typename T> - static void emit_set_value(TextBuffer& tb, const T& arg) { - tb << "_mm256_set1_pd("; - emit_operands(tb, arg_emitter(arg)); - tb << ")"; - } - -private: - static int varcnt; - const static std::string varprefix; -}; - -int simd_intrinsics<simdKind::avx2>::varcnt = 0; -const std::string simd_intrinsics<simdKind::avx2>::varprefix = "_r"; - -} // namespace modcc diff --git a/modcc/printer/backends/avx512.hpp b/modcc/printer/backends/avx512.hpp deleted file mode 100644 index 2d856349..00000000 --- a/modcc/printer/backends/avx512.hpp +++ /dev/null @@ -1,162 +0,0 @@ -// -// AVX512 backend -// - -#pragma once - -#include "backends/base.hpp" - -namespace modcc { - -// Specialize for the different architectures -template<> -struct simd_intrinsics<simdKind::avx512> { - - static bool has_scatter() { - return true; - } - - static bool has_gather() { - return true; - } - - static std::string emit_headers() { - return - "#include <immintrin.h>\n" - "#include <backends/multicore/intrin.hpp>"; - }; - - static std::string emit_simd_width() { - return "512"; - } - - static std::string emit_value_type() { - return "vecd_avx512"; - } - - static std::string emit_index_type() { - return "__m256i"; - } - - template<typename T1, typename T2> - static void emit_binary_op(TextBuffer& tb, tok op, - const T1& arg1, const T2& arg2) { - switch (op) { - case tok::plus: - tb << "add("; - break; - case tok::minus: - tb << "sub("; - break; - case tok::times: - tb << "mul("; - break; - case tok::divide: - tb << "div("; - break; - case tok::max: - tb << "max("; - break; - case tok::min: - tb << "min("; - break; - default: - throw std::invalid_argument("Unable to generate avx512 for binary operator " + token_map[op]); - } - - emit_operands(tb, arg_emitter(arg1), arg_emitter(arg2)); - tb << ")"; - } - - template<typename T> - static void emit_unary_op(TextBuffer& tb, tok op, const T& arg) { - switch (op) { - case tok::minus: - tb << "sub(set(0), "; - break; - case tok::exp: - tb << "_mm512_exp_pd("; - break; - case tok::log: - tb << "_mm512_log_pd("; - break; - case tok::abs: - tb << "abs("; - break; - case tok::exprelr: - tb << "exprelr("; - break; - default: - throw std::invalid_argument("Unable to generate avx512 for unary operator " + token_map[op]); - } - - emit_operands(tb, arg_emitter(arg)); - tb << ")"; - } - - template<typename B, typename E> - static void emit_pow(TextBuffer& tb, const B& base, const E& exp) { - tb << "_mm512_pow_pd("; - emit_operands(tb, arg_emitter(base), arg_emitter(exp)); - tb << ")"; - } - - template<typename A, typename V> - static void emit_store_unaligned(TextBuffer& tb, const A& addr, - const V& value) { - tb << "_mm512_storeu_pd("; - emit_operands(tb, arg_emitter(addr), arg_emitter(value)); - tb << ")"; - } - - template<typename A> - static void emit_load_unaligned(TextBuffer& tb, const A& addr) { - tb << "_mm512_loadu_pd("; - emit_operands(tb, arg_emitter(addr)); - tb << ")"; - } - - template<typename A> - static void emit_load_index(TextBuffer& tb, const A& addr) { - tb << "_mm256_lddqu_si256("; - emit_operands(tb, arg_emitter(addr)); - tb << ")"; - } - - template<typename A, typename I, typename V, typename S> - static void emit_scatter(TextBuffer& tb, const A& addr, - const I& index, const V& value, const S& scale) { - tb << "_mm512_i32scatter_pd("; - emit_operands(tb, arg_emitter(addr), arg_emitter(index), - arg_emitter(value), arg_emitter(scale)); - tb << ")"; - } - - template<typename A, typename I, typename S> - static void emit_gather(TextBuffer& tb, const A& addr, - const I& index, const S& scale) { - tb << "_mm512_i32gather_pd("; - emit_operands(tb, arg_emitter(index), arg_emitter(addr), - arg_emitter(scale)); - tb << ")"; - } - - // In avx512 require 8-wide gather of i32 indices. - template<typename A, typename I, typename S> - static void emit_gather_index(TextBuffer& tb, const A& addr, - const I& index, const S& scale) { - tb << "_mm256_i32gather_epi32("; - emit_operands(tb, arg_emitter(addr), arg_emitter(index), - arg_emitter(scale)); - tb << ")"; - } - - template<typename T> - static void emit_set_value(TextBuffer& tb, const T& arg) { - tb << "set("; - emit_operands(tb, arg_emitter(arg)); - tb << ")"; - } -}; - -} // namespace modcc diff --git a/modcc/printer/backends/base.hpp b/modcc/printer/backends/base.hpp deleted file mode 100644 index b0b9398e..00000000 --- a/modcc/printer/backends/base.hpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Base SIMD backend functionality -// - -#pragma once - -#include <functional> -#include <stdexcept> -#include <string> -#include <type_traits> - -#include "token.hpp" -#include "textbuffer.hpp" - -enum class simdKind { - none, avx2, avx512 -}; - -namespace modcc { - -template <bool V, typename R = void> -using enable_if_t = typename std::enable_if<V, R>::type; - -using operand_fn_t = std::function<void(TextBuffer&)>; - -static void emit_operands(TextBuffer& tb, operand_fn_t emitter) { - emitter(tb); -} - -template<typename ... Args> -static void emit_operands(TextBuffer& tb, operand_fn_t emitter, Args ... args) { - emitter(tb); - tb << ", "; - emit_operands(tb, args ...); -} - -template<typename T> -static enable_if_t<!std::is_convertible<T, operand_fn_t>::value, operand_fn_t> -arg_emitter(const T& arg) { - return [arg](TextBuffer& tb) { tb << arg; }; -} - -static operand_fn_t arg_emitter(const operand_fn_t& arg) { - return arg; -} - -template<simdKind Arch> -struct simd_intrinsics { - static std::string emit_headers(); - static std::string emit_simd_width(); - static std::string emit_simd_value_type(); - static std::string emit_simd_index_type(); - - template<typename T1, typename T2> - static void emit_binary_op(TextBuffer& tb, tok op, - const T1& arg1, const T2& arg2); - - template<typename T> - static void emit_unary_op(TextBuffer& tb, tok op, const T& arg); - - template<typename B, typename E> - static void emit_pow(TextBuffer& tb, const B& base, const E& exp); - - template<typename A, typename V> - static void emit_store_unaligned(TextBuffer& tb, const A& addr, const V& value); - - template<typename A> - static void emit_load_unaligned(TextBuffer& tb, const A& addr); - - template<typename A> - static void emit_load_index(TextBuffer& tb, const A& addr); - - template<typename A, typename I, typename V, typename S> - static void emit_scatter(TextBuffer& tb, const A& addr, - const I& index, const V& value, const S& scale); - - template<typename A, typename I, typename S> - static void emit_gather(TextBuffer& tb, const A& addr, - const I& index, const S& scale); - - // int32 value version of `emit_gather` to look up cell indices - template<typename A, typename I, typename S> - static void emit_gather_index(TextBuffer& tb, const A& addr, - const I& index, const S& scale); - - template<typename T> - static void emit_set_value(TextBuffer& tb, const T& arg); - - static bool has_gather(); - static bool has_scatter(); -}; - -} // namespace modcc diff --git a/modcc/printer/backends/simd.hpp b/modcc/printer/backends/simd.hpp deleted file mode 100644 index 63c034d7..00000000 --- a/modcc/printer/backends/simd.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#include "backends/avx2.hpp" -#include "backends/avx512.hpp" diff --git a/modcc/printer/printerutil.cpp b/modcc/printer/printerutil.cpp index 12df7d87..6050fa06 100644 --- a/modcc/printer/printerutil.cpp +++ b/modcc/printer/printerutil.cpp @@ -145,7 +145,7 @@ indexed_variable_info decode_indexed_variable(IndexedVariable* sym) { data_var=ion_pfx+".external_concentration"; break; default: - throw compiler_exception("unrecognized indexed data source: "+to_string(sym), sym->location()); + throw compiler_exception(pprintf("unrecognized indexed data source: %", sym), sym->location()); } return {data_var, index_var}; diff --git a/modcc/scope.hpp b/modcc/scope.hpp index 831a3e6d..be2eee29 100644 --- a/modcc/scope.hpp +++ b/modcc/scope.hpp @@ -1,11 +1,12 @@ #pragma once -#include "modccutil.hpp" - #include <memory> #include <string> #include <unordered_map> +#include "io/pprintf.hpp" + + // Scope is templated to avoid circular compilation issues. // When performing semantic analysis of expressions via traversal of the AST // each node in the AST has a reference to a Scope. This leads to circular diff --git a/modcc/util.hpp b/modcc/util.hpp new file mode 100644 index 00000000..5d39e311 --- /dev/null +++ b/modcc/util.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include <type_traits> +#include <initializer_list> + +namespace impl { + template <typename C, typename V> + struct has_count_method { + template <typename T, typename U> + static decltype(std::declval<T>().count(std::declval<U>()), std::true_type{}) test(int); + template <typename T, typename U> + static std::false_type test(...); + + using type = decltype(test<C, V>(0)); + }; + + template <typename X, typename C> + bool is_in(const X& x, const C& c, std::false_type) { + for (const auto& y: c) { + if (y==x) return true; + } + return false; + } + + template <typename X, typename C> + bool is_in(const X& x, const C& c, std::true_type) { + return !!c.count(x); + } +} + +template <typename X, typename C> +bool is_in(const X& x, const C& c) { + return impl::is_in(x, c, typename impl::has_count_method<C,X>::type{}); +} + +template <typename X> +bool is_in(const X& x, const std::initializer_list<X>& c) { + return impl::is_in(x, c, std::false_type{}); +} + diff --git a/modcc/visitor.hpp b/modcc/visitor.hpp index 8179b977..b6ae70ca 100644 --- a/modcc/visitor.hpp +++ b/modcc/visitor.hpp @@ -2,7 +2,6 @@ #include "error.hpp" #include "expression.hpp" -#include "modccutil.hpp" /// visitor base class /// The visitors for all AST nodes throw an exception diff --git a/test/unit-modcc/common.hpp b/test/unit-modcc/common.hpp index d0059e3c..e5e4ac6f 100644 --- a/test/unit-modcc/common.hpp +++ b/test/unit-modcc/common.hpp @@ -6,7 +6,6 @@ #include "expression.hpp" #include "parser.hpp" -#include "modccutil.hpp" extern bool g_verbose_flag; diff --git a/test/unit-modcc/expr_expand.cpp b/test/unit-modcc/expr_expand.cpp index 340acdcc..0dd1f3f0 100644 --- a/test/unit-modcc/expr_expand.cpp +++ b/test/unit-modcc/expr_expand.cpp @@ -2,7 +2,7 @@ #include <sstream> #include "expression.hpp" -#include "modccutil.hpp" +#include "io/pprintf.hpp" #include "token.hpp" #include "alg_collect.hpp" @@ -47,7 +47,7 @@ alg::prodsum expand_expression(Expression* e, const id_prodsum_map& exmap) { case tok::pow: if (!rhs.is_scalar()) { // make an opaque term for this case (i.e. too hard to simplify) - return prodterm("("+to_string(lhs)+")^("+to_string(rhs)+")"); + return prodterm(pprintf("(%)^(%)", lhs, rhs)); } else return lhs.pow(rhs.first_coeff()); default: @@ -60,13 +60,13 @@ alg::prodsum expand_expression(Expression* e, const id_prodsum_map& exmap) { case tok::minus: return -inner; case tok::exp: - return prodterm("exp("+to_string(inner)+")"); + return prodterm(pprintf("exp(%)", inner)); case tok::log: - return prodterm("log("+to_string(inner)+")"); + return prodterm(pprintf("log(%)", inner)); case tok::sin: - return prodterm("sin("+to_string(inner)+")"); + return prodterm(pprintf("sin(%)", inner)); case tok::cos: - return prodterm("cos("+to_string(inner)+")"); + return prodterm(pprintf("cos(%)", inner)); default: throw std::runtime_error("unrecognized unaryop"); } diff --git a/test/unit-modcc/test_parser.cpp b/test/unit-modcc/test_parser.cpp index 75ae2a62..6e83fc28 100644 --- a/test/unit-modcc/test_parser.cpp +++ b/test/unit-modcc/test_parser.cpp @@ -4,7 +4,6 @@ #include "common.hpp" #include "module.hpp" -#include "modccutil.hpp" #include "parser.hpp" #include "io/bulkio.hpp" diff --git a/test/unit-modcc/test_symdiff.cpp b/test/unit-modcc/test_symdiff.cpp index 9cc1ded5..410e7700 100644 --- a/test/unit-modcc/test_symdiff.cpp +++ b/test/unit-modcc/test_symdiff.cpp @@ -4,7 +4,6 @@ #include "symdiff.hpp" #include "parser.hpp" -#include "modccutil.hpp" // Test visitors for extended constant reduction, // identifier presence detection and symbolic differentiation. diff --git a/test/unit-modcc/test_visitors.cpp b/test/unit-modcc/test_visitors.cpp index 8a516001..348e4a8d 100644 --- a/test/unit-modcc/test_visitors.cpp +++ b/test/unit-modcc/test_visitors.cpp @@ -2,7 +2,6 @@ #include "perfvisitor.hpp" #include "parser.hpp" -#include "modccutil.hpp" // overload for parser errors template <typename EPtr> -- GitLab