Bonjour
Suite à des discutions sur ce forum, j'ai voulu tester l'option O3 sur un programme qui fonctionnait bien sans. Comme cela ne fonctionnait plus très bien, j'ai fini par cerner le noeud du problème : il semble y avoir un problème quand on introduit une fonction écrite en assembleur. Voila ce que cela donne
Je travaille sous Windows avec Code::Blocks (dernière version) et MinGW_w64 comme compilateur (mais j'ai aussi testé avec Clang).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 #include <iostream> using namespace std; #define uint64_t unsigned long long #define uint32_t unsigned long //------------------------------------------ void print(uint64_t A[], uint32_t N) { cout <<"{"; for (int k = 0; k < N; ++k){ cout<<A[k] <<", "; } cout <<'\b'<<'\b'<<"}"<<endl ; } ; // new T = T + k*A // dim A = 2; dim T = 4; // T[j] + k*A[j] = u[j] + b*v[j] void mul_add(uint64_t k, uint64_t A[], uint64_t T[]) { uint64_t c ; __asm__ __volatile__( " mov %[A], %%rsi ;" " mov %[T], %%rdi ;" " mov $0, %[c] ;" // carry = 0 " mov $2, %%rcx ;" // loop counter (j = 2 - rcx) " 0: ;" " mov (%%rsi), %%rax ;" // rax = A[j] " mul %[k] ;" // k*A[j] = rax + rdx*b " add (%%rdi), %%rax ;" // rax = rax + T[j] = u[j] " adc $0, %%rdx ;" // rdx = rdx + CF = v[j] " add %[c], %%rax ;" // rax = u[j] + carry -> new T[j] " adc $0, %%rdx ;" // rdx = v[j] + CF -> new carry " mov %%rax, (%%rdi) ;" // new T[j] = rax " mov %%rdx, %[c] ;" // new carry = rdx " add $8, %%rsi ;" " add $8, %%rdi ;" " loop 0b ;" " add %[c], (%%rdi) ;" // new T[2] = T[2] + carry : : [A] "r" (A) , [T] "r" (T) , [k] "r" (k) , [c] "r" (c) // carry : "cc", "memory", "%rax", "%rcx", "%rdx" ); } //----------------------------------- int main(void) { uint64_t x = 2; uint64_t y = 3755218545365861964ULL; uint64_t n = 10203806521854051703ULL; uint64_t q = 17966832521566772153ULL; uint64_t X[2] = {x,0}, Y[2] = {y,0}, N[2] = {n,0}, T[4] = {0}; // cout<<endl<<"X = ";print(X,2); // cout<<endl<<"Y = ";print(Y,2); // cout<<endl<<"N = ";print(N,2); // cout<<endl<<"T = ";print(T,4); // cout<<endl<<"------------"<<endl; mul_add(x,Y,T); cout<<endl<<"T = "; print(T,4); return 0; }
Avec ces données, mul_add calcule 2*3755218545365861964 et place le résultat dans T
Sans O3 le résultat est correct (aussi bien avec Clang qu'avec MinGW_w64.) On obtient
Les problème surviennent avec O3T = {7510437090731723928, 0, 0, 0}
Process returned 0 (0x0) execution time : 0.042 s
Press any key to continue.
----------- Avec MinGW_w64 -----------------------
Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est correct. On obtient
Mais si on décommente une des lignes (ou plusieurs), on obtientT = {7510437090731723928, 0, 0, 0}
Process returned 0 (0x0) execution time : 0.013 s
Press any key to continue.
---------- Avec Clang -------------Process returned -1073741819 (0xC0000005) execution time : 0.838 s
Press any key to continue.
Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est faux. On obtient
De plus, si on décommente une ou plusieurs lignes, on obtient, suivant les casT = {15020874181463447856, 0, 0, 0}
Process returned 0 (0x0) execution time : 0.042 s
Press any key to continue.
ou bienProcess returned -1073741819 (0xC0000005) execution time : 0.509 s
Press any key to continue.
Cela est juste un exemple. J'ai obtenu d'autres situations tout aussi bizarresterminate called after throwing an instance of 'std::bad_cast'
what(): std::bad_cast
Process returned -1073740791 (0xC0000409) execution time : 0.489 s
Press any key to continue.
- une erreur (0xC0000005) si on place un 'exit()' quelque part mais qui disparaît si on place cet 'exit()' un peu plus loin.
- une variable de boucle réinitialisée, ce qui donne une boucle infinie
- la modification de la valeur d'un constante, etc.
Merci pour vos lumières.







Répondre avec citation
Partager