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); }
Created attachment 13400 [details] Preprocessed source
Confirmed on GCC 4.1.2.
Testcase fails for 4.2.0 and 4.3-20070525.
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);
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?
(In reply to comment #5) Oops forgot to tell I am using avr-gcc 4.1.2
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.
(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.
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
I have in my list this bug as fixed in 4.4.0. Closing.