status-im / nim-stew

stew is collection of utilities, std library extensions and budding libraries that are frequently used at Status, but are too small to deserve their own git repository.
139 stars 18 forks source link

work around pointless copy in isZeroMemory #233

Closed tersec closed 1 week ago

tersec commented 1 week ago

For example, given

import stew/objects
discard isZeroMemory(default(array[1024, byte]))

The previous code under Nim 2.0.8 with refc compiles to:

N_LIB_PRIVATE N_NIMCALL(NIM_BOOL,
                        _ZN7objects12isZeroMemoryE5arrayI10range010235uInt8E)(
    tyArray__P46RzO9bG1lpfJxQ2itJfAA x_p0) {
  NIM_BOOL result;
  {
    result = (NIM_BOOL)0;
    {
      NU8 b;
      tyArray__P46RzO9bG1lpfJxQ2itJfAA colontmp_;  /* stack copy of the array */
      NI i;
      b = (NU8)0;
      nimZeroMem((void *)colontmp_, sizeof(tyArray__P46RzO9bG1lpfJxQ2itJfAA));
      nimCopyMem((void *)colontmp_, (NIM_CONST void *)((NU8 *)(x_p0)),
                 sizeof(tyArray__P46RzO9bG1lpfJxQ2itJfAA));
      i = ((NI)0);
      {
        while (1) {
          b = colontmp_[(i)-0];
          {
            if (!!((b == ((NU8)0))))
              goto LA6_;
            result = NIM_FALSE;
            goto BeforeRet_;
          }
        LA6_:;
          {
            if (!(((NI)1023) <= ((NI)(i))))
              goto LA10_;
            goto LA2;
          }
        LA10_:;
          i += ((NI)1);
        }
      }
    LA2:;
    }
    result = NIM_TRUE;
  }
BeforeRet_:;
  popFrame();
  return result;
}

which this PR changes to codegen to

N_LIB_PRIVATE N_NIMCALL(NIM_BOOL,
                        _ZN7objects12isZeroMemoryE5arrayI10range010235uInt8E)(
    tyArray__P46RzO9bG1lpfJxQ2itJfAA x_p0) {
  NIM_BOOL result;
  NU8 *bufPtr;
  {
    result = (NIM_BOOL)0;
    bufPtr = ((NU8 *)(x_p0));
    {
      NU8 b;
      NI i;
      b = (NU8)0;
      i = ((NI)0);
      {
        while (1) {
          b = bufPtr[(i)-0];
          {
            if (!!((b == ((NU8)0))))
              goto LA6_;
            result = NIM_FALSE;
            goto BeforeRet_;
          }
        LA6_:;
          {
            if (!(((NI)1023) <= ((NI)(i))))
              goto LA10_;
            goto LA2;
          }
        LA10_:;
          i += ((NI)1);
        }
      }
    LA2:;
    }
    result = NIM_TRUE;
  }
BeforeRet_:;
  popFrame();
  return result;
}

which as intended does not trigger a copy of isZeroMemory's parameter.

initHashSet unconditionally exists in std/sets since at the latest 1.6.0: https://github.com/nim-lang/Nim/blob/v1.6.0/lib/pure/collections/sets.nim#L112-L129

default unconditionally also unconditionally exists since at the latest 1.6.0: https://github.com/nim-lang/Nim/blob/v1.6.0/lib/system.nim#L982-L998