p4lang / p4-spec

Apache License 2.0
177 stars 80 forks source link

Clarifications on implicit cast on function/method calls #1312

Open jaehyun1ee opened 3 weeks ago

jaehyun1ee commented 3 weeks ago

There seems to be unspecified bits regarding implicit cast on function/method/(and action) calls.

Spec section 8.20. Method invocations and function calls mentions:

The calling convention is copy-in/copy-out (Section 6.8). For generic functions the type arguments can be explicitly specified in the function call. The compiler only inserts implicit casts for direction in arguments to methods or functions as described in Section 8.11. The types for all other arguments must match the parameter types exactly.

(1) How do we define implicit cast for action calls?

Strictly speaking, actions are neither a function nor a method, while they are quite similar constructs. But, the spec does not mention how casts should be inserted on action calls. Would it be safe to consider that implicit cast on action arguments behave the same as function/method arguments?

(2) Do we insert implicit cast for directionless arguments?

While the spec mentions that we only insert cast for direction in arguments, there exist some examples in the p4c compiler test suite where it expects to insert implicit casts for directionless arguments also.

(a) extern2.p4

extern ext<H> {
    ext(H v);
    void method<T>(H h, T t);
}

control c() {
    ext<bit<16>>(16w0) x;
    apply {
        x.method(0, 8w0);
    }
}

Here, it is expected that the first directionless argument, 0 of x.method is implicitly casted to bit<16>.

(b) action-bind.p4

control c(inout bit<32> x) {
    action a(inout bit<32> b, bit<32> d) {
        b = d;
    }
    table t {
        actions = { a(x); }
        default_action = a(x, 0);
    }
    apply {
        t.apply();
    }
}

control proto(inout bit<32> x);
package top(proto p);

top(c()) main;

Also here, the second directionless argument 0 for the default action a is expected to be implicitly cast to bit<32> type.

I wonder whether the p4c test suite is in a disagreement with the current spec, or the current spec is ambiguous.

jaehyun1ee commented 3 hours ago

For (1), I noticed that the spec mentions the following in section 6.8.1.

Actions can also be explicitly invoked using function call syntax, either from a control block or from another action. In this case, values for all action parameters must be supplied explicitly, including values for the directionless parameters. The directionless parameters in this case behave like in parameters.

So a directionless parameter passed to an action in a P4 program can be implicitly cast, because they are treated as direction in.

But regarding (2), I found a lot of use cases in the p4c compiler test suite that expects implicit cast on function/method and constructor calls.

List of tests * extern-funcs-bmv2.p4 * extern2.p4 * gauntlet_extern_arguments_2.p4 * gauntlet_hdr_in_value-bmv2.p4 * issue1001-1-bmv2.p4 * issue1001-bmv2.p4 * issue1043-bmv2.p4 * issue1334.p4 * issue1642-bmv2.p4 * issue1653-bmv2.p4 * issue1653-complex-bmv2.p4 * issue1660-bmv2.p4 * issue1765-1-bmv2.p4 * issue2648.p4 * issue3246-1.p4 * issue383-bmv2.p4 * issue562-bmv2.p4 * issue933-1.p4 * named-arg1.p4 * v1model-special-ops-bmv2.p4 * bfd_offload.p4 * calc-ebpf.p4 * constructor_cast.p4 * issue1006.p4 * issue1097-2-bmv2.p4 * issue1097-bmv2.p4 * issue1814-1-bmv2.p4 * issue1814-bmv2.p4 * issue1958.p4 * issue2844-enum.p4 * issue298-bmv2.p4 * issue4288.p4 * issue754.p4 * list7.p4 * pr1363.p4 * psa-action-profile1.p4 * psa-action-profile3.p4 * psa-action-profile4.p4 * psa-basic-counter-bmv2.p4 * psa-counter1.p4 * psa-counter2.p4 * psa-counter3.p4 * psa-custom-type-counter-index.p4 * psa-end-of-ingress-test-bmv2.p4 * psa-example-dpdk-byte-alignment_1.p4 * psa-example-dpdk-byte-alignment_2.p4 * psa-example-dpdk-byte-alignment_3.p4 * psa-example-dpdk-byte-alignment_5.p4 * psa-example-dpdk-byte-alignment_6.p4 * psa-example-dpdk-byte-alignment_7.p4 * psa-example-dpdk-byte-alignment_8.p4 * psa-example-dpdk-byte-alignment_9.p4 * pse-example-dpdk-counter.p4 * psa-example-dpdk-externs.p4 * psa-example-dpdk-meter-execute-err.p4 * psa-example-dpdk-meter.p4 * psa-example-dpdk-meter1.p4 * psa-example-dpdk-varbit-bmv2.p4 * psa-meter1.p4 * psa-meter3.p4 * psa-meter7-bmv2.p4 * psa-random.p4 * psa-register-complex-bmv2.p4 * psa-register-read-write-2-bmv2.p4 * psa-register-read-write-bmv2.p4 * psa-register1.p4 * psa-register2.p4 * psa-register3.p4 * rcp.p4 * rcp1.p4 * register-serenum-bmv2.p4 * simple-firewall_ubpf.p4 * unused-counter-bmv2.p4 * value-sets.p4

Would allowing implicit cast for directionless parameters, as well as in parameters make sense?