NO

Author Topic: How does the compiler translate  (Read 3674 times)

Grincheux

  • Guest
How does the compiler translate
« on: April 03, 2021, 07:09:29 PM »
I have two lines of code:

Code: [Select]
            _iEditField = (_k + _j) + IDC_EDIT_0001 ;
            GetDlgItemText(hMainWindow,_iEditField,_lpszTmp,sizeof(_szTmp)) ;

I woulid like to know if I change in:
Code: [Select]
            GetDlgItemText(hMainWindow,(_k + _j) + IDC_EDIT_0001,_lpszTmp,sizeof(_szTmp)) ;

is more efficient or if the comoiler does it at my place?

Second question:

I have a char variable _szTmp[1024] it is often used in a loop.
Is it better to have a pointer on that variable or not.

Code: [Select]
alignas(int) char _szTmp[1024] ;
alignas(LPSTR) LPSTR _lpszTmp ;

_lpszTmp = _szTmp ;

      for(_i = _iStart ; _i < _iEnd ; _i++)
      {
         for(_j = _iStart ; _j < _iEnd ; _j++)
         {
            _iEditField = (_k + _j) + IDC_EDIT_0001 ;
            GetDlgItemText(hMainWindow,_iEditField,_lpszTmp,sizeof(_szTmp)) ;  // Removed _szTmp

            lpCurrentFilter->Filter.Matrix[_iIndice] = atoi(_lpszTmp) ;   // Removed _szTmp

            _iIndice++ ;
         }

         _k += MAX_EDIT_COLUMNS ;
      }

For me the compiler must generate something like LEA RAX,_szTmp followed by PUSH RAX.
When using _lpszTmp the code woud be PUSH [_lpszTmp + RIP] The best use would that this is in a register.
Is it better and exact?

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2112
Re: How does the compiler translate
« Reply #1 on: April 03, 2021, 11:29:18 PM »
The compiler does everything required to produce efficient code through the optimization phases. They are generally at least two, the first at level of AST (Abstract Syntax Tree), then the intermediate code, if used by the compiler, then are ran the 'peep-hole' optimization on the emitted code at assembly level.
Almost always the code is much more efficient of hand coded assembly because the compiler use standardized techniques suggested by processor producers.
Consider that not always what seems an efficient assembly coding is such during execution due to CPU internal architecture and hardware. That's why the assembly coder is a difficult life, isn't enough the knowledge of the processor instructions, they must know how the CPU works indeed. For this reason most C code executes faster and more efficient of manual assembled code.
Of course if you select no-optimization on compiler the code emitted is coincident with 'C' source, you can easily follow the execution flow, but the efficiency is counter-efficiency...
« Last Edit: April 04, 2021, 04:39:43 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Grincheux

  • Guest
Re: How does the compiler translate
« Reply #2 on: April 04, 2021, 05:55:21 AM »
If I resume, write your code like a pig and the compiler make the rest!

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2266
    • http://www.smorgasbordet.com
Re: How does the compiler translate
« Reply #3 on: April 04, 2021, 01:31:55 PM »
The compiler will do it's best to produce quality assembly from the provided code. It has little understanding of algorithms: give the compiler a poor algorithm and it will optimize this algorithm, not replace it with a better one.

Many optimizations are done on the "intermediate code" where modern compilers normally use SSA "Static Single Assignment" form which greatly simplifies many analysis and transformations - at least as long as the language doesn't include pointers, which C unfortunately does. With pointers we enter the complicated world of "aliasing" (which I will ignore right now).

Here is a wikipedia link that may be helpful:
https://en.wikipedia.org/wiki/Optimizing_compiler

A random (somewhat silly) example from a compiler book, to make things more concrete:

This C code...

Code: [Select]
int length, width, radius;
enum figure { RECTANGLE, CIRCLE };

extern void process(int,int);

void the_function(void)
{
    int area = 0,
        volume = 0,
        height;
    enum figure kind = RECTANGLE;
    for (height = 0;
         height < 10;
         height++)
    {
        if (kind == RECTANGLE)
        {
            area += length * width;
            volume += length * width * height;
        }
        else if (kind == CIRCLE)
        {
            area += 3.14 * radius * radius;
            volume += 3.14 * radius * radius * height;
        }
    }
    process(area, volume);
}

...will be translated to this X64 code with the current compiler:

Code: [Select]
the_function:
  [0000000000000000] 8B0500000000                 mov               eax,dword ptr [length]
  [0000000000000006] 0FAF0500000000               imul              eax,dword ptr [width]
  [000000000000000D] 678D14C0                     lea               edx,[eax+eax*8]
  [0000000000000011] 678D1492                     lea               edx,[edx+edx*4]
  [0000000000000015] 678D0C80                     lea               ecx,[eax+eax*4]
  [0000000000000019] 01C9                         add               ecx,ecx
  [000000000000001B] E900000000                   jmp               process

Bottom line: don't worry about "micro-optimizations" like argument passing, the compiler will handle it. Over the years I have seen lots of code where the programmers tried to "improve" things with "clever" tricks. They hardly ever improved things, but they often managed to confuse the compiler enough to stop it from doing better optimizations (so they ended up with less optimal code). Try to aim for readable code, code you can still understand even after forgetting it for three years. This is the best advice I can give you.


/Pelle

Grincheux

  • Guest
Re: How does the compiler translate
« Reply #4 on: April 04, 2021, 06:32:10 PM »
Thank You for the lesson.
I will apply your advices.