Sunteți pe pagina 1din 22

Limbajul C pentru programarea DSP

 C este un limbaj de programare structurat


gândit să realizeze o translaţie compactă şi
eficientă a unui program în limbaj maşină
 Limbaj de nivel înalt dar apropiat de nivelul de
CAPITOLUL 4 asamblare
 Există o gama largă de medii de dezvoltare C
Tehnici de optimizare
p C  Flexibil
Flexibil, portabil => programele pot fi
pentru StarCore SC140 reutilizate

1 2

Arhitecturi
tectu DSP
S “prietenoase”
p ete oase pentru
pe t u Exemplu - StarCore SC140
compilatorul C  Arhitectura Variable Length Execution Set (VLES)
 număr mare de registre  un set de execuţie poate efectua până la:
 patru instrucţiuni DALU
 set de registre
g ortogonale
g
 două
ă instrucţiuni AGU
 moduri de adresare flexibile
 arhitectură scalabilă cu set bogat de instrucţiuni
 puţine restricţii de execuţie a instrucţiunilor  set de registre ortogonal (independente)
 suport pentru for diversele tipuri de date  16 registre de date DALU (d0 – d15)
 16 + 4 + 4 registre AGU (r0-r15, n0-n3, m0-m3)
 etape puţine pipeline => nu apar conflicte
 suport hardware pentru întregi şi fracţionare

3 4
Exemplu - StarCore SC140 Este C potrivit pentru DSPuri?
[
move.4f (r0)+,d0:d1:d2:d3
( ) ,
 Limbajul C nu poate produce un cod în
move.4f (r1)+,d4:d5:d6:d7 asamblare optim, care să utilizeze la maximum
]
LOOPSTART3 resursele procesorului.
[
mac d0,d4,d8  De exemplu în limbajul C nu sunt prezente:
mac d1,d5,d9
mac d2
d2,d6,d10
d6 d10
 lucrul în virgulă
g fixă;;
mac d3,d7,d11  nu este prezent suportul pentru arhitecturi duale de
move.4f (r0)+,d0:d1:d2:d3
move.4f (r1)+,d4:d5:d6:d7
( ) , memorie;
]
 nu sunt prezente porturi speciale de intrare/ieşire, şi
LOOPEND3
[ nici instrucţiuni specializate;
mac d0,d4,d8
 nu este prezent suportul pentru instrucţiuni de tipul
mac d1,d5,d9
mac d2,d6,d10 SIMD (Single Instruction Multiple Data).
mac d3
d3,d7,d11
d7 d11
]
5 6

Eficienţa C pentru paralelism Poate fi făcut C eficient pentru DSP?


 practic, NU EXISTĂ DA,
 C = un limbaj de programare secvenţial  în condiţiile în care programatorul, cel care
 nu p
pot fi exprimate
p acţiuni
ţ în p
paralel p ţ pentru
dezvoltă aplicaţii p procesoarele
p de
 nu există echivalent pentru instrucţiuni SIMD semnal, înţelege şi stăpâneşte următoarele
 Compilatorul trebuie să analizeze planificarea p
aspecte:
operaţiilor independente  extensiile compilatorului
 analiza depinde de stilul de programare  tehnicile de programare
p g
 comportamentul compilatorului.
c = a * b; sunt independente
independente, pot fi efectuate în paralel
d = b + c;
e = a * a; depinde de rezultatul operaţiei anterioare

7 8
Realizarea unui proiect pentru DSP SC140
 Trecerea de la virgulă mobilă (float) la
reprezentarea în virgulă fixă
 scalarea datelor şi a funcţiilor pentru reprezentarea pe
domeniu de valori subunitare
 Adaptarea codului C la formatul specific DSP
SC140
Trecerea de la virgulă mobilă
 definirea tipurilor specifice DSP
 introducerea operaţiilor de virgulă fixă reprezentate (float) la reprezentarea în
prin funcţii intrinseci g
virgulă fixă
 Optimizarea codului C pentru reducerea
timpului de execuţie şi a dimensiunii codului
9 10

Trecerea virgulă mobilă - virgulă fixă Trecerea virgulă mobilă - virgulă fixă
 Se consideră codul de referinţă în C cu formatul  Scalarea este operaţia prin care variabilele (de
datelor de tip float, double etc. intrare, rezultatele etc.) pentru toate funcţiile
din program sunt aduse la valori subunitare
Definire variabile:
(păstrând formatul float).
float x[]={6.4, -5.5, 14.3, 0.5}, e, a=2.0;

Definire funcţii
var1 var2 var3
float energie(float a,float* x) {float s; F1 F2
f
for (i
(int
t i
i=0;
0 i<N
i<N; i++) M1 M2 M3
s+=pow(x[i],a);
return s;}

Apel funcţii
e=energie(a, x);  M1,M2,M3 > 1

11 12
Trecerea virgulă mobilă - virgulă fixă Trecerea virgulă mobilă - virgulă fixă
 Scalarea este operaţia prin care variabilele (de  Scalarea variabilelor de intrare
intrare, rezultatele etc.) pentru toate funcţiile  Apare o modificare a rezultatului final prin propagarea
din program sunt aduse la valori subunitare scalarii iniţiale în rezultatul fiecărei funcţii
(păstrând formatul float).  Propagarea poate să nu fie liniară dacă funcţiile
efectuează operaţii neliniare (pow, exp etc.)

var1_s var2_s var3_s var1 var1_s var2 var3


F1_s F2_s _1_ F1 F2
1 1 1 M1 M1 1 M2 M3
M1 M1

13 14

Trecerea virgulă mobilă - virgulă fixă Trecerea virgulă mobilă - virgulă fixă
 Compensarea scalării la ieşirea fiecărei funcţii  Scalarea funcţiei pentru ieşire subunitară
 Se evaluează variaţia ieşirii funcţiei dacă se face  Se scalează operaţiile efectuate în funcţie astfel ca
scalare la intrare rezultatul să fie subunitar
 Se înmulţeşte ieşirea funcţiei cu inversul acestuia  Factorul de scalare S intern al funcţiei este
 Astfel rezultatul final nu este influenţat  verificare compensat la ieşire pentru a păstra rezultatul final

1 1/S
var1 var1_s var2 var1 var1_s F1_s var2_s var2
_1_ F1 _1_  1 
M1  1  M1 F1 
M1 1 F1  M2 M1 1 S 1
 M1  M2
 M1 

15 16
Trecerea virgulă mobilă - virgulă fixă Trecerea virgulă mobilă - virgulă fixă
 Exemplu: programul de calcul al energiei  Exemplu: programul de calcul al energiei
 Prin împărţirea cu 16 a intrării la ieşire se va regăsi
float x[]={6.4, -5.5, 14.3, 0.5}; un factor de atenuare de 1/162.
 M1=14.3.  Se înmulţeşte rezultatul cu 162, astfel rezultatul final
 Se poate alege o scalare cu 16 echivalentă cu rămâne nemodificat.
shiftarea la dreapta cu 4 biţi.

energie energie
x[] e x[] x_s[] e
N 1 _1_ N 1
M1 e   x i 
2
M2 16 16 1 e   x i 2 162
M2
i 0 i 0

17 18

Trecerea virgulă mobilă - virgulă fixă Trecerea virgulă mobilă - virgulă fixă
 Exemplu: programul de calcul al energiei  Exemplu: programul de calcul al energiei
 Se scalează operaţiile efectuate în funcţie astfel ca  Dacă rezultatul funcţiei energie este folosit într-o
rezultatul să fie subunitar. funcţie următoare atunci se reia operaţia de scalare a
 Suma de N termeni pozitivi subunitari poate avea o i t ă ii ffuncţiei
intrării ţi i F2
F2, compensarea lla iieşire,
i scalarea
l
valoare maximă egală cu N  factorul de scalare funcţiei F2 etc.
intern al funcţiei este 1/N.
1/N  Compensarea ieşirii primei funcţii şi scalarea intrării
funcţiei următoare se anulează reciproc.
energie s
energie_s
x[] x_s[] e_s[] e e_s[] e e_s[] var3
_1_ 1 N 1
energie_s _1__ F2
N.162 N.162
16 16 1 e_s 
N
 x i 
i 0
i
2
1 M2 1 M2 N.162 1 M3

19 20
Adaptarea codului la formatul SC140
 Formate de date pentru DSP
 identice cu tipurile de bază C
 întregi
 de aceeaşi lungime dar cu semnificaţie diferită
 fracţionare pe 16 şi 32 biţi
 specifice DSP (de ex. incluzând partea de extensie)
Adaptarea codului C la  fracţionare pe 40 biţi

formatele specifice SC140

21 22

Adaptarea codului la formatul SC140 Adaptarea codului la formatul SC140


 Limbajul C nu are o reprezentare pentru  Orice variabilă cu valori subunitare fracţionare
tipurile şi operaţiile cu numere fracţionare trebuie să fie definită utilizându-se echivalentul
p
 Sunt definite tipuri de date echivalente ca acestora în întreg.
reprezentare cu numere întregi:  Relaţiile pentru a obţine aceste reprezentări în
 Word16 p
pentru fracţii
ţ pep 16 biţi
ţ g din cele de tip
întreg p fracţionar
ţ sunt:
 Word32 pentru fracţii pe 32 biţi  16 biţi: valoare întreagă = valoare fracţionară * 215.
 Word40 p
pentru fracţii
ţ pep 40 biţi
ţ ((32 biţi
ţ pplus 8 biţi
ţ ţ valoare întreagă
 32 biţi: g = valoare fracţionară
ţ * 231.
gardă)  40 biţi: valoare întreagă = valoare fracţionară * 239.
 Word64 pentru fracţii pe 64 biţi (nu sunt direct
reprezentabile pe SC140)

23 24
Adaptarea codului la formatul SC140 Adaptarea codului la formatul SC140
 Exemplu: interpretarea datelor pe 16 biţi  Funcţiile intrinseci
Reprezentare Reprezentare Reprezentare  Sunt funcţii speciale prin care compilatorul realizează
Reprezentare în binar
hexazecimală ca întregi ca fracţionar o mapare în C a instrucţiunilor din asamblare
specifice
ifi operaţiilor
ţiil pe precizie
i i fi
finită.
ită
0100 0000 0000 0000 0x4000 16384 0.5
 Această categorie de funcţii presupune definirea unor
0001 0000 0000 0000 0x1000 4096 0 125
0.125 mulţimi de noi tipuri de date
 precizie simplă, dublă şi extinsă pentru numere
0000 0000 0000 0000 0x0000 0 0.0
fracţionale.
ţ

1100 0000 0000 0000 0xC000 -16384 -0.5  Utilizarea acestor funcţii intrinseci asigură emularea
programelor şi pe alte platforme.
1111 0000 0000 0000 0xF000 -4096 -0.125

valoare fracţionară = valoare întreagă / (215)


25 26

Adaptarea codului la formatul SC140 Adaptarea codului la formatul SC140


 Funcţiile intrinseci  Funcţiile intrinseci
 Permit folosirea datelor de tip întreg pentru a  în C operatorii * sau + sunt mapaţi de compilator în
implementa operaţii de tip fracţionar instrucţiuni de asamblare asociate numerelor întregi
 Sunt funcţii speciale prin care compilatorul realizează  funcţiile intrinseci stabilesc formatul fracţionar pentru
o mapare în C a instrucţiunilor din asamblare operanzi şi instrucţiunile în asamblare folosite
specifice operaţiilor pe precizie finită
finită.

W d16
Word16 add(Word16,
dd(W d16 W Word16);
d16)
Word32 L_add(Word32, Word32);
Word40 X_add(Word40, Word40);
Word64 D_add(Word64, Word64);

27 28
Adaptarea codului la formatul SC140 Adaptarea codului la formatul SC140
 Exemplu: calculul energiei  Înlocuirea tipurilor datelor şi a funcţiilor
float x[]={6.4, -5.5, 14.3, 0.5}; intrinseci
double e=0;  0.4 x 215 = 13107.2 (int) = 13107 = 0x3333
for (int i=0; i<N; i++)  Se poate folosi macroul WORD16() care transformă
e+=x[i]*x[i]; valoarea fracţionară în reprezentarea hexa pe 16 biţi

 după scalare //float x_s[]={0.4, -0.34375, 0.89375, 0.03125}


Word16 x_s[]={13107, WORD16(-0.34375),
fl t x_s[]={0.4,
float [] {0 4 -0.34375,
0 34375 0.89375,
0 89375 00.03125};
03125} WORD16(0 89375) WORD16(0.03125)};
WORD16(0.89375), WORD16(0 03125)};
// x_s[]={6.4/16, -5.5/16, 14.3/16, 0.5/16} Word32 e_s=0;
double e_s=0;
for (int i=0; i<N; i++)
for (int i=0; i<N; i++) e_s=L_mac(e_s,x_s[i],x_s[i]); //e_s+=x_s[i]*x_s[i]
e_s+=x_s[i]*x_s[i];
e s=(1/N)*e
e_s=(1/N) e_s;
s; e s=L
e_s L_shr(e_s,2);
shr(e s,2); //e s=(1/N)*e
//e_s (1/N) e_s
s
29 30

Adaptarea codului la formatul SC140


 Deoarece funcţiile intrinseci efectuează operaţiile cu
saturaţie
t ţi este
t maii bi
bine ca îîmpărţirea
ă ţi cu N să
ă fi
fie făcută
fă tă
înainte de sumare. N 1
1
e _ s   x 2 i 
i 0 N

 N=4. Se poate împărţi variabila x_s cu 2 (prin ridicare


la pătrat înseamnă împărţirea cu 4)

Word16 xx, x_s[]={13107, WORD16(-0.34375),


Tehnici de optimizare C
WORD16(0 89375) WORD16(0.03125)};
WORD16(0.89375),
Word32 e_s=0;
WORD16(0 03125)};
pentru SC140
for (int i=0; i<N; i++) {
xx=shr(x_s[i],1);
e_s=L_mac(e_s,xx,xx);
}
31 32
Tehnici de optimizare C pentru SC140 Tehnici de optimizare C pentru SC140
 Optimizarea aplicaţiilor DSP înseamnă un  Optimizarea înseamnă [
move.4f ((r0)+,d0:d1:d2:d3
) ,
utilizarea
tili lla maximum
i a
compromis între: move.4f (r1)+,d4:d5:d6:d7
resurselor procesorului. ]
 încadrarea timpului de execuţie a programului într-un LOOPSTART3
 Se pot face în paralel
interval bine stabilit şi [
 patru instrucţiuni DALU mac d0,d4,d8
 cerinţa ca memoria de program ocupată de aplicaţie mac d1,d5,d9
 două transferuri AGU

ă se încadreze
î d îîn li
limitele
i l iimpuse d
de procesorull d
de mac d2
d2,d6,d10
d6 d10

semnal.  Se utilizează un set de mac d3,d7,d11


move.4f (r0)+,d0:d1:d2:d3
registre
g ortogonal
g move.4f ( (r1)+,d4:d5:d6:d7
) ,

 16 registre de date ]
LOOPEND3
DALU (d0 – d15) [
 16 + 4 + 4 registre AGU mac d0,d4,d8
mac d1,d5,d9
r0-r15, n0-n3, m0-m3
mac d2,d6,d10
mac d3
d3,d7,d11
d7 d11
]
33 34

Tehnici de optimizare C pentru SC140 Dezvoltarea de aplicaţii pe DSP


 Limbajul C nu poate produce un cod în  Compromis între:
asamblare optim, care să utilizeze la maximum  încadrarea timpului de execuţie a programului într-un
resursele procesorului. interval bine stabilit şi
 cerinţa ca memoria de program ocupată de aplicaţie
 C = un limbaj de programare secvenţial
să se încadreze în limitele impuse de procesorul de
 nu p
pot fi exprimate
p acţiuni
ţ în p
paralel
semnal.
semnal
 nu există echivalent pentru instrucţiuni SIMD
 Necesitatea de găsire de metode de optimizare
 Compilatorul trebuie să analizeze planificarea a programelor
l subb ambele
b l aspecte,
t atât
tât di
din
operaţiilor independente punct de vedere al timpilor de execuţie dar şi a
 optimizarea depinde de stilul de programare
memoriei
i id
de program ocupatet dde aplicaţie.
li ţi

35 36
Ce înseamnă optimizarea? Pragme
 reducerea timpului de execuţie  Prin p
pragme
g se înţelege
ţ g un mod standard de
 reducerea dimensiunii codului comunicare cu un compilator.
 reducerea dimensiunii datelor  Acestea descriu nu numai caracteristicile
 reducerea memoriei alocate stivei codului scris în limbaj C dar şi a datelor
 reducerea
d consumului
l idde memorie
i utilizate.
utilizate
 Utilizarea pragmelor nu afectează cu nimic
valoarea rezultatelor,
rezultatelor dar influenţează într-o
într o
măsură deosebit de importantă performanţele
#pragma align signal 8
#pragma loop_unroll 4
#pragma inline
#pragma loop_count (20, 40, 4)
37 38

Pragme pentru alinierea datelor Pragme pentru alinierea datelor

 #pragma align ptr 8  #pragma


p g align
g *ptr
p 8
 pentru alinierea în memorie la declararea vectorilor  pentru parametri transmişi funcţiilor prin adresă
Word16 x[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; p
 compilatorul consideră că vectorii au fost aliniaţi
ţ în
#pragma align x 8 programul care apelează funcţia
#define LENGTH 10 Word32 Prod(Word16 a[], Word16 b[])
x[11] x[10] x[9] x[8] 16
{
x[7] x[6] x[5] x[4] 8 Word16 x[LENGTH], y[LENGTH]; #pragma align *a 8
#pragma align x 8 #pragma align *b 8
x[3] x[2] x[1] x[0] 0 #pragma align y 8 Word16 j;
Word32 res_rout = 0;
 Permit folosirea transferurilor cu mai multe int main(void)
cuvinte {
Word32 result;
for(j=0; j<LENGTH; j++)
{
… res_rout += a[j] * b[j];
move.4f (r0)+,d0:d1:d2:d3 result = Prod(&x[0],&y[0]); }

return 0; return res_rout;
39 } } 40
Asamblarea Inline Asamblarea Inline
 Presupune tehnica prin care în interiorul  Utilizarea directivelor de asamblare presupune
codului scris în limbaj C se pot introduce faptul că avem un acces special la unele
directive de asamblare, instrucţiuni de caracteristici ale procesorului, imposibil de
asamblare. utilizat în cazul folosirii funcţiilor intrinseci.
 Acest lucru se p
poate realiza:  convenţii
ţ de apelare
p speciale
p
 sub forma unei singure instrucţiuni  integrarea rapidă a funcţiilor în asamblare cu
 asm(“ di”); programele C
 sub forma unei întregi funcţii.
 Acces dificil la simboluri locale în funcţii
 datele globale pot fi accesate prin numele lor

41 42

Asamblare Inline - Exemplu Optimizări făcute de compilator


asm Flag GetOverflow(void)  optimizările standard din C
{
asm_header  optimizări (low level) specifice arhitecturii
return in $d0;
.reg $d0,$d1;  mai multe niveluri de optimizarea disponibile
asm_body
clr d0 ; extra cycle needed to allow DOVF to  pentru un cod mai rapid
; be written even by the instructions
; i the
in h ddelay
l slot
l of
f JSRD  pentru un cod mai mic
 optimizări globale
bmtsts #$0004,EMR.L ; test the Overflow bit from EMR
move.w #1,d1
tfrt d1,d0
asm_end
; if Overflow return 1, else return 0
 toate fişierele sunt analizate ca un întreg
}

43 44
Obţinerea de aplicaţii optimizate pe DSP Tehnici de optimizare pentru SC140
 arhitectură DSP performantă  tehnici generale aplicabile DSP
 compilator cu grad mare de optimizare  loop merging
 loop unrolling
 stilul de scriere a codului sursă C
 loop splitting
 singurul factor dependent de programator
 tehnici specifice StarCore
 scrierea
i codului
d l i C ttrebuie
b i să
ă respecte
t unele
l
 split computation
tehnici de programare precizate în manualul
p
 multisample
compilatorului
il t l i pentru
t
 eliminarea dependenţelor datelor
 completarea operaţiilor făcute de compilator pentru
structurarea codului

45 46

Loop Merging Loop Merging - Exemplu


 combinarea a două bucle într-una singură /* scaling loop */
for ( i = 0; i < SIG
SIG_LEN;
LEN; i++)
 dacă cele două bucle sunt caracterizate de acelaşi {
număr de iteraţii. }
y[i] = shr(y[i], 2);

 se poate diminua timpul necesar executării celor /* energy computation */


e = 0;
două bucle. for ( i = 0; i < SIG_LEN; i++)
/* Compute in the same time the */
/* energy of the scaled signal */
{
 reduce întârzierile
î â pentru iniţializarea buclelor e = L_mac(e, y[i], y[i]);
e = 0;
for (i = 0; i < SIG_LEN; i ++) {
}
 creşte utilizarea registrelor DALU Word16 temp;
temp = shr(y[i]
shr(y[i], 2);
 reduce mărimea codului e = L_mac(e, temp, temp);
y[i] = temp;
}

47 48
Loop Unrolling int i;
;
Word16 signal[SIGNAL_SIZE];
Word16 scaled_signal[SIGNAL_SIZE];
Loop Unrolling
L U lli
 repetarea conţinutului unei bucle - Exemplu
 permite gruparea mai multor instrucţiuni
/* ... */
for(i=0; i<SIGNAL_SIZE; i++)
pentru ca acestea sa se execute în paralel, în {
scaled_signal[i]
g [ ] = shr(signal[i],
( g [ ], 2);
)
cadrul
d l unuii aceluiaşi
l i i ciclu
i l iinstrucţiune.
t ţi }

 creşte utilizarea DALU


/* ... */ int i;
Word16 signal[SIGNAL_SIZE];
 creşte dimensiunea codului #
#pragma align
li signal
i l 8
Word16 scaled_signal[SIGNAL_SIZE];
 depinde de #pragma align scaled_signal 8

 dependenţele datelor între iteraţii /* ... */


for(i=0; i<SIGNAL_SIZE; i+=4)
 alinierea elementelor vectorilor {
 presiunea
i pe registrele
i t l DALU pe it
iteraţie
ţi scaled_signal[i+0]
l d i l[i+0] = shr(signal[i+0],
h ( i l[i+0] 2)2);
scaled_signal[i+1] = shr(signal[i+1], 2);
 numărul de itaraţii scaled_signal[i+2] = shr(signal[i+2], 2);
 păstrează precizia operaţiilor }
scaled_signal[i+3]
g [ ] = shr(signal[i+3],
( g [ ], 2);
);

49 /* ... */ 50

Compiler
p g
generated code Loop Unrolling
; Without loop unrolling : 6 cycles
; With
t loop
oop uunrolling
o g : 2 cyc
cycles
es inside
s de
 permite specificarea explicită a folosirii de către
compilator a operaţilor în paralel
; inside the loop ; the loop.
loopstart3 ; The complier uses software pipelining
L5 [
[ move.4f (r0)+,d0:d1:d2:d3 p
 factroul de desfacere a buclei depinde de
add
dd #
#<2,d3
2 d3 ;[20,1]
[20 1]
move.ll #
#_scaled_signal,r1
l d i l 1
move.l
move.l
d3,r2;[20,1] ]
<_signal,r1 ;[20,1]
[
 alinierea datelor
]
move.l <
<_scaled_signal,r4
asrr
scaled signal,r4 asrr
#<2,d0
#<2
#<2,d1
d1
asrr
asrr
#<2,d3
#<2,d2
#<2 d2  numărul de transferuri cu memoria
adda r2,r1 ]
[ loopstart3  numărul de operaţii aritmetice
move.w (r1),d4 [
]
adda r2,r4 moves.4f d0:d1:d2:d3,(r1)+
,( ) ţ
 numărul de iteraţii
asrr #<2,d4 move.4f (r0)+,d0:d1:d2:d3
move.w d4,(r4) ]
[
 se face unroll până nu mai rezultă nici o
loopend3
asrr
asrr
#<2,d0
# 2 d2
#<2,d2
asrr
asrr
#<2,d1
#
#<2,d3
2 d3 îmbunătăţire
]
loopend3  în general se face unroll cu un factor 2 sau 4
moves.4f d0:d1:d2:d3,(r1)+

51 52
Loop Unrolling – Exemplu 1 Loop Unrolling – Exemplu 1
#include <prototype.h> _Prod #include <prototype.h> ... mpyr ...
#define VectorSize 40 doensh3 #39 #define VectorSize 40
Word16 Prod(Word16 a[], Word16 b[]) move.f (r0)+,d4 Word16 Prod(Word16 a[], Word16 b[]) LOOPSTART3
{ move.f (r1)+,d5 { [
Word16 c[VectorSize]; mpyr d4,d5,d3 #pragma align *a 8 move.4f (r0)+,d8:d9:d10:d11
i
int i
i; #
#pragma align
li *b 8 move.4f
4f (
(r1)+,d4:d5:d6:d7
1) d4 d5 d6 d7
Word32 sum=0L; LOOPSTART3 Word16 c[VectorSize]; ]
[ #pragma align c 8 [
for(i 0;i<VectorSize;i++)
for(i=0;i<VectorSize;i++) move.f (r0)+,d0 int i; mpyr d8,d4,d0
{ move.f (r1)+,d4 Word32 sum=0L; mpyr d9,d5,d1
c[i]=mult_r(a[i],b[i]); ] mpyr d10,d6,d2
} [ for(i=0;i<VectorSize;i+=4) mpyr d11,d7,d3
for(i=0;i<DataBlockSize;i++) mpyr d0,d4,d3 { moves.4f d0:d1:d2:d3,(r3)+
{ moves.f d3,(r3)+ c[i+0]=mult_r(a[i+0],b[i+0]); ]
sum=mult_r(c[i+0],c[i+0]); ] c[i+1]=mult_r(a[i+1],b[i+1]); LOOPEND3
} LOOPEND3 c[i+2]=mult_r(a[i+2],b[i+2]);
[i+2] lt ( [i+2] b[i+2])
return(round(sum)) c[i+3]=mult_r(a[i+3],b[i+3]); moves.4f d0:d1:d2:d3,(r3)
} moves.f d3,(r3) }

...
53 54
}

Loop Unrolling – Exemplu 2 Loop Unrolling – Exemplu 2


#include <prototype.h> _Prod #include <prototype.h> ... mpyr ...
#define VectorSize 40 doensh3 #39 #define VectorSize 40
Word16 Prod(Word16 a[], Word16 bb) move.f (r0)+,d4 Word16 Prod(Word16 a[], Word16 bb) move.4f (r0)+,d4:d5:d6:d7
{ { LOOPSTART3
Word16 c[VectorSize]; mpyr d4,d0,d3 #pragma align *a 8 [
i
int i
i; mpyr d4 d14 d0
d4,d14,d0
Word32 sum=0L; move.f (r0)+,d4 Word16 c[VectorSize]; mpyr d5,d14,d1
#pragma align c 8 mpyr d6,d14,d2
for(i 0;i<VectorSize;i++)
for(i=0;i<VectorSize;i++) LOOPSTART3 int i; mpyr d7,d14,d3
{ [ Word32 sum=0L; moves.4f d0:d1:d2:d3,(r4)+
c[i]=mult_r(a[i],bb); mpyr d4,d0,d3 move.4f (r0)+,d4:d5:d6:d7
} moves.f d3,(r2)+ for(i=0;i<VectorSize;i+=4) ]
for(i=0;i<DataBlockSize;i++) move.f (r0)+,d4 { LOOPEND3
{ ] c[i+0]=mult_r(a[i+0],bb); [
sum=mult_r(c[i+0],c[i+0]); LOOPEND3 c[i+1]=mult_r(a[i+1],bb); mpyr d4,d14,d0
} [ c[i+2]=mult_r(a[i+2],bb);
[i+2] lt ( [i+2] bb) mpyr d5 d14 d1
d5,d14,d1
return(round(sum)) mpyr d4,d0,d3 c[i+3]=mult_r(a[i+3],bb); mpyr d6,d14,d2
} moves.f d3,(r2)+ } mpyr d7,d14,d3
] moves.4f d0:d1:d2:d3,(r4)+
moves.f d3,(r2) ... ]
55 56
}
Loop Unrolling – Exemplu 3 Loop Unrolling – Exemplu 4
#include <prototype.h> ... #include <prototype.h> ...
#define VectorSize 40 doensh3 #8 #define VectorSize 40 move.4f (r0)+,d0:d1:d2:d3
Word16 Prod(Word16 a[], Word16 bb) move.4f (r0)+,d4:d5:d6:d7 Word16 Prod(Word16 a[], Word16 bb) [
{ [ { asrr #<2,d0
#pragma align *a 8 asr d5,d1 #pragma align *a 8 asrr #<2,d2
asr d4 d0
d4,d0 asrr # 2 d1
#<2,d1
Word16 c[VectorSize]; asr d6,d2 Word16 c[VectorSize]; asrr #<2,d3
#pragma align c 8 asr d7,d3 #pragma align c 8 ]
int i; move.4f (r0)+,d4:d5:d6:d7 int i; LOOPSTART3
Word32 sum=0L; ] Word32 sum=0L; [
LOOPSTART3 moves.4f d0:d1:d2:d3,(r3)+
for(i=0;i<VectorSize;i+=4) [ for(i=0;i<VectorSize;i+=4) move.4f (r0)+,d0:d1:d2:d3
{ asr d4,d0 { ]
c[i+0]=shr(a[i+0],1); asr d5,d1 c[i+0]=shr(a[i+0],2); [
c[i+1]=shr(a[i+1],1); asr d6,d2 c[i+1]=shr(a[i+1],2); asrr #<2,d0
c[i+2]=shr(a[i+2],1);
[i+2] h ( [i+2] 1) asr d7 d3
d7,d3 c[i+2]=shr(a[i+2],2);
[i+2] h ( [i+2] 2) asrr #<2 d1
#<2,d1
c[i+3]=shr(a[i+3],1); moves.4f d0:d1:d2:d3,(r3)+ c[i+3]=shr(a[i+3],2); asrr #<2,d2
} move.4f (r0)+,d4:d5:d6:d7 } asrr #<2,d3
] ]
... LOOPEND3 ... LOOPEND3
57 58
} ... } moves.4f d0:d1:d2:d3,(r3)

Split Computation Split Computation


 aplicaţii tipice în calculul:  De exemplu
p calculul energiei
g unui semnal:
 energiei N 1

 erorii pătratice medii e   x2 i 


0
 maximului
 Formula este echivalentă cu separarea în 4 sume
 creşte utilizarea DALU
N 1
 creşte dimensiunea codului e 
i  0,4,8...
x 2  i   x 2  i  1  x 2  i  2   x 2  i  3
 poate necesita alinierea datelor
 poate influenţa precizia

59 60
int i; Word32 e;
Split Computation Câte separări?
Word16 signal[SIGNAL_LEN];
 depinde de alinierea în memorie
/* ... */
e = 0;  numărul de iteraţii trebuie să fie multiplu de
for(i = 0; i < SIGNAL_LEN; i++) {
e = L_mac(e, signal[i], signal[i]); p
numărul de separări a sumei
} int i; Word32 e0, e1, e2, e3;
Word16 signal[SIGNAL_LEN];  sumele calculate separat trebuie recombinate
pentru a obţine rezultatul final
#pragma align signal 8

/* ... */
e0 = e1 = e2 = e3 = 0;
for(i = 0; i < SIGNAL
SIGNAL_LEN;
LEN; i+=4)
i+ 4) {
e0 = L_mac(e0, signal[i+0], signal[i+0]);
e1 = L_mac(e1, signal[i+1], signal[i+1]);
e2 = L_mac(e2, signal[i+2], signal[i+2]);
e3
3 = L_mac(e3,
L ( 3 signal[i+3],
i l[i 3] signal[i+3]);
i l[i 3])
}
e0 = L_add(e0, e1);
e1 = L_add(e2,
( , e3);
);
e0 = L_add(e0, e1);
/* the energy is now in e0 */ 61 62

Multisample Multisample Example - Step 1


 transformarea codului pentru bucle efectuate Word32 acc;
1 for (j = 0; j < N; j += 4) {
[], c[];
Word16 x[], []; 2
una în interiorul alteia int i,j,N,T; acc0
0 = 00;
assert((N % 4) == 0); for (i = 0; i < T; i++)
acc0 = L_mac(acc0, x[i], c[j+0+i]);
p
 Etape assert((T % 4) == 0);
res[j+0] = acc0;
acc1 = 0;
 loop unroling pentru bucla exterioară; for (j = 0; j < N; j++) {
for (i = 0; i < T; i++)
acc = 0;
p merging
 loop g gp pentru bucla din interior;; for (
(i = 0; i < T; i++)
) { acc1 = L_mac(acc1, x[i], c[j+1+i]);
acc=L_mac(acc,x[i],c[j+i]); res[j+1]
[j 1] = acc1;
1
 loop unroling pentru bucla din interior la care s-a } acc2 = 0;
for (i = 0; i < T; i++)
aplicat tehnica anterioară. res[j] = acc;
acc2 = L_mac(acc2,
acc ac(acc , x[i],
[ ], c[j
c[j+2+i]);
]);
}
 păstrează precizia rezultatelor
res[j+2] = acc2;
acc3 = 0;

 nu necesită alinierea datelor în memorie Outer loop unrolling for (i = 0; i < T; i++)
acc33 = L_mac(acc3,
L ( 3 x[i],
[i] c[j+3+i]);
[j+3+i])
res[j+3] = acc3;
 reduce numărul de operaţii de transfer al }
datelor
63 64
Multisample Example - Step 2 Multisample Example - Step 3
for (j = 0; j < N; j += 4) { for (j = 0; j < N; j += 4) {
3
acc0 = 0; 2 for (j = 0; j < N; j += 4) {
acc0 = 0;
Inner loop merging
for (i = 0; i < T; i++)
acc0 = 0; 3 acc1 = 0;
acc2 = 0;
acc0 = L_mac(acc0, x[i], c[j+0+i]); for (j = 0; j < N; j += 4) {
acc1 = 0; acc3 = 0;
res[j+0] = acc0; acc0 = 0;
acc2 = 0;
acc1 = 0;
acc3 = 0;
f
for (i = 00; i < TT; i++)
acc0 = L_mac(acc0, x[i],
acc1 = 0;
c[j+0+i]);
4
for (i = 0; i < T; i++) acc2 = 0;
for (i = 0; i < T; i++) for (i = 0; i < T; i++)
acc1 = L_mac(acc1, x[i], c[j+1+i]); acc3 = 0;
acc0 = L_mac(acc0, x[i], c[j+0+i]); acc1 = L_mac(acc1,
( , x[i],
[ ], c[j+1+i]);
[j ]) (i = 0; i < T; i++) {
res[j+1] = acc1; for
for (i = 0; i < T; i++) for (i = 0; i < T; i++)
acc2 = 0; acc0 = L_mac(acc0, x[i], c[j+0+i]);
acc1 = L_mac(acc1, x[i], c[j+1+i]); acc2 = L_mac(acc2, x[i], c[j+2+i]);
for (i = 0; i < T; i++) acc1 = L_mac(acc1, x[i], c[j+1+i]);
for (i = 0; i < T; i++) for (i = 0; i < T; i++)
acc2 = L_mac(acc2, x[i], c[j+2+i]); acc2 = L_mac(acc2, x[i], c[j+2+i]);
acc2 = L_mac(acc2,
L mac(acc2, x[i], c[j+2+i]); acc3 = LL_mac(acc3,
mac(acc3 x[i]
x[i], c[j+3+i]);
res[j+2]
[j 2] = acc2;
2 acc3 = L_mac(acc3, x[i], c[j+3+i]);
for (i = 0; i < T; i++) res[j+0] = acc0;
acc3 = 0; }
acc3 = L_mac(acc3, x[i], c[j+3+i]); res[j+1] = acc1;
for (i = 0; i < T; i++) res[j+0] = acc0;
res[j+0] = acc0; j
res[j+2] = acc2;
acc3 = L_mac(acc3,
ac(acc3, x[i],
[ ], c[j
c[j+3+i]);
3 ]); res[j+1] = acc1;
res[j+1] = acc1; res[j+3] = acc3;
res[j+3] = acc3; res[j+2] = acc2;
res[j+2] = acc2; }
} res[j+3] = acc3;
res[j+3] = acc3;
Rearrangement
}
}

65 66

Multisample Example - Step 4 Multisample Example - Step 5


for (j = 0; j < N; j += 4) { for (j = 0; j < N; j += 4) { Explicit scalarization
acc0 = 0; for (j
j = 0; j < N; j += 4) { 5 for (j = 0; j < N; j +=
+ 4) {
acc1 = 0; 4 acc0 = 0;acc1 = 0;acc2 = 0;acc3 = 0; 5 acc0 = 0;acc1 = 0;acc2 = 0;acc3 = 0; acc0=acc1=acc2=acc3=0; xx = x[i+0];
acc2 = 0; for (i = 0; i < T; i += 4) { for (i = 0; i < T; i += 4) { c0 = c[j+0]; c1 = c[j+1];
acc3 = 0; acc0 = L_mac(acc0, x[i+0], c[j+0+i]); acc0 = L_mac(acc0, c2 = c[j+2]; c3 =
x[i+0], c[j+0+i]); c[j+3];
f
for (i = 00; i < T
T; i++) { acc1 = L
L_mac(acc1,
mac(acc1 x[i+0]
x[i+0], c[j+1+i]); acc1
1 = L_mac(acc1,
( 1 x[i+0], [j 1 i])for
[i 0] c[j+1+i]);f (i = 0;
0 i < TT; i += 4) {
acc2 = L_mac(acc2, x[i+0], c[j+2+i]);
acc0 = L_mac(acc0, x[i], c[j+0+i]); acc2 = L_mac(acc2, x[i+0], c[j+2+i]); acc0 = L_mac(acc0, xx, c0); 6
acc3 = L_mac(acc3, x[i+0], c[j+3+i]);
acc1 = L_mac(acc1, x[i], c[j+1+i]); acc3 = L_mac(acc3, x[i+0], c[j+3+i]); acc1 = L_mac(acc1, xx, c1);
acc2 = L_mac(acc2,
( , x[i],
[ ], c[j+2+i]);
[j ]) acc2 = L_mac(acc2, xx, c2);
acc3
3 = L
L_mac(acc3,
( 3 xx, c3);
3)
acc0 = L_mac(acc0, x[i+1], c[j+1+i]);
acc3 = L_mac(acc3, x[i], c[j+3+i]); acc0 = L_mac(acc0, x[i+1], c[j+1+i]); xx = x[i+1]; c0 = c[j+4+i];
} acc1 = L_mac(acc1, x[i+1], c[j+2+i]); acc1 = L_mac(acc1, x[i+1], c[j+2+i]); acc0 = L_mac(acc0, xx, c1);
res[j+0] = acc0; acc2 = L_mac(acc2, x[i+1], c[j+3+i]); acc2 = L_mac(acc2, x[i+1], c[j+3+i]); acc1 = L_mac(acc1, xx, c2);
res[j+1] = acc1; acc3 = L
L_mac(acc3,
mac(acc3 x[i+1]
x[i+1], c[j+4+i]); acc3
3 = L_mac(acc3,
L ( 3 x[i+1],
[i 1] c[j+4+i]);
[j 4 i]) acc2 = L_mac(acc2, xx, c3);
res[j+2] = acc2; /* third loop body for x[i+2] */ /* third loop body for x[i+2] */ acc3 = L_mac(acc3, xx, c0);
res[j+3] = acc3; /* fourth loop body for x[i+3] */ /* fourth loop body for x[i+3] */ xx = x[i+2]; c1 = c[j+5+i];
} } } /* similar third and fourth loop */
res[j+0] = acc0; res[j+1] = acc1; res[j+0] = acc0; res[j+1] = acc1; }
res[j+0] = acc0; res[j+1] = acc1;
Inner loop unrolling }
res[j+2] = acc2; res[j+3] = acc3;
}
res[j+2] = acc2; res[j+3] = acc3;
}
res[j+2] = acc2; res[j+3] = acc3;

67 68
Multisample Example - Final Result Exemplu – Funcţia de autocorelaţie
for (j = 0; j < N; j += 4) { Word16 Autocorr (  Loop unroll
acc0=acc1=acc2=acc3=0; xx = x[i+0]; Word16 x[], Word16 m,
c0 = c[j+0]; c1 = c[j+1];
Word32 r[], Word16 wind[] )
c2 = c[j+2]; c3 = c[j+3];
for (i = 0; i < T; i += 4) { { for (i = 0; i < L_WINDOW; i += 4)
acc0 = L
L_mac(acc0,
mac(acc0 xx
xx, c0); Word16 i, j, norm; {
acc1 = L_mac(acc1, xx, c1);
acc2 = L_mac(acc2, xx, c2);
one cycle (4 macs + 2 moves) Word16 y[L_WINDOW]; y[i+0] = mult_r(x[i+0], wind[i+0]);
Word32 sum;
acc3 = L_mac(acc3, xx, c3); y[i+1] = mult_r(x[i+1], wind[i+1]);
Word16 overfl,
overfl overfl
overfl_shft;
shft;
xx = x[i+1]; c0 = c[j+4+i]; y[i+2] = mult_r(x[i+2], wind[i+2]);
acc0 = L_mac(acc0, xx, c1);
acc1 = L_mac(acc1, xx, c2); /* Windowing of signal */ y[i+3] = mult_r(x[i+3], wind[i+3]);
acc2 = L
L_mac(acc2,
mac(acc2 xx
xx, c3); one cycle (4 macs + 2 moves) }
acc3 = L_mac(acc3, xx, c0); for (i = 0; i < L_WINDOW; i++)
xx = x[i+2]; c1 = c[j+5+i];
{
/* similar third and fourth loop */
} y[i] = mult
mult_r(x[i],wind[i]);
r(x[i] wind[i]);
res[j+0] = acc0; res[j+1] = acc1; }
res[j+2] = acc2; res[j+3] = acc3;
}
69 70

Exemplu – Funcţia de autocorelaţie Exemplu – Funcţia de autocorelaţie


/* Compute r[0] */  Split computation /* r[1] to r[m] */  Multisample
overfl_shft = 0; for(i=1; i<=m; i++) for (i = 1; i <=8 ; i+=4)
do L_sum0=L_sum1=L_sum2=L_sum3 = 0L; { {
{ for (i = 0; i < L_WINDOW;
L WINDOW; i += 4) sum = 0; L sum0 = 0; L_sum1
L_sum0 L sum1 = 0;
overfl = 0; { L_sum2 = 0; L_sum3 = 0;
sum = 0L; for(j = 0; j<L_WINDOW-i; j++)
L_sum0=L_mac(L_sum0,y[i+0],y[i+0]);
for (i = 0; i < L_WINDOW;
L WINDOW; i++) {
{ L_sum1=L_mac(L_sum1,y[i+1],y[i+1]); sum = L_mac(sum,y[j],y[j+i]); y4= y[i]; y5= y[i+1];
sum = L_mac(sum, y[i], y[i]); L_sum2=L_mac(L_sum2,y[i+2],y[i+2]); } y6= y[i+2]; y7= y[i+3];
} L sum3=L mac(L sum3 y[i+3] y[i+3]);
L_sum3=L_mac(L_sum3,y[i+3],y[i+3]);
} r[i]=L_shl(sum,norm); for (j = 0; j < L_WINDOW-i; j+=4)
L_sum = L_add(L_add(L_sum0,L_sum1), } {
L_add(L_sum2, L_sum3)); #pragma loop_count(10,20)
y0= y[j]; y1= y[j+1];
y2= y[j+2]; y3= y[j+3];
71 72
Exemplu – Funcţia de autocorelaţie Search Techniques Adapted for SC140
L_sum0=L_mac(L_sum0,y0,y4); y6=y[j+i+6];
L sum1=L mac(L sum1 y0 y5);
L_sum1=L_mac(L_sum1,y0,y5); L sum0=L mac(L sum0 y3 y7);
L_sum0=L_mac(L_sum0,y3,y7);
L_sum2=L_mac(L_sum2,y0,y6); L_sum1=L_mac(L_sum1,y3,y4);  finding for maximum
L_sum3=L_mac(L_sum3,y0,y7); L_sum2=L_mac(L_sum2,y3,y5);
 finding the maximum and its position
y4=y[j+i+4]; L_sum3=L_mac(L_sum3,y3,y6);
L_sum0=L_mac(L_sum0,y1,y5); y7=y[j+i+7];  finding the maximum ratio
L sum1=L mac(L sum1 y1 y6);
L_sum1=L_mac(L_sum1,y1,y6); }
 finding
fi di th
the position
iti off th
the maximum
i ratio
ti
L_sum2=L_mac(L_sum2,y1,y7); r[i+0]=L_shr_nosat(L_sum0,norm);
L_sum3=L_mac(L_sum3,y1,y4); r[i+1]=L_shr_nosat(L_sum1,norm);
y5=y[j+i+5]; r[i+2]=L_shr_nosat(L_sum2,norm);
L_sum0=L_mac(L_sum0,y2,y6); r[i+3]=L_shr_nosat(L_sum3,norm);
L sum1=L mac(L sum1 y2 y7);
L_sum1=L_mac(L_sum1,y2,y7); }
L_sum2=L_mac(L_sum2,y2,y4);
L_sum3=L_mac(L_sum3,y2,y5);

73 74

Maximum search Maximum search - Comments


 reduction operation => split maximum  presented solution works for both 16-bit and
32-bit values
#include <prototype.h>

Word16 max_search(Word16
max search(Word16 vector[],
vector[] unsigned short int length ) {
 better solution for 16-bit ((asm only)
y)
#pragma align *vector 8  based on max2 instruction (SIMD style)
signed short int i = 0; Word16 max0, max1, max2, max3;
 fetches two 16-bit values as a 32-bit one
max0 = vector[i+0]; max1 = vector[i+1];
max2 = vector[i+2]; max3 = vector[i+3];  eight maxima per cycle

for(i=4; i<length; i+=4) {


max0 = max(max0, vector[i+0]); max1 = max(max1, vector[i+1]);
max2 = max(max2, vector[i+2]); max3 = max(max3, vector[i+3]);
}
max0 = max(max0, max1); max1 = max(max2, max3);
return max(max0, max1);
}

75 76
Maximum Search – ASM with max2 Maximum position
 based on comparisons
move.2l (r0)+n0,d4:d5 move.2l (r1)+n0,d6:d7
 around N cycles
move.2l (r0)+n0,d0:d1 move.2l (r1)+n0,d2:d3
FALIGN  in C, two maxima required
LOOPSTART3
[  based on maximum search
max2 d0,d4 max2 d1,d5
max2 d2,d6 max2 d3,d7  around N/2 cycles
y
move.2l (r0)+n0,d0:d1 move.2l (r1)+n0,d2:d3
]  based on max2-based maximum search
LOOPEND3
[  around N/4 cycles
max2 d0,d4 max2 d1,d5
max2 d2,d6 max2 d3,d7  care must be taken to preserve the original
semantics
]

77 78

Maximum ratio Max ratio position


 given Word16 a[ ] and Word16 b[ ] vectors of  based on max ratio search, plus
positive values, compute max{a[i]/b[i]}  movet, tfrt instructions
y expensive
 division is very p on StarCore  position is kept as pointer, not index

 ideas:  software pipelining plus loop unrolling three


 a/b < c/d  a
a*d
d < b*c
b c times
 keep a[ ] and b[ ] intermixed
 two 16-bit
16 bit values form a 32
32-bit
bit one
 use cross multiplication (mpyus, mpysu)
 final solution in N cycles

79 80
DSP Coding Recommendations DSP Coding Recommendations (2)
 use loops with a fixed number of iterations  replace tests with computations
 enables the detection of hardware loops  small tests are ok due to predicative execution
 p
provide extensive static information  use synonym
y y operations
p if more flexible in the
 pragmas, constants target architecture
 use only supported data types  use modulo addressing
 do not mix integer and fractional operations on  alignment in data structures should be
the same value provided using field arrangement
 use custom calling conventions

81 82

Software Development Notes Speed versus Size


 SDN database contains coding guidelines  typically cannot be both optimized
 try different solutions for the same problem  follow the 80%-20% rule
 analyze the generated assembly file  speed
p optimize
p 20% of the code
 save the best solution in the SDN database  size optimize 80% of the code
 SDN DB captures team experience  loop merging may optimize both
 leverage organizational development skills  a high register pressure may kill both
 multisample
lti l provides
id b bestt speed
d
 but also significant kernel size increase

83 84
Diet Speed Optimization C Optimization Limits
 compile for speed only time-consuming loops
 compile for
fo size
si e the rest
est
 effort concentrated on loops
 try speed and size optimizations combined  no packed moves outside loops
 loops and ifs delimit optimization blocks
 reduce the unroll factors in the multisample
transformation
 avoid register pressure that creates spill code

85 86

Conclusions
 complexity of future DSP applications require
development using C
 C can be transformed in efficient DSP C
 compiler extensions are a must
 the coding style is programmer
programmer’s
s key
 optimized C code is suitable for high
performance applications
 assembly remains for critical sections

87

S-ar putea să vă placă și