31 void sort_state_primitives() {
32 for (
auto p : state->extracts) {
33 if (
auto e = p->to<IR::BFN::LoweredExtractPhv>()) {
34 phv_extracts.push_back(e);
35 }
else if (
auto e = p->to<IR::BFN::LoweredExtractClot>()) {
36 clot_extracts.push_back(e);
39 for (
auto p : state->checksums) {
40 if (
auto c = p->to<IR::BFN::LoweredParserChecksum>()) {
41 checksums.push_back(c);
44 for (
auto p : state->counters) {
45 if (
auto pc = p->to<IR::BFN::ParserCounterPrimitive>()) {
46 counters.push_back(pc);
52 bool lo =
false, hi =
false;
53 bool preorder(
const IR::BFN::LoweredPacketRVal *rval)
override {
55 hi |= rval->range.hi >= max;
56 lo |= rval->range.lo >= max;
62 static bool within_buffer(
const T *p) {
74 : lpm_allocator(lpm_allocator) {}
76 virtual void allocate() = 0;
78 void add_to_result() {
79 for (
auto c : current) lpm_allocator.current_statements.push_back(c);
81 for (
auto s : spilled) lpm_allocator.spilled_statements.push_back(s);
85 struct ExtractAllocator : Allocator {
87 container_to_extracts;
89 virtual std::pair<size_t, unsigned> inbuf_extractor_use(
size_t container_size) = 0;
91 virtual std::map<size_t, unsigned> constant_extractor_use_choices(
92 uint32_t value,
size_t container_size) = 0;
94 std::map<size_t, unsigned> constant_extractor_use_choices(
97 std::map<size_t, unsigned> rv;
98 bool has_clr_on_write =
false;
100 unsigned c = merge_const_source(extracts, has_clr_on_write);
102 if (c || has_clr_on_write) {
103 rv = constant_extractor_use_choices(c, container.size());
105 LOG4(
"constant: " << c);
107 for (
auto &[size, count] : rv)
108 LOG4(
"extractors needed: " << size <<
" : " << count);
114 std::map<size_t, unsigned> inbuf_extractor_needed(
117 std::map<size_t, unsigned> rv;
119 if (has_inbuf_extract(extracts)) {
120 auto iu = inbuf_extractor_use(container.size());
128 for (
auto e : extracts) {
129 if (e->source->is<IR::BFN::LoweredInputBufferRVal>())
return true;
135 bool &has_clr_on_write) {
138 for (
auto e : extracts) {
139 if (
auto c = e->source->to<IR::BFN::LoweredConstantRVal>()) {
140 merged = c->constant;
142 if (e->write_mode == IR::BFN::ParserWriteMode::CLEAR_ON_WRITE)
143 has_clr_on_write =
true;
150 bool extract_out_of_buffer(
const IR::BFN::LoweredExtractPhv *e) {
151 GetExtractBufferPos get_buf_pos;
152 e->apply(get_buf_pos);
157 void allocate()
override {
158 std::map<size_t, unsigned> extractors_by_size;
160 std::map<size_t, unsigned> constants_by_size;
162 std::map<size_t, unsigned> csum_verify_by_size;
165 for (
auto c : lpm_allocator.current_statements) {
166 if (
auto lpc = c->to<IR::BFN::LoweredParserChecksum>()) {
167 const IR::BFN::ContainerRef *dest = lpc->phv_dest;
168 if (lpc->type == IR::BFN::ChecksumMode::VERIFY && lpc->csum_err)
169 dest = lpc->csum_err->container;
172 auto container = dest->container;
173 BUG_CHECK(container.size() != 32,
174 "checksum verification cannot be 32-bit container");
176 extractors_by_size[container.size()]++;
177 csum_verify_by_size[container.size()]++;
182 if (Device::currentDevice() == Device::TOFINO)
183 extractors_by_size[container.size()]++;
185 LOG2(
"reserved " << container.size()
186 <<
"b extractor for checksum verification");
190 for (
auto &kv : container_to_extracts) {
191 auto container = kv.first;
192 auto &extracts = kv.second;
194 auto ibuf_needed = inbuf_extractor_needed(container, extracts);
196 auto constant_choices = constant_extractor_use_choices(container, extracts);
198 bool constant_avail =
true;
200 if (!constant_choices.empty()) {
201 if (Device::currentDevice() == Device::TOFINO) {
202 std::map<size_t, unsigned> valid_choices;
204 for (
auto &choice : constant_choices) {
205 if (choice.first == 16 || choice.first == 32) {
206 if (choice.second + constants_by_size[choice.first] > 2)
continue;
221 if (choice.first < container.size() &&
222 csum_verify_by_size[choice.first] == 1 && choice.first == 16)
225 valid_choices.insert(choice);
228 constant_choices = valid_choices;
229 constant_avail = !valid_choices.empty();
230 }
else if (Device::currentDevice() == Device::JBAY) {
231 constant_avail = constant_choices.at(16) + constants_by_size[16] <= 2;
235 bool extractor_avail =
true;
237 std::pair<size_t, unsigned> constant_needed;
239 std::map<size_t, unsigned> total_needed;
241 if (!constant_choices.empty()) {
242 extractor_avail =
false;
244 for (
auto it = constant_choices.rbegin(); it != constant_choices.rend(); ++it) {
247 total_needed = ibuf_needed;
249 if (total_needed.count(choice.first))
250 total_needed[choice.first] += choice.second;
252 total_needed.insert(choice);
254 bool choice_ok =
true;
256 for (
auto &kv : total_needed) {
257 auto avail = Device::pardeSpec().
extractorSpec().at(kv.first);
258 if (extractors_by_size[kv.first] + kv.second > avail) {
265 extractor_avail =
true;
266 constant_needed = choice;
271 total_needed = ibuf_needed;
273 for (
auto &kv : total_needed) {
274 auto avail = Device::pardeSpec().
extractorSpec().at(kv.first);
275 if (extractors_by_size[kv.first] + kv.second > avail) {
276 extractor_avail =
false;
284 if (extractor_avail && constant_avail) {
285 for (
auto e : extracts) {
286 if (extract_out_of_buffer(e)) {
293 if (!oob && extractor_avail && constant_avail) {
295 for (
auto e : extracts) current.push_back(e);
297 for (
auto &kv : total_needed) extractors_by_size[kv.first] += kv.second;
299 constants_by_size[constant_needed.first] += constant_needed.second;
301 std::stringstream reason;
303 if (oob) reason <<
"(out of buffer) ";
304 if (!extractor_avail) reason <<
"(ran out of extractors) ";
305 if (!constant_avail) reason <<
"(ran out of constants) ";
307 for (
auto e : extracts) LOG3(
"spill " << e <<
" { " << reason.str() <<
"}");
310 for (
auto e : extracts) spilled.push_back(e);
316 : Allocator(lpm_allocator) {
318 for (
auto e : lpm_allocator.phv_extracts) {
319 auto container = e->dest->container;
320 container_to_extracts[container].insert(e);
325 class TofinoExtractAllocator :
public ExtractAllocator {
326 bool can_extract(
unsigned val,
unsigned extractor_size) {
327 if (val == 0)
return true;
329 switch (extractor_size) {
331 for (
int i = 0; i < 32; i++) {
332 if ((val & 1) && (0x7 & val) == val)
return true;
333 val = ((val >> 1) | (val << 31)) & 0xffffffffU;
337 if ((val >> 16) && !can_extract(val >> 16, extractor_size))
return false;
339 for (
int i = 0; i < 16; i++) {
340 if ((val & 1) && (0xf & val) == val)
return true;
341 val = ((val >> 1) | (val << 15)) & 0xffffU;
351 std::map<size_t, unsigned> constant_extractor_use_choices(
unsigned value,
352 size_t container_size)
override {
353 std::map<size_t, unsigned> rv;
355 for (
const auto extractor_size : {PHV::Size::b32, PHV::Size::b16, PHV::Size::b8}) {
357 if (container_size <
size_t(extractor_size))
continue;
359 if (can_extract(value,
unsigned(extractor_size)))
360 rv[size_t(extractor_size)] = container_size / unsigned(extractor_size);
363 BUG_CHECK(!rv.empty(),
"Impossible constant value write in parser: %1%", value);
368 std::pair<size_t, unsigned> inbuf_extractor_use(
size_t container_size)
override {
369 return {container_size, 1};
374 : ExtractAllocator(lpm_allocator) {
380 class JBayExtractAllocator :
public ExtractAllocator {
381 std::map<size_t, unsigned> constant_extractor_use_choices(uint32_t value,
382 size_t container_size)
override {
383 std::map<size_t, unsigned> rv;
387 if (container_size ==
size_t(PHV::Size::b32) && value)
388 num = bool(value & 0xffff) + bool(value >> 16);
397 std::pair<size_t, unsigned> inbuf_extractor_use(
size_t container_size)
override {
398 return {16, container_size == 32 ? 2 : 1};
403 : ExtractAllocator(lpm_allocator) {
410 sort_state_primitives();
411 for (
const auto &checksum : checksums) current_statements.push_back(checksum);
413 if (Device::currentDevice() == Device::TOFINO) {
414 TofinoExtractAllocator tea(*
this);
415 }
else if (Device::currentDevice() == Device::JBAY) {
416 JBayExtractAllocator jea(*
this);
418 BUG(
"Unknown device");
421 for (
auto o : others) {
422 if (within_buffer(o)) {
423 current_statements.push_back(o);
425 spilled_statements.push_back(o);
426 LOG3(
"spill " << o <<
" (out of buffer)");
435 bool preorder(
const IR::BFN::LoweredExtractPhv *extract)
override {
436 if (
auto rval = extract->source->to<IR::BFN::LoweredPacketRVal>()) {
437 min = std::min(min, rval->range.lo);
438 max = std::max(max, rval->range.hi);
446 : state(s), clot(clot) {
450 const IR::BFN::LoweredParserMatch *state;
454 std::vector<const IR::BFN::LoweredExtractPhv *> phv_extracts;
455 std::vector<const IR::BFN::LoweredExtractClot *> clot_extracts;
456 std::vector<const IR::BFN::LoweredParserChecksum *> checksums;
457 std::vector<const IR::BFN::ParserCounterPrimitive *> counters;
458 std::vector<const IR::BFN::LoweredParserPrimitive *> others;
461 bool spill_selects =
false;