From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1666) id 9CDA43858C2D; Tue, 11 Oct 2022 12:06:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9CDA43858C2D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1665490003; bh=wcsoxCLvtiwwfkcxY6gZGKrhRpHcHxe/FKjqCMai2Ok=; h=From:To:Subject:Date:From; b=oDzjtZgJMOXjpswO1BIKybyw4bIRqxS8rEV1nBsodacY+6+O942uUeAOZwi5zqztd IX5sXEbrkhdpgbb1KSuc4Sv/3++PwlhPGPzq0gEqr+4TVfudG9ROw59uIIcsyDY3dd F8hUYTiFH3Go2gMzB+ClcsdZ7VDE21e/nw0LVjyA= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Richard Biener To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-8818] tree-optimization/105937 - avoid uninit diagnostics crossing iterations X-Act-Checkin: gcc X-Git-Author: Richard Biener X-Git-Refname: refs/heads/releases/gcc-12 X-Git-Oldrev: 97374f25e1ee7ea45293c244f29425c9f9abcf5a X-Git-Newrev: 627132c9bf9439bf0ac83bb092182055c1e0f3ab Message-Id: <20221011120643.9CDA43858C2D@sourceware.org> Date: Tue, 11 Oct 2022 12:06:43 +0000 (GMT) List-Id: https://gcc.gnu.org/g:627132c9bf9439bf0ac83bb092182055c1e0f3ab commit r12-8818-g627132c9bf9439bf0ac83bb092182055c1e0f3ab Author: Richard Biener Date: Fri Aug 19 14:12:52 2022 +0200 tree-optimization/105937 - avoid uninit diagnostics crossing iterations The following avoids adding PHIs to the worklist for uninit processing if we reach them following backedges. That confuses predicate analysis because it assumes the use is happening in the same iteration as the the definition. For the testcase in the PR the situation is like void foo (int val) { int uninit; # val = PHI <..> (B) for (..) { if (..) { .. = val; (C) val = uninit; } # val = PHI <..> (A) } } and starting from (A) with 'uninit' as argument we arrive at (B) and from there at (C). Predicate analysis then tries to prove the predicate of (B) (not the backedge) can prove that the path from (B) to (C) is unreachable which isn't really what it necessary - that's what we'd need to do when the preheader edge of the loop were the edge with the uninitialized def. So the following makes those cases intentionally false negatives. PR tree-optimization/105937 * tree-ssa-uninit.cc (find_uninit_use): Do not queue PHIs on backedges. (execute_late_warn_uninitialized): Mark backedges. * g++.dg/uninit-pr105937.C: New testcase. (cherry picked from commit c77fae1ca796d6ea06d5cd437909905c3d3d771c) Diff: --- gcc/testsuite/g++.dg/uninit-pr105937.C | 235 +++++++++++++++++++++++++++++++++ gcc/tree-ssa-uninit.cc | 14 +- 2 files changed, 247 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/g++.dg/uninit-pr105937.C b/gcc/testsuite/g++.dg/uninit-pr105937.C new file mode 100644 index 00000000000..26b4f74c5e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/uninit-pr105937.C @@ -0,0 +1,235 @@ +// { dg-do compile } +// { dg-require-effective-target c++17 } +// { dg-options "-O2 -Wall" } + +#include +#include +#include + +using utf8 = char; + +enum +{ + FONT_SIZE_TINY = 2, + FONT_SIZE_SMALL = 0, + FONT_SIZE_MEDIUM = 1, + FONT_SIZE_COUNT = 3 +}; + +constexpr const uint16_t FONT_SPRITE_GLYPH_COUNT = 224; + +enum class FontSpriteBase : int16_t +{ + MEDIUM_EXTRA_DARK = -2, + MEDIUM_DARK = -1, + + TINY = FONT_SIZE_TINY * FONT_SPRITE_GLYPH_COUNT, + SMALL = FONT_SIZE_SMALL * FONT_SPRITE_GLYPH_COUNT, + MEDIUM = FONT_SIZE_MEDIUM * FONT_SPRITE_GLYPH_COUNT, +}; + +struct TTFSurface; + +class CodepointView +{ +private: + std::string_view _str; + +public: + class iterator + { + private: + std::string_view _str; + size_t _index; + + public: + iterator(std::string_view str, size_t index) + : _str(str) + , _index(index) + { + } + + bool operator==(const iterator& rhs) const + { + return _index == rhs._index; + } + bool operator!=(const iterator& rhs) const + { + return _index != rhs._index; + } + char32_t operator*() const + { + return GetNextCodepoint(&_str[_index], nullptr); + } + iterator& operator++() + { + return *this; + } + iterator operator++(int) + { + auto result = *this; + if (_index < _str.size()) + { + const utf8* nextch; + GetNextCodepoint(&_str[_index], &nextch); + _index = nextch - _str.data(); + } + return result; + } + + size_t GetIndex() const + { + return _index; + } + + static char32_t GetNextCodepoint(const char* ch, const char** next); + }; + + CodepointView(std::string_view str) + : _str(str) + { + } + + iterator begin() const + { + return iterator(_str, 0); + } + + iterator end() const + { + return iterator(_str, _str.size()); + } +}; + +struct InternalTTFFont; +using TTF_Font = InternalTTFFont; +struct TTFFontDescriptor +{ + const utf8* filename; + const utf8* font_name; + int32_t ptSize; + int32_t offset_x; + int32_t offset_y; + int32_t line_height; + int32_t hinting_threshold; + TTF_Font* font; +}; +using codepoint_t = uint32_t; + +#define abstract = 0 + +struct ITTF +{ + virtual ~ITTF() = default; + virtual TTFFontDescriptor* ttf_get_font_from_sprite_base(FontSpriteBase spriteBase) abstract; + virtual TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, std::string_view text) abstract; +}; + +namespace OpenRCT2 { + struct IContext + { + virtual ~IContext() = default; + + virtual ITTF* GetTTF() abstract; + }; +} + +static void ttf_draw_string_raw_ttf(OpenRCT2::IContext* context, std::string_view text) +{ + TTFFontDescriptor* fontDesc = context->GetTTF()->ttf_get_font_from_sprite_base(FontSpriteBase::MEDIUM_EXTRA_DARK); + if (fontDesc->font == nullptr) + { + return; + } + + TTFSurface* surface = context->GetTTF()->ttf_surface_cache_get_or_add(fontDesc->font, text); + if (surface == nullptr) + return; +} + +namespace UnicodeChar +{ + // Punctuation + constexpr char32_t leftguillemet = 0xAB; + constexpr char32_t rightguillemet = 0xBB; + constexpr char32_t german_quote_open = 0x201E; + constexpr char32_t quote_open = 0x201C; + constexpr char32_t quote_close = 0x201D; + + // Dingbats + constexpr char32_t up = 0x25B2; + constexpr char32_t small_up = 0x25B4; + constexpr char32_t right = 0x25B6; + constexpr char32_t down = 0x25BC; + constexpr char32_t small_down = 0x25BE; + constexpr char32_t left = 0x25C0; + constexpr char32_t tick = 0x2713; + constexpr char32_t plus = 0x2795; + constexpr char32_t minus = 0x2796; + + // Emoji + constexpr char32_t cross = 0x274C; + constexpr char32_t variation_selector = 0xFE0F; + constexpr char32_t eye = 0x1F441; + constexpr char32_t road = 0x1F6E3; + constexpr char32_t railway = 0x1F6E4; +}; // namespace UnicodeChar + + +static bool ShouldUseSpriteForCodepoint(char32_t codepoint) +{ + switch (codepoint) + { + case UnicodeChar::up: + case UnicodeChar::down: + case UnicodeChar::leftguillemet: + case UnicodeChar::tick: + case UnicodeChar::cross: + case UnicodeChar::right: + case UnicodeChar::rightguillemet: + case UnicodeChar::small_up: + case UnicodeChar::small_down: + case UnicodeChar::left: + case UnicodeChar::quote_open: + case UnicodeChar::quote_close: + case UnicodeChar::german_quote_open: + case UnicodeChar::plus: + case UnicodeChar::minus: + case UnicodeChar::variation_selector: + case UnicodeChar::eye: + case UnicodeChar::road: + case UnicodeChar::railway: + return true; + default: + return false; + } +} + +void ttf_process_string_literal(OpenRCT2::IContext* context, std::string_view text) +{ + CodepointView codepoints(text); + std::optional ttfRunIndex; + for (auto it = codepoints.begin(); it != codepoints.end(); it++) + { + auto codepoint = *it; + if (ShouldUseSpriteForCodepoint(codepoint)) + { + if (ttfRunIndex.has_value()) + { + // Draw the TTF run + auto len = it.GetIndex() - ttfRunIndex.value(); // { dg-bogus "may be used uninitialized" } + ttf_draw_string_raw_ttf(context, text.substr(ttfRunIndex.value(), len)); + ttfRunIndex = std::nullopt; + } + + // Draw the sprite font glyph + } + else + { + if (!ttfRunIndex.has_value()) + { + ttfRunIndex = it.GetIndex(); + } + } + } +} diff --git a/gcc/tree-ssa-uninit.cc b/gcc/tree-ssa-uninit.cc index f326f1775c0..30aafda68f7 100644 --- a/gcc/tree-ssa-uninit.cc +++ b/gcc/tree-ssa-uninit.cc @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-predicate-analysis.h" #include "domwalk.h" #include "tree-ssa-sccvn.h" +#include "cfganal.h" /* This implements the pass that does predicate aware warning on uses of possibly uninitialized variables. The pass first collects the set of @@ -1191,8 +1192,16 @@ find_uninit_use (gphi *phi, unsigned uninit_opnds, basic_block use_bb; if (gphi *use_phi = dyn_cast (use_stmt)) - use_bb = gimple_phi_arg_edge (use_phi, - PHI_ARG_INDEX_FROM_USE (use_p))->src; + { + edge e = gimple_phi_arg_edge (use_phi, + PHI_ARG_INDEX_FROM_USE (use_p)); + use_bb = e->src; + /* Do not look for uses in the next iteration of a loop, predicate + analysis will not use the appropriate predicates to prove + reachability. */ + if (e->flags & EDGE_DFS_BACK) + continue; + } else use_bb = gimple_bb (use_stmt); @@ -1339,6 +1348,7 @@ execute_late_warn_uninitialized (function *fun) /* Mark all edges executable, warn_uninitialized_vars will skip unreachable blocks. */ set_all_edges_as_executable (fun); + mark_dfs_back_edges (fun); /* Re-do the plain uninitialized variable check, as optimization may have straightened control flow. Do this first so that we don't accidentally