Skip to content

arc: fix for extvsi split patterns - #270

Open
Alexehv77 wants to merge 1 commit into
trunkfrom
fix_extvsi
Open

arc: fix for extvsi split patterns#270
Alexehv77 wants to merge 1 commit into
trunkfrom
fix_extvsi

Conversation

@Alexehv77

Copy link
Copy Markdown
Contributor

Description change to the pattern define_insn_and_split "*extvsi_n_0"

If using && reload_completed the compiler is forced to wait until after the RA/Reload pass is entirely finished. Physical registers are already permanently locked down. If using && 1 the split is allowed to occur early such as during the combine pass when registers are still flexible pseudos. Splitting earlier (using && 1) is generally better than waiting until after reload—provided as it provides significant optimization advantages.

Description change to pattern define_insn_and_split "*extvsi_1_0" keeping "0" with && 1 is not in accordance with the GCC instruction pattern rules:

  1. According to RTL instruction definition by writing "0" we are telling the dataflow analysis that operand 0 and operand 1 must share the exact same physical register. By writing && 1 we are telling the compiler to split this instruction into pieces during the very early optimization passes (like combine) which is before physical registers are even handed out the "0" constraint.

  2. When you split an instruction early using && 1 the purpose is to allow subsequent optimization passes (like Scheduling for register pressure, cse, dce etc) to optimize the broken instructions. If you combine an early split with a restrictive "0" the df-scan gets confused about the exact life ranges of the pseudo registers. Because it thinks the destination and source are linked it may assume a register becomes dead earlier than it actually does. This prevents subsequent passes from safely reordering instructions or eliminating redundant operations resulting in less optimized code.

Description change to the pattern define_insn_and_split "*extvsi_n_0"

If using && reload_completed the compiler is forced to wait until after
the RA/Reload pass is entirely finished. Physical registers are already
permanently locked down. If using && 1 the split is allowed to occur early
such as during the combine pass when registers are still flexible pseudos.
Splitting earlier (using && 1) is generally better than waiting until after
reload—provided as it provides significant optimization advantages.

Description change to pattern define_insn_and_split "*extvsi_1_0"
keeping "0" with && 1 is not in accordance with the GCC instruction pattern rules:

1. According to RTL instruction definition by writing "0" we are telling the
dataflow analysis that operand 0 and operand 1 must share the exact same physical register.
By writing && 1 we are telling the compiler to split this instruction into pieces during the
very early optimization passes (like combine) which is before physical registers are
even handed out the "0" constraint.

2. When you split an instruction early using && 1 the purpose is to allow subsequent
optimization passes (like Scheduling for register pressure, cse, dce etc) to optimize
the broken instructions. If you combine an early split with a restrictive "0" the df-scan
gets confused about the exact life ranges of the pseudo registers.
Because it thinks the destination and source are linked it may assume a register becomes
dead earlier than it actually does. This prevents subsequent passes from safely
reordering instructions or eliminating redundant operations resulting in less optimized code.
Comment thread gcc/config/arc/arc.md
(define_insn_and_split "*extvsi_1_0"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "0")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that this was a functional issue.
But the resulting RTL pattern is correct?

This is just for performance?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first define_insn_and_split has potential to generate incorrect code.

For the second one there was a change from && 1 to &&reload_completed and at the same time there was a change from (sign_extract:SI (match_operand:SI 1 "register_operand" "0")
to (sign_extract:SI (match_operand:SI 1 "register_operand" "r").

My point is that there is no need to have the both as the second change (i.e, (sign_extract:SI (match_operand:SI 1 "register_operand" "0") to (sign_extract:SI (match_operand:SI 1 "register_operand" "r")) is enough allowing the split to take place even before ra.

@Alexehv77
Alexehv77 requested a review from MichielDerhaeg June 19, 2026 06:57
@MichielDerhaeg

Copy link
Copy Markdown
Contributor

I'm inclined not to go through the effort of arguing to get this merged upstream unless it solves a real functional issue.
It is simply not worth the effort.

According to RTL instruction definition by writing "0" we are telling the dataflow analysis that operand 0 and operand 1 must share the exact same physical register.

df-scan doesn't read the constraints, just checks which registers are filled in the operands in RTL, which are not enforced to be the same before RA. They are, in fact, different registers in the test you made. After RA they will be the same, which might also happen after your change by chance, don't see a problem there.

By grepping GCC i found that constraints are only read here:
ira.cc reload.cc reload1.cc lra-constraints.cc
caller-save.cc postreload-gcse.cc ree.cc reorg.cc (post-reload)
Which means that when the split happens before reload, the register constraints don't have any effect. So why bother?

Also the test doesn't fail before the changes in arc.md, so I don't see the point of that either.

So again, if this is not a functional issue, let's not bother with this. Don't think this is worth the effort, and let's drop it.
And that includes #269 because I don't want downstream to deviate from upstream.

@MichielDerhaeg

Copy link
Copy Markdown
Contributor

I think we agreed to keep it simple and push it upstream as an non-functional change.
Can you update this?
Keep the commit message very short and simple. And I would drop the test as it is fixing a functional issue.

@Alexehv77 Alexehv77 self-assigned this Jul 5, 2026
luismgsilva pushed a commit that referenced this pull request Jul 29, 2026
The test hard-codes two "fcmla ..., #0", which was the number trunk
happened to emit when it was added.  BB SLP now also vectorises the two
plain-multiply subroutines: r17-141-g76b8869f08a6 ("tree-optimization/
124222 - rewrite BB SLP costing scalar coverage") taught
vect_bb_slp_scalar_cost to attribute the statements an SLP pattern node
covers, so the subgraph for c_add_ab and c_sub_ab is no longer costed as
unprofitable.  They form .COMPLEX_MUL, and cmul<mode>3 expands each to
"fcmla #0" plus "fcmla #90", taking the #0 total from two to four.

For c_add_ab the loop body goes from a scalar pair of complex multiplies

	ldr	d26, [x5, x0]
	ldr	d27, [x3, x0]
	ldr	d29, [x2, x0]
	fmul	d24, d30, d26
	ldr	d28, [x1, x0]
	fnmsub	d24, d31, d27, d24
	fmul	d25, d30, d27
	fmadd	d25, d31, d26, d25
	fadd	d24, d29, d24
	fadd	d25, d25, d28
	str	d24, [x2, x0]
	str	d25, [x1, x0]
	add	x0, x0, 16
	cmp	x4, x0
	bne	.L3

to the vectorised form

	ldr	q29, [x2, x0]
	movi	v27.4s, 0
	ldr	q28, [x3, x0]
	fcmla	v27.2d, v28.2d, v31.2d, #0
	fcmla	v27.2d, v28.2d, v31.2d, #90
	fadd	v27.2d, v27.2d, v29.2d
	str	q27, [x2, x0]
	add	x0, x0, 16
	cmp	x0, x1
	bne	.L3

i.e. ten instructions instead of fifteen, and the whole rotation mix
across the file changes from

	#0=2  #90=0  #180=0  #270=2

to

	#0=4  #90=2  #180=0  #270=2

The loop vectoriser is unchanged: its dumps are identical before and
after, the two conjugate subroutines still form .COMPLEX_MUL_CONJ, and
the #270 directive that actually tests PR122408 still passes.  The
runtime companion pr122408_2.f90 also still runs clean.

Update the counts, and add a #90 count and a #180 scan-assembler-not.
PR122408 was about picking the wrong rotation pair after operand
swapping, so pinning the full rotation mix guards the regression more
directly than the #0 count did.

gcc/testsuite/ChangeLog:

	* gfortran.target/aarch64/pr122408_1.f90: Update the fcmla
	rotation counts.

Signed-off-by: Kyrylo Tkachov <ktkachov@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants