[Bug c++/67529] New: rx-elf C++ inherited class malformed call to overridden methods

2015-09-09 Thread ericns1 at spirilis dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

Bug ID: 67529
   Summary: rx-elf C++ inherited class malformed call to
overridden methods
   Product: gcc
   Version: 5.2.0
Status: UNCONFIRMED
  Severity: critical
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: ericns1 at spirilis dot net
  Target Milestone: ---

Created attachment 36313
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=36313&action=edit
Files needed to reproduce this bug using rx-elf-g++ cmd listed in bug report.

I've been able to reproduce what appears to be a glitch in the rx-elf-g++ C++
compiler.  Originally found on GCC 4.8.4 (KPIT Cummins' GNURXv15.01-SP1 release
that pairs with Renesas' e2studio IDE), I have compiled GCC 5.2.0 from scratch
for the rx-elf target and confirmed similar ASM output.

In this example, I am writing an all-pure virtual method-laden class to define
an interface of sorts for a common hardware API, and writing implementation
classes which override the pure virtual methods with their correct
implementations.  When a method inside the class attempts to execute another
method inside the class that was overriding a pure virtual method in the parent
class, the actual function call produced includes a JSR instruction against a
register value which appears to be derived from the in-SRAM address of the
object's data storage, not the actual in-Flash location of the function itself.

Example:

my_template_parent.h:
#ifndef MY_TEMPLATE_PARENT_H_
#define MY_TEMPLATE_PARENT_H_

#include 
#include 
#include 

class MyTemplateParent {
public:
// prove it doesn't need to be a pure virtual function for the bug to
occur
virtual void begin(void) { return; };
virtual void check(void) = 0;
};



my_template.h:
#ifndef MY_TEMPLATE_H_
#define MY_TEMPLATE_H_

#include 
#include 
#include 
#include "my_template_parent.h"


class MyTemplate : MyTemplateParent {
private:
uint8_t buffer[256];
unsigned int head;
uint8_t value = 0;

public:
__noinline
void begin(void) {
head = 0;
buffer[0] = value;
}

__noinline
void begin(uint8_t val1) {
buffer[1] = val1;
//begin();  // set buffer[0] to value (template argument)
check();
};

__noinline
void check(void) {
if (buffer[2] == 0xF3)
buffer[3] = 0xF3;
}
};

#endif /* MY_TEMPLATE_H_ */


Main provided by "main.cpp":
#include "my_template.h"

MyTemplate obj;

int main(void)
{
volatile unsigned long i = 0;

obj.begin(33);
while(1)
i++;
}


Compiled using: rx-elf-g++ -T rx2108.ld -ffunction-sections -fdata-sections
-Wl,--gc-sections -D__RX_LITTLE_ENDIAN__=1 -DCPPAPP -mlittle-endian-data
-mcpu=rx200 -nofpu -o a.out main.cpp
(rx2108.ld provided as an attachment)

The assembler output, rx-elf-objdump -C -dS, produces the following for the
MyTemplate-related functions:



fff80160 :
fff80160:   7e a6   push.l  r6
fff80162:   71 06 fcadd #-4, r0, r6
fff80165:   ef 60   mov.l   r6, r0
fff80167:   e3 61   mov.l   r1, [r6]
fff80169:   03  nop
fff8016a:   3f 66 02rtsd#8, r6-r6

fff8016d :
fff8016d:   6e 6b   pushm   r6-r11
fff8016f:   71 06 fcadd #-4, r0, r6
fff80172:   ef 60   mov.l   r6, r0
fff80174:   e3 61   mov.l   r1, [r6]
fff80176:   ec 6a   mov.l   [r6], r10
fff80178:   f9 a6 41 00 mov.l   #0, 260[r10]
fff8017c:   ec 6a   mov.l   [r6], r10
fff8017e:   ce ab 08 01 mov.b   264[r10], r11
fff80182:   ec 6a   mov.l   [r6], r10
fff80184:   c7 ab 04mov.b   r11, 4[r10]
fff80187:   03  nop
fff80188:   3f 6b 07rtsd#28, r6-r11

fff8018b :
fff8018b:   6e 6b   pushm   r6-r11
fff8018d:   71 06 f8add #-8, r0, r6
fff80190:   ef 60   mov.l   r6, r0
fff80192:   e3 61   mov.l   r1, [r6]
fff80194:   81 62   mov.b   r2, 4[r6]
fff80196:   ec 6a   mov.l   [r6], r10
fff80198:   cd 6b 04mov.b   4[r6], r11
fff8019b:   c7 ab 05mov.b   r11, 5[r10]
fff8019e:   ec 6a   mov.l   [

[Bug c++/67529] rx-elf C++ inherited class malformed call to overridden methods

2015-09-09 Thread ericns1 at spirilis dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

Eric  changed:

   What|Removed |Added

  Attachment #36313|0   |1
is obsolete||

--- Comment #1 from Eric  ---
Created attachment 36315
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=36315&action=edit
Updated version of first attachment including my_template_parent.h

Forgot to include my_template_parent.h in the first attachment.


[Bug c++/67529] rx-elf C++ inherited class malformed call to overridden methods

2015-09-09 Thread ericns1 at spirilis dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

--- Comment #2 from Eric  ---
A little more sleuthing, using --save-temps -dP...

The "inherited", bug-ridden case has the following before JSR R10:

 ;(call_insn 16 15 19 (parallel [
 ;(call (mem:QI (reg/f:SI 10 r10 [orig:25 D.2187 ] [25]) [0
*OBJ_TYPE_REF(_7;(struct MyTemplate)this_2(D)->1) S1 A8])
 ;(const_int 0 [0]))
 ;(clobber (reg:CC 16 cc))
 ;]) my_template.h:34 18 {call_internal}
 ; (nil)
 ;(expr_list:SI (use (reg:SI 1 r1))
 ;(nil)))
jsr r10  ; 16   call_internal/1 [length = 2]


The non-inherited version:

 ;(call_insn 12 11 15 (parallel [
 ;(call (mem:QI (symbol_ref/i:SI ("_ZN10MyTemplate5checkEv") [flags
0x3] ) [0 check S1 A8])
 ;(const_int 0 [0]))
 ;(clobber (reg:CC 16 cc))
 ;]) my_template.h:34 18 {call_internal}
 ; (expr_list:REG_EH_REGION (const_int 0 [0])
 ;(nil))
 ;(expr_list:SI (use (reg:SI 1 r1))
 ;(nil)))
bsr __ZN10MyTemplate5checkEv ; 12   call_internal/2 [length
= 4]


So I'm not too familiar with this lingo, but clearly the compiler knows what
it's doing, and for some reason it's interpreting the execution of the
overridden method in terms relative to the location of the class's instance
struct, whereas without inheritance it's looking for the method correctly.  I
don't *think* that is right... at least the eventual behavior experienced
doesn't match what the code should do.


[Bug c++/67529] rx-elf C++ inherited class malformed call to overridden methods

2015-09-09 Thread ericns1 at spirilis dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

--- Comment #3 from Eric  ---
Further clarifying, creating a whole new function "void check2(void)" inside
MyTemplate which did *not* exist as a virtual function inside MyTemplateParent
produces correct code when begin(uint8_t) tries to call it:


 ;(call_insn 12 11 15 (parallel [
 ;(call (mem:QI (symbol_ref/i:SI ("_ZN10MyTemplate6check2Ev")
[flags 0x3] ) [0 check2 S1 A8])
 ;(const_int 0 [0]))
 ;(clobber (reg:CC 16 cc))
 ;]) my_template.h:34 18 {call_internal}
 ; (expr_list:REG_EH_REGION (const_int 0 [0])
 ;(nil))
 ;(expr_list:SI (use (reg:SI 1 r1))
 ;(nil)))
bsr __ZN10MyTemplate6check2Ev; 12   call_internal/2 [length
= 4]


[Bug c++/67529] rx-elf C++ inherited class malformed call to overridden methods

2015-09-09 Thread ericns1 at spirilis dot net
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67529

--- Comment #4 from Eric  ---
Okay, I think I've figured out what I'm looking at here.

The inheritance has to do with the use of virtual functions - so the JSR vs BSR
argument in here is a red herring, overridden virtual functions use JSR because
it's doing a lookup inside the vtable.

GCC 5.2.0 is providing the vtable with a general gcc/newlib-derived ldscript I
have.

The GNURX example which failed on my RX210, otoh, does not appear to have the
vtable when I disassemble using rx-elf-objdump -C -DS and search for 'vtable'. 
Probably an incomplete ldscript there.  Need to figure out what sections vtable
et al fall under... then I will go complain to the KPIT folks.

Sorry for the wild goose chase :-)