Bug 31644 - [avr] can't find a register in class 'BASE_POINTER_REGS' while reloading 'asm'
[avr] can't find a register in class 'BASE_POINTER_REGS' while reloading 'asm'
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: target
4.1.1
: P3 normal
: 4.4.0
Assigned To: Not yet assigned to anyone
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2007-04-21 08:25 UTC by Dave Hylands
Modified: 2010-01-29 17:47 UTC (History)
6 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: avr
Build:
Known to work:
Known to fail: 4.1.1 4.1.2 4.2.0
Last reconfirmed: 2007-05-30 19:34:44


Attachments
Preprocessed source (9.88 KB, text/plain)
2007-04-21 09:55 UTC, Joerg Wunsch
Details
another asm code block triggering the error (2.33 KB, text/plain)
2008-01-08 19:29 UTC, Sascha Silbe
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dave Hylands 2007-04-21 08:25:27 UTC
The following code snippet fails to compile with -Os -O1 -O2 or -O3. It compiles fine using -O0

I tested both the Win32 and linux versions of the compiler and they both fail the same way.

The exact command line used was:
avr-gcc -c -mmcu=atmega168 -Os ee-fail.c

Removing the second call to fill_pwm_table also allows the code to compile.

The error message received from the compiler are as follows:
ee-fail.c: In function 'build_pwm_table':
/home/dhylands/avr-4.1.1/lib/gcc/avr/4.1.1/../../../../avr/include/avr/eeprom.h:208: error: can't find a register in class 'BASE_POINTER_REGS' while reloading 'asm'
/home/dhylands/avr-4.1.1/lib/gcc/avr/4.1.1/../../../../avr/include/avr/eeprom.h:208: error: can't find a register in class 'BASE_POINTER_REGS' while reloading 'asm'

avr-gcc -v on my linux box reports:
Using built-in specs.
Target: avr
Configured with: ../../source/gcc-4.1.1/configure -v --target=avr --disable-nls --prefix=/home/dhylands/avr-4.1.1 --with-gnu-ld --with-gnu-as --enable-languages=c,c++ --quiet --disable-libssp --with-dwarf2
Thread model: single
gcc version 4.1.1


#include <avr/eeprom.h>

uint8_t    pwm_tab_1 [126];

static uint16_t  ee_chan_1_min EEMEM = 140,
                ee_chan_1_cent EEMEM = 188,
                ee_chan_1_max EEMEM = 240,
                ee_chan_1_forw_min EEMEM = 20,
                ee_chan_1_forw_max EEMEM = 90,
                ee_chan_1_back_max EEMEM = 80;

void fill_pwm_table (int8_t chan_num, uint8_t pwm [], int16_t forward_max,
                    int16_t center, int16_t reverse_min, int16_t forward_high,
                    int16_t forward_low, int16_t reverse_high );

void build_pwm_table (void)
{
 int16_t   center_1,
           forward_max_1,
           reverse_min_1,
           forward_high_1,
           forward_low_1,
           reverse_high_1;

 center_1 = eeprom_read_word (&ee_chan_1_cent);

 forward_max_1 = eeprom_read_word (&ee_chan_1_max);
 reverse_min_1 = eeprom_read_word (&ee_chan_1_min);
 forward_high_1 = eeprom_read_word (&ee_chan_1_forw_max);
 forward_low_1 = eeprom_read_word (&ee_chan_1_forw_min);
 reverse_high_1 = eeprom_read_word (&ee_chan_1_back_max);

 fill_pwm_table (1, pwm_tab_1, forward_max_1, center_1, reverse_min_1,
                 forward_high_1, forward_low_1, reverse_high_1);

 fill_pwm_table (1, pwm_tab_1, forward_max_1, center_1, reverse_min_1,
                 forward_high_1, forward_low_1, reverse_high_1);
}
Comment 1 Joerg Wunsch 2007-04-21 09:55:36 UTC
Created attachment 13400 [details]
Preprocessed source
Comment 2 Eric Weddington 2007-05-03 16:56:59 UTC
Confirmed on GCC 4.1.2.
Comment 3 Eric Weddington 2007-05-30 19:34:44 UTC
Testcase fails for 4.2.0 and 4.3-20070525.
Comment 4 Pavel Petrovic 2007-07-28 20:24:17 UTC
This bug is quite cruel. I have similar application, also for atmega168 and WinAVR (avr-gcc (GCC) 4.1.2 (WinAVR 20070525)), and the following lines do not compile giving the same error. Even worse, if the code is with for-loop, it
compiles, but it crashes when the variable is accessed, or it overwrites
it with a value of a different variable (that is not very neighboring one).
  
  //load calibrated values from eeprom  
  left_ir_min = eeprom_read_word((uint16_t*)0);
  left_ir_center = eeprom_read_word((uint16_t*)2);
  left_ir_max = eeprom_read_word((uint16_t*)4);
  right_ir_min = eeprom_read_word((uint16_t*)6);
  right_ir_center = eeprom_read_word((uint16_t*)8);
  right_ir_max = eeprom_read_word((uint16_t*)10);
  
  left_rot[0] = eeprom_read_word((uint16_t*)12);
  right_rot[0] = eeprom_read_word((uint16_t*)14);
  left_rot[1] = eeprom_read_word((uint16_t*)16);
  right_rot[1] = eeprom_read_word((uint16_t*)18);
  left_rot[2] = eeprom_read_word((uint16_t*)20); 
  /* any of the following lines, if present, cause compiler to fail */
  right_rot[2] = eeprom_read_word((uint16_t*)22); 
  left_rot[3] = eeprom_read_word((uint16_t*)24); 
  right_rot[3] = eeprom_read_word((uint16_t*)26); 
Comment 5 Wouter van Gulik 2007-11-01 21:50:45 UTC
It seems that this is caused by the fact that eeprom_read_word is actually a piece of inline assembler returning it's value in the Z register, using z as "pointer class" description.

This then somehow eliminates the compiler's ability allocate a pointer.

Here is my test file source:
compile using: -Wall, -Os -mmcu=atmega16

===========================================================
#define u16 unsigned int

//If both are defined it will not compile

#define EXTRA_VAR   //Use this to create extra variable parsing
#define USE_REG_Z   //Use this to make use of Z register

static inline u16 eeprom_read_word(u16* p)
{

#ifdef USE_REG_Z
  register u16 result asm("r30");
#else
  register u16 result asm("r24");
#endif  
  
  asm volatile (
  " ; Do nothing, just fake write to result"
      : "+x" (p),
         "=r" (result)
      :  );    
  return result;  

}


extern void foo(  u16 in0,
                  u16 in1, 
                  u16 in2, 
                  u16 in3, 
                  u16 in4, 
#ifdef EXTRA_VAR
                  u16 in5, 
#endif
                  u16 in6);


void bar(void) 
{
  u16 in0 = eeprom_read_word((u16*)0);
  u16 in1 = eeprom_read_word((u16*)1);
  u16 in2 = eeprom_read_word((u16*)2);
  u16 in3 = eeprom_read_word((u16*)3);
  u16 in4 = eeprom_read_word((u16*)4);
  u16 in5 = eeprom_read_word((u16*)5);
  u16 in6 = eeprom_read_word((u16*)6);
  
  foo(  in0,
        in1,
        in2,
        in3,
        in4,
#ifdef EXTRA_VAR
        in5, 
#endif
        in6 );
  
  foo(  in0,
        in1,
        in2,
        in3,
        in4,
#ifdef EXTRA_VAR
        in5, 
#endif
        in6  );  
  
}

When compiling you can see that adding an extra variable gives the problem. But then changing the return variable to r24 solves the problem.

Hmm while typing I found another fishy thing:
Compiling for r24 with and without extra_var gives pushes of all registers. However r12 is not used when compiled for non extra var. But using extra stack instead

And trying -mcall-prologues does not invoke the prologue call when using extra var and r24... it does for the other 2 ok compiling combinations.

I hope someone can make something out of this.

Oh and the r30 instead of z gives the following (more descriptive) error:

(insn 14 12 16 0 (set (reg/v:HI 54 [ in0 ])
        (reg/v:HI 30 r30 [ result ])) 12 {*movhi} (insn_list:REG_DEP_TRUE 12 (ni
l))
    (expr_list:REG_DEAD (reg/v:HI 30 r30 [ result ])
        (nil)))
test.c:67: confused by earlier errors, bailing out

This involves movhi* which is in other bugreports as well, maybe this is the vital clue?
Comment 6 Wouter van Gulik 2007-11-01 21:53:15 UTC
(In reply to comment #5)
Oops forgot to tell I am using avr-gcc 4.1.2
Comment 7 Sascha Silbe 2008-01-08 19:29:05 UTC
Created attachment 14902 [details]
another asm code block triggering the error

Just been hit by this after upgrading to Ubuntu gutsy (avr-gcc 4.1.0). Custom asm snippet triggering the error (does NOT use movhi) is attached. This compiled fine previously.
Comment 8 Eric Weddington 2008-01-08 19:49:28 UTC
(In reply to comment #7)
> Created an attachment (id=14902) [edit]
> another asm code block triggering the error
> 
> Just been hit by this after upgrading to Ubuntu gutsy (avr-gcc 4.1.0). Custom
> asm snippet triggering the error (does NOT use movhi) is attached. This
> compiled fine previously.
> 

Could you post your command line for this test case? And can you please post a pre-processed source for your test case? This case produces additional errors other than the one described in the bug.

Comment 9 aesok 2008-09-14 12:51:48 UTC
Subject: Bug 31644

Author: aesok
Date: Sun Sep 14 12:50:10 2008
New Revision: 140360

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=140360
Log:
	PR target/19636
	PR target/24894
	PR target/31644
	PR target/31786
	* config/avr/avr.c (legitimate_address_p): Fix problem where subreg
	is not recognized as a valid register usage. Allow REG_X to be used
	as a base pointer.
	* config/avr/avr.h (LEGITIMIZE_RELOAD_ADDRESS): Remove code that
	forces a reload when using a base register.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/avr/avr.c
    trunk/gcc/config/avr/avr.h

Comment 10 Eric Weddington 2010-01-29 17:47:33 UTC
I have in my list this bug as fixed in 4.4.0. Closing.