Как оптимизировать копирование блока и сдвиг вправо + насыщение до max = 5, для Cortex-M3 - PullRequest
2 голосов
/ 13 апреля 2019

По сути, мне нужно сделать этот фрагмент кода более эффективным, либо уменьшив размер всего кода, чтобы уменьшить объем памяти, либо повысить его эффективность в работе. Я использую Thumb 2, а также Cortex-M3.

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

THUMB
  AREA RESET, CODE, READONLY
  EXPORT  __Vectors
  EXPORT Reset_Handler
__Vectors 
  DCD 0x00180000     ; top of the stack 
  DCD Reset_Handler  ; reset vector - where the program starts

  AREA 2a_Code, CODE, READONLY
Reset_Handler
  ENTRY

num_words EQU (end_source-source)/4  ; number of words to copy

start   
  LDR r0,=source     ; point to the start of the area of memory to copy from
  LDR r1,=dest       ; point to the start of the area of memory to copy to
  MOV r2,#num_words  ; get the number of words to copy

  ; find out how many blocks of 8 words need to be copied - it is assumed
  ; that it is faster to load 8 data items at a time, rather than load
  ; individually
block
  MOVS r3,r2,LSR #3  ; find the number of blocks of 8 words
  BEQ individ        ; if no blocks to copy, just copy individual words

  ; copy and process blocks of 8 words 
block_loop
  LDMIA r0!,{r5-r12}  ; get 8 words to copy as a block
  MOV r4,r5           ; get first item
  BL data_processing  ; process first item 
  MOV r5,r4           ; keep first item
  MOV r4,r6           ; get second item
  BL data_processing  ; process second item 
  MOV r6,r4           ; keep second item
  MOV r4,r7           ; get third item
  BL data_processing  ; process third item
  MOV r7,r4           ; keep third item  
  MOV r4,r8           ; get fourth item
  BL data_processing  ; process fourth item 
  MOV r8,r4           ; keep fourth item
  MOV r4,r9           ; get fifth item
  BL data_processing  ; process fifth item
  MOV r9,r4           ; keep fifth item  
  MOV r4,r10          ; get sixth item
  BL data_processing  ; process sixth item 
  MOV r10,r4          ; keep sixth item
  MOV r4,r11          ; get seventh item
  BL data_processing  ; process seventh item
  MOV r11,r4          ; keep seventh item 
  MOV r4,r12          ; get eighth item
  BL data_processing  ; process eighth item
  MOV r12,r4          ; keep eighth item  
  STMIA r1!,{r5-r12}  ; copy the 8 words 
  SUBS r3,r3,#1       ; move on to the next block
  BNE block_loop      ; continue until last block reached

  ; there may now be some data items available (fewer than 8)
  ; find out how many of these individual words need to be copied 
individ
  ANDS r3,r2,#7   ; find the number of words that remain to copy individually
  BEQ exit        ; skip individual copying if none remains

  ; copy the excess of words
individ_loop
  LDR r4,[r0],#4      ; get next word to copy
  BL data_processing  ; process the item read
  STR r4,[r1],#4      ; copy the word 
  SUBS r3,r3,#1       ; move on to the next word
  BNE individ_loop    ; continue until the last word reached

  ; languish in an endless loop once all is done
exit    
  B exit

  ; subroutine to scale a value by 0.5 and then saturate values to a maximum of 5 
data_processing
  CMP r4,#10           ; check whether saturation is needed
  BLT divide_by_two    ; if not, just divide by 2
  MOV r4,#5            ; saturate to 5
  BX lr
divide_by_two
  MOV r4,r4,LSR #1     ; perform scaling
  BX lr

  AREA 2a_ROData, DATA, READONLY
source  ; some data to copy
  DCD 1,2,3,4,5,6,7,8,9,10,11,0,4,6,12,15,13,8,5,4,3,2,1,6,23,11,9,10 
end_source

  AREA 2a_RWData, DATA, READWRITE
dest  ; copy to this area of memory
  SPACE end_source-source
end_dest
  END

В основном мне нужен код для хранения результатов в каждом регистре, при этом его размер либо уменьшается, либо выполняется быстрее. Спасибо за вашу помощь.

1 Ответ

3 голосов
/ 15 апреля 2019

Вот слегка оптимизированная версия вашего основного цикла. Учитывая, что вы программируете для Cortex M3, нет реальной возможности для суперскалярной или SIMD-обработки, поскольку ваш процессор не поддерживает ее. Основные различия между этим и вашим кодом:

  • все соответствующие функции встроены
  • логика была немного оптимизирована
  • бесполезные инструкции по перемещению опущены

Этот код выполняется в 10 циклах для каждой записи таблицы, а также содержит несколько инструкций для начальной ветви и возможных ошибок ветвления.

        .syntax unified
        .thumb

        @ r0: source
        @ r1: destination
        @ r2: number of words to copy
        @ the number in front of the comment is the number
        @ of cycles needed to execute the instruction
block:  cbz r2, .Lbxlr          @ 2 return if nothing to copy

.Loop:  ldmia r0!, {r3}         @ 2 load one item from source
        cmp r3, #10             @ 1 need to scale?
        ite lt                  @ 1 if r3 < 10:
        lsrlt r3, r3, #1        @ 1 then r3 >>= 1
        movge r3, #5            @ 1 else r3 = 5
        stmia r1!, {r3}         @ 2 store to destination
        subs r2, r2, #1         @ 1 decrement #words
        bne .Loop               @ 1 continue if not done yet

.Lbxlr: bx lr

Вы можете уменьшить это значение до 16 циклов для двух записей (8 циклов на запись), развернув цикл один раз. Обратите внимание, что это почти в три раза увеличивает длину кода только для небольшого увеличения производительности.

        .syntax unified
        .thumb

        @ r0: source
        @ r1: destination
        @ r2: number of words to copy
        @ the number in front of the comment is the number
        @ of cycles needed to execute the instruction

        @ first check if the number of elements is even or odd
        @ leave this out if it's know to be even
block:  tst r2, #1              @ 1 odd number of entries to copy?
        beq .Leven              @ 2 if not, proceed with eveness check

        ldmia r0!, {r3}         @ 2 load one item from source
        cmp r3, #10             @ 1 need to scale?
        ite lt                  @ 1 if r3 < 10:
        lsrlt r3, r3, #1        @ 1 then r3 >>= 1
        movge r3, #5            @ 1 else r3 = 5
        stmia r1!, {r3}         @ 2 store to destination
        subs r2, r2, #1         @ 1 decrement #words

        @ check if any elements are left
        @ remove if you know that at least two elements are present
.Leven: cbz r2, .Lbxlr          @ 2 return if no entries left.

.Loop:  ldmia r0!, {r3, r4}     @ 3 load two items from source

        cmp r3, #10             @ 1 need to scale?
        ite lt                  @ 1 if r3 < 10:
        lsrlt r3, r3, #1        @ 1 then r3 >>= 1
        movge r3, #5            @ 1 else r3 = 5

        cmp r4, #10             @ 1 need to scale?
        ite lt                  @ 1 if r5 < 10:
        lsrlt r4, r4, #1        @ 1 then r4 >>= 1
        movge r4, #5            @ 1 else r4 = 5

        stmia r1!, {r3, r4}     @ 3 store to destination
        subs r2, r2, #2         @ 1 decrement #words twice
        bne .Loop               @ 1 continue if not done yet

.Lbxlr: bx lr

7 циклов на элемент можно выполнить, развернув цикл четыре раза, но я считаю, что это чрезмерно.

Обратите внимание, что этот код используется в GNU как синтаксис. Это должно быть тривиально изменить его для вашего ассемблера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...