netlist: Add parse optimization to pfunction.

* "(1 + 2)*a" now during parse step will be rewritten to "3*a".
This commit is contained in:
couriersud 2020-10-02 19:33:22 +02:00
parent 58b4e89c0c
commit 1dcedeee9d
2 changed files with 100 additions and 21 deletions

View File

@ -157,6 +157,7 @@ namespace plib {
} }
if (stk != 1) if (stk != 1)
throw pexception(plib::pfmt("pfunction: stack count {1} different to one on <{2}>")(stk, expr)); throw pexception(plib::pfmt("pfunction: stack count {1} different to one on <{2}>")(stk, expr));
compress();
} }
static bool is_number(const pstring &n) static bool is_number(const pstring &n)
@ -339,25 +340,29 @@ namespace plib {
return narrow_cast<NT>(lfsr); return narrow_cast<NT>(lfsr);
} }
#endif #endif
#define ST0 stack[ptr+1] #define ST0 *(ptr+1)
#define ST1 stack[ptr] #define ST1 *ptr
#define ST2 stack[ptr-1] #define ST2 *(ptr-1)
#define OP(OP, ADJ, EXPR) \ #define OP(OP, ADJ, EXPR) \
case OP: \ case OP: \
ptr-= (ADJ); \ ptr-= (ADJ); \
stack[ptr-1] = (EXPR); \ *(ptr-1) = (EXPR); \
break;
#define OP0(OP, EXPR) \
case OP: \
*(ptr++) = (EXPR); \
break; break;
template <typename NT> template <typename NT>
NT pfunction<NT>::evaluate(const values_container &values) noexcept NT pfunction<NT>::evaluate(const values_container &values) noexcept
{ {
std::array<value_type, MAX_STACK> stack = { plib::constants<value_type>::zero() }; std::array<value_type, MAX_STACK> stack;
unsigned ptr = 0; value_type *ptr = stack.data();
constexpr auto zero = plib::constants<value_type>::zero(); constexpr const auto zero = plib::constants<value_type>::zero();
constexpr auto one = plib::constants<value_type>::one(); constexpr const auto one = plib::constants<value_type>::one();
stack[0] = plib::constants<value_type>::zero(); for (const auto &rc : m_precompiled)
for (auto &rc : m_precompiled)
{ {
switch (rc.m_cmd) switch (rc.m_cmd)
{ {
@ -379,23 +384,92 @@ namespace plib {
OP(COS, 0, plib::cos(ST2)) OP(COS, 0, plib::cos(ST2))
OP(MAX, 1, std::max(ST2, ST1)) OP(MAX, 1, std::max(ST2, ST1))
OP(MIN, 1, std::min(ST2, ST1)) OP(MIN, 1, std::min(ST2, ST1))
OP(TRUNC, 0, plib::trunc(ST2)) OP(TRUNC, 0, plib::trunc(ST2))
case RAND: OP0(RAND, lfsr_random<value_type>(m_lfsr))
stack[ptr++] = lfsr_random<value_type>(m_lfsr); OP0(PUSH_INPUT, values[rc.m_param.index])
break; OP0(PUSH_CONST, rc.m_param.val)
case PUSH_INPUT:
stack[ptr++] = values[rc.m_param.index];
break;
case PUSH_CONST:
stack[ptr++] = rc.m_param.val;
break;
// please compiler // please compiler
case LP: case LP:
case RP: case RP:
break; break;
} }
} }
return stack[ptr-1]; return *(ptr-1);
}
#undef ST0
#undef ST1
#undef ST2
#undef OP
#undef OP0
#define ST0 m_precompiled[ptr+0].m_param.val
#define ST1 m_precompiled[ptr-1].m_param.val
#define ST2 m_precompiled[ptr-2].m_param.val
#define OP(OP, ADJ, EXPR) \
case OP: \
if (ADJ == 2) {\
if (m_precompiled[ptr-3].m_cmd == PUSH_CONST && m_precompiled[ptr-2].m_cmd == PUSH_CONST && m_precompiled[ptr-1].m_cmd == PUSH_CONST) \
{ ptr--; m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 3; ptr++; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr-2)); ptr-=2;} \
else { ptr++; } \
} else if (ADJ == 1) {\
if (m_precompiled[ptr-2].m_cmd == PUSH_CONST && m_precompiled[ptr-1].m_cmd == PUSH_CONST) \
{ m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 2; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr-1)); ptr--;} \
else { ptr++; } \
} else if (ADJ == 0) {\
if (m_precompiled[ptr-1].m_cmd == PUSH_CONST) \
{ ptr++; m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 1; ptr--; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr)); } \
else { ptr++; } \
} else ptr++; \
break;
#define OP0(OP, EXPR) \
case OP: \
ptr++; \
break;
template <typename NT>
void pfunction<NT>::compress()
{
constexpr const auto zero = plib::constants<value_type>::zero();
constexpr const auto one = plib::constants<value_type>::one();
unsigned ptr = 0;
auto n = m_precompiled.size();
for (; ptr < n; )
{
switch (m_precompiled[ptr].m_cmd)
{
OP(ADD, 1, ST2 + ST1)
OP(MULT, 1, ST2 * ST1)
OP(SUB, 1, ST2 - ST1)
OP(DIV, 1, ST2 / ST1)
OP(EQ, 1, ST2 == ST1 ? one : zero)
OP(NE, 1, ST2 != ST1 ? one : zero)
OP(GT, 1, ST2 > ST1 ? one : zero)
OP(LT, 1, ST2 < ST1 ? one : zero)
OP(LE, 1, ST2 <= ST1 ? one : zero)
OP(GE, 1, ST2 >= ST1 ? one : zero)
OP(IF, 2, (ST2 != zero) ? ST1 : ST0)
OP(NEG, 0, -ST2)
OP(POW, 1, plib::pow(ST2, ST1))
OP(LOG, 0, plib::log(ST2))
OP(SIN, 0, plib::sin(ST2))
OP(COS, 0, plib::cos(ST2))
OP(MAX, 1, std::max(ST2, ST1))
OP(MIN, 1, std::min(ST2, ST1))
OP(TRUNC, 0, plib::trunc(ST2))
OP0(RAND, lfsr_random<value_type>(m_lfsr))
OP0(PUSH_INPUT, values[rc.m_param.index])
OP0(PUSH_CONST, rc.m_param.val)
// please compiler
case LP:
case RP:
break;
}
}
//printf("func %lld %lld\n", m_precompiled.size(), n);
m_precompiled.resize(n);
} }
template class pfunction<float>; template class pfunction<float>;

View File

@ -62,6 +62,10 @@ namespace plib {
{ {
m_param.val = plib::constants<NT>::zero(); m_param.val = plib::constants<NT>::zero();
} }
rpn_inst(NT v) : m_cmd(PUSH_CONST)
{
m_param.val = v;
}
rpn_cmd m_cmd; rpn_cmd m_cmd;
union union
{ {
@ -138,6 +142,7 @@ namespace plib {
private: private:
void compress();
void compile_postfix(const inputs_container &inputs, void compile_postfix(const inputs_container &inputs,
const std::vector<pstring> &cmds, const pstring &expr); const std::vector<pstring> &cmds, const pstring &expr);