http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49936
Summary: [4.7 regression] IRA handles CANNOT_CHANGE_MODE_CLASS poorly, + spills to memory on 4.7 Product: gcc Version: 4.7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization AssignedTo: unassig...@gcc.gnu.org ReportedBy: san...@codesourcery.com CC: vmaka...@redhat.com Created attachment 24885 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=24885 test case abstest.c Consider the attached test case, compiled for MIPS with mipsisa32r2-sde-elf-gcc -O3 -fno-inline -fno-unroll-loops -march=74kf1_1 -S abstest.c On MIPS, the hardware floating-point abs and neg instructions aren't usable by default because they do the wrong thing with NaNs. And, the sign-bit-twiddling used by the optabs.c expansions can't be performed in a floating-point register because of CANNOT_CHANGE_MODE_CLASS. With a GCC 4.6 compiler, this snippet of code from the test1 function for (i=0; i<n; i++) { accum -= a[i]; } accum = fabs (accum); return accum; produces ... .L3: mtc1 $3,$f2 ldc1 $f0,0($5) addiu $5,$5,8 mtc1 $2,$f3 sub.d $f2,$f2,$f0 mfc1 $3,$f2 bne $5,$4,.L3 mfc1 $2,$f3 ext $5,$2,0,31 move $4,$3 .L2: mtc1 $4,$f0 j $31 mtc1 $5,$f1 ... Because it thinks it cannot use a floating-point register, IRA has decided to put accum in a general-purpose register pair $2/$3, and is shuffling it back and forth to $f2/$f3 on every iteration of the loop. On 4.7 mainline trunk, it's now deciding accum must live in memory instead of a register: .L3: ldc1 $f0,0($2) addiu $2,$2,8 sub.d $f2,$f2,$f0 bne $2,$3,.L3 sdc1 $f2,0($sp) lw $2,0($sp) ext $3,$2,0,31 lw $2,4($sp) .L2: sw $2,4($sp) sw $3,0($sp) lw $3,4($sp) lw $2,0($sp) addiu $sp,$sp,8 mtc1 $3,$f0 j $31 mtc1 $2,$f1 I think a big part of the problem here is the code in ira-costs.c that refuses to consider the FP regs at all in computing the costs for where to put the accum variable. Better that it should just add in the move costs for reloading to some other register class, much as it would to satisfy normal insn register constraints. Naively commenting out all the #ifdef CANNOT_CHANGE_MODE_CLASS....#endif instances in ira-costs.c gave this code in 4.6: .L3: ldc1 $f2,0($2) addiu $2,$2,8 bne $2,$4,.L3 sub.d $f0,$f0,$f2 mfc1 $2,$f0 mfc1 $3,$f0 ext $5,$2,0,31 move $4,$3 .L2: mtc1 $4,$f0 j $31 mtc1 $5,$f1 However, same change on 4.7 didn't help; it's still preferring to spill to memory. I think there must be some other bug lurking here that's responsible for these additional memory spills on 4.7. I also saw them when experimenting with a patch to the MIPS backend to attack this problem in a target-specific way. Also, while splitting live ranges might help with the code in the test1 function where the fabs call appears outside the loop, the code for the test2 function (fabs in the body of the loop) suffers from the same problem and is spilling to memory on 4.7.