The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My work

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,842 other followers

`Inc(I)` versus `I := I + 1;` in Delphi – they’re the same, but not atomic per se.

Posted by jpluimers on 2017/10/10

Given a variable I: Integer, some people like Inc(I); others like I := I + 1;.

You might think that part of that discussion nowadays should be multithreading.

In practice this does not matter: the compiler will use the same instructions for both statements.

TL;DR: This might make you think they are always atomic. But that’s not always true, as the below differences show. In addition, it can also depend on your processor archicture.

In the Win32 Delphi Compiler, this is how they look:

var
  I: Integer;
begin
  I := 1;
  Inc(I, 1);
  I := I + 1;
end;

Disassembly of the Inc(I); instruction: 

Disassembly of the I := I + 1; instruction: 

The same holds for Inc(I, 1); which disassembled is: 

But it can go wrong when you have this piece of code:

var
  I: Integer;
  One: Integer;
begin
  I := 1;
  One := 1;
  Inc(I, One);
  I := I + One;
end;

Disassembly of the Inc(I); instruction: 

Disassembly of the I := I + One; instruction: 

Win32 conclusione

So on Win32:

  • The Inc(I); and I := I + 1; are atomic when using constant increments.
  • Neither are atomic when using increments from variables.

This is true for 32-bit data types and (on modern x64 processors that have a 64-bit memory bus) also for 64-bit data types that have proper memory alignment.

So there are a lot of buts and ifs: atomicity is hard and platform dependend.

Architecture neutral

To be absolutely sure you are doing atomic increments, use the AtomicIncrement [WayBack] intrinsic which was introduced in Delphi XE3, is cross-platform and on Win32 looks like this:

Disassembled AtomicIncrement(I); instruction: 

Disassembled AtomicIncrement(I, 1); instruction: 

Disassembled AtomicIncrement(I, One); instruction: 

I’m not sure what the superfluous add eax instructions are for. I guess a missed compiler optimisation issue.

–jeroen

References:

4 Responses to “`Inc(I)` versus `I := I + 1;` in Delphi – they’re the same, but not atomic per se.”

  1. jpluimers said

    16-bit era LLoyd’s Helpfile: https://web.archive.org/web/19961221204016/http://www.borland.com:80/techsupport/delphi/download_files/ldelphi.zip via https://web.archive.org/web/20171013114622/http://www.delphigroups.info/2/8b/128808.html

  2. jpluimers said

    TJoe commenting on G+ https://plus.google.com/+JeroenPluimers/posts/BV8ByGcSDr1 including a patch for TPrinter when printing with some buggy Xerox drivers: https://code4sale.com/texcellent/PrnFAQ.htm#Xerox

  3. abouchez said

    And the last “add” is mandatory, to return properly the newly stored value. See http://x86.renejeschke.de/html/file_module_x86_id_327.html

    Also note that AtomicIncrement has a noticeable performance cost, since it may flush the CPU cache lines in heavily multi-threaded context.

  4. abouchez said

    Your test is confusing: inc(i) is NOT atomic either, in multi-thread execution: if two threads access the same i variable simultaneously, the result stored may be +1 and not +2.
    AtomicIncrement() is the only cross-platform incrementation function.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: