Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug
Bug#: 41894
Product:  
Component:  
Status: NEW
Resolution:
Assigned To: Not yet assigned to anyone <unassigned@gcc.gnu.org>
Host:
Reported against  
Priority:  
Severity:  
Target Milestone:  
 
 
Target:
Reporter: Frank Boesing <frank@mynety.net>
Add CC:
CC:
Remove selected CCs
Build:
URL:
Summary:
Keywords:
Known to work:
Known to fail:

Attachment Description Type Created Size Actions
bug.s Full assembler code I get from GCC 4.3.2 application/octet-stream 2009-10-31 23:10 413 bytes Edit
pr41894.c.175r.lreg dump file application/octet-stream 2009-11-01 17:27 3.08 KB Edit
pr41894.c.176r.greg dump file application/octet-stream 2009-11-01 17:27 3.33 KB Edit
Create a New Attachment (proposed patch, testcase, etc.) View All

Bug 41894 depends on: Show dependency tree
Show dependency graph
Bug 41894 blocks:

Additional Comments:





Mark bug as waiting for feedback
Mark bug as suspended




View Bug Activity   |   Format For Printing   |   Clone This Bug


Description:   Last confirmed: 2009-10-31 23:55 Opened: 2009-10-31 21:43
Commandline:
avr-gcc -S -mmcu=atmega128 -Os 
-fno-inline-small-functions -fno-split-wide-types bug.c

Sourcecode:

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;

typedef union
{
  struct {
    uint8_t sekunden;
    uint8_t minuten;
  } x;
  uint16_t sekmin;
} zeit_t;


void testmich2 (zeit_t tmp) {
  // just something that cannot be optimized out
  asm volatile("nop");
}

void testmich (zeit_t zeit) {

  zeit_t tmp;

  tmp.x = zeit.x;

  do {
    testmich2(tmp);

    if (tmp.x.sekunden)
      tmp.x.sekunden--;
    else {
      tmp.x.sekunden = 59;
      tmp.x.minuten--;
    }
  } while (tmp.x.sekunden || tmp.x.minuten);
}

int main (void) {
  zeit_t zeit;

  zeit.x.minuten = 1;
  zeit.x.sekunden = 2;

  testmich(zeit);

  return 0;
}


The statements

if (tmp.x.sekunden)
      tmp.x.sekunden--;

translate to:

        mov r18,r28
        subi r18,lo8(-(-1))
        movw r28,r18

which is wrong; r19 (used by movw) has a not defined value.

------- Comment #1 From Andy Hutchinson 2009-10-31 23:02 -------
Please post entire assembler code.

------- Comment #2 From Joerg Wunsch 2009-10-31 23:10 -------
Created an attachment (id=18944) [edit]
Full assembler code I get from GCC 4.3.2

------- Comment #3 From Joerg Wunsch 2009-10-31 23:11 -------
The bug was originally reported in the (Germany-language) mikrocontroller.net
forum, and I confirmed the bug on my local GCC 4.3.2 setup before asking
Frank to submit it as an official bug report.

------- Comment #4 From Andy Hutchinson 2009-11-01 17:24 -------
The problem is still present on 4.3.5 head
I cannot reproduce on 4.5 

It looks like reload issue with SUBREG. 

Instruction 18 gets reloaded. The output reload is HImode. I will post dump
files but here is extract that appears to highlight problem.

From lreg dump file:

;; Pred edge  3 [50.0%]  (fallthru)
(note 16 15 17 4 [bb 4] NOTE_INSN_BASIC_BLOCK)

(note 17 16 18 4 NOTE_INSN_DELETED)

(insn 18 17 54 4 pr41894.c:29 (set (subreg:QI (reg/v:HI 43 [ tmp ]) 0)
        (plus:QI (reg:QI 42 [ D.1188 ])
            (const_int -1 [0xffffffff]))) 15 {addqi3} (expr_list:REG_DEAD
(reg:QI 42 [ D.1188 ])
        (nil)))

(jump_insn 54 18 55 4 (set (pc)
        (label_ref 26)) 101 {jump} (nil))
;; End of basic block 4 -> ( 6)
;; lr  out       28 [r28] 32 [__SP_L__] 34 [argL] 43
;; live  out     28 [r28] 32 [__SP_L__] 34 [argL] 43


from greg dump file:

Spilling for insn 18.
Using reg 18 for reload 0
Spilling for insn 18.
Using reg 18 for reload 0

Reloads for insn # 18
Reload 0: reload_in (QI) = (reg:QI 24 r24 [orig:42 D.1188 ] [42])
        reload_out (HI) = (reg/v:HI 28 r28 [orig:43 tmp ] [43])
        LD_REGS, RELOAD_OTHER (opnum = 0)
        reload_in_reg: (reg:QI 24 r24 [orig:42 D.1188 ] [42])
        reload_out_reg: (reg/v:HI 28 r28 [orig:43 tmp ] [43])
        reload_reg_rtx: (reg:HI 18 r18)
deleting insn with uid = 2.
;; Register dispositions:
42 in 24  43 in 28  44 in 24  

;; Hard regs used:  18 19 24 25 28 29 32


Giving


(insn 57 17 18 4 pr41894.c:29 (set (reg:QI 18 r18)
        (reg:QI 24 r24 [orig:42 D.1188 ] [42])) 4 {*movqi} (nil))

(insn 18 57 58 4 pr41894.c:29 (set (reg:QI 18 r18)
        (plus:QI (reg:QI 18 r18)
            (const_int -1 [0xffffffff]))) 15 {addqi3} (nil))

(insn 58 18 54 4 pr41894.c:29 (set (reg/v:HI 28 r28 [orig:43 tmp ] [43])
        (reg:HI 18 r18)) 8 {*movhi} (nil))

(jump_insn 54 58 55 4 (set (pc)

------- Comment #5 From Andy Hutchinson 2009-11-01 17:27 -------
Created an attachment (id=18945) [edit]
dump file

------- Comment #6 From Andy Hutchinson 2009-11-01 17:27 -------
Created an attachment (id=18946) [edit]
dump file

------- Comment #7 From Eric Weddington 2009-11-01 17:44 -------
(In reply to comment #4)
> The problem is still present on 4.3.5 head
> I cannot reproduce on 4.5 

Can someone check this to see if bug exists on any 4.4.x?

------- Comment #8 From Andy Hutchinson 2009-11-02 00:54 -------
The problem seems related to use of R28+r29 - which is also frame pointer.

avr_hard_regno_mode_ok allows R28 in HIMODE but not any other mode. (This hack
was made to avoid reload problem where r29 was used as well as R28 frame
pointer)

It looks like the "not ok" QI subreg 28/29 of "ok" HImode r28 is not handled
well. 

The mode restriction is ignored for input reload. (Perhaps because reload
decides to use available frame pointer)

The output reload needed is 16bit HImode but must be accessible as two QImode 
subregs. Somehow the mode of output reload gets mangled so we get movw r28,r18


Originally ~2005 the rejection of other modes by avr_hard_regno_mode_ok for r28
was only applied when reload was in progress and frame_pointer_required.

So I reapplied this condition and the bug was solved. This function does not
need frame pointer so r28 and r29 are indeed freely available.

  /* Otherwise disallow all regno/mode combinations that span r28:r29.  */
  if (reload_in_progress && frame_pointer_needed && regno <= (REG_Y + 1) &&
(regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
    return 0;


This also produces better code!

One concern is that the modes deemed ok or not are now not constant - and
perhaps is the reason why condition was removed.

In Gcc 4.5 the spill is exactly the same but it uses R16/r17 with the correct
output reload subreg - so seems to figure out that r28 is "not ok" - suggesting
problem is fixed.


This may take a while to resolve, with some further research and testing.

Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug