Ok, so I was wrong with my explanation of `sink`. I was under the impression 
that the code: 
    
    
    proc a(x : var X, y : sink Y) =
      x.v = y
    proc b(x : var X, y : sink Y) =
      a(x, y)
    proc test() =
      var y = Y()
      var x : X
      b(x, y)
    
    
    Run

would compile to the following (shortened for readability) C code: 
    
    
    void a(X* x, Y* y) {
      eqsink(x.v, y);
    }
    void b(X* x, Y* y) {
      a(x, y);
    }
    void test() {
      Y y;
      X x;
      // ...
      b(&x, &y);
      // ...
    }
    
    
    Run

While in reality this code gets generated: 
    
    
    void a(X* x, Y* y) {
      eqsink(x.v, y);
    }
    void b(X* x, Y* y) {
      Y blitTmp;
      blitTmp = *y;
      a(x, &blitTmp);
    }
    void test() {
      Y y;
      X x;
      Y blitTmp;
      // ...
      blitTmp = y;
      b(&x, &blitTmp);
      // ...
    }
    
    Run

I did some testing and from what I gathered, it seems like gcc is, in some very 
simple cases, able to optimize the blit temporaries aways and do a direct copy. 
In more complex cases however this seems to not be the case. Example: 
    
    
    type
      Y = object
        s : string
        a : array[30, int]
      X = object
        v : X
    
    # using `a` and `b` function from sample above
    
    proc test() =
      var y = Y(s : "abcd")
      var x : X
      b(x, y)
    
    Run

The gcc optimizer fails to elide the blit temporaries in this case, which 
results in two extra unnecessary memset/memcpy pairs.

Compiler info:

  * Nim 1.6.0
  * gcc version 11.1.0 (MinGW x86_64-posix-seh)



Command line: `nim c --gc:arc -d:release`

Reply via email to