asm woes...

rikki cattermole via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri May 27 02:51:56 PDT 2016


On 27/05/2016 8:20 PM, Era Scarecrow wrote:
>  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...

Me and p0nce solved this on IRC.

struct Foo {
         int x;

         void foobar() {
                 asm {
                         mov EAX, this;
                         inc [EAX+Foo.x.offsetof];
                 }
         }
}

void main() {
         import std.stdio;

         Foo foo = Foo(8);
         foo.foobar;

         writeln(foo.x);
}

You have to reference the field via a register.


More information about the Digitalmars-d-learn mailing list