p4c icon indicating copy to clipboard operation
p4c copied to clipboard

Compiler Bug: cannot find allocation of a field in header

Open HeRaNO opened this issue 3 months ago • 1 comments

Compile the following P4 code under p4c 1.2.5.10 (SHA: cceb17da1 BUILD: Release) (current main HEAD).

p4c --target tofino2 --arch t2na my_simple_switch_tna.p4
#include <core.p4>
#if __TARGET_TOFINO__ == 3
#include <t3na.p4>
#elif __TARGET_TOFINO__ == 2
#include <t2na.p4>
#else
#include <tna.p4>
#endif

#include "common/headers.p4"
#include "common/util.p4"

const ether_type_t ETHERTYPE_PROBE = 16w0x88b5;

header probe_h {
    bit<8>  stage;
    @padding bit<7> _pad1;
    bit<9>  port;
    bit<24> qdepth;
}

struct metadata_t {
    bit<24> qlen;
}

struct ingress_header_t {
    ethernet_h ethernet;
    probe_h probe;
    ipv4_h ipv4;
}

// ---------------------------------------------------------------------------
// Ingress parser
// ---------------------------------------------------------------------------
parser SwitchIngressParser(
        packet_in pkt,
        out ingress_header_t hdr,
        out metadata_t ig_md,
        out ingress_intrinsic_metadata_t ig_intr_md) {

    TofinoIngressParser() tofino_parser;

    state start {
        tofino_parser.apply(pkt, ig_intr_md);
        transition parse_ethernet;
    }

    state parse_ethernet {
        pkt.extract(hdr.ethernet);
        transition select (hdr.ethernet.ether_type) {
            ETHERTYPE_IPV4 : parse_ipv4;
            ETHERTYPE_PROBE : parse_recir;
            default : reject;
        }
    }

    state parse_recir {
        pkt.extract(hdr.probe);
        transition accept;
    }

    state parse_ipv4 {
        pkt.extract(hdr.ipv4);
        transition accept;
    }
}

control SwitchIngress(
        inout ingress_header_t hdr,
        inout metadata_t ig_md,
        in ingress_intrinsic_metadata_t ig_intr_md,
        in ingress_intrinsic_metadata_from_parser_t ig_intr_prsr_md,
        inout ingress_intrinsic_metadata_for_deparser_t ig_intr_dprsr_md,
        inout ingress_intrinsic_metadata_for_tm_t ig_intr_tm_md) {
    
    Counter<bit<32>, bit<2>>(3, CounterType_t.PACKETS_AND_BYTES) counter;
    const bit<32> sfc_ingress_port_idx_cnt = 32w512;
    Register<bit<32>, PortId_t>(sfc_ingress_port_idx_cnt) sfc_qdepth;
    RegisterAction<bit<32>, PortId_t, void>(sfc_qdepth) qlen_write = {
        void apply(inout bit<32> value) {
            value = (bit<32>)hdr.probe.qdepth;
        }
    };
    RegisterAction<bit<32>, PortId_t, bit<24>>(sfc_qdepth) qlen_read = {
        void apply(inout bit<32> value, out bit<24> read_value) {
            read_value = (bit<24>)value;
        }
    };

    action recir_recv() {
        counter.count(0);
        qlen_write.execute(hdr.probe.port);
        ig_intr_dprsr_md.drop_ctl = 0x1;
    }
    action recir_send(PortId_t port) {
        counter.count(1);
        ig_intr_tm_md.ucast_egress_port = port;
    }
    action nop() {
        counter.count(2);
    }

    table recir_pkt {
        key = {
            hdr.ethernet.ether_type : exact;
            hdr.probe.stage : exact;
        }

        actions = {
            recir_send;
            recir_recv;
            nop;
        }

        size = 2;
        const default_action = nop;
    }

    action hit(PortId_t port) {
        ig_intr_tm_md.ucast_egress_port = port;
        ig_md.qlen = qlen_read.execute(port);
    }

    action miss() {}

    table forward {
        key = {
            hdr.ethernet.dst_addr : ternary;
        }

        actions = {
            hit;
            miss;
        }

        size = 1024;
        const default_action = miss;
    }

    apply {
        recir_pkt.apply();
        forward.apply();
    }
}

// ---------------------------------------------------------------------------
// Ingress Deparser
// ---------------------------------------------------------------------------
control SwitchIngressDeparser(
        packet_out pkt,
        inout ingress_header_t hdr,
        in metadata_t ig_md,
        in ingress_intrinsic_metadata_for_deparser_t ig_intr_dprsr_md) {
    apply {
        pkt.emit(hdr);
    }
}

Pipeline(SwitchIngressParser(),
         SwitchIngress(),
         SwitchIngressDeparser(),
         EmptyEgressParser(),
         EmptyEgress(),
         EmptyEgressDeparser()) pipe;

Switch(pipe) main;

The compiler output is:

In file: /home/yhr/p4c/backends/tofino/bf-p4c/mau/ixbar_realign.cpp:63
Compiler Bug: cannot find allocation of 19:ingress::hdr.probe.qdepth<24> ^0 ^bit[0..47] deparsed exact_containers mocha MW0(0..23), read in forward_0 (SwitchIngress.forward)

Internal compiler error. Please submit a bug report with your code.

However, p4c can compile this code successfully using tofino target and tna arch.

HeRaNO avatar Nov 25 '25 05:11 HeRaNO

UPD: Added a minimal reproduction.

HeRaNO avatar Dec 18 '25 06:12 HeRaNO