PSoC 4 Compiler optimization problem

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
YuAr_3514996
Level 1
Level 1
First like received First like given

Hi,

I'm using PSoC 4 in a BLE application. The specific device is CY8C4247LQI-BL473.

I have the following piece of code:

int32 passwd;

uint8 cypher[16];

/*

     some code here, cypher buffer is loaded

*/

passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;

if(passwd < (int32) 0)

{

     passwd = passwd * (int32)(-1);

}

I'm facing the following issue: depending on the optimization level I choose, the test at 10th line is always false.

Optimization levels None, Debug and Minimal work fine. But with level High, Speed and Size the "if" command result is always false, even with valid values.

I'm setting the optimization level via "Build -> Build Settings -> Configuration: Release -> ARM GCC 5.4-2016-q2-update -> Optimization -> Optimization Level".

Can someone please help me understand what is going on here? Is there something I'm missing?

Here follows some further details:

Environment:

PSoC Creator  4.3 (4.3.0.1445)

Culture: Portuguese (Brazil)

OS Version: Microsoft Windows NT 10.0.18362.0

CLR Version: 4.0.30319.42000

Installed CyInstaller Products:

Peripheral Driver Library 3.0.1

Peripheral Driver Library 3.1.1

PSoC Programmer 3.28.7

PSoC Creator 4.3

Loaded Plugins:

Name: Toolchain Manager

Version: 4.3.0.1445

Company: Cypress Semiconductor

Description: PSoC Creator Toolchain Manager

Name: ARM GCC Generic

Version: 4.3.0.1445

Company: Cypress Semiconductor

Description: ARM GNU Generic

Name: ARM MDK Generic

Version: 4.3.0.1445

Company: Cypress Semiconductor

Description: ARM MDK Generic

Name: ARM IAR Generic

Version: 4.3.0.1445

Company: Cypress Semiconductor

Description: ARM IAR Generic

Name: DP8051 Keil Generic

Version: 4.3.0.1445

Company: Cypress Semiconductor

Description: DP8051 Keil Generic



Thank you very much.

Cheers,

Yuri

0 Likes
1 Solution
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I'm just curious, but I wonder if you add volatile to passwd, will it help?

> int32 passwd

< volatile int32 passwd

moto

View solution in original post

0 Likes
9 Replies
Rakshith
Moderator
Moderator
Moderator
250 likes received 1000 replies posted 750 replies posted

Hi yuar_3514996​,

I modified your code slightly to test it. I added an LED pin and if the 'if condition' is true, I toggle the LED. Please let me know if there is any issue with the test code.

    int32 passwd; 

    uint8 cypher[16]; 

    cypher[0] = 0xFF;

    cypher[1] = 0xFF;

    cypher[2] = 0xFF;

    cypher[3] = 0xFF;

   

    passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000; 

   

    for(;;)

    {

        /* Place your application code here. */

        if(passwd < (int32) 0) 

        { 

            LED_Write(1);

            CyDelay(500);

            LED_Write(0);

            CyDelay(500);

            LED_Write(1);

            CyDelay(500);

            LED_Write(0);

            CyDelay(500);

        } 

        else

        {

            LED_Write(1);

        }

    }

I programmed this code using all optimization levels and irrespective of the optimization level the LED was toggling. Could it be possible that the issue is with other code in your project? If I am missing something, please let me know.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
0 Likes

Hi RakshithM_16! Thank you for the help.

The piece of code I've posted it's part of a pretty straight forward function. It just generates a random password based on some input parameters.

I just made some testing and figured out that if I load "cypher" array manually as you did the code works fine for any optimization level.

In my original code, "cypher" array is loaded by an AES encrpytion function. Depending on the optimization level, even with the encryption value loaded into "cypher[3:0]" being negative the test "passwd < (int32) 0" returns always FALSE. The odd thing here is if I get the value returned by the AES function and recompile the code loading it manually into "cypher", the code then works.

Here follows the actual code I'm running:

uint32 bleGeneratePasskey(uint8 random, uint8 *addr1, uint8 *addr2)

{

    uint8 key[16];

    uint8 plain[16];

    uint8 cypher[16];

    int32 passwd;

  

    /* init KEY array with constant values and "random" var at one position */

  

    /* init PLAIN array with both "addr1[6]" and "addr2[6]" content plus 4 constants */

  

    CyBle_AesEncrypt(plain, key, cypher);

    passwd = cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;

  

    #ifdef DEBUG_PRINT

        char temp[128];

        uint8 i;

      

        sprintf(temp, "-> P: ");

        for(i = 0; i < 16; i++)

            sprintf(temp, "%s%02X ", temp, plain);

        debugPrint(temp);

      

        sprintf(temp, "-> K: ");

        for(i = 0; i < 16; i++)

            sprintf(temp, "%s%02X ", temp, key);

        debugPrint(temp);

      

        sprintf(temp, "-> C: ");

        for(i = 0; i < 16; i++)

            sprintf(temp, "%s%02X ", temp, cypher);

        debugPrint(temp);

      

        sprintf(temp, "-> 1: %ld (0x%08lX)", passwd, passwd);

        debugPrint(temp);

      

    #endif

      

    if(passwd < (int32) 0)

    {

        passwd = passwd * (int32)(-1);

      

        #ifdef DEBUG_PRINT

            sprintf(temp, "******** < 0 ********\n");

            debugPrint(temp);

        #endif

    }

      

    #ifdef DEBUG_PRINT

        sprintf(temp, "-> 2: %ld (0x%08lX)", passwd, passwd);

        debugPrint(temp);

    #endif

  

    if(passwd > (int32)999999)

        passwd &= 0x7FFFF;

      

    #ifdef DEBUG_PRINT

        sprintf(temp, "-> 3: %ld (0x%08lX)", passwd, passwd);

        debugPrint(temp);

    #endif

  

    return ((uint32) passwd);  

}

And here some outputs I got from my debug terminal:

Optimization level: SIZE, loading CYPHER from AES

[07388] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2

[07396] -> 1: -1567336056 (0xA2945988)

[07400] -> 2: -1567336056 (0xA2945988)

[07404] -> 3: -1567336056 (0xA2945988)

[07408] -> PASSKEY: 2727631240

Optimization level: SIZE, loading CYPHER manually

[09731] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2

[09739] -> 1: -1567336056 (0xA2945988)

[09743] ******** < 0 ********

[09746] -> 2: 1567336056 (0x5D6BA678)

[09750] -> 3: 239224 (0x0003A678)

[09753] -> PASSKEY: 239224

       

Optimization level: SIZE, loading CYPHER from AES

[36946] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D

[36954] -> 1: -78646829 (0xFB4FF1D3)

[36958] -> 2: -78646829 (0xFB4FF1D3)

[36962] -> 3: -78646829 (0xFB4FF1D3)

[36966] -> PASSKEY: 4216320467

Optimization level: SIZE, loading CYPHER manually

[03803] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D

[03811] -> 1: -78646829 (0xFB4FF1D3)

[03815] ******** < 0 ********

[03818] -> 2: 78646829 (0x04B00E2D)

[03822] -> 3: 3629 (0x00000E2D)

[03825] -> PASSKEY: 3629

Optimization level: MINIMAL, loading CYPHER from AES

[08129] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85

[08137] -> 1: -1157658236 (0xBAFF8984)

[08141] ******** < 0 ********

[08144] -> 2: 1157658236 (0x4500767C)

[08148] -> 3: 30332 (0x0000767C)

[08151] -> PASSKEY: 30332

Optimization level: MINIMAL, loading CYPHER manually

[06334] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85

[06342] -> 1: -1157658236 (0xBAFF8984)

[06346] ******** < 0 ********

[06349] -> 2: 1157658236 (0x4500767C)

[06353] -> 3: 30332 (0x0000767C)

[06356] -> PASSKEY: 30332

I could workaround this in other ways, like declaring "passwd" as volatile as MoTa_728816​ suggested. But I'd like to know why this is happening.

Cheers,

Yuri

0 Likes

Hi Yuri,

Would it be okay for you to share the entire project or at least a minimalistic version of your project in which you are facing the issue so that we can test it out?

Also, can you try changing the datatype of cypher from uint8 to int16 and let me know if that makes any difference?

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
0 Likes
lock attach
Attachments are accessible only for community members.

Hi Rakshith,

I've made a minimal project with the problem still going on. I removed all my source code and all componentes not needed to show the problem.

It just initializes the BLE stack to use the encryption function and calls my password function once in a second.

With optimization enabled, the above mentioned test returns always false. Without optimizations it works well.

By the way, changing "uint8" arrays to "uint16" was of no success.

Cheers,

Yuri

0 Likes

Hi Yuri,

We tried debugging and placing a breakpoint to check the result of the if condition and with high optimization the if statement was skipped. So, we believe the compiler is optimizing out the if condition.

One thought was that, because the cypher is an unsigned int and the passwd is a sum of unsigned int the compiler might be assuming that passwd will not be less than 0. So, we tried declaring cypher as int8 and typecasting it as shown and this worked. We had to typecast it while printing too.

CyBle_AesEncrypt(plain, key, (uint8*) cypher); 

Can you please let me know if this works?

I think using volatile as suggested by MoTa_728816​-san is a better solution in this case.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
Kenshow
Level 8
Level 8
Distributor - Marubun (Japan)
50 solutions authored 25 solutions authored 10 solutions authored

Hi Yuri,

I don't know if it applies to your program, but I'll talk about optimization in general.

An ANSI C compliant compiler compiles with optimization options to eliminate unnecessary code and data. The compiler deletes all variables except those related to I/O. The input and output variables here are global variables, function arguments and return value variables. The compiler considers removing local variables by optimization. To prevent this, the programmer must explicitly declare "This variable is necessary". It consists in using global variables and arguments. Even local variables can be survived from optimization if they have a relationship with them. Conversely, if you create a function with only local variables, a function with no contents will be created.

In addition to this, if optimization progresses, variables located in memory will be replaced by registers inside the CPU, and it will become impossible to access peripheral registers.  "volatile" is declared to mean that the specified address is always accessed.

You can get more detailed information by searching for "gcc optimization option" on the Web.

I hope this information is useful for you.

Best Regards,

Kenshow

Hi,

Thank you MoTa_728816​ and RakshithM_16​ for the help.

I knew basically how optimization works in microcontrollers. Very often when using a debugger (mostly in other architechtures), if I place a breakpoint in some lines it just doesn't stop because of the optimization (usually when the variable being loaded in that line is not used anymore inside the same function). To workaround that, I just declare the related variable as "volatile" (telling the compiler "compile this line, no matter what"). This works fine for my debugging purposes.

In this case, I didn't think it would be a problem because after the variable "passwd" being loaded first time, it is tested, modified and returned as function value. I thought this process would be considered "important enough" by the compiler.

Anyway, I'll stick with the volatile solution (it works fine for me). I'd like to understand what happens under the hood of gcc, but to really clear this out I'd had to go through compiler's internals and that should not be my focus by now.

Thank you guys!

Cheers,

Yuri

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I'm just curious, but I wonder if you add volatile to passwd, will it help?

> int32 passwd

< volatile int32 passwd

moto

0 Likes

Hi! Declaring "int32 passwd" as volatile works fine. Thank you.