intel / intel/llvm

DPC++ device frontend never terminates on imgui_internal.h

Open
#22,972 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
LLVM
Stars
1.5k
Forks
854
Avg merge
3d 17h
Merged PRs (30d)
137

Description

### Describe the bug

Just including `imgui_internal.h` (Dear ImGui v1.92.9b) spins "forever", 100% CPU, memory flat at 54 MB.

| compiler | |
| --- | --- |
| oneAPI 2025.1 / .2 / .3 | ok ~1.5 s |
| v6.2.0 | ok 0.9 s |
| v7.0.0 | killed at 300 s |
| nightly-2026-08-17 | killed at 90 s, i.e. not fixed upstream |

### To reproduce

```sh
git clone --depth 1 --branch v1.92.9b https://github.com/ocornut/imgui.git
echo '#include "imgui_internal.h"' > repro.cpp
clang++ -fsycl -fsycl-device-only -fsyntax-only -Iimgui repro.cpp
```

Device pass only. `-fsycl-is-host` and plain C++ 0.2 s, preprocessing unaffected.
Up to v7.0.0 one cc1 flag on the host triple suffices, no SYCL headers: `clang++ -fsyntax-only -Xclang -fsycl-is-device -Iimgui repro.cpp`.
Newer nightlies reject a non-SPIR-V triple there, so use `-fsycl -fsycl-device-only` for cross-version runs.

Including `imgui.h` alone is fine. Needs the dense mutually-referential graph of `ImGuiContext`/`ImGuiWindow`.

Attaching files failed, minimal self-contained (no `#include`) repro by reducing the header, ill-formed by design (`-ferror-limit=0`): 0.1 s v6.2.0 vs 2.0 s v7.0.0, 20x slowdown (not hanging):

```cpp
typedef signed short ImS16;
typedef unsigned short ImU16;
typedef signed int ImS32;
typedef unsigned int ImU32;
typedef signed long long ImS64;
typedef unsigned long long ImU64;
struct ImDrawChannel;
struct ImDrawCmd;
struct ImDrawData;
struct ImDrawList;
struct ImDrawListSharedData;
struct ImDrawListSplitter;
struct ImDrawVert;
struct ImFont;
struct ImFontAtlas;
struct ImFontAtlasBuilder;
struct ImFontConfig;
struct ImFontGlyph;
struct ImFontGlyphRangesBuilder;
struct ImFontLoader;
struct ImTextureData;
struct ImTextureRect;
struct ImGuiSelectionExternalStorage;
struct ImGuiSelectionRequest;
struct ImGuiSizeCallbackData;
struct ImGuiStorage;
enum ImGuiDir : int;
enum ImGuiKey : int;
enum ImGuiMouseSource : int;
enum ImGuiSortDirection : ImU8;
typedef int ImGuiCol;
typedef int ImGuiListClipperFlags;
typedef unsigned short ImWchar16;
template struct ImVector {
int Size;
int Capacity;
T *Data;
ImVec2 WindowTitleAlign;
ImGuiDir WindowMenuButtonPosition;
float ChildRounding;
float ChildBorderSize;
float PopupRounding;
ImVec2 DisplayWindowPadding;
ImVec2 DisplaySafeAreaPadding;
float MouseCursorScale;
bool AntiAliasedLines;
bool AntiAliasedLinesUseTex;
bool AntiAliasedFill;
float CurveTessellationTol;
float CircleTessellationMaxError;
ImVec4 Colors[ImGuiCol_COUNT];
float HoverStationaryDelay;
float HoverDelayShort;
float HoverDelayNormal;
ImGuiHoveredFlags HoverFlagsForTooltipMouse;
ImGuiHoveredFlags HoverFlagsForTooltipNav;
ImFontAtlas *Fonts;
ImFont *FontDefault;
void SetStatus(ImTextureStatus status) {
Status = status;
if (status == ImTextureStatus_Destroyed && !WantDestroyNextFrame &&
Pixels != nullptr)
Status = ImTextureStatus_WantCreate;
}
ImFont *DstFont;
const ImFontLoader *FontLoader;
void *FontLoaderData;
ImFontAtlasFlags_NoBakedLines = 1 << 2,
};
struct ImFontAtlas {
ImFontAtlas();
~ImFontAtlas();
ImFont *AddFont(const ImFontConfig *font_cfg);
ImFont *AddFontDefault(const ImFontConfig *font_cfg = 0);
ImVector TexList;
bool RendererHasTextures;
bool TexIsBuilt;
ImVec2 TexUvWhitePixel;
ImVector Fonts;
ImVector Sources;
ImVec4 TexUvLines[(32) + 1];
int TexNextUniqueID;
int FontNextUniqueID;
ImVector DrawListSharedDatas;
ImFontAtlasBuilder *Builder;
const ImFontLoader *FontLoader;
const char *FontLoaderName;
void *FontLoaderData;
int RefCount;
ImGuiContext *OwnerContext;
ImVector IndexAdvanceX;
float FallbackAdvanceX;
float Size;
float RasterizerDensity;
ImVector IndexLookup;
ImVector Glyphs;
int FallbackGlyphIndex;
float Ascent, Descent;
unsigned int MetricsTotalSurface : 26;
unsigned int WantDestroy : 1;
unsigned int LoadNoFallback : 1;
unsigned int LoadNoRenderOnLayout : 1;
int LastUsedFrame;
ImGuiID BakedId;
ImFont *OwnerFont;
};
struct ImFont {
ImFontBaked *LastBaked;
ImFontAtlas *OwnerAtlas;
ImFontFlags Flags;
float CurrentRasterizerDensity;
ImVector Sources;
}
}
;
struct ImRect {
ImVec2 Min;
ImVec2 Max;
ImVector TempBuffer;
ImVector DrawLists;
ImVector FontAtlases;
ImFont *Font;
ImVector ItemWidthStack;
ImVector TextWrapPosStack;
};
struct ImGuiWindow {
ImGuiWindowFlags Flags;
ImRect OuterRectClipped;
ImRect InnerRect;
ImRect InnerClipRect;
ImRect WorkRect;
ImRect ParentWorkRect;
ImRect ClipRect;
ImGuiWindow *ParentWindow;
ImGuiWindow *ParentWindowInBeginStack;
ImGuiWindow *RootWindow;
ImGuiWindow *RootWindowPopupTree;
};
ImGuiWindow *OuterWindow;
```

### Environment

- OS: independent
- Target device and vendor: N/A, frontend only
- DPC++ version: bisected
```
last good: nightly-2025-09-24 3276ddd75dae5563f336737daddcbb151484702b
first bad: nightly-2025-09-30 0ff1a5c2b4e4bc56799ec2dd17a89c3c57608890
```

### Additional context

Hypothesis from Claude:

`checkSYCLType()` in clang/lib/Sema/SemaSYCL.cpp, from `SemaSYCL::checkSYCLDeviceVarDecl`, device mode only. Walks all fields, follows pointers/arrays into the pointee's fields. `Visited` passed **by value** => memoizes per DFS path, not globally => enumerates simple paths instead of visiting each type once. See [#17313](https://github.com/intel/llvm/issues/17313) (open, wants checkSYCLType merged into `Sema::checkTypeSupport`); mentions no perf impact, but same function.

Exponential in both versions: on v6.2.0, nesting `struct W { ImGuiContext* a; ImGuiContext* b; };`
N deep multiplies time by ~1.8/level (0.7, 0.9, 1.3, 2.0, 3.7 s). So not a new loop — something in the Sept 2025 window weakened dedup enough to push ImGui's graph past any usable threshold;
v6.2.0 needs ~9 extra doublings to reach v7.0.0.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the device-only command with imgui_internal.h and the reduced self-contained example, then inspect checkSYCLType() in clang/lib/Sema/SemaSYCL.cpp and its use from SemaSYCL::checkSYCLDeviceVarDecl. Compare behavior around the bisected nightly commits and the existing context in #17313. Done means the frontend no longer becomes unusably slow on this include while preserving the relevant device checks.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.