Nim icon indicating copy to clipboard operation
Nim copied to clipboard

Dereferencing result of `cast` in single expression triggers unnecessary copy

Open tersec opened this issue 1 year ago • 4 comments

Description

let a = new array[1000, byte]
block:
  for _ in cast[typeof(a)](a)[]:
    discard
block:
  let x = cast[typeof(a)](a)   # not even var
  for _ in x[]:
    discard

Here, the first block/for loop triggers a whole-array copy:

typedef NU8 tyArray__29bRqg639bXs9cqGw2sQY470Q[1000];
...
    {{tyArray__29bRqg639bXs9cqGw2sQY470Q colontmp_;
    NI i;
    nimZeroMem((void *)colontmp_, sizeof(tyArray__29bRqg639bXs9cqGw2sQY470Q));
    nimCopyMem((void *)colontmp_, (NIM_CONST void *)((NU8 *)(a__k_u54)),
               sizeof(tyArray__29bRqg639bXs9cqGw2sQY470Q));
    i = ((NI)0);
    {
      while (1) {
        ___k_u99 = colontmp_[(i)-0];
        {
          if (!(((NI)999) <= i))
            goto LA7_;
          goto LA3;
        }
      LA7_:;
        i += ((NI)1);
      }
    }
  LA3:;
  }
}

i.e. the for loop constructs the colontmp_ variable as the object to loop over, given:

  for _ in cast[typeof(a)](a)[]:
    discard

By contrast, splitting that apart a bit:

  let x = cast[typeof(a)](a)   # not even var
  for _ in x[]:
    discard

results in:

{
  NU8 *colontmpD_;
  colontmpD_ = NIM_NIL;
  colontmpD_ = eqdup___k_u19(((NU8 *)(a__k_u54)));
  x__k_u100 = colontmpD_;
  {
    NI i_2;
    i_2 = ((NI)0);
    {
      while (1) {
        ___k_u105 = x__k_u100[(i_2)-0];
        {
          if (!(((NI)999) <= i_2))
            goto LA16_;
          goto LA12;
        }
      LA16_:;
        i_2 += ((NI)1);
      }
    }
  LA12:;
  }
  {
  LA10_:;
  }
  { eqdestroy___k_u13(x__k_u100); }
  if (NIM_UNLIKELY(*nimErr_))
    goto BeforeRet_;
}

Which does not have any copies. This is with --mm:orc; --mm:refc has a similar pattern but with, refc details, where for _ in cast[typeof(a)](a)[]: triggers a copy and let x = cast[typeof(a)](a) / for _ in x[]: doesn't.

Nim Version

Nim Compiler Version 2.0.9 [Linux: amd64]
Compiled at 2024-09-10
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: 8d254a5945c5cb7612dff2a53be8f8d12b846d60
active boot switches: -d:release
Nim Compiler Version 2.1.99 [Linux: amd64]
Compiled at 2024-09-10
Copyright (c) 2006-2024 by Andreas Rumpf

git hash: 21771765a2c1f1fc86d87ad6e032d4050d8a651b
active boot switches: -d:release

Current Output

Extra copies-on-dereference

Expected Output

Dereference operator never copies

Known Workarounds

No response

Additional Information

No response

tersec avatar Sep 10 '24 10:09 tersec