Bug 108847 - [12/13/14/15 Regression] unnecessary bitwise AND on boolean types and shifting of the "sign" bit
Summary: [12/13/14/15 Regression] unnecessary bitwise AND on boolean types and shiftin...
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 13.0
: P2 trivial
Target Milestone: 14.3
Assignee: Andrew Pinski
URL:
Keywords: deferred, missed-optimization
Depends on:
Blocks:
 
Reported: 2023-02-19 13:37 UTC by LIU Hao
Modified: 2024-08-01 09:31 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-*-* aarch64-*-*
Build:
Known to work: 4.1.2, 4.7.2, 4.9.0
Known to fail: 5.1.0, 7.1.0
Last reconfirmed: 2023-02-20 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description LIU Hao 2023-02-19 13:37:50 UTC
Godbolt: https://gcc.godbolt.org/z/fsavMzMo7

```
void
set_bool(bool& fl, __UINT32_TYPE__ value)
  {
    fl |= value >> 31;
  }
```

This code shifts a `uint32` to the right by 31 bits, so the result will only be 0 or 1.

Clang outputs:

```
set_bool(bool&, unsigned int):                         # @set_bool(bool&, unsigned int)
        shr     esi, 31
        or      byte ptr [rdi], sil
        ret
```

but GCC emits an additional unnecessary bitwise AND operation on the destination operand:

```
set_bool(bool&, unsigned int):
        shr     esi, 31
        or      BYTE PTR [rdi], sil
        and     BYTE PTR [rdi], 1
        ret
```
Comment 1 Andrew Pinski 2023-02-20 18:43:50 UTC
The workaround in this case is just to do:
((__INT32_TYPE__)value) < 0

instead of value>>31.
Comment 2 Andrew Pinski 2023-05-20 01:14:26 UTC
I am messing around in this area ....
Comment 3 Andrew Pinski 2023-05-20 23:31:53 UTC
So looking into this a little futher.
The problem is VRP turns !=0 into (bool) and then expand comes along and decides that a cast to bool needs &1 because well it just. I am going to look into see if I can remove the &1 there ...
Comment 4 Andrew Pinski 2023-05-20 23:36:24 UTC
VRP starting doing this in GCC 5:
Folding statement: _5 = _4 != 0;
Folded into: _5 = (bool) _4;
Comment 5 Andrew Pinski 2023-05-27 06:50:38 UTC
Oh simple way to solve this to convert:
  t2_7 = (unsigned int) t_4;
  _1 = t1_6 | t2_7;
  t_8 = _1 != 0;

Into:
  t3_8 = t1_7 != 0;
  _1 = t_5 | t3_8;

Which is smaller even.

(for bit_op (bit_ior bit_and bit_xor)
 (simplify
  (ne (bit_op (convert @0) @1) integer_zerop@2)
   (if (TREE_CODE (TREE_TYPE (@0)) == BOOLEAN_TYPE
        && types_match (type, @0))
    (bit_op @0 (ne @1 @2))))
Comment 6 Andrew Pinski 2023-05-27 07:02:01 UTC
Just for reference here are the functions I tried to see which way was the best (set_bool0 and set_bool0_ produce the best for x86):
void
set_bool(bool& fl, __UINT32_TYPE__ value)
  {
    bool t = fl;
    __UINT32_TYPE__ t1 = value>>31;
    __UINT32_TYPE__ t2 = t;
    t = t2 | t1;
    fl = t;
  }
  
void
set_bool0(bool& fl, __UINT32_TYPE__ value)
  {
    bool t = fl;
    __UINT32_TYPE__ t1 = value>>31;
    bool t3 = t1;
    t = t | t3;
    fl = t;
  }  

void
set_bool0_(bool& fl, __INT32_TYPE__ value)
  {
    bool t = fl;
    __UINT32_TYPE__ t1 = value<0;
    bool t3 = t1;
    t = t | t3;
    fl = t;
  }
  
  void
set_bool1(bool& fl, __UINT32_TYPE__ value)
  {

    fl |= value >> 31;
  }
Comment 7 Andrew Pinski 2023-09-17 01:49:23 UTC
Funny, the match pattern in comment #5 is similar to the one which I was working on for PR 52345 .
Comment 8 Richard Biener 2024-05-07 07:40:11 UTC
GCC 14.1 is being released, retargeting bugs to GCC 14.2.
Comment 9 Jakub Jelinek 2024-08-01 09:31:52 UTC
GCC 14.2 is being released, retargeting bugs to GCC 14.3.