Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Code optimization problem with icl 16.0

Mick_Pont
Beginner
740 Views

I have come across what I think is a code optimization problem with icl version 16.0. I'm running on Windows using this:

  Intel(R) C++ Intel(R) 64 Compiler for applications running on Intel(R) 64,
  Version 16.0.0.110 Build 20150815

Here's my test program:

  #include <stdio.h>

  typedef struct
  {
    int init1;
    int init2;
  } my_options;

  void init_options(my_options *options)
  {
    options->init1 = -11111;
    options->init2 = -11111;
  }

  void check_options_init(my_options *options)
  {
    if ((options->init1 != -11111) || (options->init2 != -11111))
      {
        printf("XXXX error: options struct is not initialised\n");
        printf("options->init1 = %d\n", options->init1);
        printf("options->init2 = %d\n", options->init2);
        printf("(options->init1 != -11111) = %d\n", (options->init1 != -11111));
        printf("(options->init2 != -11111) = %d\n", (options->init2 != -11111));
        printf("(options->init1 != -11111) || (options->init2 != -11111) = %d\n",
               (options->init1 != -11111) || (options->init2 != -11111));
      }
    else
      printf("OK - options struct is correctly initialised\n");
  }

  int main (void)
  {
    my_options options;
    init_options(&options);
    check_options_init(&options);
    return 0;
  }

The main program declares a variable of structure type my_options, which contains two integers. It calls a function init_options() to initialise the two integers in the variable. It then calls another function check_options_init() which is supposed to check whether the two integers have been initialised as expected.

I compile from a command line like this:

icl /Od /Z7 /Femain.exe main.c

With older versions of icl (I've tried 15.0, 14.0, 13.0, 12.0) this all works correctly, and the message

OK - options struct is correctly initialised

gets printed. With icl 16.0, though, I get this output:

  XXXX error: options struct is not initialised
  options->init1 = -11111
  options->init2 = -11111
  (options->init1 != -11111) = 0
  (options->init2 != -11111) = 0
  (options->init1 != -11111) || (options->init2 != -11111) = 0

Tracing through the assembly with the Visual Studio debugger it seems pretty clear what the problem is. When compiled with icl 15.0, this is the assembly code generated for function check_options_init():

  void check_options_init(my_options *options)
  {
  000000013F72104D  push        rbp  
  000000013F72104E  sub         rsp,50h  
  000000013F721052  lea         rbp,[rsp+20h]  
  000000013F721057  mov         qword ptr [rbp+20h],rbx  
  000000013F72105B  mov         qword ptr [options],rcx  
    if ((options->init1 != -11111) || (options->init2 != -11111))
  000000013F72105F  mov         rax,qword ptr [options]  
  000000013F721063  mov         eax,dword ptr [rax]  
  000000013F721065  cmp         eax,0FFFFD499h  
  000000013F72106A  jne         check_options_init+31h (013F72107Eh)  
  000000013F72106C  mov         rax,qword ptr [options]  
  000000013F721070  mov         eax,dword ptr [rax+4]  
  000000013F721073  cmp         eax,0FFFFD499h  
  000000013F721078  je          check_options_init+111h (013F72115Eh)  
      {
        printf("XXXX error: options struct is not initialised\n");

Notice that the line

    if ((options->init1 != -11111) || (options->init2 != -11111))

got compiled into two seprate checks on init1 and init2, using register eax, and the constant 0FFFFD499h is -11111.

With icl 16.0 though, this is the assembly:

  void check_options_init(my_options *options)
  {
  000000013F176661  push        rbp  
  000000013F176662  sub         rsp,50h  
  000000013F176666  lea         rbp,[rsp+20h]  
  000000013F17666B  mov         qword ptr [rbp+20h],rbx  
  000000013F17666F  mov         qword ptr [options],rcx  
    if ((options->init1 != -11111) || (options->init2 != -11111))
  000000013F176673  mov         rax,qword ptr [options]  
  000000013F176677  mov         rax,qword ptr [rax]  
  000000013F17667A  cmp         rax,0FFFFFFFFFFFFD499h  
  000000013F176680  je          check_options_init+105h (013F176766h)  
      {
        printf("XXXX error: options struct is not initialised\n");

The two separate checks have been merged into one, so just before the compare instruction at address 000000013F17667A, the register rax contains the value 0FFFFD499FFFFD499h - i.e. two consecutive copies of -11111. The problem is that the constant being compared with is given as 0FFFFFFFFFFFFD499h instead of the correct 0FFFFD499FFFFD499h.

If I modify my struct definition to add a padding item between the two integers, e.g. like this:

  typedef struct
  {
    int init1;
    double pad;
    int init2;
  } my_options;

then the problem goes away - the 16.0 compiler generates two separate comparisons using register eax instead of combining into a single comparison with rax, and the assembly looks similar to that generated with the 15.0 and older compilers.

It looks to me like this is a code optimization gone wrong - although I'm compiling with optimization switched off. It's causing me bother because I'm building a large library with many files which get caught by this problem.

Mick Pont

0 Kudos
1 Solution
JenniferJ
Moderator
740 Views

Hello Mick Pont,

Got some update to this issue. Our compiler engineer has root caused the issue and fixed the problem already. The fix should be in the next coming 2016 update 1 release.

If anyone else thinks your program might be affected by this, and could not use the workaround, please let us know through Intel Premier Support.

Thank you very much Mick for getting a small test case.

Jennifer

 

View solution in original post

0 Kudos
3 Replies
JenniferJ
Moderator
740 Views

Wow. Thank you very much for reporting it, it's escalated to the compiler team.

I did find a simple workaround. please use a "int cont_var = -11111;" for the const. Please use this workaround for now.

I'll give you an update in a couple of days.

Jennifer

0 Kudos
JenniferJ
Moderator
741 Views

Hello Mick Pont,

Got some update to this issue. Our compiler engineer has root caused the issue and fixed the problem already. The fix should be in the next coming 2016 update 1 release.

If anyone else thinks your program might be affected by this, and could not use the workaround, please let us know through Intel Premier Support.

Thank you very much Mick for getting a small test case.

Jennifer

 

0 Kudos
Mick_Pont
Beginner
740 Views

Thanks Jennifer for getting this resolved quickly

Mick

0 Kudos
Reply