From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id B91103858C41; Wed, 17 May 2023 18:34:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B91103858C41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1684348479; bh=w9v0WZPvHH6WZCmlcYnmdyyGZdS/X13ZTOFJzZ3ybM8=; h=From:To:Subject:Date:From; b=uWS77HhiuZosU/9jOjb0RfX26Sg3e6xmbsjqQ80RvMyTwBvK/R2jVX/q7FUzAwHDC FAk2anJjPXiMB1xy7gFeGpUt3cyNT0APn35xCG9MztBwS9HT72Pm1K6HI4tkBl6Wy6 L4CspcFC0N17Qh0gJ1MO1ElGQ6r0nInx8iDOXwzA= From: "thiago at kde dot org" To: gcc-bugs@gcc.gnu.org Subject: [Bug target/109896] New: Missed optimisation: overflow detection in multiplication instructions for operator new Date: Wed, 17 May 2023 18:34:39 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: target X-Bugzilla-Version: 13.1.1 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: thiago at kde dot org X-Bugzilla-Status: UNCONFIRMED 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: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: 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=3D109896 Bug ID: 109896 Summary: Missed optimisation: overflow detection in multiplication instructions for operator new Product: gcc Version: 13.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: thiago at kde dot org Target Milestone: --- In the following code: struct S { char buf[47]; // weird size }; void *f(unsigned long paramCount) { return new S[paramCount]; } GCC generates (see https://gcc.godbolt.org/z/o5eocj5n9): movabsq $196241958230952676, %rax cmpq %rdi, %rax jb .L2 imulq $47, %rdi, %rdi jmp operator new[](unsigned long) f(unsigned long) [clone .cold]: .L2: pushq %rax call __cxa_throw_bad_array_new_length That's a slight pessimisation of the typical, non-exceptional case because = of the presence of the compare instructions. On modern x86, that's 3 retire sl= ots and 2 uops, in addition to the multiplication's 3 cycles (which may be speculated and start early). But the presence of a 10-byte instruction and = the fact that the jump is further than 8-bit displacement range mean those three instructions occupy 18 bytes, meaning the front-end is sub-utilised, requir= ing 2 cycles to decode the 5 instructions (pre-GLC [I think] CPUs decode 4 instructions in 16 bytes per cycle). Instead, GCC should emit the multiplication and check if the overflow flag = was set. I believe the optimal code for GCC would be: imulq $47, %rdi, %rdi jo .L2 jmp operator new[](unsigned long) That's 15 bytes, so 1 cycle for the decoder to decode all 3 instructions. That's 3+1 cycles and 2 retire slots before the JMP. In the Godbolt link above, Clang and MSVC emitted a CMOV: mulq %rcx movq $-1, %rdi cmovnoq %rax, %rdi jmp operator new[](unsigned long)@PLT This is slightly worse (19 bytes, 4 instructions, though also 3+1 cycles). = For GCC's -fno-exceptions case, I recommend keeping the IMUL+JO case and only l= oad -1 in the .text.unlikely section. But see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D109895=