P4C
The P4 Compiler
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
bf-asm/phv.h
1
17
18#ifndef BACKENDS_TOFINO_BF_ASM_PHV_H_
19#define BACKENDS_TOFINO_BF_ASM_PHV_H_
20
21#include <set>
22#include <vector>
23
24#include "backends/tofino/bf-asm/json.h"
25#include "backends/tofino/bf-asm/target.h"
26#include "bfas.h"
27#include "lib/bitvec.h"
28#include "match_source.h"
29#include "misc.h"
30#include "sections.h"
31
32class Phv : public Section {
33 void start(int lineno, VECTOR(value_t) args) override;
34 void input(VECTOR(value_t) args, value_t data) override;
35 void output(json::map &) override;
36 Phv() : Section("phv") {}
37 Phv(const Phv &) = delete;
38 Phv &operator=(const Phv &) = delete;
39 ~Phv() {}
40 static Phv phv; // singleton class
41 Target::Phv *target = nullptr;
42 FOR_ALL_TARGETS(FRIEND_TARGET_CLASS, ::Phv)
43
44 public:
45 struct Register {
46 char name[8];
47 enum type_t { NORMAL, TAGALONG, CHECKSUM, MOCHA, DARK } type;
48 // uid is used for "phv_number" in the context.json, but otherwise is just
49 // a unique id for the register, encoded differently for different targets
50 unsigned short index = 0, uid = 0, size = 0;
51 Register() { type = NORMAL; }
52 Register(const Register &) = delete;
53 Register &operator=(const Register &) = delete;
54 Register(const char *n, type_t t, unsigned i, unsigned u, unsigned s)
55 : type(t), index(i), uid(u), size(s) {
56 strncpy(name, n, sizeof(name));
57 name[7] = 0;
58 }
59 bool operator==(const Register &a) const { return uid == a.uid; }
60 bool operator!=(const Register &a) const { return uid != a.uid; }
61 bool operator<(const Register &a) const { return uid < a.uid; }
62 virtual int parser_id() const { return -1; }
63 virtual int mau_id() const { return -1; }
64 virtual int ixbar_id() const { return -1; }
65 virtual int deparser_id() const { return -1; }
67 const char *type_to_string() const {
68 switch (type) {
69 case NORMAL:
70 return "normal";
71 case TAGALONG:
72 return "tagalong";
73 case CHECKSUM:
74 return "checksum";
75 case MOCHA:
76 return "mocha";
77 case DARK:
78 return "dark";
79 }
80 return "";
81 }
82 };
83 class Slice : public IHasDbPrint {
84 static const Register invalid;
85
86 public:
87 const Register &reg;
88 int lo = -1, hi = -1;
89 bool valid;
90 Slice() : reg(invalid), valid(false) {}
91 Slice(const Register &r, int l, int h) : reg(r), lo(l), hi(h) {
92 valid = lo >= 0 && hi >= lo && hi < reg.size;
93 }
94 Slice(const Register &r, int b) : reg(r), lo(b), hi(b) {
95 valid = lo >= 0 && hi >= lo && hi < reg.size;
96 }
97 Slice(const Slice &s, int l, int h) : reg(s.reg), lo(s.lo + l), hi(s.lo + h) {
98 valid = lo >= 0 && hi >= lo && hi <= s.hi && hi < reg.size;
99 }
100 Slice(const Slice &) = default;
101 explicit operator bool() const { return valid; }
102 Slice &operator=(const Slice &a) {
103 new (this) Slice(a.reg, a.lo, a.hi);
104 return *this;
105 }
106 const Slice *operator->() const { return this; }
107 bool operator==(const Slice &s) const {
108 return valid && s.valid && reg.uid == s.reg.uid && lo == s.lo && hi == s.hi;
109 }
110 bool operator<(const Slice &a) const {
111 if (reg.uid < a.reg.uid) return true;
112 if (reg.uid > a.reg.uid) return false;
113 if (lo < a.lo) return true;
114 if (lo > a.lo) return false;
115 return (hi < a.hi);
116 }
117 bool overlaps(const Slice &a) const {
118 return valid && a.valid && reg.uid == a.reg.uid && lo <= a.hi && a.lo <= hi;
119 }
120 unsigned size() const { return valid ? hi - lo + 1 : 0; }
121 std::string toString() const;
122 void dbprint(std::ostream &out) const;
123 };
124
125 protected:
126 // registers indexed according to MAU id
127 std::vector<Register *> regs;
128 std::map<int, std::map<int, std::string>> phv_pov_names;
130 int max_stage = INT_MAX;
131 Slice slice;
132 };
133 std::map<std::string, std::map<int, PerStageInfo>> names[3];
134
135 private:
136 typedef std::map<int, std::set<std::string>> user_stagenames_t;
137 std::map<const Register *, std::pair<gress_t, user_stagenames_t>, ptrless<Register>>
138 user_defined;
139 bitvec phv_use[3];
140 std::map<std::string, int> phv_field_sizes[3];
141 std::map<std::string, int> phv_pov_field_sizes[3];
142
143 // Maps P4-level field names (i.e. returned by stack_asm_name_to_p4()) to a
144 // map to be embedded in the field's context_json "records" node.
145 json::map field_context_json;
146
147 void init_phv(target_t);
148 bool is_pov(std::string name) {
149 // There are 2 types of POV bits we are interested in
150 // Either ending with .$valid or .$deparse...
151 return (name.find(".$valid") != std::string::npos ||
152 name.find(".$deparse") != std::string::npos);
153 }
154 void gen_phv_field_size_map();
155 int addreg(gress_t gress, const char *name, const value_t &what, int stage = -1,
156 int max_stage = INT_MAX);
157 int get_position_offset(gress_t gress, std::string name);
158 void add_phv_field_sizes(gress_t gress, std::string name, int size) {
159 auto &phv_field_map = is_pov(name) ? phv_pov_field_sizes : phv_field_sizes;
160 phv_field_map[gress][name] += size;
161 }
162 int get_phv_field_size(gress_t gress, std::string name) {
163 if (phv_field_sizes[gress].count(name) > 0) return phv_field_sizes[gress][name];
164 if (phv_pov_field_sizes[gress].count(name) > 0) return phv_pov_field_sizes[gress][name];
165 return 0;
166 }
167
168 public:
169 static const Slice *get(gress_t gress, int stage, const std::string &name) {
170 phv.init_phv(options.target);
171 auto phvIt = phv.names[gress].find(name);
172 if (phvIt == phv.names[gress].end()) return 0;
173 auto &per_stage = phvIt->second;
174 auto it = per_stage.upper_bound(stage);
175 if (it == per_stage.begin()) {
176 if (it == per_stage.end() || stage != -1) return 0;
177 } else {
178 --it;
179 }
180 if (stage > it->second.max_stage) return 0;
181 return &it->second.slice;
182 }
183 static const Slice *get(gress_t gress, int stg, const char *name) {
184 return get(gress, stg, std::string(name));
185 }
186 class Ref : public MatchSource {
187 protected:
188 gress_t gress_;
189 std::string name_;
190 int stage = -1;
191 int lo = -1, hi = -1;
192
193 public:
194 int lineno;
195 Ref() : gress_(INGRESS), lineno(-1) {}
196 Ref(gress_t g, int stage, const value_t &n);
197 Ref(gress_t g, int stage, int line, const std::string &n, int l, int h)
198 : gress_(g), name_(n), stage(stage), lo(l), hi(h), lineno(line) {}
199 Ref(const Ref &r, int l, int h)
200 : gress_(r.gress_),
201 name_(r.name_),
202 stage(r.stage),
203 lo(r.lo < 0 ? l : r.lo + l),
204 hi(r.lo < 0 ? h : r.lo + h),
205 lineno(r.lineno) {
206 BUG_CHECK(r.hi < 0 || hi <= r.hi, "Out of bounds slice: %s", r.toString().c_str());
207 }
208 Ref(const Register &r, gress_t gr, int lo = -1, int hi = -1);
209 explicit operator bool() const { return lineno >= 0; }
210 Slice operator*() const {
211 if (auto *s = phv.get(gress_, stage, name_)) {
212 if (hi >= 0) return Slice(*s, lo, hi);
213 return *s;
214 } else {
215 error(lineno, "No phv record %s (%s, stage %d)", name_.c_str(),
216 gress_ == INGRESS ? "INGRESS" : "EGRESS", stage);
217 phv.get(gress_, stage, name_);
218 return Slice();
219 }
220 }
221 bool operator<(const Ref &r) const {
222 return (**this).reg.parser_id() < (*r).reg.parser_id();
223 }
224 Slice operator->() const { return **this; }
225 bool operator==(const Ref &a) const {
226 if (name_ == a.name_ && lo == a.lo && hi == a.hi) return true;
227 return **this == *a;
228 }
229 bool check(bool err = true) const {
230 if (auto *s = phv.get(gress_, stage, name_)) {
231 if (hi >= 0 && !Slice(*s, lo, hi).valid) {
232 error(lineno, "Invalid slice of %s", name_.c_str());
233 return false;
234 }
235 return true;
236 } else if (lineno >= 0 && err) {
237 error(lineno, "No phv record %s", name_.c_str());
238 }
239 return false;
240 }
241 gress_t gress() const { return gress_; }
242 const char *name() const override { return name_.c_str(); }
243 std::string desc() const;
244 int lobit() const { return lo < 0 ? 0 : lo; }
245 int hibit() const { return hi < 0 ? (**this).size() - 1 : hi; }
246 unsigned size() const override {
247 if (lo >= 0) return hi - lo + 1;
248 if (auto *s = phv.get(gress_, stage, name_)) return s->size();
249 return 0;
250 }
251 bool merge(const Ref &r);
252 std::string toString() const override;
253 void dbprint(std::ostream &out) const override;
254
255 int get_lineno() const override { return lineno; }
256 int fieldlobit() const override { return lobit(); }
257 int fieldhibit() const override { return hibit(); }
258 int slicelobit() const override { return (**this).lo; }
259 int slicehibit() const override { return (**this).hi; }
260 };
261 // Return register using mau_id as @arg index
262 static const Register *reg(int idx) {
263 BUG_CHECK(idx >= 0 && size_t(idx) < phv.regs.size(), "Register index out of range");
264 return phv.regs[idx];
265 }
266
267 static const Register *reg(std::string name) {
268 for (auto &reg : phv.regs)
269 if (reg->name == name) return reg;
270 return nullptr;
271 }
272
273 // Return the number registers
274 static int num_regs() { return phv.regs.size(); }
275
276 // Return POV name allocated in @arg reg at @arg index
277 static const std::string get_pov_name(int reg, int index) {
278 if (phv.phv_pov_names.count(reg) && phv.phv_pov_names.at(reg).count(index))
279 return phv.phv_pov_names[reg][index];
280 return " ";
281 }
282
283 static const bitvec &use(gress_t gress) { return phv.phv_use[gress]; }
284 static void setuse(gress_t gress, const bitvec &u) { phv.phv_use[gress] |= u; }
285 static void unsetuse(gress_t gress, const bitvec &u) { phv.phv_use[gress] -= u; }
286 static std::string db_regset(const bitvec &s);
287 static unsigned mau_groupsize();
288
289 // Return all field names in @arg reg at @arg stage
290 static const std::set<std::string> &aliases(const Register *reg, int stage) {
291 static std::set<std::string> empty;
292 if (!phv.user_defined.count(reg)) return empty;
293 auto &m = phv.user_defined.at(reg).second;
294 auto it = m.upper_bound(stage);
295 if (it == m.begin()) return empty;
296 return (--it)->second;
297 }
298
299 // For use by gtests
300 static void test_clear() {
301 phv.target = nullptr;
302 phv.regs.clear();
303 phv.phv_pov_names.clear();
304 phv.names[INGRESS].clear();
305 phv.names[EGRESS].clear();
306 phv.names[GHOST].clear();
307 }
308};
309
310extern void merge_phv_vec(std::vector<Phv::Ref> &vec, const Phv::Ref &r);
311extern void merge_phv_vec(std::vector<Phv::Ref> &v1, const std::vector<Phv::Ref> &v2);
312extern std::vector<Phv::Ref> split_phv_bytes(const Phv::Ref &r);
313extern std::vector<Phv::Ref> split_phv_bytes(const std::vector<Phv::Ref> &v);
314
315class Target::Phv {
316 friend class ::Phv;
317 virtual void init_regs(::Phv &) = 0;
318 virtual target_t type() const = 0;
319 virtual unsigned mau_groupsize() const = 0;
320};
321
322inline unsigned Phv::mau_groupsize() { return phv.target->mau_groupsize(); }
323
324#include "jbay/phv.h"
325#include "tofino/phv.h"
326
327#endif /* BACKENDS_TOFINO_BF_ASM_PHV_H_ */
Definition match_source.h:32
Definition stringify.h:33
Definition bitvec.h:120
Definition bf-asm/phv.h:186
Definition bf-asm/phv.h:83
Definition bf-asm/phv.h:129
Definition backends/tofino/bf-asm/json.h:300
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition bf-asm/phv.h:45
const char * type_to_string() const
return a string representation based on the container type
Definition bf-asm/phv.h:67
Definition misc.h:102
Definition asm-types.h:114