Re: [PATCH] LoongArch: improve 64-bit bitwise AND operation
Xi Ruoyao <[email protected]> Sun, 02 Aug 2026 05:11:25 +0800
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On Sun, 2026-08-02 at 04:49 +0800, Xi Ruoyao wrote:
> On Sat, 2026-08-01 at 05:54 -0600, Jeffrey Law wrote:
> >
> >
> > On 7/31/2026 3:47 AM, Ben Shi wrote:
> > > It usually costs 4-5 instructions for 64-bit bitwise AND with a large
> > > immediate. For some immediates the operation can be simplified to two
> > > 'BSTRINS.D' instructions if the immediate satisfies:
> > > 1. its top bit is not zero.
> > > 2. has two sections of consecutive zero bits.
> > >
> > > gcc/ChangeLog:
> > > * config/loongarch/loongarch.md: Add a new RTL expression
> > > (define_insn_and_split "bstrins_bstrins_for_and_imm").
> > >
> > > * config/loongarch/loongarch.cc: Add a helper function
> > > 'loongarch_use_bstrins_bstrins_for_and' for the above RTL expression.
> > >
> > > * config/loongarch/loongarch-protos.h: Add prototype of function
> > > 'loongarch_use_bstrins_bstrins_for_and'.
> > >
> > > * testsuite/gcc.target/loongarch/la64/and-large-immediate-opt-2.c:
> > > Add a new test.
> > You might want ot look at how RISC-V handles this. There's all kinds of
> > primitives you can use to clear bits and you're usually better using
> > those primitives to synthesize the logical operation during initial
> > expansion without constructing the constant. For example you can use
> > shifts in pairs or triplets, bit clear style instructions, zero
> > extensions, and-immediate if you have them, rotates in combination with
> > and-immediate, and so-on. These are composable.
> >
> > In general define_insn_and_split is not a great way to solve these
> > problems because it effectively lies about the cost of the patterns it
> > matches and it will tend to inhibit further optimizations because of
> > those lies about the cost (and to be clear, I'm not talking about
> > rtx_cost or insn cost, but instead the internal costing done by combine
> > which relies solely on insn counts, particularly with regards to insn
> > splitting).
> >
> > I'm not at all familiar with the details of the loongarch port and this
> > should not be considered a review. Just some advice based on working in
> > this space on the RISC-V port.
>
> I tried doing this in define_expand but then combine insists to
> transform the bstrins pair back to materializing the mask. The reason
> is we have
>
> /* When not optimizing for size, we care more about the cost
> of hot code, and hot code is often in a loop. If a constant
> operand needs to be forced into a register, we will often be
> able to hoist the constant load out of the loop, so the load
> should not contribute to the cost. */
> if (speed || loongarch_immediate_operand_p (outer_code, INTVAL (x)))
> {
> *total = 0;
> return true;
> }
>
> in loongarch_rtx_costs for CONST_INT, i.e. the cost for materializing
> the immediate is considered 0 unless optimizing for size...
>
> Perhaps this loongarch_rtx_costs logic is incorrect but I'm not sure.
Tweaking loongarch_rtx_costs prevents the combine:
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index a0f91ab2843..7a86b904264 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -4090,18 +4090,13 @@ loongarch_rtx_costs (rtx x, machine_mode mode, int outer_code,
switch (code)
{
case CONST_INT:
- if (TARGET_64BIT && outer_code == AND && UINTVAL (x) == 0xffffffff)
+ if (outer_code == AND && and_operand (x, mode))
{
*total = 0;
return true;
}
- /* When not optimizing for size, we care more about the cost
- of hot code, and hot code is often in a loop. If a constant
- operand needs to be forced into a register, we will often be
- able to hoist the constant load out of the loop, so the load
- should not contribute to the cost. */
- if (speed || loongarch_immediate_operand_p (outer_code, INTVAL (x)))
+ if (loongarch_immediate_operand_p (outer_code, INTVAL (x)))
{
*total = 0;
return true;
@@ -4118,8 +4113,6 @@ loongarch_rtx_costs (rtx x, machine_mode mode, int outer_code,
if (cost == 1 && outer_code == SET
&& !(float_mode_p && TARGET_HARD_FLOAT))
cost = 0;
- else if ((outer_code == SET || GET_MODE (x) == VOIDmode))
- cost = 1;
*total = COSTS_N_INSNS (cost);
return true;
}
The first diff is obviously correct, while the following diffs remove
some special cases for const materialization. I don't know if removing
them will cause a net win, or lose.
P.S. even if the logic in the comment removed above is incorrect, there
might be still a valid reason not to penalty const_int materialization:
the micro architecture likely has some optimization for it.
--
Xi Ruoyao <[email protected]>