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.

Compiler/MSP432P401R: Optimizer bug or user error

Part Number: MSP432P401R


Tool/software: TI C/C++ Compiler

Hello.

I've run into a problem where I'm trying to add two large numbers and I'm losing the carry bit when I increase the optimizer level to 2.

To demonstrate the problem I have lightly modified the uart loopback example (uart_loopback_24mhz_brclk.c). At none, 0 or 1 optimization it outputs a "y" for successful result.

At level 2 and above, I get a "n". The carry bit is not being carried between each 32bit addition.

Is this user error, or failure of the optimizer? I've tried a for() loop instead of while() and get the same result.

/* --COPYRIGHT--,BSD
 * Copyright (c) 2017, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/******************************************************************************
 * MSP432 UART - Loopback with 24MHz DCO BRCLK
 *
 * Description: This demo connects TX to RX of the MSP432 UART
 * The example code shows proper initialization of registers
 * and interrupts to receive and transmit data. If data is incorrect P1.0 LED
 * is turned ON.
 *
 *  MCLK = HSMCLK = SMCLK = DCO of 24MHz
 *
 *               MSP432P401
 *             -----------------
 *            |                 |
 *       RST -|     P1.3/UCA0TXD|----|
 *            |                 |    |
 *           -|                 |    |
 *            |     P1.2/UCA0RXD|----|
 *            |                 |
 *            |             P1.0|---> LED
 *            |                 |
 *
 *******************************************************************************/
/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

uint8_t TXData = 1;
uint8_t RXData = 0;

/* UART Configuration Parameter. These are the configuration parameters to
 * make the eUSCI A UART module to operate with a 115200 baud rate. These
 * values were calculated using the online calculator that TI provides
 * at:
 * software-dl.ti.com/.../index.html
 */
const eUSCI_UART_Config uartConfig =
{
        EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        13,                                      // BRDIV = 13
        0,                                       // UCxBRF = 0
        37,                                      // UCxBRS = 37
        EUSCI_A_UART_NO_PARITY,                  // No Parity
        EUSCI_A_UART_MSB_FIRST,                  // MSB First
        EUSCI_A_UART_ONE_STOP_BIT,               // One stop bit
        EUSCI_A_UART_MODE,                       // UART mode
        EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // Oversampling
};

uint32_t BigAdd(uint32_t *result, const uint32_t *x,
                          const uint32_t *y, size_t size)
{
    uint64_t carry = 0;
    while (size > 0) {
        carry += *x++;
        carry += *y++;
        *result++ = (uint32_t)carry;
        carry >>= 32;
        --size;
    }
    return (uint32_t)carry;
}
const uint32_t one_256bit[8] = {0x00000001, 0x00000000,
                                0x00000000, 0x00000000,
                                0x00000000, 0x00000000,
                                0x00000000, 0x00000000 };
const uint32_t efs_256bit[8] = {0xFFFFFFFF, 0xFFFFFFFF,
                                0xFFFFFFFF, 0xFFFFFFFF,
                                0xFFFFFFFF, 0xFFFFFFFF,
                                0xFFFFFFFF, 0xFFFFFFFF };

int main(void)
{
    uint32_t result[8];
    /* Halting WDT  */
    MAP_WDT_A_holdTimer();

    /* Selecting P1.2 and P1.3 in UART mode and P1.0 as output (LED) */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
             GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);

    /* Setting DCO to 24MHz (upping Vcore) */
    FlashCtl_setWaitState(FLASH_BANK0, 1);
    FlashCtl_setWaitState(FLASH_BANK1, 1);
    MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
    CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24);

    /* Configuring UART Module */
    MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
    MAP_UART_enableModule(EUSCI_A0_BASE);

    /* Enabling interrupts */
    MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
    MAP_Interrupt_enableInterrupt(INT_EUSCIA0);
    MAP_Interrupt_enableSleepOnIsrExit();

    if(BigAdd(result,one_256bit,efs_256bit,8))
        MAP_UART_transmitData(EUSCI_A0_BASE, 'y');
    else
        MAP_UART_transmitData(EUSCI_A0_BASE, 'n');
    while(1)
    {
        MAP_UART_transmitData(EUSCI_A0_BASE, TXData);

        MAP_Interrupt_enableSleepOnIsrExit();
        MAP_PCM_gotoLPM0InterruptSafe();
    }
}

/* EUSCI A0 UART ISR - Echos data back to PC host */
void EUSCIA0_IRQHandler(void)
{
    uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);

    MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status);

    if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
    {
        RXData = MAP_UART_receiveData(EUSCI_A0_BASE);

        if(RXData != TXData)              // Check value
        {
            MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
            while(1);                       // Trap CPU
        }
        TXData++;
        MAP_Interrupt_disableSleepOnIsrExit();
    }

}

  • I've got myself past the immediate problem with:

    uint32_t BigAdd(uint32_t *result, const uint32_t *x,
                              const uint32_t *y, size_t size)
    {
        uint64_t carry = 0;
        while (size > 0) {
            carry = ((uint64_t)(*x++)) + (*y++) + (carry >> 32);
            *result++ = (uint32_t)carry;
            --size;
        }
        return (uint32_t)(carry >> 32);
    }

    ... but I'd really like to know what went wrong with the original implementation.

  • Edward Cheeseman said:
    I have lightly modified the uart loopback example (uart_loopback_24mhz_brclk.c).

    I am not familiar with this example.  Please show the version of the compiler (not CCS).  Also show the all the build options exactly as the compiler sees them.  That should allow me to reproduce the problem.

    Thanks and regards,

    -George

  • Compiler version: TI v 18.12.2.LTS

    Only "Product" selected is SimpleLink MSP432P4 SDK v3.10.0.08

    Example was found in Tirex MSP_EXP432P401R. I used it mainly to get something printed out the serial port, but as I have modified the Launchpad a little the original uart isn't connected to USB debug anymore, so haven't checked if that is working.I have been setting a breakpoint and following the result of the if statement, and examining contents of "result" array.

    Summary of flags set: (works)

    -mv7M4 --code_state=16 --float_support=FPv4SPD16 -me -O1 --include_path="C:/workspace/uart_loopback_24mhz_brclk_MSP_EXP432P401R_nortos_ccs" --include_path="C:/ti/simplelink_msp432p4_sdk_3_10_00_08/source" --include_path="C:/ti/simplelink_msp432p4_sdk_3_10_00_08/source/third_party/CMSIS/Include" --include_path="C:/ti/ccs901/ccs/tools/compiler/ti-cgt-arm_18.12.2.LTS/include" --advice:power=none --define=__MSP432P401R__ --define=DeviceFamily_MSP432P401x -g --diag_warning=225 --diag_warning=255 --diag_wrap=off --display_error_number --gen_func_subsections=on

    Doesn't work:

    -mv7M4 --code_state=16 --float_support=FPv4SPD16 -me -O2 --include_path="C:/workspace/uart_loopback_24mhz_brclk_MSP_EXP432P401R_nortos_ccs" --include_path="C:/ti/simplelink_msp432p4_sdk_3_10_00_08/source" --include_path="C:/ti/simplelink_msp432p4_sdk_3_10_00_08/source/third_party/CMSIS/Include" --include_path="C:/ti/ccs901/ccs/tools/compiler/ti-cgt-arm_18.12.2.LTS/include" --advice:power=none --define=__MSP432P401R__ --define=DeviceFamily_MSP432P401x -g --diag_warning=225 --diag_warning=255 --diag_wrap=off --display_error_number --gen_func_subsections=on

  • Since the central function of interest, BigAdd, only uses standard types, I can build it with the information you sent.  I carefully looked through the compiler generated assembly, and I do not see any problems.  There must be something about it how it is called, or maybe it gets inlined, or something like that.  So I can look into that, please preprocess the entire source file which contains the problem implementation of BigAdd, as described in the first part of the article How to Submit a Compiler Test Case.  Then attach that to your next post.  So the forum will accept it, add the file extension .txt to it.

    Thanks and regards,

    -George

  • I think I've found the error in the assembly. The second ADDS instruction in the loop overwrites the carry status of the first ADDS instruction, so the only carry being passed on is if the carry from the last cycle of the loop is set, which of course it never is the in the first place.

    I hope this is reproduceable.

    ;*****************************************************************************
    ;* FUNCTION NAME: BigAdd                                                     *
    ;*                                                                           *
    ;*   Regs Modified     : A1,A2,A3,A4,V1,V2,V3,V4,V5,V6,SP,SR                 *
    ;*   Regs Used         : A1,A2,A3,A4,V1,V2,V3,V4,V5,V6,SP,LR,SR              *
    ;*   Local Frame Size  : 0 Args + 0 Auto + 28 Save = 28 byte                 *
    ;*****************************************************************************
    BigAdd:
    ;* --------------------------------------------------------------------------*
    ;* V3    assigned to result
    ;* A2    assigned to x
    ;* A3    assigned to y
    ;* A1    assigned to size
    ;* V5    assigned to carry
            PUSH      {A4, V1, V2, V3, V4, V5, V6, LR} ; save registers
            MOV       V3, A1                ; put *result into V3
            MOV       V5, #0                ; zero V5
            MOVS      A1, A4                ; put size into A1, setting the zero flag if zero
            MOV       V6, V5                ; zero V6
            BEQ       ||$C$L2||             ; if(Z) skip loop
            MOVS      V1, #0                ; zero V1, setting the zero flag
    ;* --------------------------------------------------------------------------*
    ;*   BEGIN LOOP ||$C$L1||
    ;*
    ;*   Loop source line                : 88
    ;*   Loop closing brace source line  : 94
    ;*   Known Minimum Trip Count        : 1
    ;*   Known Maximum Trip Count        : 2147483647
    ;*   Known Max Trip Count Factor     : 1
    ;* --------------------------------------------------------------------------*
    ||$C$L1||:    
            LDR       V2, [A3], #4          ; V2 = *y , y++
            LDR       A4, [A2], #4          ; A4 = *x, x++ 
            ADDS      A4, A4, V2            ; A4 = x + y, maybe set carry 
            ADDS      V5, V5, A4            ; V5 += x + y + carry, OVERWRITES THE CARRY STATUS OF (x+y)
            ADC       V6, V6, V1            ; V6 += 0+CARRY
            STR       V5, [V3], #4          ; *result = V5, result++
            SUBS      A1, A1, #1            ; size--, maybe set Zero
            MOV       V5, V6                ; V5 = CARRY
            MOV       V6, V1                ; V6 = 0
            BNE       ||$C$L1||             ; if(size!=0) goto ||$C$L1||
    ||$C$L2||:    
            MOV       A1, V5                ; return CARRY
            POP       {A4, V1, V2, V3, V4, V5, V6, PC} ; restore registers
            ; BRANCH OCCURS                  ; [] 
    

  • I think you make a good point.  I can reproduce that same assembly code.  I filed the entry CODEGEN-6362 in the SDOWP system to have this investigated.  You are welcome to follow it with the SDOWP link below in my signature.

    Thanks and regards,

    -George