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
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;
}
Je travaille sous Windows avec Code::Blocks (dernière version) et MinGW_w64 comme compilateur (mais j'ai aussi testé avec Clang).
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
T = {7510437090731723928, 0, 0, 0}

Process returned 0 (0x0) execution time : 0.042 s
Press any key to continue.
Les problème surviennent avec O3

----------- Avec MinGW_w64 -----------------------
Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est correct. On obtient
T = {7510437090731723928, 0, 0, 0}

Process returned 0 (0x0) execution time : 0.013 s
Press any key to continue.
Mais si on décommente une des lignes (ou plusieurs), on obtient
Process returned -1073741819 (0xC0000005) execution time : 0.838 s
Press any key to continue.
---------- Avec Clang -------------

Avec O3 (et toutes les lignes commentées comme ci-dessus), le résultat est faux. On obtient
T = {15020874181463447856, 0, 0, 0}

Process returned 0 (0x0) execution time : 0.042 s
Press any key to continue.
De plus, si on décommente une ou plusieurs lignes, on obtient, suivant les cas
Process returned -1073741819 (0xC0000005) execution time : 0.509 s
Press any key to continue.
ou bien
terminate 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.
Cela est juste un exemple. J'ai obtenu d'autres situations tout aussi bizarres
  • 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.