• AVR Freaks

XC16 not treating 'inline' functions correctly

Author
Dhersneg
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2015/03/31 18:55:56
  • Location: 0
  • Status: offline
2015/03/31 19:05:27 (permalink)
5 (1)

XC16 not treating 'inline' functions correctly

Following the direction in section 13.6 of the MPLAB® XC16 C Compiler User’s Guide I've declared some simple methods inline. I've added the '-finline' (as well as '-Winline') compiler options. However when I come to link my application the linker complains of duplicate symbols for the inline functions. This indicates that the compiler is not doing the right thing for inline functions. Below are three very simple .c/.h files as well as the build output that illustrates the problem (relevant sections bolded). Any thoughts on whether I'm doing something wrong or whether the compiler is broken?
 
------------ test.h ------------
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
inline int func1(int a, int b)
{
return a + b;
}
extern int func2(int a, int b);

#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
 
------------ main.c ------------
#include "test.h"
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char** argv)
{
func1(1, 2);
func2(2, 3);
return (EXIT_SUCCESS);
}
 
------------ func2.c ------------
#include "test.h"
int func2(int a, int b)
{
return func1(a, b);
}
 
------------ Build Output ------------
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/leon_000/MPLABXProjects/test.X'
make -f nbproject/Makefile-default.mk dist/default/production/test.X.production.hex
make[2]: Entering directory 'C:/Users/leon_000/MPLABXProjects/test.X'
"C:\Program Files (x86)\Microchip\xc16\v1.24\bin\xc16-gcc.exe" func2.c -o build/default/production/func2.o -c -mcpu=24FV32KA301 -MMD -MF "build/default/production/func2.o.d" -g -omf=elf -O0 -msmart-io=1 -Wall -msfr-warn=off -finline -Winline
"C:\Program Files (x86)\Microchip\xc16\v1.24\bin\xc16-gcc.exe" main.c -o build/default/production/main.o -c -mcpu=24FV32KA301 -MMD -MF "build/default/production/main.o.d" -g -omf=elf -O0 -msmart-io=1 -Wall -msfr-warn=off -finline -Winline
"C:\Program Files (x86)\Microchip\xc16\v1.24\bin\xc16-gcc.exe" -o dist/default/production/test.X.production.elf build/default/production/main.o build/default/production/func2.o -mcpu=24FV32KA301 -omf=elf -Wl,,--defsym=__MPLAB_BUILD=1,,--script=p24FV32KA301.gld,--stack=16,--check-sections,--data-init,--pack-data,--handles,--isr,--no-gc-sections,--fill-upper=0,--stackguard=16,--no-force-link,--smart-io,-Map="dist/default/production/test.X.production.map",--report-mem
build/default/production/func2.o(.text+0x0): In function `func1':
C:\Users\leon_000\MPLABXProjects\test.X/test.h:9: multiple definition of `_func1'
build/default/production/main.o(.text+0x0):C:\Users\leon_000\MPLABXProjects\test.X/test.h:9: first defined here
c:\program files (x86)\microchip\xc16\v1.24\bin\bin\..\bin/elf-ld.exe: Link terminated due to previous error(s).
make[2]: *** [dist/default/production/test.X.production.hex] Error 255
nbproject/Makefile-default.mk:137: recipe for target 'dist/default/production/test.X.production.hex' failed
make[1]: *** [.build-conf] Error 2
make[2]: Leaving directory 'C:/Users/leon_000/MPLABXProjects/test.X'
make: *** [.build-impl] Error 2
nbproject/Makefile-default.mk:78: recipe for target '.build-conf' failed
make[1]: Leaving directory 'C:/Users/leon_000/MPLABXProjects/test.X'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
BUILD FAILED (exit value 2, total time: 1s)
#1

7 Replies Related Threads

    davekw7x
    Entropy++
    • Total Posts : 1738
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Left Coast, USA
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2015/04/02 09:16:08 (permalink)
    -1 (3)
    Dhersneg
    ...the linker complains of duplicate symbols...

    In test.h:
    static inline int func1(int a, int b) //<---Designate it "static" to prevent multiple definition linker error
    {
        return a + b;
    }

     
     
    Regards,
     
    Dave

    Sometimes I just can't help myself...
    #2
    Dhersneg
    New Member
    • Total Posts : 3
    • Reward points : 0
    • Joined: 2015/03/31 18:55:56
    • Location: 0
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2015/04/02 11:03:41 (permalink)
    0 (2)
    I've seen that advice given multiple times as a "solution" to this problem. But it really isn't a *solution*. As you will see from the disassembly listing below, adding the "static" keyword just makes the function static irrespective of the 'inline' keyword presence. It is still treated as a function call with all the overhead associated with that. In fact it is a really poor practice to place a 'static' function in a header file. You get all the overhead of duplicate code (a copy of you so-called inline function will be generated for each source file that the header is included in) but you still incur all the overhead of the function call. In other words its a lose-lose proposition.
     

    Disassembly Listing for test
    Generated From:
    C:/Users/leon_000/MPLABXProjects/test.X/dist/default/production/test.X.production.elf
    Apr 2, 2015 10:55:15 AM

    --- C:/Users/leon_000/MPLABXProjects/test.X/test.h ----------------------------------------------------
    1: #ifndef TEST_H
    2: #define TEST_H
    3:
    4: #ifdef __cplusplus
    5: extern "C" {
    6: #endif
    7:
    8: static inline int func1(int a, int b)
    9: {
    00029E FA0004 LNK #0x4
    0002A0 780F00 MOV W0, [W14]
    0002A2 980711 MOV W1, [W14+2]
    0002C8 FA0004 LNK #0x4
    0002CA 780F00 MOV W0, [W14]
    0002CC 980711 MOV W1, [W14+2]
    10: return a + b;
    0002A4 90021E MOV [W14+2], W4
    0002A6 42021E ADD W4, [W14], W4
    0002CE 90021E MOV [W14+2], W4
    0002D0 42021E ADD W4, [W14], W4
    11: }
    0002A8 780004 MOV W4, W0
    0002AA FA8000 ULNK
    0002AC 060000 RETURN
    0002D2 780004 MOV W4, W0
    0002D4 FA8000 ULNK
    0002D6 060000 RETURN
    12:
    13: extern int func2(int a, int b);
    14:
    15:
    16: #ifdef __cplusplus
    17: }
    18: #endif
    19:
    20: #endif /* TEST_H */
    --- C:/Users/leon_000/MPLABXProjects/test.X/main.c ----------------------------------------------------
    1: #include "test.h"
    2:
    3: #include <stdio.h>
    4: #include <stdlib.h>
    5:
    6: int
    7: main(int argc, char** argv)
    8: {
    0002AE FA0004 LNK #0x4
    0002B0 780F00 MOV W0, [W14]
    0002B2 980711 MOV W1, [W14+2]
    9: func1(1, 2);
    0002B4 200021 MOV #0x2, W1
    0002B6 200010 MOV #0x1, W0
    0002B8 07FFF2 RCALL _func1
    10: func2(2, 3);
    0002BA 200031 MOV #0x3, W1
    0002BC 200020 MOV #0x2, W0
    0002BE 07000C RCALL func2
    11: return (EXIT_SUCCESS);
    0002C0 EB0200 CLR W4
    12: }
    0002C2 780004 MOV W4, W0
    0002C4 FA8000 ULNK
    0002C6 060000 RETURN
    13:
    --- C:/Users/leon_000/MPLABXProjects/test.X/func2.c ---------------------------------------------------
    1: #include "test.h"
    2:
    3: int func2(int a, int b)
    4: {
    0002D8 FA0004 LNK #0x4
    0002DA 780F00 MOV W0, [W14]
    0002DC 980711 MOV W1, [W14+2]
    5: return func1(a, b);
    0002DE 90009E MOV [W14+2], W1
    0002E0 78001E MOV [W14], W0
    0002E2 07FFF2 RCALL func1
    0002E4 780200 MOV W0, W4
    6: }
    0002E6 780004 MOV W4, W0
    0002E8 FA8000 ULNK
    0002EA 060000 RETURN
    7:

    #3
    CCP1CON
    Super Member
    • Total Posts : 469
    • Reward points : 0
    • Joined: 2007/04/15 12:49:28
    • Location: good old Germany
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2015/04/02 11:26:46 (permalink)
    +2 (4)
    If I remember correctly there is information in the compilers userguide ...
     
    #4
    CCP1CON
    Super Member
    • Total Posts : 469
    • Reward points : 0
    • Joined: 2007/04/15 12:49:28
    • Location: good old Germany
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2015/04/02 12:17:05 (permalink)
    +1 (1)
    put this in main.h
    extern inline __attribute__((always_inline)) int func1();
    #5
    davekw7x
    Entropy++
    • Total Posts : 1738
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Left Coast, USA
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2015/04/02 13:46:19 (permalink)
    +4 (4)
    Dhersneg
    I've seen that advice given multiple times as a "solution" to this problem. But it really isn't a *solution*. As you will see from the disassembly listing below, adding the "static" keyword just makes the function static irrespective of the 'inline' keyword presence.

     
    With all due respect, I don't post things that I haven't tested.
     
    Just because your attempt at inlining the simple function didn't work with XC16 doesn't mean it can't work.  (You can't prove a negative just by giving one example.)
     
    This is the biggie for this simple function: in MPLABX version 2.35 with XC16 version 1.24 there is a box in the Project->Properties->gcc-xc16->Optimizatons thingie that says "Do not override "inline."
     
    That box is unchecked by default.
     
    With "static inline" for func1, and that box unchecked, the compiler gave warnings about not being able to inline the function.
     
    However...
     
    With that box checked and the "static inline " designation for func1, not only did it not give warnings, but it in-lined the function.  Really.  I tested it.  (But I said that already.)
     
    In order to make sure I could see what was happening specifically with the function calls, I made some volatile variables and called func1 and func2:
    In main:
        volatile int x, y, z;
        x = 1;
        y = 2;
        z = func1(x,y);
        printf("in main: func1(%d,%d) = %d\n", x, y, z);
        
        x = 3;
        y = 4;
        z = func2(x,y);
        printf("in main: func2(%d,%d) = %d\n", x, y, z);

     
    func2.c looks like this:
    #include "test.h"
    int func2(int a, int b)
    {
        return func1(a, b);
    }

     
    And test.h looks like this:
    #include <xc.h>

    #ifndef TEST_H
    #define    TEST_H
    static inline int func1(int a, int b)
    {
        return a + b;
    }
    extern int func2(int a, int b);

    #endif    /* TEST_H */

     
    Here are excerpts from the disassembly listing.
    In main, where I call func1 and func2:
     
    77:                    volatile int x, y, z;
    78:                    x = 1;
    000FF6  200014     MOV #0x1, W4
    000FF8  9FB7F4     MOV W4, [W15-18]
    79:                    y = 2;
    000FFA  200024     MOV #0x2, W4
    000FFC  9FBF84     MOV W4, [W15-16]
    80:                    z = func1(x,y);
    000FFE  97BA0F     MOV [W15-16], W4
    001004  9FBF94     MOV W4, [W15-14]
    81:                    printf("in main: func1(%d,%d) = %d\n", x, y, z);
    001006  97BB1F     MOV [W15-14], W6
    001008  97BA8F     MOV [W15-16], W5
    00100A  97B27F     MOV [W15-18], W4
    00100C  781F86     MOV W6, [W15++]
    00100E  781F85     MOV W5, [W15++]
    001010  781F84     MOV W4, [W15++]
    001012  28E9D4     MOV #0x8E9D, W4
    001014  781F84     MOV W4, [W15++]
    001016  07F98F     RCALL __printf_cdnopsuxX
    82:                
    83:                    x = 3;
    001018  200034     MOV #0x3, W4
    00101A  9FB7B4     MOV W4, [W15-26]
    84:                    y = 4;
    00101C  200044     MOV #0x4, W4
    00101E  9FB7C4     MOV W4, [W15-24]
    85:                    z = func2(x,y);
    001020  97B0CF     MOV [W15-24], W1
    001022  97B03F     MOV [W15-26], W0
    001024  07000C     RCALL func2
    001026  9FB7D0     MOV W0, [W15-22]
    86:                    printf("in main: func2(%d,%d) = %d\n", x, y, z);
    001028  97B35F     MOV [W15-22], W6
    00102A  97B2CF     MOV [W15-24], W5
    00102C  97B23F     MOV [W15-26], W4
    00102E  781F86     MOV W6, [W15++]
    001030  781F85     MOV W5, [W15++]
    001032  781F84     MOV W4, [W15++]
    001034  28EB94     MOV #0x8EB9, W4
    001036  781F84     MOV W4, [W15++]
    001038  07F97E     RCALL __printf_cdnopsuxX


    and
     
    13:                static inline int func1(int a, int b)
    14:                {
    15:                    return a + b;
    001000  97B2FF     MOV [W15-18], W5
    001002  428204     ADD W5, W4, W4
    00103E  408000     ADD W1, W0, W0
    16:                }
    17:                extern int func2(int a, int b);
    18:                
    19:                
    20:                #endif    /* TEST_H */
    21:                
    ---  /home/dave/MPLABXProjects/24FJ128GB202/24FJ128GB202_InlineTest.X/func2.c  --------------------------
    1:                 /*------------ func2.c ------------*/
    2:                 #include "test.h"
    3:                 int func2(int a, int b)
    4:                 {
    5:                     return func1(a, b);
    6:                 }
    001040  060000     RETURN
     
    Bottom line:
    By following my suggestion, func1 was not compiled; it was expanded in-line, as requested.
     
     
    If anyone is interested in all of the details, I have attached a packaged project for my test program.  And, by the way, I didn't just look at the disassembly listing; i executed the program saw correct output.
     
    Output
    PIC24FJ128BP202 inline function test with XC16 version 1024
    Compiled on Apr  2 2015 at 13:32:51
    in main: func1(1,2) = 3
    in main: func2(3,4) = 7


     
    My setup: MPLABX version 2.35, XC16 version 1.24 in Free mode with Optimization settings 1.
     
    PIC24FJ128GB202 on solderless breadboard.
     
     
    Regards,
     
    Dave
     
     
    post edited by davekw7x - 2015/04/02 14:35:12

    Sometimes I just can't help myself...
    #6
    markQ
    Junior Member
    • Total Posts : 78
    • Reward points : 0
    • Joined: 2013/09/24 07:53:59
    • Location: 0
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2016/10/26 01:16:05 (permalink)
    0
    I am trying to inline and have noticed that it will not work with optimization 0. Even with the -finline added to the compiler options, as suggested in the manual. Does any one know if there is a work around for this as I prefer to work with no optimization because it does not interfere with the debugger as level 1 does?
    #7
    markQ
    Junior Member
    • Total Posts : 78
    • Reward points : 0
    • Joined: 2013/09/24 07:53:59
    • Location: 0
    • Status: offline
    Re: XC16 not treating 'inline' functions correctly 2016/10/26 02:03:27 (permalink)
    +1 (1)
    Looks like I cracked it. Following CCP1CON's advise I used the "extern inline __attribute__((always_inline))" to replace "static inline" in my header function definitions. This does the job, without placing the functions in a library ( or other c file assumed in CCP1CON's example which would not work for me ) as advised in the last paragraph of the section 13.6 of the XC "16 C Compiler User’s Guide".
    i.e in test.h
    #include <xc.h>

    #ifndef TEST_H
    #define    TEST_H
    extern inline __attribute((always_inline)) int func1(int a, int b)
    {
        return a + b;
    }
    #endif    /* TEST_H */
     
    For reference I am using XC16 version 1.26 from MPLABX 3.35 with PIC24FJ1024GB610 and needed to inline functions into my ISRs, for speed and stack economy.
     
    #8
    Jump to:
    © 2019 APG vNext Commercial Version 4.5