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/TMS570LC4357: opt_for_speed=2 creates holes in .text

Part Number: TMS570LC4357

Tool/software: TI C/C++ Compiler

I am using the TI ARM compiler (tried version 5.1.6 and 16.9.4) to compile code for the TMS570LC43xx device, which is an R5 cache based device. When I invoke opt_for_speed=2 or greater, the compiler forces the .text section of each file to a 16 byte alignment. That creates lots of wasted flash space with holes of 2 to 14 bytes. I assume this is because the compiler is aligning the .text section to a cache page. It seems a pretty high code size hit for the speed optimization. Is there a way to turn off the forced alignment and still get the other speed enhancements that come with opt_for_speed=2?

  • Hello Bob,
    based on your example, how huge is this loss in percentages?
    I assume that your question/concern comes from a potential loss of cache efficiency.
    16 bytes alignment is not something I would expect on a 32 bit platform.
    I would be a bystander.
  • Bob Crosby said:
    Is there a way to turn off the forced alignment and still get the other speed enhancements that come with opt_for_speed=2?

    Unfortunately, no.  Using --opt_for_speed=1 or 0 is the only way to disable that alignment.

    One suggestion to consider ...   Set the default build options to --opt_for_speed=1, then, for the few files where performance is a concern, override the default with a higher --opt_for_speed value.  If you build with CCS, you can do that with file specific options.  

    Another suggestion ... If you build with CCS, use Optimizer Assistant to quickly experiment with different values for --opt_for_speed.

    Thanks and regards,

    -George

  • George,

    I expected response from you as first, glad you did!
    My understanding is that, in many/most cases, a 16 byte alignment is optimal for speed.
    Thanks for a pointer to file specific options.

    In case of TMS570LC4357, having performance/code size issues I would look for a solution at architecture level.
  • It looks like I got about a 0.65% increase in code size going from opt_for_speed=1 to opt_for_speed=2. That is pretty much inline with the increase when going from =2 to =3.

  • Bob,
    many thanks for your solid piece of engineering.
    In my opinion we should not worry about 1-2%.

    ARM R5F is 8-Stage Pipeline architecture.
    From cache effectiveness perspective, at so deep stage pipeline, very important is to predict jumps, calls and to keep a pipeline.
    ARM guys did like this:

    Conditional execution

    Almost every ARM instruction has a conditional execution feature called predication, which is implemented with a 4-bit condition code selector (the predicate). To allow for unconditional execution, one of the four-bit codes causes the instruction to be always executed. Most other CPU architectures only have condition codes on branch instructions.

    Though the predicate takes up four of the 32 bits in an instruction code, and thus cuts down significantly on the encoding bits available for displacements in memory access instructions, it avoids branch instructions when generating code for small if statements. Apart from eliminating the branch instructions themselves, this preserves the fetch/decode/execute pipeline at the cost of only one cycle per skipped instruction.

    The standard example of conditional execution is the subtraction-based Euclidean algorithm:

    In the C programming language, the loop is:

    while (i != j) // We enter the loop when i<j or i>j, not when i==j
    {
    if (i > j) // When i>j we do this
    i -= j;
    else // When i<j we do that (no if(i<j) needed since i!=j is checked in while condition)
    j -= i;
    }

    For ARM assembly, the loop can be effectively transformed into:

    loop:
    // Compare i and j
    GT = i > j;
    LT = i < j;
    NE = i != j;

    // Perform operations based on flag results
    if(GT) i -= j; // Subtract *only* if greater-than
    if(LT) j -= i; // Subtract *only* if less-than
    if(NE) goto loop; // Loop *only* if compared values were not equal

    and coded as:

    loop: CMP Ri, Rj ; set condition "NE" if (i != j),
    ; "GT" if (i > j),
    ; or "LT" if (i < j)
    SUBGT Ri, Ri, Rj ; if "GT" (Greater Than), i = i-j;
    SUBLT Rj, Rj, Ri ; if "LT" (Less Than), j = j-i;
    BNE loop ; if "NE" (Not Equal), then loop

    which avoids the branches around the then and else clauses. If Ri and Rj are equal then neither of the SUB instructions will be executed, eliminating the need for a conditional branch to implement the while check at the top of the loop, for example had SUBLE (less than or equal) been used.

    One of the ways that Thumb code provides a more dense encoding is to remove the four-bit selector from non-branch instructions.