From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 00F9438708B3; Sat, 11 May 2024 16:05:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 00F9438708B3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1715443555; bh=Yb/WDXqr5EOUQCTKWD5lhEqxq0220PfWIIxxYQz/Leg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jYp26BplLEhzyWxYH0nqKfPB6Nk1UFz5BTZS2wvEXAD3o+Stuv8J5oxfDzYgXH79c j/4iqjgz4wsfAz/fS24spUphQuMwJ0pebW6THJVqXdy+a5H7Iwx7zRanN9Z6aKU2If cXSuS+nQUU5KeAQmVzOfjDiw1q4PrkV0gvuzfbPQ= From: "hubicka at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/109442] Dead local copy of std::vector not removed from function Date: Sat, 11 May 2024 16:05:52 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 13.0 X-Bugzilla-Keywords: missed-optimization X-Bugzilla-Severity: normal X-Bugzilla-Who: hubicka at gcc dot gnu.org X-Bugzilla-Status: REOPENED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 List-Id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D109442 --- Comment #19 from Jan Hubicka --- Note that the testcase from PR115037 also shows that we are not able to optimize out dead stores to the vector, which is another quite noticeable problem. void test() { std::vector test; test.push_back (1); } We alocate the block, store 1 and immediately delete it. void test () { int * test$D25839$_M_impl$D25146$_M_start; struct vector test; int * _61; [local count: 1073741824]: _61 =3D operator new (4); [local count: 1063439392]: *_61 =3D 1; operator delete (_61, 4); test =3D{v} {CLOBBER}; test =3D{v} {CLOBBER(eol)}; return; [count: 0]: : test =3D{v} {CLOBBER}; resx 2 } So my understanding is that we decided to not optimize away the dead stores since the particular operator delete does not pass test: /* If the call is to a replaceable operator delete and results from a delete expression as opposed to a direct call to such operator, then we can treat it as free. */ if (fndecl && DECL_IS_OPERATOR_DELETE_P (fndecl) && DECL_IS_REPLACEABLE_OPERATOR (fndecl) && gimple_call_from_new_or_delete (stmt)) return ". o "; This is because we believe that operator delete may be implemented in an in= sane way that inspects the values stored in the block being freed. I can sort of see that one can write standard conforming code that allocates some data that is POD and inspects it in destructor. However for std::vector this argument is not really applicable. Standard do= es specify that new/delete is used to allocate/deallocate the memory but does = not say how the memory is organized or what happens before deallocation. (i.e. it is probably valid for std::vector to memset the block just before deallocating it). Similar argument can IMO be used for eliding unused memory allocations. It = is kind of up to std::vector implementation on how many allocations/deallocati= ons it does, right? So we need a way to annotate the new/delete calls in the standard library as safe for such optimizations (i.e. implement clang's __bulitin_operator_new/delete?) How clang manages to optimize this out without additional hinting?=