HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
subgraph_function_generation.cpp
Go to the documentation of this file.
2 
8 #include "z3_utils/z3_utils.h"
9 
10 #include <queue>
11 
12 namespace hal
13 {
14  namespace z3_utils
15  {
16  namespace
17  {
18  // the Boolean function of each gate output pin, keyed by gate ID and pin
19  using GateFunctionCache = std::map<std::pair<u32, const GatePin*>, BooleanFunction>;
20 
21  Result<z3::expr> get_function_of_net(const std::vector<Gate*>& subgraph_gates,
22  const Net* net,
23  z3::context& ctx,
24  std::map<u32, z3::expr>& net_cache,
25  GateFunctionCache& gate_cache)
26  {
27  if (const auto it = net_cache.find(net->get_id()); it != net_cache.end())
28  {
29  return OK(it->second);
30  }
31 
32  const std::vector<Endpoint*> sources = net->get_sources();
33 
34  // net is multi driven
35  if (sources.size() > 1)
36  {
37  return ERR("cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": net is multi driven.");
38  }
39 
40  // net has no source
41  if (sources.empty())
42  {
43  z3::expr ret = ctx.bv_const(BooleanFunctionNetDecorator(*net).get_boolean_variable_name().c_str(), 1);
44  net_cache.insert({net->get_id(), ret});
45  return OK(ret);
46  }
47 
48  const Endpoint* src_ep = sources.front();
49 
50  if (src_ep->get_gate() == nullptr)
51  {
52  return ERR("cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": net source is null.");
53  }
54 
55  const Gate* src = src_ep->get_gate();
56 
57  // source is not in subgraph gates
58  if (std::find(subgraph_gates.begin(), subgraph_gates.end(), src) == subgraph_gates.end())
59  {
60  z3::expr ret = ctx.bv_const(BooleanFunctionNetDecorator(*net).get_boolean_variable_name().c_str(), 1);
61  net_cache.insert({net->get_id(), ret});
62  return OK(ret);
63  }
64 
65  BooleanFunction bf;
66  if (const auto it = gate_cache.find({src->get_id(), src_ep->get_pin()}); it == gate_cache.end())
67  {
68  const auto bf_res = src->get_boolean_function(src_ep->get_pin(), true, true);
69  if (bf_res.is_error())
70  {
71  return ERR_APPEND(bf_res.get_error(),
72  "cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": failed to get function of gate.");
73  }
74  bf = bf_res.get();
75 
76  gate_cache.insert({{src->get_id(), src_ep->get_pin()}, bf});
77  }
78  else
79  {
80  bf = it->second;
81  }
82 
83  std::map<std::string, z3::expr> input_to_expr;
84 
85  for (const std::string& in_net_str : bf.get_variable_names())
86  {
87  const auto in_net_res = BooleanFunctionNetDecorator::get_net_from(src->get_netlist(), in_net_str);
88  if (in_net_res.is_error())
89  {
90  return ERR_APPEND(in_net_res.get_error(),
91  "cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": failed to reconstruct input net from variable "
92  + in_net_str + ".");
93  }
94  const auto in_net = in_net_res.get();
95 
96  const auto in_bf_res = get_function_of_net(subgraph_gates, in_net, ctx, net_cache, gate_cache);
97  if (in_bf_res.is_error())
98  {
99  // NOTE since this can lead to a deep recursion we do not append the error and instead only propagate it.
100  return in_bf_res;
101  }
102  const auto in_bf = in_bf_res.get();
103 
104  input_to_expr.insert({in_net_str, in_bf});
105  }
106 
107  z3::expr ret = z3_utils::from_bf(bf, ctx, input_to_expr).simplify();
108  net_cache.insert({net->get_id(), ret});
109 
110  return OK(ret);
111  }
112 
113  Result<z3::expr> get_subgraph_z3_function_internal(const std::vector<Gate*>& subgraph_gates,
114  const Net* net,
115  z3::context& ctx,
116  std::map<u32, z3::expr>& net_cache,
117  GateFunctionCache& gate_cache)
118  {
119  // check validity of subgraph_gates
120  if (subgraph_gates.empty())
121  {
122  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": subgraph contains no gates");
123  }
124  else if (std::any_of(subgraph_gates.begin(), subgraph_gates.end(), [](const Gate* g) { return g == nullptr; }))
125  {
126  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": subgraph contains a gate that is a 'nullptr'");
127  }
128  else if (net == nullptr)
129  {
130  return ERR("could not get subgraph z3 function: net is a 'nullptr'");
131  }
132  else if (net->get_num_of_sources() > 1)
133  {
134  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": net has more than one source");
135  }
136  else if (net->is_global_input_net())
137  {
138  const auto net_dec = BooleanFunctionNetDecorator(*net);
139  return OK(ctx.bv_const(net_dec.get_boolean_variable_name().c_str(), 1));
140  }
141  else if (net->get_num_of_sources() == 0)
142  {
143  return ERR("could not get subgraph function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": net has no sources");
144  }
145 
146  return get_function_of_net(subgraph_gates, net, ctx, net_cache, gate_cache);
147  }
148 
149  } // namespace
150 
151  Result<z3::expr> get_subgraph_z3_function(const std::vector<Gate*>& subgraph_gates, const Net* subgraph_output, z3::context& ctx)
152  {
153  std::map<u32, z3::expr> net_cache;
154  GateFunctionCache gate_cache;
155 
156  return get_subgraph_z3_function_internal(subgraph_gates, subgraph_output, ctx, net_cache, gate_cache);
157  }
158 
159  Result<std::vector<z3::expr>> get_subgraph_z3_functions(const std::vector<Gate*>& subgraph_gates, const std::vector<Net*>& subgraph_outputs, z3::context& ctx)
160  {
161  std::map<u32, z3::expr> net_cache;
162  GateFunctionCache gate_cache;
163 
164  std::vector<z3::expr> results;
165 
166  for (const auto& net : subgraph_outputs)
167  {
168  const auto res = get_subgraph_z3_function_internal(subgraph_gates, net, ctx, net_cache, gate_cache);
169  if (res.is_error())
170  {
171  return ERR_APPEND(res.get_error(),
172  "unable to generate subgraph functions: failed to generate function for net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ".");
173  }
174 
175  results.push_back(res.get());
176  }
177 
178  return OK(results);
179  }
180 
181  } // namespace z3_utils
182 } // namespace hal
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
Definition: net.h:58
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Definition: z3_utils.cpp:15
Result< z3::expr > get_subgraph_z3_function(const std::vector< Gate * > &subgraph_gates, const Net *subgraph_output, z3::context &ctx)
Get the z3 expression representation of a combined Boolean function of a subgraph of combinational ga...
Result< std::vector< z3::expr > > get_subgraph_z3_functions(const std::vector< Gate * > &subgraph_gates, const std::vector< Net * > &subgraph_outputs, z3::context &ctx)
Get the z3 expression representations of combined Boolean functions of a subgraph of combinational ga...
Definition: defines.h:45
Net * net