Developpez.com

Le Club des Développeurs et IT Pro

Sortie de GCC 6.1 : cette version du système de compilation libre arrive avec C++14 activé par défaut

Et l'implémentation complète de OpenMP 4.5

Le 2016-04-28 12:32:41, par dourouc05, Responsable Qt & Livres
GCC vient de sortir sa version majeure annuelle, numérotée 6.1. Elle cumule les développements d’une année entière, avec des évolutions dans tous les domaines  : côté C++, le compilateur se positionnera sur la norme C++14 par défaut, au lieu de C++98 auparavant, quelques fonctionnalités de C++17 ont été implémentées ; pour le domaine HPC, OpenMP 4.5 est complètement implémenté, les calculs peuvent être déportés sur des coprocesseurs Intel Xeon Phi « Knights Landing » et sur du matériel AMD par HSAIL ; l’implémentation de OpenACC 2.0a a été améliorée, avec une possible déportation sur du matériel NVIDIA par PTX. Au niveau matériel, les prochains processeurs d’AMD, basés sur l’architecture Zen, sont déjà pris en charge ; les plateformes ARM ont été le théâtre de bon nombre d’améliorations ; l’architecture PowerPC a reçu la compatibilité avec POWER9, la prochaine itération des processeurs d’IBM.

Côté C++

La précédente version majeure de GCC, numérotée 5.1, apportait les dernières touches à l’implémentation de C++14, en apportant des fonctionnalités comme la désallocation d’une partie d’un tableau, des constexpr plus généraux, des fonctions anonymes génériques.

Cette nouvelle version de GCC s’arme déjà pour C++17, avec par exemple, la définition d’attributs sur les énumérateurs ou encore des expressions utilisant l’opérateur fold (aussi nommé reduce ou autre, selon les modes) :

Code :
1
2
3
4
5
// Cette fonction somme tous ses arguments. 
template<typename... Args>
  bool f(Args... args) { 
    return (true + ... + args);
  }


Plus de détails dans la documentation


Une nouvelle optimisation en C++ casse du code existant

Une nouvelle optimisation fait parler d’elle : la propagation de valeurs considère désormais que le pointeur this en C++ (qui pointe vers l’objet courant) est toujours initialisé (sa valeur n’est jamais nullptr). Ce point particulier n’a jamais été précisé dans une norme, les compilateurs sont donc libres quant à son interprétation — même si Qt 5 ou Chromium exploitaient l’implémentation précédente. Ce cas peut arriver pour des structures, comme un arbre binaire :

Code :
1
2
3
4
struct Node {
  Node * left;
  Node * right;
};
Pour traverser cet arbre en C, la manière la plus naturelle d’écrire l’algorithme est récursive. Pour traiter le cas d’une branche absente, la fonction commence par vérifier que le pointeur passé en argument est bien valide :

Code :
1
2
3
4
5
void in_order(Node* n) {
  if (! n) return;
  in_order(n->left);
  in_order(n->right);
}
En C++, la syntaxe est plus plaisante avec une fonction membre. Dans ce cas, l’argument de la fonction est passé de manière implicite, à travers le pointeur this :

Code :
1
2
3
4
5
void in_order() {
  if (this == nullptr) return;
  left->in_order();
  right->in_order();
}
Cependant, avec cette optimisation (permise par le standard C++), le premier test sera toujours faux, puisque, par hypothèse, this est toujours un pointeur valide… et ce code plantera lamentablement à l’arrivée d’une feuille. Heureusement, cette optimisation peut être désactivée avec un simple paramètre lors de la compilation (-fno-delete-null-pointer-checks) et l’absence de tel code peut aussi être vérifiée (-fsanitize=undefined).

Bien évidemment, une meilleure manière d'écrire le code vérifie directement chacun des deux pointeurs contenus dans la structure avant de continuer la récursion — ce qui évite en passant les problèmes potentiels avec cette optimisation :

Code :
1
2
3
4
void in_order() {
   if (left)   left->in_order();
  if (right) right->in_order();
}


Sources : GCC 6.1 Released, GCC 6 Release Series: Changes, New Features, and Fixes, C++ Standards Support in GCC.
Ce contenu a été publié dans C++, HPC et calcul scientifique par dourouc05.
  Discussion forum
7 commentaires
  • mintho carmo
    Membre éclairé
    Envoyé par foetus
    Il est bizarre ce code
    En effet. Il provient directement du draft. Juste apres ce code, il y a un autre code comme exemple faux :

    Code :
    1
    2
    3
    4
    template<typename... Args>
      bool f(Args... args) { 
        return (args && ... && args); // error: both operands contain unexpanded parameter packs
      }
    A mon avis, c'est une erreur de frappe (Surtout que true sera traduit pas une valeur non nulle, donc la somme sera une valeur non nulle et le resultat sera non null, donc toujours true. Cela n'aurait pas grand interet). Le code correcte qu'ils voulaient (probablement) mettre est avec des && :

    Code :
    1
    2
    3
    4
    5
    // Cette fonction somme tous ses arguments. 
    template<typename... Args>
      bool f(Args... args) { 
        return (true && ... && args);
      }
    Cf aussi http://en.cppreference.com/w/cpp/language/fold
  • frfancha
    Membre éprouvé
    Envoyé par dourouc05

    Code :
    1
    2
    3
    4
    5
    void in_order() {
      if (this == nullptr) return;
      left->in_order();
      right->in_order();
    }
    Cependant, avec cette optimisation (permise par le standard C++), le premier test sera toujours faux, puisque, par hypothèse, this est toujours un pointeur valide… et ce code plantera lamentablement à l’arrivée d’une feuille.
    Soit je suis très fatigué, soit l'exemple est complètement erroné: de toute façon à l'appel de la méthode (par left->in_order() par exemple) this n'est PAS null et l'élimination du test ne pose aucun problème.
    Ce qui pose problème et qui fait que ce code est pourri c'est l'appel left->in_order() sans vérifier que left est null ou pas, et ça n'a rien à voir avec l'optimisation.
    Non?
  • athlon64
    Membre confirmé
    Envoyé par dourouc05
    pour le domaine HPC, OpenMP 4.5 est complètement implémenté, les calculs peuvent être déportés sur des coprocesseurs Intel Xeon Phi « Knights Landing » et sur du matériel AMD par HSAIL ; l’implémentation de OpenACC 2.0a a été améliorée, avec une possible déportation sur du matériel NVIDIA par PTX. Au niveau matériel, les prochains processeurs d’AMD, basés sur l’architecture Zen, sont déjà pris en charge ; .
    Tout bon ça... GPGPU en force.
  • foetus
    Expert éminent sénior
    Envoyé par dourouc05
    Code :
    1
    2
    3
    4
    5
    // Cette fonction somme tous ses arguments. 
    template<typename... Args>
      bool f(Args... args) { 
        return (true + ... + args);
      }
    Il est bizarre ce code

    D'accord je veux bien que je ne sois pas à jour en C++14-17-19-22-XX et le brouillon C++11, mais:
    • On fait une somme et on retourne un booléen: il est où le résultat?
    • On met un true dans une addition. Il y a de fortes chances que soit le true devient une valeur (si c'est possible) soit la somme est castée en booléen.
    • À moins qu'en mettant true dans l'addition on teste si l'addition des paramètres est possible. Mais il est où le résultat?
  • Envoyé par dourouc05

    [...]Une nouvelle optimisation fait parler d’elle : la propagation de valeurs considère désormais que le pointeur this en C++ (qui pointe vers l’objet courant) est toujours initialisé (sa valeur n’est jamais nullptr).[...]
    Il va sûrement falloir que je relise encore, mais c'est plutôt cool pour le destructeur.

    Envoyé par Michael Guilloux

    [...]Il faut par ailleurs préciser que tous les nouveaux développements autour de la collection de compilateurs GNU sont centrés sur la prochaine version majeure : GCC 7, qui est attendue au début de l’année prochaine.[...]
    Cool.
  • laerne
    Membre éprouvé
    J'aurais cru qu'une fonction non-virtuelle aurait été appelée en poussant `this` sur la stack en copiant directement le pointeur utilisé pour l'appel sans vérifier si c'est nullptr, mais en codant un test compilé avec GCC6.2, ce n'est pas le cas. Donc tu as raison.…