bmv2
Designing your own switch target with bmv2
expressions.h
1 /* Copyright 2013-2019 Barefoot Networks, Inc.
2  * Copyright 2019 VMware, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * Antonin Bas
19  *
20  */
21 
22 #ifndef BM_BM_SIM_EXPRESSIONS_H_
23 #define BM_BM_SIM_EXPRESSIONS_H_
24 
25 #include <unordered_map>
26 #include <string>
27 #include <vector>
28 
29 #include "data.h"
30 #include "headers.h"
31 #include "header_unions.h"
32 #include "phv_forward.h"
33 #include "stacks.h"
34 
35 namespace bm {
36 
37 class RegisterArray;
38 class RegisterSync;
39 
40 struct ExpressionTemps;
41 
42 enum class ExprOpcode {
43  LOAD_FIELD, LOAD_HEADER, LOAD_HEADER_STACK, LOAD_LAST_HEADER_STACK_FIELD,
44  LOAD_UNION, LOAD_UNION_STACK, LOAD_BOOL, LOAD_CONST, LOAD_LOCAL,
45  LOAD_REGISTER_REF, LOAD_REGISTER_GEN,
46  ADD, SUB, MOD, DIV, MUL, SHIFT_LEFT, SHIFT_RIGHT,
47  EQ_DATA, NEQ_DATA, GT_DATA, LT_DATA, GET_DATA, LET_DATA,
48  EQ_HEADER, NEQ_HEADER,
49  EQ_UNION, NEQ_UNION,
50  EQ_BOOL, NEQ_BOOL,
51  AND, OR, NOT,
52  BIT_AND, BIT_OR, BIT_XOR, BIT_NEG,
53  VALID_HEADER, VALID_UNION,
54  TERNARY_OP, SKIP,
55  TWO_COMP_MOD,
56  USAT_CAST, SAT_CAST,
57  DATA_TO_BOOL, BOOL_TO_DATA,
58  DEREFERENCE_HEADER_STACK,
59  DEREFERENCE_UNION_STACK,
60  LAST_STACK_INDEX, SIZE_STACK,
61  ACCESS_FIELD,
62  ACCESS_UNION_HEADER,
63 };
64 
65 enum class ExprType {
66  UNKNOWN, DATA, HEADER, HEADER_STACK, BOOL, UNION, UNION_STACK
67 };
68 
69 class ExprOpcodesMap {
70  public:
71  static ExprOpcode get_opcode(std::string expr_name);
72 
73  private:
74  static ExprOpcodesMap *get_instance();
75 
76  ExprOpcodesMap();
77 
78  private:
79  std::unordered_map<std::string, ExprOpcode> opcodes_map{};
80 };
81 
82 class ExprOpcodesUtils {
83  public:
84  static ExprOpcode get_eq_opcode(ExprType expr_type);
85  static ExprOpcode get_neq_opcode(ExprType expr_type);
86 
87  static ExprType get_opcode_type(ExprOpcode opcode);
88 };
89 
90 struct Op {
91  ExprOpcode opcode;
92 
93  union {
94  int data_dest_index;
95 
96  struct {
97  header_id_t header;
98  int field_offset;
99  } field;
100 
101  header_id_t header;
102 
103  header_stack_id_t header_stack;
104 
105  struct {
106  header_stack_id_t header_stack;
107  int field_offset;
108  } stack_field;
109 
110  header_union_id_t header_union;
111 
112  header_union_stack_id_t header_union_stack;
113 
114  bool bool_value;
115 
116  int const_offset;
117 
118  int local_offset;
119 
120  int field_offset;
121 
122  int header_offset;
123 
124  // In theory, if registers cannot be resized, I could directly store a
125  // pointer to the correct register cell, i.e. &(*array)[idx]. However, this
126  // gives me more flexibility in case I want to be able to resize the
127  // registers arbitrarily in the future.
128  struct {
129  RegisterArray *array;
130  unsigned int idx;
131  } register_ref;
132 
133  RegisterArray *register_array;
134 
135  int skip_num;
136  };
137 };
138 
139 class Expression {
140  public:
141  Expression();
142 
143  virtual ~Expression() { }
144 
145  void push_back_load_field(header_id_t header, int field_offset);
146  void push_back_load_bool(bool value);
147  void push_back_load_header(header_id_t header);
148  void push_back_load_header_stack(header_stack_id_t header_stack);
149  void push_back_load_last_header_stack_field(header_stack_id_t header_stack,
150  int field_offset);
151  void push_back_load_header_union(header_union_id_t header_union);
152  void push_back_load_header_union_stack(
153  header_union_stack_id_t header_union_stack);
154  void push_back_load_const(const Data &data);
155  void push_back_load_local(const int offset);
156  void push_back_load_register_ref(RegisterArray *register_array,
157  unsigned int idx);
158  void push_back_load_register_gen(RegisterArray *register_array);
159  void push_back_op(ExprOpcode opcode);
160  void push_back_ternary_op(const Expression &e1, const Expression &e2);
161  void push_back_access_field(int field_offset);
162  void push_back_access_union_header(int header_offset);
163 
164  void build();
165 
166  void grab_register_accesses(RegisterSync *register_sync) const;
167 
168  bool eval_bool(const PHV &phv, const std::vector<Data> &locals = {}) const;
169  Data eval_arith(const PHV &phv, const std::vector<Data> &locals = {}) const;
170  void eval_arith(const PHV &phv, Data *data,
171  const std::vector<Data> &locals = {}) const;
172  Data &eval_arith_lvalue(PHV *phv, const std::vector<Data> &locals = {}) const;
173  Header &eval_header(PHV *phv, const std::vector<Data> &locals = {}) const;
174  HeaderStack &eval_header_stack(
175  PHV *phv, const std::vector<Data> &locals = {}) const;
176  HeaderUnion &eval_header_union(
177  PHV *phv, const std::vector<Data> &locals = {}) const;
178  HeaderUnionStack &eval_header_union_stack(
179  PHV *phv, const std::vector<Data> &locals = {}) const;
180 
181  bool empty() const;
182 
183  // I am authorizing copy for this object
184  Expression(const Expression &other) = default;
185  Expression &operator=(const Expression &other) = default;
186 
187  Expression(Expression &&other) /*noexcept*/ = default;
188  Expression &operator=(Expression &&other) /*noexcept*/ = default;
189 
190  private:
191  int assign_dest_registers();
192  void eval_(const PHV &phv,
193  const std::vector<Data> &locals,
194  ExpressionTemps *temps) const;
195  size_t get_num_ops() const;
196  void append_expression(const Expression &e);
197 
198  private:
199  std::vector<Op> ops{};
200  std::vector<Data> const_values{};
201  int data_registers_cnt{0};
202  bool built{false};
203 
204  friend class VLHeaderExpression;
205 };
206 
207 
208 class ArithExpression : public Expression {
209  public:
210  void eval(const PHV &phv, Data *data,
211  const std::vector<Data> &locals = {}) const {
212  eval_arith(phv, data, locals);
213  }
214 
215  Data &eval_lvalue(PHV *phv, const std::vector<Data> &locals = {}) const {
216  return eval_arith_lvalue(phv, locals);
217  }
218 };
219 
220 
221 class BoolExpression : public Expression {
222  public:
223  bool eval(const PHV &phv, const std::vector<Data> &locals = {}) const {
224  return eval_bool(phv, locals);
225  }
226 };
227 
228 
229 class VLHeaderExpression {
230  public:
231  explicit VLHeaderExpression(const ArithExpression &expr);
232 
233  ArithExpression resolve(header_id_t header_id);
234 
235  const std::vector<int> &get_input_offsets() const;
236 
237  private:
238  ArithExpression expr;
239  std::vector<int> offsets{};
240 };
241 
242 } // namespace bm
243 
244 #endif // BM_BM_SIM_EXPRESSIONS_H_
header_unions.h
headers.h
bm::HeaderStack
detail::MyStack< Header > HeaderStack
Definition: stacks.h:212
bm::HeaderUnionStack
detail::MyStack< HeaderUnion > HeaderUnionStack
Definition: stacks.h:223
stacks.h