P4C
The P4 Compiler
Loading...
Searching...
No Matches
asm-types.h
1
17
18#ifndef BACKENDS_TOFINO_BF_ASM_ASM_TYPES_H_
19#define BACKENDS_TOFINO_BF_ASM_ASM_TYPES_H_
20
21#include <assert.h>
22#include <stdarg.h>
23#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <algorithm>
28#include <functional>
29#include <iostream>
30#include <set>
31#include <sstream>
32
33#include "backends/tofino/bf-asm/json.h"
34#include "backends/tofino/bf-asm/map.h"
35#include "bfas.h"
36#include "lib/bitops.h"
37#include "lib/bitvec.h"
38#include "mask_counter.h"
39#include "vector.h"
40
41enum gress_t { INGRESS, EGRESS, GHOST, NUM_GRESS_T };
42
43/* All timing related uses combine the INGRESS and GHOST threads (they run in lockstep), so
44 * we remap GHOST->INGRESS when dealing with timing */
45inline gress_t timing_thread(gress_t gress) { return gress == GHOST ? INGRESS : gress; }
46/* imem similarly shares color between INGRESS and GHOST */
47inline gress_t imem_thread(gress_t gress) { return gress == GHOST ? INGRESS : gress; }
48
49struct match_t {
50 uint64_t word0, word1;
51#ifdef __cplusplus
52 operator bool() const { return (word0 | word1) != 0; }
53 bool operator==(const match_t &a) const { return word0 == a.word0 && word1 == a.word1; }
54 bool matches(uint64_t v) const {
55 return (v | word1) == word1 && ((~v & word1) | word0) == word0;
56 }
57 bool matches(const match_t &v) const {
58 assert(0);
59 return false;
60 }
61 unsigned dirtcam(unsigned width, unsigned bit);
62#endif /* __cplusplus */
63};
64
65DECLARE_VECTOR(match_t);
66
67struct wmatch_t {
68 bitvec word0, word1;
69#ifdef __cplusplus
70 wmatch_t() = default;
71 wmatch_t(const wmatch_t &) = default;
72 wmatch_t(wmatch_t &&) = default;
73 wmatch_t &operator=(const wmatch_t &) = default;
74 wmatch_t &operator=(wmatch_t &&) = default;
75 wmatch_t(const match_t &v) : word0(v.word0), word1(v.word1) {} // NOLINT(runtime/explicit)
76 wmatch_t(const VECTOR(match_t) & v) { // NOLINT(runtime/explicit)
77 for (int i = 0; i < v.size; ++i) {
78 word0.putrange(i * 64, 64, v.data[i].word0);
79 word1.putrange(i * 64, 64, v.data[i].word1);
80 }
81 }
82 operator bool() const { return word0 || word1; }
83 bool operator==(const wmatch_t &a) const { return word0 == a.word0 && word1 == a.word1; }
84 bool matches(bitvec v) const { return (v | word1) == word1 && ((word1 - v) | word0) == word0; }
85 bool matches(const wmatch_t &v) const {
86 assert(0);
87 return false;
88 }
89 unsigned dirtcam(unsigned width, unsigned bit);
90#endif /* __cplusplus */
91};
92
93enum value_type { tINT, tBIGINT, tRANGE, tSTR, tMATCH, tBIGMATCH, tVEC, tMAP, tCMD };
94extern const char *value_type_desc[];
95
96struct value_t;
97struct pair_t;
98#ifdef __cplusplus
99DECLARE_VECTOR(
100 value_t, value_t &operator[](int) const; value_t & back() const;
101 value_t * begin() const { return data; } value_t * end() const; value_t & front() const;
102 VECTOR(value_t) & add(value_t &&); VECTOR(value_t) & add(int);
103 VECTOR(value_t) & add(const char *);)
104DECLARE_VECTOR(
105 pair_t, void push_back(const char *, value_t &&); // NOLINT(whitespace/operators)
106 pair_t & operator[](int) const; pair_t * operator[](const char *) const; pair_t & back() const;
107 pair_t * begin() const { return data; } pair_t * end() const; pair_t & front() const;)
108#else
109DECLARE_VECTOR(value_t)
110DECLARE_VECTOR(pair_t)
111#endif /* __cplusplus */
112DECLARE_VECTOR(uintptr_t);
113
114struct value_t {
115 enum value_type type;
116 int lineno;
117 union {
118 int64_t i;
119 VECTOR(uintptr_t) bigi;
120 struct {
121 int lo;
122 int hi;
123 } range;
124 char *s;
125 match_t m;
126 VECTOR(match_t) bigm;
127 VECTOR(value_t) vec;
128 VECTOR(pair_t) map;
129 };
130#ifdef __cplusplus
131 value_t &operator[](int i) const {
132 assert(type == tVEC || type == tCMD);
133 return vec[i];
134 }
135 bool startsWith(const char *pfx) const {
136 if (type == tSTR) return strncmp(s, pfx, strlen(pfx)) == 0;
137 if (type == tCMD && vec.size > 0 && vec[0].type == tSTR)
138 return strncmp(vec[0].s, pfx, strlen(pfx)) == 0;
139 return false;
140 }
141 bool checkSize() const {
142 if (type == tVEC) return (vec.size > 0);
143 if (type == tMAP) return (map.size > 0);
144 if (type == tCMD) return (vec.size > 0);
145 return true;
146 }
147#endif /* __cplusplus */
148};
149
150struct pair_t {
151 struct value_t key, value;
152#ifdef __cplusplus
153 pair_t() = default;
154 pair_t(const value_t &k, const value_t &v) : key(k), value(v) {}
155#endif /* __cplusplus */
156};
157
158void free_value(value_t *p);
159const char *value_desc(const value_t *v);
160static inline void free_pair(pair_t *p) {
161 free_value(&p->key);
162 free_value(&p->value);
163}
164bool get_bool(const value_t &v);
165
166// If max_bits is zero, no testing or masking is carried out.
167// If error_message is set, values larger than max_bits will error, otherwise the value is masked.
168bitvec get_bitvec(const value_t &v, unsigned max_bits = 0, const char *error_message = nullptr);
169uint64_t get_int64(const value_t &v, unsigned max_bits = 0, const char *error_message = nullptr);
170
171#ifdef __cplusplus
172bool operator==(const struct value_t &, const struct value_t &);
173inline bool operator==(const struct value_t &a, const char *b) {
174 if (a.type == tCMD && a.vec.size > 0 && a[0].type == tSTR) return !strcmp(a[0].s, b);
175 return a.type == tSTR && !strcmp(a.s, b);
176}
177inline bool operator==(const char *a, const struct value_t &b) {
178 if (b.type == tCMD && b.vec.size > 0 && b[0].type == tSTR) return !strcmp(a, b[0].s);
179 return b.type == tSTR && !strcmp(a, b.s);
180}
181inline bool operator==(const struct value_t &a, int b) { return a.type == tINT && a.i == b; }
182inline bool operator==(int a, const struct value_t &b) { return b.type == tINT && a == b.i; }
183
184inline const char *value_desc(const value_t &v) { return value_desc(&v); }
185
186inline value_t &VECTOR(value_t)::operator[](int i) const {
187 assert(i >= 0 && i < size);
188 return data[i];
189}
190inline pair_t &VECTOR(pair_t)::operator[](int i) const {
191 assert(i >= 0 && i < size);
192 return data[i];
193}
194inline pair_t *VECTOR(pair_t)::operator[](const char *k) const {
195 for (int i = 0; i < size; i++)
196 if (data[i].key == k) return &data[i];
197 return 0;
198}
199inline value_t *VECTOR(value_t)::end() const { return data + size; }
200inline value_t &VECTOR(value_t)::front() const {
201 assert(0 < size);
202 return data[0];
203}
204inline value_t &VECTOR(value_t)::back() const {
205 assert(0 < size);
206 return data[size - 1];
207}
208inline pair_t *VECTOR(pair_t)::end() const { return data + size; }
209inline pair_t &VECTOR(pair_t)::front() const {
210 assert(0 < size);
211 return data[0];
212}
213inline pair_t &VECTOR(pair_t)::back() const {
214 assert(0 < size);
215 return data[size - 1];
216}
217
218/* can't call VECTOR(pair_t)::push_back directly except from the compilation unit where
219 * it is defined, due to gcc bug. Workaround via global function */
220extern void push_back(VECTOR(pair_t) & m, const char *s,
221 value_t &&v); // NOLINT(whitespace/operators)
222
223inline void fini(value_t &v) { free_value(&v); }
224inline void fini(pair_t &p) { free_pair(&p); }
225inline void fini(VECTOR(value_t) & v) {
226 VECTOR_foreach(v, free_value);
227 VECTOR_fini(v);
228}
229inline void fini(VECTOR(pair_t) & v) {
230 VECTOR_foreach(v, free_pair);
231 VECTOR_fini(v);
232}
233void collapse_list_of_maps(value_t &, bool singleton_only = false);
234
235std::unique_ptr<json::obj> toJson(value_t &);
236std::unique_ptr<json::vector> toJson(VECTOR(value_t) &);
237std::unique_ptr<json::map> toJson(pair_t &);
238std::unique_ptr<json::map> toJson(VECTOR(pair_t) &);
239
240#endif /* __cplusplus */
241
242#define CHECKTYPE(V, T) \
243 ((V).type == (T) || (error((V).lineno, "Syntax error, expecting %s", value_type_desc[T]), 0))
244#define CHECKTYPESIZE(V, T) \
245 (CHECKTYPE(V, T) && \
246 ((V).checkSize() || (error((V).lineno, "Syntax error, empty %s", value_type_desc[T]), 0)))
247#define PCHECKTYPE(P, V, T) \
248 (((P) && (V).type == (T)) || \
249 (error((V).lineno, "Syntax error, expecting %s", value_type_desc[T]), 0))
250#define CHECKTYPEM(V, T, M) \
251 ((V).type == (T) || (error((V).lineno, "Syntax error, expecting %s", M), 0))
252#define CHECKTYPEPM(V, T, P, M) \
253 (((V).type == (T) && (P)) || (error((V).lineno, "Syntax error, expecting %s", M), 0))
254#define PCHECKTYPEM(P, V, T, M) \
255 (((P) && (V).type == (T)) || (error((V).lineno, "Syntax error, expecting %s", M), 0))
256#define CHECKTYPE2(V, T1, T2) \
257 ((V).type == (T1) || (V).type == (T2) || \
258 (error((V).lineno, "Syntax error, expecting %s or %s but got %s", value_type_desc[T1], \
259 value_type_desc[T2], value_desc(V)), \
260 0))
261#define CHECKTYPE3(V, T1, T2, T3) \
262 ((V).type == (T1) || (V).type == (T2) || (V).type == (T3) || \
263 (error((V).lineno, "Syntax error, expecting %s or %s or %s", value_type_desc[T1], \
264 value_type_desc[T2], value_type_desc[T3]), \
265 0))
266#define PCHECKTYPE2(P, V, T1, T2) \
267 (((P) && ((V).type == (T1) || (V).type == (T2))) || \
268 (error((V).lineno, "Syntax error, expecting %s or %s", value_type_desc[T1], \
269 value_type_desc[T2]), \
270 0))
271#define CHECKTYPE2M(V, T1, T2, M) \
272 ((V).type == (T1) || (V).type == (T2) || \
273 (error((V).lineno, "Syntax error, expecting %s but got %s", M, value_desc(V)), 0))
274#define PCHECKTYPE2M(P, V, T1, T2, M) \
275 (((P) && ((V).type == (T1) || (V).type == (T2))) || \
276 (error((V).lineno, "Syntax error, expecting %s", M), 0))
277#define VALIDATE_RANGE(V) \
278 ((V).type != tRANGE || (V).range.lo <= (V).range.hi || \
279 (error((V).lineno, "Invalid range %d..%d", (V).range.lo, (V).range.hi), 0))
280
281inline value_t *get(VECTOR(pair_t) & map, const char *key) {
282 for (auto &kv : map)
283 if (kv.key == key) return &kv.value;
284 return 0;
285}
286inline const value_t *get(const VECTOR(pair_t) & map, const char *key) {
287 for (auto &kv : map)
288 if (kv.key == key) return &kv.value;
289 return 0;
290}
291
292#ifdef __cplusplus
293
294template <class T>
295inline void parse_vector(std::vector<T> &vec, const VECTOR(value_t) & data) {
296 for (auto &v : data) vec.emplace_back(v);
297}
298template <>
299inline void parse_vector(std::vector<int> &vec, const VECTOR(value_t) & data) {
300 for (auto &v : data)
301 if (CHECKTYPE(v, tINT)) vec.push_back(v.i);
302}
303template <>
304inline void parse_vector(std::vector<int64_t> &vec, const VECTOR(value_t) & data) {
305 for (auto &v : data)
306 if (CHECKTYPE(v, tINT)) vec.push_back(v.i);
307}
308template <>
309inline void parse_vector(std::vector<std::string> &vec, const VECTOR(value_t) & data) {
310 for (auto &v : data)
311 if (CHECKTYPE(v, tSTR)) vec.emplace_back(v.s);
312}
313template <class T>
314inline void parse_vector(std::vector<T> &vec, const value_t &data) {
315 if (data.type == tVEC)
316 parse_vector(vec, data.vec);
317 else
318 vec.emplace_back(data);
319}
320template <>
321inline void parse_vector(std::vector<int> &vec, const value_t &data) {
322 if (CHECKTYPE2(data, tINT, tVEC)) {
323 if (data.type == tVEC)
324 parse_vector(vec, data.vec);
325 else
326 vec.push_back(data.i);
327 }
328}
329template <>
330inline void parse_vector(std::vector<int64_t> &vec, const value_t &data) {
331 if (CHECKTYPE2(data, tINT, tVEC)) {
332 if (data.type == tVEC)
333 parse_vector(vec, data.vec);
334 else
335 vec.push_back(data.i);
336 }
337}
338template <>
339inline void parse_vector(std::vector<std::string> &vec, const value_t &data) {
340 if (CHECKTYPE2(data, tSTR, tVEC)) {
341 if (data.type == tVEC)
342 parse_vector(vec, data.vec);
343 else
344 vec.push_back(data.s);
345 }
346}
347
348std::ostream &operator<<(std::ostream &out, match_t m);
349void print_match(FILE *fp, match_t m);
350
351inline std::ostream &operator<<(std::ostream &out, gress_t gress) {
352 switch (gress) {
353 case INGRESS:
354 out << "ingress";
355 break;
356 case EGRESS:
357 out << "egress";
358 break;
359 case GHOST:
360 out << "ghost";
361 break;
362 default:
363 out << "(invalid gress " << static_cast<int>(gress) << ")";
364 }
365 return out;
366}
367
368template <typename T>
369inline std::string to_string(T val) {
370 std::stringstream tmp;
371 tmp << val;
372 return tmp.str();
373}
374
375class MapIterChecked {
376 /* Iterate through a map (VECTOR(pair_t)), giving errors for non-string and
377 * duplicate keys (and skipping them) */
378 const VECTOR(pair_t) & map;
379 bool allow; // allow non-string keys
380 std::set<std::string> duplicates_allowed;
381 std::map<std::string, int> keys_seen;
382 class iter {
383 MapIterChecked *self;
384 pair_t *p;
385 void check() {
386 while (p != self->map.end()) {
387 if (self->allow && p->key.type != tSTR) break;
388 if (!CHECKTYPE(p->key, tSTR)) {
389 p++;
390 continue;
391 }
392 if (self->duplicates_allowed.count(p->key.s)) break;
393 if (self->keys_seen.count(p->key.s)) {
394 error(p->key.lineno, "Duplicate element %s", p->key.s);
395 warning(self->keys_seen[p->key.s], "previous element %s", p->key.s);
396 p++;
397 continue;
398 }
399 self->keys_seen[p->key.s] = p->key.lineno;
400 break;
401 }
402 }
403
404 public:
405 iter(MapIterChecked *s, pair_t *p_) : self(s), p(p_) { check(); }
406 pair_t &operator*() const { return *p; }
407 pair_t *operator->() const { return p; }
408 bool operator==(const iter &a) const { return p == a.p; }
409 iter &operator++() {
410 p++;
411 check();
412 return *this;
413 }
414 };
415
416 public:
417 explicit MapIterChecked(const VECTOR(pair_t) & map_, bool o = false,
418 const std::set<std::string> &dup = {})
419 : map(map_), allow(o), duplicates_allowed(dup) {}
420 MapIterChecked(const VECTOR(pair_t) & map_, const std::set<std::string> &dup)
421 : map(map_), allow(false), duplicates_allowed(dup) {}
422 iter begin() { return iter(this, map.begin()); }
423 iter end() { return iter(this, map.end()); }
424};
425
426class MatchIter {
427 /* Iterate through the integers that match a match_t */
428 match_t m;
429 class iter : public MaskCounter {
430 MatchIter *self;
431
432 public:
433 explicit iter(MatchIter *s) : MaskCounter(s->m.word0 & s->m.word1), self(s) {
434 if (!(self->m.word1 | self->m.word0)) overflow();
435 }
436 unsigned operator*() const {
437 return this->operator unsigned() | (self->m.word1 & ~self->m.word0);
438 }
439 iter &end() {
440 overflow();
441 return *this;
442 }
443 };
444
445 public:
446 explicit MatchIter(match_t m_) : m(m_) {}
447 iter begin() { return iter(this); }
448 iter end() { return iter(this).end(); }
449};
450
451class SrcInfo {
452 int lineno;
453 friend std::ostream &operator<<(std::ostream &, const SrcInfo &);
454
455 public:
456 explicit SrcInfo(int l) : lineno(l) {}
457};
458
459struct RegisterSetBase {
460 virtual ~RegisterSetBase() = default;
461};
462
463struct ParserRegisterSet : public RegisterSetBase {};
464
466class Parsable {
467 public:
469 virtual void input(VECTOR(value_t) args, value_t data) = 0;
470 virtual ~Parsable() = default;
471};
472
474class Configurable {
475 public:
476 virtual void write_config(RegisterSetBase &regs, json::map &json, bool legacy = true) = 0;
477 virtual ~Configurable() = default;
478};
479
481class Contextable {
482 public:
483 virtual void output(json::map &ctxtJson) = 0;
484 virtual ~Contextable() = default;
485};
486
487#endif /* __cplusplus */
488
489#endif /* BACKENDS_TOFINO_BF_ASM_ASM_TYPES_H_ */
Definition bitvec.h:120
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:128
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition match.h:36
Definition asm-types.h:150
Definition asm-types.h:114
Definition asm-types.h:67