c++ - Puis-je suggérer l'optimiseur en donnant la plage d'un nombre entier?




2 Answers

Oui c'est possible. Par exemple, pour gcc vous pouvez utiliser __builtin_unreachable pour indiquer au compilateur des conditions impossibles, comme ceci:

if (value < 0 || value > 36) __builtin_unreachable();

Nous pouvons envelopper la condition ci-dessus dans une macro:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

Et utilisez-le comme ça:

assume(x >= 0 && x <= 10);

Comme vous pouvez le voir , gcc effectue des optimisations basées sur ces informations:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

int func(int x){
    assume(x >=0 && x <= 10);

    if (x > 11){
        return 2;
    }
    else{
        return 17;
    }
}

Produit:

func(int):
    mov     eax, 17
    ret

Un inconvénient, cependant, que si votre code brise jamais de telles hypothèses, vous obtenez un comportement indéfini .

Il ne vous avertit pas lorsque cela se produit, même dans les versions de débogage. Pour déboguer / tester / attraper des bugs avec des hypothèses plus facilement, vous pouvez utiliser une macro hybride suppos / assert (générique de @David Z), comme celle-ci:

#if defined(NDEBUG)
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#else
#include <cassert>
#define assume(cond) assert(cond)
#endif

Dans les versions de débogage (avec NDEBUG non défini), il fonctionne comme un assert ordinaire, un message d'erreur d'impression et un programme d' NDEBUG , et dans les versions de release il utilise une hypothèse, produisant du code optimisé.

Notez, cependant, que ce n'est pas un substitut aux assert - cond normaux dans les versions de release, donc vous ne devriez pas faire quelque chose comme assume(VeryExpensiveComputation()) .

J'utilise un type int pour stocker une valeur. Par la sémantique du programme, la valeur varie toujours dans un très petit intervalle (0 - 36), et int (pas un caractère) est utilisé uniquement en raison de l'efficacité du processeur.

Il semble que de nombreuses optimisations arithmétiques spéciales peuvent être effectuées sur un si petit nombre d'entiers. De nombreux appels de fonctions sur ces entiers peuvent être optimisés dans un petit ensemble d'opérations "magiques", et certaines fonctions peuvent même être optimisées dans les recherches de tables.

Donc, est-il possible de dire au compilateur que cet int est toujours dans cette petite plage, et est-il possible pour le compilateur de faire ces optimisations?




La réponse actuelle est bonne dans le cas où vous savez avec certitude quelle est la portée, mais si vous voulez toujours un comportement correct lorsque la valeur est en dehors de la plage attendue, cela ne fonctionnera pas.

Pour ce cas, j'ai trouvé cette technique peut travailler:

if (x == c)  // assume c is a constant
{
    foo(x);
}
else
{
    foo(x);
}

L'idée est un compromis entre code et données: vous déplacez 1 bit de données (que ce soit x == c ) dans la logique de contrôle .
Cela indique à l'optimiseur que x est en fait une constante c connue, l'encourageant à intégrer et à optimiser la première invocation de foo séparément des autres, peut-être assez fortement.

Assurez-vous de factoriser le code dans un seul foo sous-programme, mais ne dupliquez pas le code.

Exemple:

Pour que cette technique fonctionne, vous devez avoir un peu de chance - il y a des cas où le compilateur décide de ne pas évaluer les choses statiquement, et ils sont arbitraires. Mais quand ça marche, ça marche bien:

#include <math.h>
#include <stdio.h>

unsigned foo(unsigned x)
{
    return x * (x + 1);
}

unsigned bar(unsigned x) { return foo(x + 1) + foo(2 * x); }

int main()
{
    unsigned x;
    scanf("%u", &x);
    unsigned r;
    if (x == 1)
    {
        r = bar(bar(x));
    }
    else if (x == 0)
    {
        r = bar(bar(x));
    }
    else
    {
        r = bar(x + 1);
    }
    printf("%#x\n", r);
}

Utilisez simplement -O3 et notez les constantes pré-évaluées 0x20 et 0x30e dans la sortie de l'assembleur .




Related

c++ optimization integer range compiler-optimization