1. 3

    How do you solve this problem with proposed ABI?

    struct Big { int a = 11; ... } // sizeof == 32 bytes
    Big big;
    
    void foo() {
        bar(big);
    }
    
    void bar(Big param) {
        qux();
        print(param.a); // will print 42 instead of 11
    }
    
    void qux() {
        big.a = 42;
    }
    
    1. 1

      I think the compiler would have to do some analysis and know that qux modifies big.a and bar calls qux so also modifies big.a by proxy. Because of this, bar would be responsible for making a copy of bar.a before ti calls qux.

      What makes this tricky is that you have to know what functions modify what even if it’s a nested function call and that information isn’t available in C headers so you would have to do some link time analysis. That’s a lot of extra linking complexity for some perf gains but it could be worth it.

      1. 1

        The proposed ABI says that the passed object should be immutable, I think.

        1. 1

          A correctly-specified ABI should pass large structures by immutable reference, usually obviating the copy. In the event that a copy is needed, it will happen only once, in the callee, rather than needing to be repeated by every caller. The callee also has more flexibility, and can copy only those portions of the structure that are actually modified.

          Looks like the immutability only applies to the reference that callee holds, not the original lvalue. This paragraph also says that only callee will ever need to do the copy. The only way to fix this that I see, is to do copy on caller side if it cannot guarantee that callee holds the only mutable pointer to the data.

        2. 1

          When you say “will print 42 instead of 11”, what does that mean? Is it the intended semantics, or is it the semantics guaranteed by C? If no copy is ever intended, how can it be advantageous to have an ABI copy more, as is suggested in OP?

          1. 2

            Passing by value is semantically a copy

          2. 1

            It’s a good point. I guess my answer is that structures should generally be passed by value, and that global variables should generally be avoided, meaning that there won’t generally be opportunity for aliasing. In the event that there is aliasing you have to make a copy on the caller side, but you’re not much worse off than you would otherwise have been.