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

ImGui Compilation Problem

BayesBug
Beginner
2,285 Views
Using a current master branch (bfce7750b168b5a857b4379596236dda7b58bd39) of Dear ImGUI (https://github.com/ocornut/imgui) and then building the GLFW Vulkan example in release mode results in broken scroll behavior (if you flip open enough sections in the demo window mouse scrolling will not work). This for me happens only using Intel C++ 2023 with at least O2 optimizations. The problem does not occur when suppressing either inlining or strict-aliasing. I could trace the Problem to the function CalcNextScrollFromScrollTargetAndClamp in imgui.cpp which tries to figure out first the next horizontal and then the next vertical scroll position. Looking at the disassembly it looks to me as though the compiler decided that the second axis(vertical) could just be optimized away for some reason. It might just be some aliasing bug in the imgui code that wasn't obvious to me but just in case it is some compiler bug i wanted to share it here.
0 Kudos
1 Solution
NoorjahanSk_Intel
Moderator
1,765 Views

Hi,


The LLVM optimizer does not know C++ language rules, and IR is too low-level to check them, so such warnings would have a very low detection rate in the backend.

The "return (&x)[idx]" is technically a C++ bounds violation. The compiler assumes that a pointer to one structure member cannot alias another one without reassignment.

The Intel compiler differs from gcc and Clang, in that its default behavior enables aggressive optimizations that assume that there are no C++ language violations or non-numeric FP values, etc. This might cause certain applications to fail with the default options.



 >> what would be a safe and efficient replacement for return (&x)[idx]; without changing the structure of ImVec2"


return idx ? y : x; is a reasonable approach, though it may have more branches in debug modes. It's certainly more clear.

second alternative as {{return *reinterpret_cast<float *>(reinterpret_cast<unsigned char *>(this) + (idx * sizeof(float))); }}because it's a pointer to a struct is a pointer to its first member and there will not be padding between those two members because they have the same alignment.


We suggest that to use return idx ? y : x; as any solution is strictly inferior to this.

 

Thanks & Regards,

Noorjahan.


View solution in original post

0 Kudos
13 Replies
NoorjahanSk_Intel
Moderator
2,229 Views

Hi,

 

Thanks for posting in intel communities.

 

Could you please try disabling the optimization(choose /Od) under

 

Properties -> C/C++ -> Optimization -> /Od

 

We have tried it from our end and did not observe any issues. Please let us know if you still have any issues

 

Thanks & Regards,

Noorjahan.


0 Kudos
BayesBug
Beginner
2,209 Views

With disabled optimization it works. And i just tried it again with a clean installation on a different computer with the same result. Steps using Windows:

  1. install visual studio community edition 2022
  2. install intel c++ extension (installer 2023.0.0.25932)
  3. install Vulkan SDK (https://vulkan.lunarg.com/sdk/home; 1.3.239.0)
  4. load latest master from https://github.com/ocornut/imgui (in my case c9a53aa74d84cdb6471651f7b3da14d7248d58c7)
  5. open examples/imgui_examples.sln solution and autoconvert (WinSDK 10.0.22000.0; Platform Toolset v143)
  6. rightclick solution -> Intel Compiler -> Use Intel oneAPI... to convert it to use the intel compiler
  7. make example_glfw_vulkan the startup project
  8. switch to release build
  9. build
  10. run
  11. open e.g. the help and widgets sections so scroll would be needed
  12. try scrolling -> does not work for me
  13. Look at the disassembly relating to CalcNextScrollFromScrollTargetAndClamp and it looks like the y axis just got optimized away

 

0 Kudos
NoorjahanSk_Intel
Moderator
2,171 Views

Hi,

 

Could you please let us know whether you are getting the same issue by disabling optimization on a different computer?

 

You will not observe any issues if you disable the optimization. We have followed similar steps at our end and it worked as expected without optimization.

 

Could you please provide the OS/Hardware details of different computer?

 

Thanks & Regards,

Noorjahan.


0 Kudos
BayesBug
Beginner
2,156 Views

Yes without optimization it works as expected on all Computers i tested it on. With Optimizations (/O2) enabled it did not work on any.

 

Specs of the computer i did the clean install on:

  • OS: Win10
  • CPU: i5-6600T
  • RAM: 16GB

Another Spec i tested it on:

  • OS: Win11
  • CPU: i9-9900k
  • RAM: 32GB
0 Kudos
NoorjahanSk_Intel
Moderator
2,052 Views

Hi,


We are also able to reproduce your issue at our end.

We have reported this issue to the concerned development team. They are looking into your issue.


Thanks & Regards,

Noorjahan.


0 Kudos
NoorjahanSk_Intel
Moderator
2,000 Views

Hi,


Could you please provide us with a sample reproducer by isolating the issue?


As you said you could trace the problem to the function CalcNextScrollFromScrollTargetAndClamp in imgui.cpp

Could you please make a simple application by extracting this function that can reproduce the problem?


Thanks & Regards,

Noorjahan.


0 Kudos
BayesBug
Beginner
1,981 Views

I traced it further and lets say ImGui is using a "creative" way to access member variables in their 2D vector type. So besides the potential padding issue i guess this is a straight forward case of aliasing rules violation?

I opend an issue in their github: https://github.com/ocornut/imgui/issues/6272 

 

Reduced sample code:

#include <iostream>

struct ImVec2
{
  float x, y;
  ImVec2(float _x, float _y) : x(_x), y(_y) { }
  float& operator[] (size_t idx) { return (&x)[idx]; }
};

int main(int, char**)
{
  ImVec2 a{ 0.0f, 0.0f };
  ImVec2 b{ 1.0f, 2.0f };
  ImVec2 c{ 0.0f, 0.0f };
  for (int axis = 0; axis < 2; axis++)
  {
    a[axis] = b[axis] + c[axis];
  }

  std::cout << a[0] << a[1];
  return 0;
}

 

0 Kudos
NoorjahanSk_Intel
Moderator
1,878 Views

Hi,


Thanks for providing the sample reproducer.


Could you please let us know the expected output of this sample code?

Also please let us know how you are stating(in the GitHub issue) that it is breaking ImVec2.


Thanks & Regards,

Noorjahan.


0 Kudos
BayesBug
Beginner
1,853 Views

Going by the intention of the ImVec2 class one would expect it to output "12"  as (1,2)+(0,0)=(1,2).

What i see when compiling with default O2 optimizations is "10".

When disabling optimizations, inlining and/or strict-aliasing it outputs "12".

 

That I think is acceptable behaviour as (&x) is a pointer referring to a single float and accessing it via index 1 is an aliasing violation, thus UB. Also ImVec2 would break if for some reason padding would be introduced between x and y.

 

What I would wish for in the IntelC++ compiler is some warning or optimization report entry telling me about it.

 

Also I would appriciate if someone has an insight what would be a safe and efficent replacement for return (&x)[idx]; without changing the structure of ImVec2 (see the discussion in https://github.com/ocornut/imgui/issues/6272).

 

0 Kudos
NoorjahanSk_Intel
Moderator
1,766 Views

Hi,


The LLVM optimizer does not know C++ language rules, and IR is too low-level to check them, so such warnings would have a very low detection rate in the backend.

The "return (&x)[idx]" is technically a C++ bounds violation. The compiler assumes that a pointer to one structure member cannot alias another one without reassignment.

The Intel compiler differs from gcc and Clang, in that its default behavior enables aggressive optimizations that assume that there are no C++ language violations or non-numeric FP values, etc. This might cause certain applications to fail with the default options.



 >> what would be a safe and efficient replacement for return (&x)[idx]; without changing the structure of ImVec2"


return idx ? y : x; is a reasonable approach, though it may have more branches in debug modes. It's certainly more clear.

second alternative as {{return *reinterpret_cast<float *>(reinterpret_cast<unsigned char *>(this) + (idx * sizeof(float))); }}because it's a pointer to a struct is a pointer to its first member and there will not be padding between those two members because they have the same alignment.


We suggest that to use return idx ? y : x; as any solution is strictly inferior to this.

 

Thanks & Regards,

Noorjahan.


0 Kudos
NoorjahanSk_Intel
Moderator
1,712 Views

Hi,


We haven't heard back from you. Could you please provide an update on your issue?


Thanks & Regards,

Noorjahan.


0 Kudos
BayesBug
Beginner
1,672 Views

Hi Noorjahan,

 

I accepted your answer above as solution.

 

Thanks & Regards,

Bayes

0 Kudos
NoorjahanSk_Intel
Moderator
1,596 Views

Hi,


Thanks for accepting our solution.


As this issue has been resolved, we will no longer respond to this thread. If you need any additional information, please post a new question 


Thanks & Regards,

Noorjahan.


0 Kudos
Reply