This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

strange results in constructor with large objects

I am getting some strange results in a constructor for large objects with the cl2000 compiler. The objects in question do not use any dynamic memory anywhere (within the class implementation, or by users of the class), but in certain cases the operator new is called heavily in the constructor.

I've managed to create a test case which I will post here.

It seems like it has something to do with the inlining threshold, as I can prevent this from happening by using the --auto_inlining=100000 build flag... but the problem is, that in my application I can't set this on a file-by-file basis, for various reasons, so I'm stuck.


Could one of you TI gurus please take a look at it? It seems like a bug to me.

  • Grrr. Your forum does not allow attachments of .cpp files for some strange reason. Here it is:

    bigobj.cpp:

    typedef int int16_t;
    typedef unsigned int uint16_t;

    template <typename T>
    class Reference
    {
        T& ref;
    public:
        inline T* operator&() { return &ref; }
        inline const T& getValue() const { return ref; }
        inline Reference& operator=(const T& v) { ref = v; return *this; }
        inline Reference(T& r) : ref(r) {}
    };

    class BigObj
    {
        struct tag_s0 {
            uint16_t x0;
            uint16_t y0;
            uint16_t z0;
            uint16_t w0;
           
            uint16_t x1;
            uint16_t y1;
            uint16_t z1;
            uint16_t w1;
           
            uint16_t x2;
            uint16_t y2;
            uint16_t z2;
            uint16_t w2;
           
            uint16_t x3;
            uint16_t y3;
            uint16_t z3;
            uint16_t w3;
           
            uint16_t x4;
            uint16_t y4;
            uint16_t z4;
            uint16_t w4;
           
            uint16_t x5;
            uint16_t y5;
            uint16_t z5;
            uint16_t w5;
           
            uint16_t x6;
            uint16_t y6;
            uint16_t z6;
            uint16_t w6;

            uint16_t x7;
            uint16_t y7;
            uint16_t z7;
            uint16_t w7;
           
            inline tag_s0() :
                x0(0),  y0(1),  z0(2),  w0(3),
                x1(4),  y1(5),  z1(6),  w1(7),
                x2(8),  y2(9),  z2(10), w2(11),
                x3(12), y3(13), z3(14), w3(15),
                x4(16), y4(17), z4(18), w4(19),
                x5(20), y5(21), z5(22), w5(23),
                x6(24), y6(25), z6(26), w6(27),
                x7(28), y7(29), z7(30), w7(31)
            {}
        } s0;
        struct tag_s1 {
            struct tag_s1a {
                Reference<uint16_t> rx;
                Reference<uint16_t> ry;
               
                inline tag_s1a(uint16_t& vx, uint16_t& vy)
                    : rx(vx), ry(vy)
                    {}
            } a;
            struct tag_s1b {
                Reference<uint16_t> rz;
                Reference<uint16_t> rw;
               
                inline tag_s1b(uint16_t& vz, uint16_t& vw)
                    : rz(vz), rw(vw)
                    {}
            } b;
                   
            inline tag_s1(uint16_t& vx, uint16_t& vy,
                uint16_t& vz, uint16_t& vw) :
                    a(vx,vy), b(vz,vw)
            {}
        } s1_0, s1_1, s1_2, s1_3, s1_4
    #ifdef BUILD_MORE_STUFF
        ,
        s1_5
    #endif // BUILD_MORE_STUFF
        ;
        uint16_t z;
       
    public:
        inline BigObj() :
            s0(),
            s1_0(s0.x0, s0.y0, s0.z0, s0.w0),
            s1_1(s0.x1, s0.y1, s0.z1, s0.w1),
            s1_2(s0.x2, s0.y2, s0.z2, s0.w2),
            s1_3(s0.x3, s0.y3, s0.z3, s0.w3),
            s1_4(s0.x4, s0.y4, s0.z4, s0.w4),
    #ifdef BUILD_MORE_STUFF
            s1_5(s0.x5, s0.y5, s0.z5, s0.w5),
    #endif // BUILD_MORE_STUFF
            z(0)
        {}
    };

    BigObj bigobj1, bigobj2;

    int main()
    {
    }

  • Build script:

    if defined PATH_C2000 goto go
    set ticcsroot=C:\appl\ti\ccs\4.1.2\ccsv4\tools\compiler\c2000
    set PATH=%PATH%;%ticcsroot%\bin
    set PATH_C2000=1

    :go
    set file=%1
    set def=BUILD_LESS_STUFF
    set auin=
    :loop
    SHIFT

    IF "%1"=="" GOTO Continue
    if "%1"=="more" set def=BUILD_MORE_STUFF
    if "%1"=="auin" set auin=--auto_inline=100000

    GOTO loop

    :Continue
    cl2000 --compile_only --keep_asm --opt_level=1 -g -v=28 -ml --define=%def% %file%.cpp %auin% -z -i%ticcsroot%\lib
    cl2000 -g -v=28 -ml %file%.obj -z -o %file%.out -i%ticcsroot%\lib -lrts2800_ml.lib
    ofd2000 -gv %file%.out > %file%.ofd

  • If you build with "build2 bigobj" the constructor looks nice (see below),

    but if you build with "build2 bigobj more" to enable the #ifdef'd out lines, it has all sorts of calls to ___nw__FUl() which makes no sense.

    If you build with "build2 bigobj auin" this adds the compiler flag "--auto_inline=100000"  which makes the constructor nice again.

    What's going on here??????


    ___sti___10_bigobj_cpp_bigobj1:
        .dwcfi    cfa_offset, -2
        .dwcfi    save_reg_to_mem, 26, 0
        .dwcfi    save_reg_to_reg, 78, 26
        .dwpsn    file "bigobj.cpp",line 67,column 3,is_stmt
            MOVW      DP,#_bigobj1
            MOV       @_bigobj1,#0          ; |67|
            MOVB      @_bigobj1+1,#1,UNC    ; |67|
            MOVB      @_bigobj1+2,#2,UNC    ; |67|
            MOVB      @_bigobj1+3,#3,UNC    ; |67|
            MOVB      @_bigobj1+4,#4,UNC    ; |67|
            MOVB      @_bigobj1+5,#5,UNC    ; |67|
            MOVB      @_bigobj1+6,#6,UNC    ; |67|
            MOVB      @_bigobj1+7,#7,UNC    ; |67|
            MOVB      @_bigobj1+8,#8,UNC    ; |67|
            MOVB      @_bigobj1+9,#9,UNC    ; |67|
            MOVB      @_bigobj1+10,#10,UNC  ; |67|
            MOVB      @_bigobj1+11,#11,UNC  ; |67|
            MOVB      @_bigobj1+12,#12,UNC  ; |67|
            MOVB      @_bigobj1+13,#13,UNC  ; |67|
            MOVB      @_bigobj1+14,#14,UNC  ; |67|
            MOVB      @_bigobj1+15,#15,UNC  ; |67|
            MOVB      @_bigobj1+16,#16,UNC  ; |67|
            MOVB      @_bigobj1+17,#17,UNC  ; |67|
            MOVB      @_bigobj1+18,#18,UNC  ; |67|
            MOVB      @_bigobj1+19,#19,UNC  ; |67|
            MOVB      @_bigobj1+20,#20,UNC  ; |67|
            MOVB      @_bigobj1+21,#21,UNC  ; |67|
            MOVB      @_bigobj1+22,#22,UNC  ; |67|
            MOVB      @_bigobj1+23,#23,UNC  ; |67|
            MOVB      @_bigobj1+24,#24,UNC  ; |67|
            MOVB      @_bigobj1+25,#25,UNC  ; |67|
            MOVB      @_bigobj1+26,#26,UNC  ; |67|
            MOVB      @_bigobj1+27,#27,UNC  ; |67|
            MOVB      @_bigobj1+28,#28,UNC  ; |67|
            MOVB      @_bigobj1+29,#29,UNC  ; |67|
            MOVB      @_bigobj1+30,#30,UNC  ; |67|
            MOVB      @_bigobj1+31,#31,UNC  ; |67|
        .dwpsn    file "bigobj.cpp",line 12,column 34,is_stmt
            MOVL      XAR4,#_bigobj1        ; |12|
            MOVL      @_bigobj1+32,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+1      ; |12|
            MOVL      @_bigobj1+34,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+2      ; |12|
            MOVL      @_bigobj1+36,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+3      ; |12|
            MOVL      @_bigobj1+38,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+4      ; |12|
            MOVL      @_bigobj1+40,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+5      ; |12|
            MOVL      @_bigobj1+42,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+6      ; |12|
            MOVL      @_bigobj1+44,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+7      ; |12|
            MOVL      @_bigobj1+46,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+8      ; |12|
            MOVL      @_bigobj1+48,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+9      ; |12|
            MOVL      @_bigobj1+50,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+10     ; |12|
            MOVL      @_bigobj1+52,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+11     ; |12|
            MOVL      @_bigobj1+54,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+12     ; |12|
            MOVL      @_bigobj1+56,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+13     ; |12|
            MOVL      @_bigobj1+58,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+14     ; |12|
            MOVL      @_bigobj1+60,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+15     ; |12|
            MOVL      @_bigobj1+62,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+16     ; |12|
            MOVW      DP,#_bigobj1+64
            MOVL      @_bigobj1+64,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+17     ; |12|
            MOVL      @_bigobj1+66,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+18     ; |12|
            MOVL      @_bigobj1+68,XAR4     ; |12|
            MOVL      XAR4,#_bigobj1+19     ; |12|
            MOVL      @_bigobj1+70,XAR4     ; |12|
            MOV       @_bigobj1+72,#0       ; |12|
        .dwpsn    file "bigobj.cpp",line 67,column 3,is_stmt
            MOVW      DP,#_bigobj2
            MOV       @_bigobj2,#0          ; |67|
            MOVB      @_bigobj2+1,#1,UNC    ; |67|
            MOVB      @_bigobj2+2,#2,UNC    ; |67|
            MOVB      @_bigobj2+3,#3,UNC    ; |67|
            MOVB      @_bigobj2+4,#4,UNC    ; |67|
            MOVB      @_bigobj2+5,#5,UNC    ; |67|
            MOVB      @_bigobj2+6,#6,UNC    ; |67|
            MOVB      @_bigobj2+7,#7,UNC    ; |67|
            MOVB      @_bigobj2+8,#8,UNC    ; |67|
            MOVB      @_bigobj2+9,#9,UNC    ; |67|
            MOVB      @_bigobj2+10,#10,UNC  ; |67|
            MOVB      @_bigobj2+11,#11,UNC  ; |67|
            MOVB      @_bigobj2+12,#12,UNC  ; |67|
            MOVB      @_bigobj2+13,#13,UNC  ; |67|
            MOVB      @_bigobj2+14,#14,UNC  ; |67|
            MOVB      @_bigobj2+15,#15,UNC  ; |67|
            MOVB      @_bigobj2+16,#16,UNC  ; |67|
            MOVB      @_bigobj2+17,#17,UNC  ; |67|
            MOVB      @_bigobj2+18,#18,UNC  ; |67|
            MOVB      @_bigobj2+19,#19,UNC  ; |67|
            MOVB      @_bigobj2+20,#20,UNC  ; |67|
            MOVB      @_bigobj2+21,#21,UNC  ; |67|
            MOVB      @_bigobj2+22,#22,UNC  ; |67|
            MOVB      @_bigobj2+23,#23,UNC  ; |67|
            MOVB      @_bigobj2+24,#24,UNC  ; |67|
            MOVB      @_bigobj2+25,#25,UNC  ; |67|
            MOVB      @_bigobj2+26,#26,UNC  ; |67|
            MOVB      @_bigobj2+27,#27,UNC  ; |67|
            MOVB      @_bigobj2+28,#28,UNC  ; |67|
            MOVB      @_bigobj2+29,#29,UNC  ; |67|
            MOVB      @_bigobj2+30,#30,UNC  ; |67|
            MOVB      @_bigobj2+31,#31,UNC  ; |67|
        .dwpsn    file "bigobj.cpp",line 12,column 34,is_stmt
            MOVL      XAR4,#_bigobj2        ; |12|
            MOVL      @_bigobj2+32,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+1      ; |12|
            MOVL      @_bigobj2+34,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+2      ; |12|
            MOVL      @_bigobj2+36,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+3      ; |12|
            MOVL      @_bigobj2+38,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+4      ; |12|
            MOVL      @_bigobj2+40,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+5      ; |12|
            MOVL      @_bigobj2+42,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+6      ; |12|
            MOVL      @_bigobj2+44,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+7      ; |12|
            MOVL      @_bigobj2+46,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+8      ; |12|
            MOVL      @_bigobj2+48,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+9      ; |12|
            MOVL      @_bigobj2+50,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+10     ; |12|
            MOVL      @_bigobj2+52,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+11     ; |12|
            MOVL      @_bigobj2+54,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+12     ; |12|
            MOVL      @_bigobj2+56,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+13     ; |12|
            MOVL      @_bigobj2+58,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+14     ; |12|
            MOVL      @_bigobj2+60,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+15     ; |12|
            MOVL      @_bigobj2+62,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+16     ; |12|
            MOVW      DP,#_bigobj2+64
            MOVL      @_bigobj2+64,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+17     ; |12|
            MOVL      @_bigobj2+66,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+18     ; |12|
            MOVL      @_bigobj2+68,XAR4     ; |12|
            MOVL      XAR4,#_bigobj2+19     ; |12|
            MOVL      @_bigobj2+70,XAR4     ; |12|
            MOV       @_bigobj2+72,#0       ; |12|

     

  • If I remember correctly, the boilerplate for a constructor includes a conditional call to new(), in case the passed-in object is actually NULL.  Cranking up the inlining threshold probably allows those conditions to be folded away at compile time.

    EABI mode, which is available for some other targets, doesn't do that.

  • pf said:
    If I remember correctly, the boilerplate for a constructor includes a conditional call to new(), in case the passed-in object is actually NULL.  Cranking up the inlining threshold probably allows those conditions to be folded away at compile time.

    !!!!!!!!!!!!!!!!!!!???!!!!?!?!!!!!!

    How does one disable this feature? If the answer is that you can't, could you please file a bug? At a minimum, this should be documented. Some of us working on real-time applications depend on static memory allocation to ensure proper timing, and if there's any possibility of new() being called, that puts a monkey wrench in our design.

  • We have been conferring.  I believe this is the consensus answer:

    1.  We're stuck with the conditional new(), because changing it would be an ABI change;  it's been that way as long as we've had C++ and there could be library-compatibility issues.

    2.  You can work around it by defining a dummy two-argument new() in your classes;  that will inhibit the conditional-new() boilerplate.  In other words, add something like "void *operator new(size_t x, int) {return ::operator new(x);}" to each class.  (size_t is defined in <stdlib.h>.)

    3.  Your code should be safe, because you don't do any dynamic allocation, and therefore all of your constructor calls will pass as the "this" argument the address of a variable.

    4.  We're developing a compiler improvement that will remove the conditional-new() sections in whole-program compilations, where it can tell that the constructor is never passed NULL.  Inlined constructors can already do that, as you observed;  the enhancement is to detect the situation for out-of-line constructors.

    5.  It's specific to COFF, and ELF is gradually taking over.  It will be moot in a few years.

  • cool, thanks for the answer. I'll give it a shot.

    (p.s. on a tangent: what's the timeframe for ELF? I ask because I have custom tools that parse the COFF to get at the DWARF section, + need to allocate time to update it for ELF. I assume there will be a deprecated compiler option to produce COFF for legacy purposes?)

  • I'm not sure on the time line for when C2000 tools will add support for EABI (which includes changing the object format to ELF).

    As for your custom tools, consider changing over to the cg_xml package for this purpose.  See this wiki page.  This package works with both COFF ABI and EABI object code and libraries today.  You can change over to cg_xml even while continuing to use COFF ABI.  Then when the switch to EABI happens, it will be no problem.

    When EABI support is released, COFF ABI will continue to be the default.  You have to explicitly use a different option to get EABI.

    Thanks and regards,

    -George