Перейти к содержанию
    

или лыжи не едут или глюк оптимизатора CCS3.3

Имеем CC3.3 + C6000 Code Generation Tools v6.1.21.

Компилим с таргет = -mv6740.

Функция:

void DSPF_fltoq31(const float* restrict x, int * restrict y, int n)
{
  int i0, i1, fadcr_store;
  float t00, t01, t10, t11;

  _nassert(n > 0);
  _nassert(n % 2 == 0);

  fadcr_store = FADCR; //preserve the FADCR value
  FADCR = _set(FADCR, 9, 10); //set FADCR bits to switch to ROUND TOWARD NEGATIVE INF
  FADCR = _set(FADCR, 25, 26); //set mode for both L units

  #pragma MUST_ITERATE(1, , )
  for (; (n -= 2) >= 0; ) {
    t00 = x[n];
    t01 = x[n + 1];
    t10 = t00 * 0x800000; //multiply by 2^23 for converting to Q23 format (this brings the number in the range -0x800000 to 0x800000)
    t11 = t01 * 0x800000; //multiply by 2^23 for converting to Q23 format (this brings the number in the range -0x800000 to 0x800000)
    i0 = _spint(t10);  //use intrinsic to convert the number to integer
    i1 = _spint(t11);  //use intrinsic to convert the number to integer
    *y++ = _sshl(i1, 8); //saturate the number if required
    *y++ = _sshl(i0, 8); //saturate the number if required
  }
  FADCR = fadcr_store; //restore the FADCR value
}

Как видно - результат выполнения пишется в 'y' с инкрементированием.

Но после компиляции смотрим в листинг и видим, что компилятор построил цикл с декрементированием 'y' !!! :crying:

(обратите внимание на строки: 263, 268, 269, 277, 278)

...
     241 00000090     0ce6             SPLOOP  2      ;16              ; (P)
     242 00000092     9de1  ||         SUB     .L2X    A3,4,B6
     243 00000094 018f0058  ||         SUB     .L1     A3,8,A3
     244
     245                   ;** --------------------------------------------------------------------------*
     246 00000098           $C$L4:   ; PIPED LOOP KERNEL
     247 00000098           $C$DW$L$_DSPF_fltoq31__FPCfPii$8$B:
     248
     249 00000098 030c5465             LDW     .D1T1   *A3--(8),A6      ; |116| (P) <0,0>
     250 000000a0 041854e6  ||         LDW     .D2T2   *B6--(8),B8      ; |118| (P) <0,0>
     251
     252 000000a4 00008000             NOP             5
     253
     254 000000a8 02990e01             MPYSP   .M1     A8,A6,A5         ; |116| (P) <0,6>
     255 000000ac 03a11e02  ||         MPYSP   .M2X    A8,B8,B7         ; |118| (P) <0,6>
     256
     257 000000b0 00004000             NOP             3
     258
     259 000000b4 03940159             SPINT   .L1     A5,A7            ; |116| (P) <0,10>
     260 000000b8 029c015a  ||         SPINT   .L2     B7,B5            ; |118| (P) <0,10>
     261
     262 000000bc 000b0001             SPMASK          L2
     263 000000c0 052b005a  ||         SUB     .L2     B10,8,B10
     264
     265 000000c4     0c6e             NOP             1
     266
     267 000000c6     2f66             SPMASK          S1,S2
     268 000000c8 022901a3  ||         ADD     .S2     8,B10,B4
     269 000000cc 022991a0  ||         ADD     .S1X    12,B10,A4
     270
     271 000000d0 029d08a1             SSHL    .S1     A7,8,A5          ; |119| <0,14>
     272 000000d4     0ec3  ||         SSHL    .S2     B5,8,B5          ; |118| <0,14>
     273
     274                            .dwpsn  file "DSPF_fltoq31.c",line 120,column 0,is_stmt
     275
     276 000000d6     dc67             SPKERNEL 7,0
     277 000000d8     2c54  ||         STW     .D1T1   A5,*A4++(8)      ; |119| <0,15>
     278 000000da     3c55  ||         STW     .D2T2   B5,*B4++(8)      ; |118| <0,15>
...

Естественно, что функция не работает - затирает чужую память.

Если убрать модификатор 'restrict' для 'x' и 'y' всё начинает работать, но скорость совсем не та - не строится аппаратного цикла SPLOOP насколько я понимаю.

Если делать обработку за один проход по одному сэмплу (одна операция *y++) - тоже всё нормально компилится и 'y' в листинге инкрементируется.

 

Кто-нить сталкивался? Или я чего-то недогоняю? Или в CodeTools v6.1.21 'restrict' кривой и, чтобы писать быструю обработку, придётся изучать асм C674x???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но после компиляции смотрим в листинг и видим, что компилятор построил цикл с декрементированием 'y'
С икрементированием. Вы точно хотите читать по убывающим адресам и писать по возрастающим?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С икрементированием. Вы точно хотите читать по убывающим адресам и писать по возрастающим?

С декрементированием. Посмотрите внимательнее на указанные строки листинга.

Точно хочу - в буфере входных данных данные расположены в обратном порядке, а функции DSPLIB (для которых готовит данные указанная функция) требуют прямого порядка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хотите сказать, что

 

STW .D1T1 A5,*A4++(8)

 

это декремент указателя? Хе-хе... А команды, работающие с B10, находятся под SPMASK-ом, и исполняются один раз на первой итерации, они призваны проинициализировать A4 и B4 с разносом на одно слово.

 

Так что ищите глюки не в компиляторе. а где нить в interrupt threshold например

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А команды, работающие с B10, находятся под SPMASK-ом, и исполняются один раз на первой итерации, они призваны проинициализировать A4 и B4 с разносом на одно слово.

Вон оно что... Про SPMASK не читал... я собсно не знаю асма для этого ядра, так - навскидку смотрю листинг B)

Здесь асм что-то сложный похоже... в C5502 был гораздо проще - там я всё целиком на нём писал ;)

Надо прочитать про SPMASK.

Так что ищите глюки не в компиляторе. а где нить в interrupt threshold например

Обработчики прерывания здесь в этом ядре не сохраняют состояние аппаратных циклов и на время вызова функций DSPLIB надо запрещать прерывания?

Интересно - а как тогда весь остальной код работает? Написал большой объём кода на это ядро (без использования DSPLIB и restrict) и всё прекрасно работало с множеством прерываний. С оптимизацией.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обработчики прерывания здесь в этом ядре не сохраняют состояние аппаратных циклов и на время вызова функций DSPLIB надо запрещать прерывания?

 

В этом ядре не все возможно сохранить физически. Например, если стоит команда LDW в регистр A1, и за те 4 такта, что она выполняется, с этим A1 делается еще что-то, пока он еще не получил данное от LDW, то при возникновении прерывания невовремя регистр поймает значение от LDW, а не от того, что там делается конвейеризировано.

 

например:

 

LDW .D1T1 *A3, A1

|| ADD .S1 A6,A1,A1

 

SUB .S1 A8,A1,A1

 

STW .D1T1 A1,*A4

 

NOP 2

 

; и толкьо тут в A1 придет значение от LDW

 

вот если тут между LDW || ADD и SUB, или между SUB и STW придет прерывание, то значение A1 будет испорчено результатом LDW в результате "нежданного" опустошения конвейера с приостановом исполнения

 

 

Именно для этого в build options есть interrupt threshold, показывающий, на сколько времени можно при конвейеризации запрещать прерывания. Если он не указан вообще, то считается, что компилятор за это не отвечает, а сам программер следит.

 

Хотя конкретно в том коде, что ты привел, я не вижу таких ситуаций. Он с точки зрения прерываемости вроде как корректен, во всех таких местах все NOP-ами забито.... Возможно, что после указания достаточного interrupt threshold его оптимизатор вообще до неузнаваемости извернет

 

ЗЫ

АСМ тут простой, у 5502 сложнее в разы. Однако конвейер у этого проца способен мозг вывихнуть и вынести, если писать конвейеризировно с максимальной параллельностью.

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще то мне казалось, что у interrupt threshold немного другая логика. Процессор сам умеет неявно запрещать прерывания, если они могут порушить конвейерное исполнение команд. При этом в очень плотно оптимизированных циклах неявный запрет растягивается на выполнение всего цикла. И вот тогда ключик interrupt threshold помогает сказать компилятору, чтобы он не городил такой плотной оптимизации циклов и длинных промежутков с неявно запрещенными прерываниями длиннее N тактов.

 

Справедливости ради стоит сказать, что при расчете этого времени считается, что все команды LDW и STW работают с L1. А для внешней памяти задержки могут быть в разы больше.

 

ЗЫ: Да, и мне обычно хватало линейного ассемблера для выжимания того, чего я хочу. Во всяком случае фидбэк от него еще можно понять, а вот самому юниты и регистры там планировать - это конечно жесть. На практике как раз было проверено, что на C иногда не удается никакими ухищрениями добиться желаемой оптимизации, без особого напряга получаемой на линейном ассемблере.

Изменено пользователем Hoodwin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще то мне казалось, что у interrupt threshold немного другая логика. Процессор сам умеет неявно запрещать прерывания, если они могут порушить конвейерное исполнение команд.

 

Ну лично я не имел дело с 64+, зато много писал под 67хх, в т.ч. на асме, в т.ч. с максимальной конвейеризацией и параллельностью исполнения. Базовая система команд у них совместима. Процессор там туп и глуп, ничего он не умеет неявно сам запрещать. Компилятор сам расставляет MVC в CSR согласно указанному ему interrupt threshold, и внутри этих мест, где запретил прерывания, конвейеризирует адски, а между запрещенных от прерывания кусков дает возможность прерваться.

 

Справедливости ради стоит еще отметить, что в 6000-ной базе LDW и STW это команды только D-юнита, L-юнит не может исполнять их вообще и в принципе. А задержки в смысле памяти на длины делэй-слотов не влияют, они останавливают весь конвейер целиком. И если делэй у LDW 4 такта, то хоть на 100 тактов сталл из-за памяти, все равно дэлей 4 пакета инструкций, как ни крути.

 

Мне линейного ассемблера не хватало, да и вообще он нафиг не нужен, если есть С, то же самое по большому счету - код такой же, проблемы те же, а возни с писанием кода больше. Я писал например оптимизированный кодер для аудио, там циклов почти не было, огромное кол-во линейного кода. Вручную разбил его на две половины, и A-стороной процессора обрабатывал первую половимну алгоритма для одного канала, а B-половиной - досчитывал параллеьно с этим вторую половину для предыдущего канала. Такое ни на С, ни на линейном асме, реализовать было не возможно вообще. А вручную расшедулив все операции - удалось где-то за неделю жесткого секса с элементами садо-мазо :) .

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, на самом деле неявный запрет прерываний есть. Цитата из SPRU187:

2.12 Interrupt Flexibility Options (--interrupt_threshold Option)

On the C6000 architecture, interrupts cannot be taken in the delay slots of a branch. In some instances

the compiler can generate code that cannot be interrupted for a potentially large number of cycles. For a

given real-time system, there may be a hard limit on how long interrupts can be disabled.

 

The --interrupt_threshold=n option specifies an interrupt threshold value n. The threshold value specifies

the maximum number of cycles that the compiler can disable interrupts. If the n is omitted, the compiler

assumes that the code is never interrupted. In Code Composer Studio, to specify that the code is never

interrupted, select the Interrupt Threshold check box and leave the text box blank in the Build Options

dialog box on the Compiler tab, Advanced category.

 

If the --interrupt_threshold=n option is not specified, then interrupts are only explicitly disabled around

software pipelined loops. When using the --interrupt_threshold=n option, the compiler analyzes the loop

structure and loop counter to determine the maximum number of cycles it takes to execute a loop. If it can

determine that the maximum number of cycles is less than the threshold value, the compiler generates the

fastest/optimal version of the loop. If the loop is smaller than six cycles, interrupts are not able to occur

because the loop is always executing inside the delay slots of a branch. Otherwise, the compiler

generates a loop that can be interrupted (and still generate correct results—single assignment code),

which in most cases degrades the performance of the loop.

 

The --interrupt_threshold=n option does not comprehend the effects of the memory system. When

determining the maximum number of execution cycles for a loop, the compiler does not compute the

effects of using slow off-chip memory or memory bank conflicts. It is recommended that a conservative

threshold value is used to adjust for the effects of the memory system.

 

Так что насчет LDW STW я не прав, они не влияют на неявный запрет прерываний, только ветвления.

 

А вот MVC у меня вылезали только, когда регистров для циклов не хватало и в ход шли указатели стека, и т.п.

 

Вопрос к jcxz: а в чем проявляется конкретно беда? что за память он затирает? Пробовали ли вы писать более простой код типа:

 

while( n>0 )
{
   t00 = x[n-1];
   t01 = x[n-2];
   n -= 2;
   y[0]  = f(t00);
   y[1]  = f(t01);
   y += 2;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если у вас оно не ставило MVC и не запрещало прерывания, это говорит о следующих вариантах:

 

1) Включено что-то, связанное с отладкой, отладочная инфа, или еще что-то, что не позволило компилятору совсем "скрутить цикл в бараний рог" с целью того, чтобы в отладчике можно было наблюдать значения переменных при пошаговом проходе тела цикла.

 

2) Компилятор не смог определить параметры цикла. То есть они либо не заданы явно, числами, либо не дана MUST_ITERATE, ну и компилятор не стал применять оптимизацию, требующую запрещения прерываний, так как не смог рассчитать, будет ли он в результате соответствовать порогу непрерываемости.

 

3) цикл построен так, что его вообще невозможно заоптимизировать по максимуму, и решение компилятора оказалось прерываемым само по себе.

 

4) Самый шоколадный - цикл, соптимизированный по максимуму, сам по себе оказался прерываемым.

 

5) Не менее шоколадный - оптимизатор уложил все так, что все команды и пролога, и ядра, и эпилога лежат в делэй слотах бранчей, и вся эта система в целом оказалась сама собой не прерываемая.

 

 

Для примера приведу простое побайтное копирование памяти в цикле, т.е. memcpy без извратов. Оптимизированная версия представляет собой пролог из пяти LDW, ядро из LDW || STW и эпилог из пяти STW, при этом все LDW запараллелены с бранчами и декрементом счетчика цикла. Эта конструкция непрерываемая. Вот если включить отладку, или не задать MUST_ITERATE, что компилятор не сможет понять, что этот цикл в реальности не может быть длинным - то компилятор соберет его неэффективным, но прерываемым. Если же все сойдется в лушую сторону - то цикл будет сделан с LDW || STW в ядре цикла, что каждый такт делается одно LDW и одновременно одно STW.

 

 

пример MVC - это кусок расчета alaw - тупо из рекомендации G.

 

inline int
search(
int		val,
int		*table,
int		size)
{
int		i;

for (i = 0; i < size; i++) {
	if (val <= *table++)
		return (i);
}
return (size);
}


unsigned char
linear2alaw(
int		pcm_val)	/* 2's complement (16-bit range) */
{
int		mask;
int		seg;
unsigned char	aval;

if (pcm_val >= 0) {
	mask = 0xD5;		/* sign (7th) bit = 1 */
} else {
	mask = 0x55;		/* sign bit = 0 */
	pcm_val = -pcm_val - 8;
}

/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_end, 8);

..................
..................

 

а вот и MVC в первых рядах ассемблерного кода (причем как-то не очень то и соптимизированного, я бы руками лучше расшедулил, ну или -mhXXX маловато задан был):

 

_linear2alaw:
;** --------------------------------------------------------------------------*
;** 45	-----------------------    if ( (pcm_val = pcm_val) >= 0 ) goto g3;
;** 54	-----------------------    pcm_val = (-8)-pcm_val;
;** 53	-----------------------    mask = 85;
;** 54	-----------------------    goto g4;
;**	-----------------------g3:
;** 51	-----------------------    mask = 213;
;**	-----------------------g4:
;** 58	-----------------------    val = pcm_val;
;** 58	-----------------------    table = &seg_end[-1];
;** 34	-----------------------    i = (-1);  // [0]
;** 34	-----------------------    L$1 = 8;  // [0]
;**  	-----------------------    #pragma MUST_ITERATE(1, 8, 1)
;**  	-----------------------    #pragma LOOP_FLAGS(4352u)
;**	-----------------------g5:
;** 35	-----------------------    f$1 = (val <= *(++table))-1;  // [0]
;** 34	-----------------------    ++i;  // [0]
;** 34	-----------------------    if ( (--L$1)&f$1 ) goto g5;  // [0]
;**  	-----------------------    f$1 ? (seg = 8) : (seg = i);
$C$DW$8	.dwtag  DW_TAG_formal_parameter, DW_AT_name("pcm_val")
.dwattr $C$DW$8, DW_AT_TI_symbol_name("_pcm_val")
.dwattr $C$DW$8, DW_AT_type(*$C$DW$T$10)
.dwattr $C$DW$8, DW_AT_location[DW_OP_reg4]
          MVKL    .S1     _seg_end-4,A8
          MVKH    .S1     _seg_end-4,A8
          LDW     .D1T1   *++A8,A5          ; |35| (P) <0,0>  ^ 
          MVK     .S1     0x55,A0           ; |53| 
          MVC     .S2     CSR,B5

          CMPLT   .L1     A4,0,A1           ; |45| 
||         MV      .D1     A4,A9             ; |45| 

  [ A1]   SUB     .L1     -8,A9,A9          ; |54| 
||         AND     .L2     -2,B5,B6
||         MVK     .S2     0xffffffff,B4     ; |34| 
||         MVK     .S1     0x8,A6            ; |34| 

          CMPGT   .L1     A9,A5,A4          ; |35| 
||         MV      .D1     A9,A7             ; |58| 
||         MVC     .S2     B6,CSR            ; interrupts off
|| [!A1]   MVK     .S1     0xd5,A0           ; |51| 

;*----------------------------------------------------------------------------*
;*   SOFTWARE PIPELINE INFORMATION
;*
;*      Loop source line                 : 34
;*      Loop opening brace source line   : 34
;*      Loop closing brace source line   : 37
;*      Known Minimum Trip Count         : 1                    
;*      Known Maximum Trip Count         : 8                    
;*      Known Max Trip Count Factor      : 1
;*      Loop Carried Dependency Bound(^) : 1
;*      Unpartitioned Resource Bound     : 2
;*      Partitioned Resource Bound(*)    : 2
;*      Resource Partition:
;*                                A-side   B-side
;*      .L units                     1        0     
;*      .S units                     0        1     
;*      .D units                     1        0     
;*      .M units                     0        0     
;*      .X cross paths               0        0     
;*      .T address paths             1        0     
;*      Long read paths              0        0     
;*      Long write paths             0        0     
;*      Logical  ops (.LS)           2        0     (.L or .S unit)
;*      Addition ops (.LSD)          2        1     (.L or .S or .D unit)
;*      Bound(.L .S .LS)             2*       1     
;*      Bound(.L .S .D .LS .LSD)     2*       1     
;*
;*      Searching for software pipeline schedule at ...
;*         ii = 6  Unsafe schedule for irregular loop
;*         ii = 6  Unsafe schedule for irregular loop
;*         ii = 6  Unsafe schedule for irregular loop
;*         ii = 6  Did not find schedule
;*         ii = 7  Unsafe schedule for irregular loop
;*         ii = 7  Unsafe schedule for irregular loop
;*         ii = 7  Unsafe schedule for irregular loop
;*         ii = 7  Did not find schedule
;*         ii = 8  Unsafe schedule for irregular loop
;*         ii = 8  Unsafe schedule for irregular loop
;*         ii = 8  Unsafe schedule for irregular loop
;*         ii = 8  Did not find schedule
;*         ii = 9  Schedule found with 2 iterations in parallel
;*      Done
;*
;*      Collapsed epilog stages     : 1
;*      Prolog not removed
;*      Collapsed prolog stages     : 0
;*
;*      Minimum required memory pad : 0 bytes
;*
;*      For further improvement on this loop, try option -mh56
;*
;*      Minimum safe trip count     : 1
;*----------------------------------------------------------------------------*
$C$L1:    ; PIPED LOOP PROLOG
;** --------------------------------------------------------------------------*
$C$L2:    ; PIPED LOOP KERNEL
$C$DW$L$_linear2alaw$3$B:
.dwpsn	"alaw.c",34,0
          XOR     .L1     1,A4,A3           ; |35| <0,6>  ^ 

          SUB     .L1     A6,1,A6           ; |34| <0,7>  ^ 
||         SUB     .S1     A3,1,A3           ; |35| <0,7>  ^ 

          AND     .L1     A3,A6,A1          ; |34| <0,8>  ^ 

  [ A1]   B       .S2     $C$L2             ; |34| <0,9> 
|| [ A1]   LDW     .D1T1   *++A8,A5          ; |35| <1,0>  ^ 

          NOP             4
.dwpsn	"alaw.c",37,0

          ADD     .L2     1,B4,B4           ; |34| <0,14> 
||         CMPGT   .L1     A7,A5,A4          ; |35| <1,5>  ^ 

$C$DW$L$_linear2alaw$3$E:
;** --------------------------------------------------------------------------*
$C$L3:    ; PIPED LOOP EPILOG
;** --------------------------------------------------------------------------*
;** 38	-----------------------    if ( seg < 8 ) goto g8;  // [0]
;** 63	-----------------------    return (unsigned char)(mask^0x7f);

          MVC     .S2     B5,CSR            ; interrupts on
||         MV      .L1     A3,A1
||         MVK     .S1     127,A3            ; |63| 

          MVK     .S2     0x8,B5
||         XOR     .L1     A3,A0,A3          ; |63| 

..................
..................
..................

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос к jcxz: а в чем проявляется конкретно беда? что за память он затирает? Пробовали ли вы писать более простой код типа:

Похоже дело было не в затирании памяти. Сейчас ещё проверил - все работает. Наверно висло не из-за этого, а когда я заглянул в листинг - мне показалось странным такое поведение указателя 'y'.

Спасибо SAURIS GmbH разъяснил про SPMASK :rolleyes:

Кстати эту функцию я получил из такой:

void DSPF_fltoq31(const float* restrict x, int * restrict y, int n)
{
  int fadcr_store;
  _nassert(n > 0);
  _nassert(n % 2 == 0);
  fadcr_store = FADCR; //preserve the FADCR value
  FADCR = _set(FADCR, 9, 10); //set FADCR bits to switch to ROUND TOWARD NEGATIVE INF
  FADCR = _set(FADCR, 25, 26); //set mode for both L units

  #pragma MUST_ITERATE(1, , )
  for (x += n - 1; --n >= 0; ) *y++ = _sshl(_spint(*x-- * 0x800000), 8);

  FADCR = fadcr_store; //restore the FADCR value
}

Ожидал, что если сделать групповую обработку по 4 сэмпла, это должно ускорить. По листингу вижу, что вроде тактов стало меньше, но почему-то по измерениям загрузка процессора как была 8.8% так и осталась :wacko:

Кстати - попробовал interrupt threshold в опциях проекта (==3000) и вообще попробовал перед функцией поставить: #pragma FUNC_INTERRUPT_THRESHOLD(-1);

запретив прерывания на время выполнения функции - на генерируемый компилятором листинг это не оказывает никакого влияния. :wacko:

 

Похоже всё-таки придётся изучать асм для этого процессора. Насколько я понимаю глядя на получающийся после оптимизатора код - он очень неэффективный, столько NOP-ов...

 

LDW .D1T1 *A3, A1

|| ADD .S1 A6,A1,A1

SUB .S1 A8,A1,A1

STW .D1T1 A1,*A4

NOP 2

; и толкьо тут в A1 придет значение от LDW

Вот это забавная штука... Да уж - в 5502 всё было по другому - наставил-бы stall-ов кроме того, что в первой команде был-бы конфликт ресурсов.

Значит здесь неучёт времени выполнения (или фазы выполнения?) команд ведёт к неверной работе кода, в то время как в 5502 это вело-бы просто к лишним stall-ам.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вот код конечно совсем не похож на то, что должно бы быть. ВОт у меня так выглядит:

Исходник на линейном ассемблере:

;=====================================================================
; packing bytes into 16 levels (4 bits per swel)
;=====================================================================
_pack16:   .cproc   dst, src, cnt
           .reg     inp1, inp2
           .reg     cond11, cond12
           .reg     cond21, cond22
           .reg        cond3, phase
           .reg     brightness, threashold, contrast, rescale
           .reg        eff_brght1, above_thr1
           .reg        eff_brght2, above_thr2
           .reg     prescaled_x1, scaled_x1
           .reg     prescaled_x2, scaled_x2
           .reg     val1, result1, z1, packed1
           .reg     val2, result2, z2, packed2
           .reg     trimmed
           .reg     high_nibble, low_nibble
           .reg     mask, out_byte

; prepare working registers
            ldbu    *+DP(_p16_p), threashold
            ldw     *+DP(_p16_b), brightness
            ldhu    *+DP(_p16_m), rescale
            ldhu    *+DP(_p16_c), contrast

            mvk        0F0h, mask
            shl     cnt, 2, cnt

            .no_mdep

p16_loop:    .trip   4, 256, 4
; first byte to process
            ldbu        *src++, inp1
||            zero        above_thr1
||            zero        eff_brght1
            cmplt       inp1, threashold, cond11
[!cond11]    sub         inp1, threashold, above_thr1
[!cond11]    mv          brightness, eff_brght1
            mpyu        above_thr1, rescale, prescaled_x1
            shru          prescaled_x1, 8, scaled_x1
            mpyu        scaled_x1, contrast, val1
            add         val1, eff_brght1, result1
            zero        z1
            cmpgt         result1, 0, cond12
[cond12]    sshl         result1, 11, z1
            extu        z1, 1, 28, low_nibble
; second byte to process
            ldbu        *src++, inp2
||            zero        above_thr2
||            zero        eff_brght2
            cmplt       inp2, threashold, cond21
[!cond21]    sub         inp2, threashold, above_thr2
[!cond21]    mv          brightness, eff_brght2
            mpyu        above_thr2, rescale, prescaled_x2
            shru          prescaled_x2, 8, scaled_x2
            mpyu        scaled_x2, contrast, val2
            add         val2, eff_brght2, result2
            zero        z2
            cmpgt         result2, 0, cond22
[cond22]    sshl         result2, 11, z2
            extu        z2, 1, 28, trimmed
            shl            trimmed, 4, high_nibble
            or            high_nibble, low_nibble, out_byte
            stb            out_byte, *dst++

[cnt]        sub        .l    cnt, 2, cnt
[cnt]        b            p16_loop

            .return
            .endproc

 

А вот результат так выглядит (показан только LOOP KERNEL):

;** --------------------------------------------------------------------------*
$C$L5:   ; PIPED LOOP KERNEL

   [ cond12] SSHL  .S2     result1,0xb,z1   ; |146| <0,17> 
|| [ cond22] SSHL  .S1     result2,0xb,z2   ; |161| <0,17> 
||         MPYU    .M1     scaled_x2,contrast,val2; |157| <1,12>  ^ 
|| [!cond11] SUB   .L2X    inp1,threashold,above_thr1; |138| <2,7>  ^ 
||         CMPLT   .L1     inp2,threashold,cond21; |152| <2,7>  ^ 
||         LDBU    .D1T1   *-src(1),inp2    ; |149| <3,2> 

           EXTU    .S2     z1,0x1,0x1c,low_nibble; |147| <0,18> 
||         EXTU    .S1     z2,0x1,0x1c,trimmed; |162| <0,18> 
||         ADD     .L2     val1,eff_brght1,result1; |143| <1,13>  ^ 
||         ZERO    .L1     z2               ; |159| <1,13> 
||         ZERO    .D2     eff_brght1       ; |134| <2,8>  ^ 
||         MPYU    .M2X    above_thr1,rescale,prescaled_x1; |140| <2,8>  ^ 
|| [!cond21] SUB   .D1     inp2,threashold,above_thr2; |153| <2,8>  ^ 

           SHL     .S1     trimmed,0x4,high_nibble; |163| <0,19> 
||         CMPLT   .L2     0x0,result1,cond12; |145| <1,14> 
||         ADD     .D1     val2,eff_brght2,result2; |158| <1,14>  ^ 
|| [!cond11] MV    .S2X    brightness,eff_brght1; |139| <2,9>  ^ 
||         MPYU    .M1     above_thr2,rescale,prescaled_x2; |155| <2,9>  ^ 
||         ZERO    .L1     eff_brght2       ; |149| <2,9>  ^ 
||         ZERO    .D2     above_thr1       ; |134| <3,4> 

           OR      .S1X    high_nibble,low_nibble,out_byte; |164| <0,20> 
||         ZERO    .D2     z1               ; |144| <1,15> 
||         CMPLT   .L1     0x0,result2,cond22; |160| <1,15> 
||         SHRU    .S2     prescaled_x1,0x8,scaled_x1; |141| <2,10>  ^ 
||         CMPLT   .L2X    inp1,threashold,cond11; |137| <3,5>  ^ 
||         LDBU    .D1T2   *src++(2),inp1   ; |134| <4,0> 

           STB     .D2T1   out_byte,*dst'++ ; |165| <0,21> 
|| [ cnt'] B       .S2     $C$L5            ; |168| <1,16> 
|| [ cnt'] ADD     .L2     0xfffffffe,cnt',cnt'; |167| <2,11> 
||         MPYU    .M2X    scaled_x1,contrast,val1; |142| <2,11>  ^ 
|| [!cond21] MV    .D1     brightness,eff_brght2; |154| <2,11>  ^ 
||         SHRU    .S1     prescaled_x2,0x8,scaled_x2; |156| <2,11>  ^ 
||         ZERO    .L1     above_thr2       ; |149| <3,6> 

;** --------------------------------------------------------------------------*
$C$L6:   ; PIPED LOOP EPILOG
;** --------------------------------------------------------------------------*

 

Но это я еще на C62 развлекался...

 

Кстати, важно именно какой оно дает заголовок об оптимизации. В том цикле вот что было:

;*----------------------------------------------------------------------------*
;*   SOFTWARE PIPELINE INFORMATION
;*
;*      Loop source line                 : 134
;*      Loop closing brace source line   : 168
;*      Known Minimum Trip Count         : 4                    
;*      Known Maximum Trip Count         : 256                    
;*      Known Max Trip Count Factor      : 4
;*      Loop Carried Dependency Bound(^) : 4
;*      Unpartitioned Resource Bound     : 5
;*      Partitioned Resource Bound(*)    : 5
;*      Resource Partition:
;*                                A-side   B-side
;*      .L units                     2        3     
;*      .S units                     4        4     
;*      .D units                     2        1     
;*      .M units                     2        2     
;*      .X cross paths               1        5*    
;*      .T address paths             2        1     
;*      Long read paths              1        0     
;*      Long write paths             0        0     
;*      Logical  ops (.LS)           1        1     (.L or .S unit)
;*      Addition ops (.LSD)          6        5     (.L or .S or .D unit)
;*      Bound(.L .S .LS)             4        4     
;*      Bound(.L .S .D .LS .LSD)     5*       5*    
;*
;*      Searching for software pipeline schedule at ...
;*         ii = 5  Schedule found with 5 iterations in parallel
;*      Done
;*
;*      Epilog not entirely removed
;*      Collapsed epilog stages       : 2
;*
;*      Prolog not removed
;*      Collapsed prolog stages       : 0
;*
;*      Minimum required memory pad   : 4 bytes
;*      Minimum threshold value       : -mh8
;*
;*      Minimum safe trip count       : 3
;*----------------------------------------------------------------------------*

 

То есть видите, оно делало 5 итераций параллельно. А у Вас такого пока не видно... А ключик -mf включен?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

попробуйте еще отключить всю отладочную информацию, это развяжет руки оптимизатору. Если она включена хоть в каком-то ее проявлении, то об нормальной оптимизации не может быть и речи.

 

Еще есть полезный ключик "-mhXXX" (в среде - Speculative threshold, или похоже) - разрешение коду читать данные за пределами массива, но при этом ничего с ними не делать. Это тоже нередко дает выигрышь в скорости работы.

 

а насчет сталлов - да, в этом процессоре такого понятия нету (в смысле защиты конвейера). Всем рулит программист. Хочешь тут сталл на 5 тактов - пиши NOP 5. Хочешь конфликт - будет конфликт - два юнита можно заставить записать в один регистр в одно время, и что из этого получится, никто не знает :), но что глюк, это явно.

 

 

----------------------------------------

вот Ваша ф-ция из первого поста (только стер работу с FADCR и собрал для C67+, а не 674х, ну и hint: не пытайтесь понять, почему это будет работать, без 0.5 литры, мозги можно повредить :) )

 

так что ищите что там в build options вашему оптимизатору мешает, конвейеризируется на ура, аж в каждом такте по одному LDW и одному STW

 

;******************************************************************************
;* FUNCTION NAME: DSPF_fltoq31                                                *
;*                                                                            *
;*   Regs Modified     : A1,A3,A4,A5,A6,A7,B0,B4,B5,B6                        *
;*   Regs Used         : A1,A3,A4,A5,A6,A7,B0,B3,B4,B5,B6                     *
;*   Local Frame Size  : 0 Args + 0 Auto + 0 Save = 0 byte                    *
;******************************************************************************
_DSPF_fltoq31:
;** --------------------------------------------------------------------------*
;*----------------------------------------------------------------------------*
;*   SOFTWARE PIPELINE INFORMATION
;*
;*      Loop source line                 : 13
;*      Loop opening brace source line   : 13
;*      Loop closing brace source line   : 22
;*      Known Minimum Trip Count         : 1                    
;*      Known Max Trip Count Factor      : 1
;*      Loop Carried Dependency Bound(^) : 0
;*      Unpartitioned Resource Bound     : 2
;*      Partitioned Resource Bound(*)    : 2
;*      Resource Partition:
;*                                A-side   B-side
;*      .L units                     2*       0     
;*      .S units                     1        2*    
;*      .D units                     2*       2*    
;*      .M units                     2*       0     
;*      .X cross paths               0        2*    
;*      .T address paths             2*       2*    
;*      Long read paths              0        2*    
;*      Long write paths             0        0     
;*      Logical  ops (.LS)           0        0     (.L or .S unit)
;*      Addition ops (.LSD)          0        1     (.L or .S or .D unit)
;*      Bound(.L .S .LS)             2*       1     
;*      Bound(.L .S .D .LS .LSD)     2*       2*    
;*
;*      Searching for software pipeline schedule at ...
;*         ii = 2  Schedule found with 9 iterations in parallel
;*      Done
;*
;*      Collapsed epilog stages       : 8
;*      Prolog not entirely removed
;*      Collapsed prolog stages       : 6
;*
;*      Minimum required memory pad   : 64 bytes
;*
;*      Minimum safe trip count       : 1
;*----------------------------------------------------------------------------*
$C$L1:    ; PIPED LOOP PROLOG

          ZERO    .L1     A3
||         ADDAW   .D1     A4,A6,A7
||         B       .S1     $C$L2             ; |13| (P) <0,11> 

          MVKH    .S1     0x4b000000,A3
||         LDW     .D1T1   *--A7(8),A4       ; |13| (P) <0,0> 

          SHR     .S2X    A6,1,B5           ; |13| 
||         LDW     .D1T1   *+A7(4),A5        ; |20| (P) <0,1> 
||         B       .S1     $C$L2             ; |13| (P) <1,11> 

.dwpsn	file "test.c",line 13,column 0,is_stmt

          SUB     .L2     B4,8,B6           ; |5| 
||         MVK     .S1     0x6,A1            ; init prolog collapse predicate
||         ADD     .S2     3,B5,B0
||         MV      .L1     A3,A6
||         LDW     .D1T1   *--A7(8),A4       ; |13| (P) <1,0> 

;** --------------------------------------------------------------------------*
$C$L2:    ; PIPED LOOP KERNEL
$C$DW$L$_DSPF_fltoq31$3$B:

          MV      .L2     B5,B4             ; |21| <0,15> Split a long life
|| [!A1]   STW     .D2T2   B4,*++B6(8)       ; |20| <0,15> 
||         SSHL    .S2X    A5,8,B5           ; |21| <1,13> 
|| [ B0]   B       .S1     $C$L2             ; |13| <2,11> 
||         SPINT   .L1     A3,A5             ; |13| <3,9> 
||         MPYSP   .M1     A6,A4,A3          ; |13| <5,5> 
||         LDW     .D1T1   *+A7(4),A5        ; |20| <7,1> 

.dwpsn	file "test.c",line 22,column 0,is_stmt

  [ A1]   SUB     .S1     A1,1,A1           ; <0,16> 
|| [!A1]   STW     .D2T2   B4,*+B6(4)        ; |21| <0,16> 
||         SSHL    .S2X    A3,8,B4           ; |20| <1,14> 
|| [ B0]   SUB     .L2     B0,1,B0           ; |13| <3,10> 
||         SPINT   .L1     A4,A3             ; |20| <3,10> 
||         MPYSP   .M1     A6,A5,A4          ; |20| <5,6> 
||         LDW     .D1T1   *--A7(8),A4       ; |13| <8,0> 

$C$DW$L$_DSPF_fltoq31$3$E:
;** --------------------------------------------------------------------------*
$C$L3:    ; PIPED LOOP EPILOG
;** --------------------------------------------------------------------------*
$C$DW$12	.dwtag  DW_TAG_TI_branch
.dwattr $C$DW$12, DW_AT_low_pc(0x00)
.dwattr $C$DW$12, DW_AT_TI_return
          RET     .S2     B3                ; |23| 
.dwpsn	file "test.c",line 23,column 1,is_stmt
          NOP             5
          ; BRANCH OCCURS {B3}              ; |23| 

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вот Ваша ф-ция из первого поста (только стер работу с FADCR и собрал для C67+, а не 674х, ну и hint: не пытайтесь понять, почему это будет работать, без 0.5 литры,

Во! Скомпилил как у вас для C67+ и сразу получил 4 такта внутри kernel loop (у вас 2 такта как я понимаю) - очень похоже на Ваш результат.

Вернул обратно на C674x - всё вернулось к старому моему результату - похоже не даёт оптимизить тип процессора :crying:

Все отладки у меня выключены.

Вот что получается:

;*----------------------------------------------------------------------------*
;*   SOFTWARE PIPELINE INFORMATION                                             
;*                                                                             
;*      Loop found in file               : DSPF_fltoq31.c                      
;*      Loop source line                 : 112                                 
;*      Loop opening brace source line   : 112                                 
;*      Loop closing brace source line   : 129                                 
;*      Known Minimum Trip Count         : 1                                   
;*      Known Max Trip Count Factor      : 1                                   
;*      Loop Carried Dependency Bound(^) : 0                                   
;*      Unpartitioned Resource Bound     : 2                                   
;*      Partitioned Resource Bound(*)    : 4                                   
;*      Resource Partition:                                                    
;*                                A-side   B-side                              
;*      .L units                     2        2                                
;*      .S units                     2        2                                
;*      .D units                     2        2                                
;*      .M units                     2        2                                
;*      .X cross paths               0        2                                
;*      .T address paths             4*       4*                               
;*      Long read paths              0        0                                
;*      Long write paths             0        0                                
;*      Logical  ops (.LS)           0        0     (.L or .S unit)            
;*      Addition ops (.LSD)          0        0     (.L or .S or .D unit)      
;*      Bound(.L .S .LS)             2        2                                
;*      Bound(.L .S .D .LS .LSD)     2        2                                
;*                                                                             
;*      Searching for software pipeline schedule at ...                        
;*         ii = 4  Schedule found with 5 iterations in parallel                
;*      Done                                                                   
;*                                                                             
;*      Loop will be splooped                                                  
;*      Collapsed epilog stages       : 0                                      
;*      Collapsed prolog stages       : 0                                      
;*      Minimum required memory pad   : 0 bytes                                
;*                                                                             
;*      Minimum safe trip count       : 1                                      
;*----------------------------------------------------------------------------*

 

То есть видите, оно делало 5 итераций параллельно. А у Вас такого пока не видно... А ключик -mf включен?

Ключик этот у меня включён и Partitioned Resource Bound почти ка у вас == 4, а толку нет :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут железная фича задействована. Я не работал с 64+, поэтому сразу не знал.

 

SPLOOP-нутый цикл лежит в памяти в развернутом виде, а конвейеризируется и спараллеивается аппаратно средствами этого буфера. Примеры в spru732 это хорошо показывают, Example 7-4, 7-5 например. То есть код при этом выглядит понятным :) и является прерываемым, но работает с той же скоростью

 

у меня на компилере версии 7.3.2 удалось получить в этом цикле 8 iterations in parallel, то есть тоже 2 такта внутри ядра (c разрешенной спекуляцией на загрузках).

 

короче это полезная фича плюснутых C64

Изменено пользователем SAURIS GmbH

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...