Using nonzero_bits() in insn conditions?
Georg-Johann Lay
avr@gjlay.de
Fri Mar 21 18:27:51 GMT 2025
Am 21.03.25 um 19:16 schrieb Georg-Johann Lay via Gcc:
> Am 21.03.25 um 01:02 schrieb Jeff Law:
>> On 3/19/25 4:14 AM, Georg-Johann Lay wrote:
>>> Am 16.03.25 um 14:51 schrieb Jeff Law via Gcc:
>>>> On 3/13/25 5:39 AM, Georg-Johann Lay via Gcc wrote:
>>>>> There are situations where knowledge about which bits
>>>>> of a value are (not) set can be used for optimization.
>>>>> For example in an insn combine pattern like:
>>>>>
>>>>> (define_insn_and_split ""
>>>>> [(set (match_operand:QI 0 "register_operand" "=d")
>>>>> (ior:QI (ashift:QI (match_operand:QI 1 "register_operand"
>>>>> "r")
>>>>> (match_operand:QI 2
>>>>> "const_0_to_7_operand" "n"))
>>>>> (match_operand:QI 3 "register_operand" "0")))]
>>>>> "optimize
>>>>> && !reload_completed
>>>>> && nonzero_bits (operands[1], VOIDmode) == 1"
>>>>> ...
>>>>>
>>>>> This pattern is only correct when operands[1] is 0 or 1.
>>>>>
>>>>> While such patterns seem to work, it's all quite wonky,
>>>>> in particular since nonzero_bits() may forget about known
>>>>> properties in later passes.
>>>> While it works most of the time, it's fundamentally wrong to have a
>>>> pattern where the conditional is dependent on state that changes
>>>> based on pass specific data, nearby context, etc.
>>>>
>>>>>
>>>>> For the use case I have in mind, it is in order when the
>>>>> pattern works until split1 which would transform it into
>>>>> something else (and without nonzero_bits() in the insn
>>>>> condition, asserting that the existence of the pattern
>>>>> certifies the bit condition).
>>>> It's still the wrong thing to do. You'll get away with it for a
>>>> while, but one day it'll break.
>>>>
>>>> We have similar problems in the RISC-V world where we would like to
>>>> be able to match certain patterns based on known ranges of an
>>>> operand. The most common case would be bset/bclr/binv on an SImode
>>>> object on rv64 where the bit twiddled is variable. In particular we
>>>> need to know the bit position is not bit 31.
>>>>
>>>> There's no way to really describe that in an insn's condition
>>>> because range information like that isn't available in RTL and
>>>> something like nonzero bits is pass specific.
>>>>
>>>> As a result we're limited in our ability to use the bset/bclr/binv
>>>> instructions.
>>>>
>>>> Jeff
>>>
>>> One way to support this is a new target hook that would run somewhere
>>> in recog_for_combine(). The hook would allow the backend to replace
>>> the pattern as synthesized by combine with an equivalent pattern.
>> Much simpler: Add a split pass immediately after combine. Use
>> define_insn_and_split to handle rewriting. No hooks needed.
>>
>> Jeff
>
> Unfortunately, that doesn't work:
>
> .../libgcc/config/avr/libf7/libf7.c: In function '__f7_get_float':
> .../libgcc/config/avr/libf7/libf7.c:354:1: error: wrong amount of branch
> edges after unconditional jump 18
> 354 | }
> | ^
> during RTL pass: avr-split-after-combine
> .../libgcc/config/avr/libf7/libf7.c:354:1: internal compiler error:
> verify_flow_info failed
> 0x1df2e91 internal_error(char const*, ...)
> .../gcc/diagnostic-global-context.cc:517
> 0xa580fe verify_flow_info()
> .../gcc/cfghooks.cc:287
> 0xf084c8 checking_verify_flow_info()
> .../gcc/cfghooks.h:214
> 0xf084c8 split_all_insns()
> .../gcc/recog.cc:3608
> 0xf084e8 execute
> .../gcc/recog.cc:4507
>
> This used a clone of pass_split_all_insns which runs
> checking_verify_flow_info() at the end. passes.def reads:
>
> NEXT_PASS (pass_combine);
> NEXT_PASS (pass_late_combine);
> NEXT_PASS (pass_if_after_combine);
> NEXT_PASS (pass_jump_after_combine);
> NEXT_PASS (pass_partition_blocks);
> NEXT_PASS (pass_outof_cfg_layout_mode);
> NEXT_PASS (pass_split_all_insns);
>
> So just cloning pass_split_all_insns won't work.
> But using split_all_insns_noflow() instead should
> do the trick then?
>
> Johann
...unfortunately, using split_all_insns_noflow() doesn't work, either:
sreg.c:136:1: error: flow control insn inside a basic block
(jump_insn 67 66 70 2 (set (pc)
(if_then_else (eq (zero_extract:QI (reg:QI 112 [ sreg ])
(const_int 1 [0x1])
(const_int 0 [0]))
(const_int 0 [0]))
(label_ref 69)
(pc))) "sreg.c":125:20 -1
(nil)
-> 69)
during RTL pass: avr-split-after-combine
dump file: sreg.c.305r.avr-split-after-combine
sreg.c:136:1: internal compiler error: in rtl_verify_bb_insns, at
cfgrtl.cc:2836
So something more sophisticated than just cloning a pass is needed.
Any ideas?
Johann
More information about the Gcc
mailing list