Well decided I should dig my hand in assembly just to see if it would work. Using wideint.d as a starting point I thought I would do the simplest operation I could do, an increment.

https://github.com/d-gamedev-team/gfm/blob/master/integers/gfm/integers/wideint.d
  https://dlang.org/spec/iasm.html

Most of my code was failing outright until I looked at the integrated assembler page, which TDPL doesn't go into at all. To access variables for example I have to do var[ESP] or var[RSP] to access it from the stack frame. Unintuitive, but sure I can work with it.

 So the code for incrementing is pretty simple...

  @nogc void increment() pure nothrow
    ++lo;
    if (lo == 0) ++hi;
  }

That's pretty simple to work with. I know the assembly instructions can be done 1 of 2 ways.

   add lo, 1
   adc hi, 0

 OR

   inc lo
   jnc L1 //jump if not carry
   inc hi


So I've tried. Considering the wideint basically is self calling if you want to make a larger type than 128bit, then that means I need to leave the original code alone if it's a type that's too large, but only inject assembly if it's the right time and size. Thankfully bits is there to tell us.

So, add version
  @nogc void increment() pure nothrow
  {
    static if (bits > 128) {
      ++lo;
      if (lo == 0) ++hi;
    } else {
      version(X86) {
        asm pure @nogc nothrow {
          add lo[ESP], 1;
          adc hi[ESP], 0;
        }
      } else {
        ++lo;
        if (lo == 0) ++hi;
      }
    }
  }

I compile and get: Error: asm statements cannot be interpreted at compile time

The whole thing now fails, rather than compiling to do the unittests... Doing the inc version gives the same error..

        asm pure @nogc nothrow {
          inc lo[ESP];
          jnc L1;
          inc hi[ESP];
          L1:;
        }

Naturally it wasn't very specific about if I should rely on RSP or ESP or what, but since it's X86 rather than X86_64 I guess that answers it... would be easy to write the x64 version, if it would let me.

So i figure i put a check for __ctfe and that will avoid the assembly calls if that's the case. So...

    version(X86) {
      @nogc void increment() pure nothrow
      {
        if (!__ctfe && bits == 128) {
          asm pure @nogc nothrow {
            add lo[ESP], 1;
            adc hi[ESP], 0;
          }
        } else {
          ++lo;
          if (lo == 0) ++hi;
        }
      }
    } else {
      //original declaration
    }

Now it compiles, however it hangs the program when doing the unittest. Why does it hang the program? I have no clue. Tried changing the ESP to EBP just in case that was actually what it wanted, but doesn't seem to be the case. I can tell how I will be refactoring the code, assuming i can figure out what's wrong in the first place...

Anyone with inline assembly experience who can help me out a little? 2 add instructions shouldn't cause it to hang...

Reply via email to