Bug 50910 - [avr] inefficient division by 2
Summary: [avr] inefficient division by 2
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.7.0
: P4 minor
Target Milestone: 4.7.0
Assignee: Georg-Johann Lay
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2011-10-29 12:16 UTC by Georg-Johann Lay
Modified: 2011-11-01 14:11 UTC (History)
1 user (show)

See Also:
Host:
Target: avr
Build:
Known to work:
Known to fail: 4.3.3, 4.5.2, 4.6.2, 4.7.0
Last reconfirmed: 2011-10-29 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Georg-Johann Lay 2011-10-29 12:16:07 UTC
The following source

char c;

void bar_c (int x)
{
    c = x ? x/2 : c+1;
}

reveals two issues

== 1 == 

Compiled with

$ avr-gcc -S -Os

there is a call to libgcc's division routine. RTX costs of division has to be checked and costs of loading the constant added to the costs of division.

bar_c:
	sbiw r24,0
	breq .L2
	ldi r22,lo8(2)
	clr r23
	rcall __divmodhi4
	rjmp .L3
.L2:
	lds r22,c
	subi r22,lo8(-(1))
.L3:
	sts c,r22
	ret

== 1 == 

Compiled with

$ avr-gcc -S -O2

the code is happily jumping around to L7 and then back to L3.

bar_c:
	sbiw r24,0
	brne .L6
	lds r24,c
	subi r24,lo8(-(1))
	sts c,r24
	ret
.L6:
	sbrc r25,7
	rjmp .L7
.L3:
	asr r25
	ror r24
	sts c,r24
	ret
.L7:
	adiw r24,1
	rjmp .L3

Presumably, the cause is 
	#define BRANCH_COST 0
in avr.h, and the sequence could be instead:

	...
.L6:
	sbrc r25,7
	adiw r24,1
.L3:
	asr r25
	ror r24
	sts c,r24
	ret
Comment 1 Georg-Johann Lay 2011-11-01 14:10:23 UTC
Author: gjl
Date: Tue Nov  1 14:10:13 2011
New Revision: 180739

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=180739
Log:
	PR target/50910
	* config/avr/avr.opt (-mbranch-cost=): New option.
	* config/avr/avr.h (BRANCH_COST): Define to avr_branch_cost.
	* config/avr/avr.c (avr_rtx_costs_1): Adjust [U]DIV/[U]MOD costs.
	* config/avr/avr.md (*addqi3.lt0, *addhi3.lt0, *addsi3.lt0): New insns.
	(*addhi3_zero_extend1): Remov % in constraint of operand 1.
	(*addhi3.sign_extend1, *subhi3.sign_extend2): New insns.


Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/avr/avr.c
    trunk/gcc/config/avr/avr.h
    trunk/gcc/config/avr/avr.md
    trunk/gcc/config/avr/avr.opt
Comment 2 Georg-Johann Lay 2011-11-01 14:11:19 UTC
Fixed in 4.7.0