快速计算逻辑门

时间:2019-11-15 19:54:14

标签: c++ performance simulation

我创建了以下代码来计算逻辑门的结果(AND,OR,NOT)。该功能将用于电路仿真中,从网表文件中读取电路。一个电路最多可以包含50000个逻辑门。

基于这个函数通常在仿真过程中被调用的事实,我想知道它是否可以以其他方式实现,从而使生成的机器代码更高效?

一个逻辑门可能有两个以上的输入(除了不是只有一个输入),但是大多数逻辑门只有两个。因此,我考虑过测试两个输入,然后编写如下内容:return input->predecessors[0]->result && return input->predecessors[1]->result;return input->predecessors[0]->result || return input->predecessors[1]->result;,但这可能会引入新的分支。输入的数量可以直接存储在Node中,以防止调用size()方法。

#include <vector>

enum class NodeType { NOT, AND, OR };

struct Node {
    NodeType type;
    bool result;
    std::vector<Node *> predecessors;
};

bool evaluate(Node *input) {
    switch (input->type) {
        case NodeType::NOT: {
            return !input->predecessors[0]->result;
        }

        case NodeType::AND: {
            bool result = true;

            for (const auto &node : input->predecessors) {
                result = result && node->result;
            }

            return result;
        }

        case NodeType::OR: {
            bool result = false;

            for (const auto &node : input->predecessors) {
                result = result || node->result;
            }

            return result;
        }
    };
};

3 个答案:

答案 0 :(得分:1)

我很想获得第一个输入并将其状态合并到switch()中;喜欢:

    bool result = input->predecessors[0];
    switch((input->type << 1) | result) {
         case (NodeType::NOT << 1) | false:
             return true;
         case (NodeType::NOT << 1) | true:
             return false;
         case (NodeType::AND << 1) | false:
             return false;
         case (NodeType::OR << 1) | true:
             return true;
         case (NodeType::AND << 1) | true: {
             for (const auto &node : input->predecessors) {   // Note: Can skip 1st iteration
                 result = result && node->result;
                 if(result == false) {
                     return false;
                 }
             }
             return true;
         }
         case (NodeType::OR << 1) | false:
             for (const auto &node : input->predecessors) {   // Note: Can skip 1st iteration
                 result = result || node->result;
                 if(result == true) {
                     return true;
                 }
             }
             return false;
         }

希望编译器能够将其转换为跳转表(例如,一条“ jmp [table+rax*8]”指令代替所有switch()和一半的代码)。

警告:要执行此操作,必须确保input->predecessors[0]为“ true”使用1(并且没有其他值用于true)。如果这是一个潜在的问题;您可以使用bool result = !!input->predecessors[0];

答案 1 :(得分:0)

看起来好像您正在做的是一个界面。

struct Node {
    std::vector<Node *> predecessors;
    virtual bool evaluate() const;
};

struct NodeNot : Node {
    bool evaluate() const {
        return !input->predecessors[0]->result;
    }
};

struct NodeAnd : Node {
    bool evaluate() const {
         for (const auto &node : input->predecessors) {
             if(!node->result) {
                  // there is no need to accumulate the result
                  // fail fast
                  return false;
             }
         }
         return true;
    }
};

struct NodeOr : Node {
    bool evaluate() const {
         for (const auto &node : input->predecessors) {
             if (node->result) {
                 return true;
             }
         }
         return false;
    }
};

这样一来,您完全无需使用switch,只需一次virtual调用就可以达到相同的结果。它可能比switch更快或更慢,它实际上取决于许多因素以及您在Node::result成员中缓存结果的良好程度。分析您的代码,以确保最有效。

答案 2 :(得分:0)

我正在考虑使用std::variant。还是有点骇人听闻,因为我使用的是空指针...清理它的任何帮助都很好

#include <tuple>
#include <variant>
#include <stdexcept>
#include <assert.h>

using vcpc = void const* const;

struct NOT { vcpc ptr; };
struct OR { vcpc ptr1; vcpc ptr2; };
struct AND { vcpc ptr1; vcpc ptr2; };

using Node = std::variant<NOT, OR, AND, bool>;

// from https://en.cppreference.com/w/cpp/utility/variant/visit
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;

using Ncpc = Node const* const;

constexpr bool evaluate(Ncpc input) {
    return std::visit(overloaded{
        [](NOT const& arg) { return !evaluate((Ncpc)arg.ptr); },
        [](OR const& arg) { return evaluate((Ncpc)arg.ptr1) || evaluate((Ncpc)arg.ptr2); },
        [](AND const& arg) { return evaluate((Ncpc)arg.ptr1) && evaluate((Ncpc)arg.ptr2); },
        [](bool arg) { return arg; },
        }, *input);
}

int main() {
    Node const isTrue{ true };
    Node const invTrue{ NOT{&isTrue} };
    assert(evaluate(&invTrue) == false);

    Node const andTrueFalse{ AND{&isTrue, &invTrue} };
    assert(evaluate(&andTrueFalse) == false);

    Node const orTrueFalse{ OR{&isTrue, &andTrueFalse} };
    assert(evaluate(&orTrueFalse) == true);
}