https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81601
--- Comment #27 from Jeffrey A. Law <law at redhat dot com> --- So I just prototyped a bit of code that might help with this BZ. This seems better suited for match.pd, except that match.pd doesn't seem to want to handle BIT_FIELD_REF nodes. So I did the prototype in forwprop. Given a BIT_AND_EXPR which just masks off high bits that is fed by a BIT_FIELD_REF, we can adjust the # of bits in the BIT_FIELD_REF and the type of the reference. The BIT_AND turns into a nop-conversion. So the key blocks start like this: ;; basic block 2, loop depth 0, maybe hot ;; prev block 0, next block 3, flags: (NEW, VISITED) ;; pred: ENTRY (FALLTHRU,EXECUTABLE) _13 = __builtin_object_size (tp_11(D), 0); _14 = &tp_11(D)->D.2292; .UBSAN_OBJECT_SIZE (_14, 13, _13, 0); _1 = tp_11(D)->chrono_type; _2 = (int) _1; if (_1 == 0) goto <bb 3>; [INV] else goto <bb 5>; [INV] ;; succ: 3 (TRUE_VALUE,EXECUTABLE) ;; 5 (FALSE_VALUE,EXECUTABLE) ;; basic block 3, loop depth 0, maybe hot ;; prev block 2, next block 4, flags: (NEW, VISITED) ;; pred: 2 (TRUE_VALUE,EXECUTABLE) _3 = BIT_FIELD_REF <*tp_11(D), 8, 96>; _4 = _3 & 3; if (_4 != 0) goto <bb 4>; [INV] else goto <bb 5>; [INV] ;; succ: 4 (TRUE_VALUE,EXECUTABLE) ;; 5 (FALSE_VALUE,EXECUTABLE) And the bits in block #3 turn into: ;; basic block 3, loop depth 0, maybe hot ;; prev block 2, next block 4, flags: (NEW, VISITED) ;; pred: 2 (TRUE_VALUE,EXECUTABLE) _9 = BIT_FIELD_REF <*tp_11(D), 2, 96>; _4 = (unsigned char) _9; if (_9 != 0) goto <bb 4>; [INV] else goto <bb 5>; [INV] ;; succ: 4 (TRUE_VALUE,EXECUTABLE) ;; 5 (FALSE_VALUE,EXECUTABLE) That's good enough that FRE can see the redundancy between tp->chrono_type and the BIT_FIELD_REF and all the right things just happen from that point onward.