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/TMS320F28377D: Cannot get the compiler to emit a RPT || MIN instruction

Part Number: TMS320F28377D

Tool/software: TI C/C++ Compiler

I am trying to get the compiler to generate efficient code for finding the minimum of a 16-bit integer array:

int array_min_i16( const int *array, int num )
{
int min;

_nassert( num > 0 );

min = *array++;
while ( --num )
{
min = __min(min, *array++);
}

return min;
}

 

This produces the assembly (compiler options can be gleaned from the .compiler_opts tag)

;***************************************************************
;* TMS320C2000 C/C++ Codegen PC v17.9.0.STS *
;* Date/Time created: Tue Nov 14 16:56:02 2017 *
;***************************************************************
.compiler_opts --abi=coffabi --cla_support=cla1 --diag_wrap=off --float_support=fpu32 --hll_source=on --mem_model:code=flat --mem_model:data=large --object_format=coff --section_sizes=on --silicon_version=28 --symdebug:none --tmu_support=tmu0
.asg XAR2, FP
; C:\ti\ccsv6\tools\compiler\ti-cgt-c2000_17.9.0.STS\bin\opt2000.exe --gen_opt_info=1 C:\\Users\\XXXX\\AppData\\Local\\Temp\\{B44A09E1-C4D6-4F83-8D85-016C0A54BF9C} C:\\Users\\rist-1\\AppData\\Local\\Temp\\{1B9ACCCD-52A8-467C-A4F1-6323A6F25624} --opt_info_filename=temp.nfo
; C:\ti\ccsv6\tools\compiler\ti-cgt-c2000_17.9.0.STS\bin\ac2000.exe -@C:\\Users\\XXX\\AppData\\Local\\Temp\\{74F4C8A9-E322-45BA-9328-AB0817806698}
.sect ".TI.ramfunc:_array_min_i16"
.clink
.global _array_min_i16

;***************************************************************
;* FNAME: _array_min_i16 FR SIZE: 0 *
;* *
;* FUNCTION ENVIRONMENT *
;* *
;* FUNCTION PROPERTIES *
;* 0 Parameter, 0 Auto, 0 SOE *
;***************************************************************

_array_min_i16:
;*** 7 ----------------------- min = *array;
;*** 8 ----------------------- if ( !(--num) ) goto g7;
ADDB AL,#-1 ; [CPU_ALU] |8|
MOVZ AR6,AL ; [CPU_ALU] |8|
MOV AL,*+XAR4[0] ; [CPU_ALU] |7|
MOV AH,AR6 ; [CPU_ALU] |7|
BF $C$L3,EQ ; [CPU_ALU] |8|
; branchcc occurs ; [] |8|
;*** 10 ----------------------- d$1 = num&1;
;*** 7 ----------------------- ++array;
;*** 10 ----------------------- if ( num < 2 ) goto g5;
ANDB AH,#1 ; [CPU_ALU] |10|
MOVZ AR7,AH ; [CPU_ALU] |10|
ADDB XAR4,#1 ; [CPU_ALU] |7|
MOV AH,AR6 ; [CPU_FPU] |7|
CMPB AH,#2 ; [CPU_ALU] |10|
BF $C$L2,LT ; [CPU_ALU] |10|
; branchcc occurs ; [] |10|
;*** ----------------------- L$1 = (num>>1)-1;
;*** ----------------------- #pragma MUST_ITERATE(1, 16383, 1)
;*** ----------------------- // LOOP BELOW UNROLLED BY FACTOR(2)
;*** ----------------------- #pragma LOOP_FLAGS(4102u)
ASR AH,1 ; [CPU_ALU]
ADDB AH,#-1 ; [CPU_ALU]
MOVZ AR6,AH ; [CPU_ALU]
$C$L1:
;*** -----------------------g4:
;*** 10 ----------------------- min = __min(min, *array++);
;*** 10 ----------------------- min = __min(min, *array++);
;*** 8 ----------------------- if ( (--L$1) != (-1) ) goto g4;
MIN AL,*XAR4++ ; [CPU_ALU] |10|
MIN AL,*XAR4++ ; [CPU_ALU] |10|
BANZ $C$L1,AR6-- ; [CPU_ALU] |8|
; branchcc occurs ; [] |8|
$C$L2:
;*** -----------------------g5:
;*** ----------------------- if ( d$1 <= 0 ) goto g7;
MOV AH,AR7 ; [CPU_ALU]
BF $C$L3,LEQ ; [CPU_ALU]
; branchcc occurs ; []
; Peeled loop iterations for unrolled loop:
;*** 10 ----------------------- min = __min(min, *array);
;*** -----------------------g7:
;*** 13 ----------------------- return min;
MIN AL,*+XAR4[0] ; [CPU_ALU] |10|
$C$L3:
LRETR ; [CPU_ALU]
; return occurs ; []

I cannot get the compiler to produce the much more efficient 

_array_min_i16:
SUBB ACC,#2
MOV AH,AL
MOV AL,*XAR4++
RPT AH
|| MIN AL,*XAR0++ ;
LRETR ;

How can I get the compiler to produce a more optimised version of the function? Is there a compiler switch I am missing (max uninterruptable sequence perhaps)?

  • When I use C2000 compiler version 17.9.0.STS, and the compiler options shown in the assembly file plus -O2, I get RPT||MIN:

    % cl2000 -s -O3 foo.c --abi=coffabi --cla_support=cla1 --diag_wrap=off --float_support=fpu32 
             --mem_model:code=flat --mem_model:data=large --object_format=coff --section_sizes=on 
             --silicon_version=28 --symdebug:none --tmu_support=tmu0
    
    % egrep 'RPT|MIN' foo.asm
           RPT       AR5
    ||     MIN       AH,*XAR4++            ; [CPU_ALU] |10|

    I'm guessing you're using an additional option that does not show up in the assembly file which is affecting the loop.  Please show me your complete command line options.  The best thing to do would be to rebuild this file, then send me the entire build console window.

  • I have reproduced your output by creating a new project in CCS and used the default Release build options (with keep_asm turned on).

    I found optimisation level to have no effect on the compiler output.

    I found 'optimise for speed' (opt_for_speed) option to be the culprit. Changing opt_for_speed from 2 to 3 provokes the change from RPT || MIN to an unrolled loop.

    I've been bitten by this before on the C6000 compiler a few years ago, and was told the opt_for_speed loop unrolling pass occurs prior to the instruction optimiser. At that point either the instruction optimiser cannot optimise the unrolled loop back to a single loop kernel, or it is explicitly told not to.

    I can confirm that a #pragma UNROLL(1) achieves the desired output even when opt_for_speed is set to 5.

    This opens up the following question: is opt_for_speed a useful option or should I leave it at the default?
  • It is useful for some benchmarks, but your milage may vary, as they say. I was not aware of this particular wrinkle. In this case, I'd bet the unroller was thwarted by the minimum loop size on RPTB instructions. Do what's best for your code; in this case, I'd suggest keeping the UNROLL(1) pragma and then experimenting with the setting of --opt_for_speed.