diff --git a/projet/plugin.cpp b/projet/plugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa259bce7cd3135ef5c1ae5c2e7b0ffc37bef36c
--- /dev/null
+++ b/projet/plugin.cpp
@@ -0,0 +1,665 @@
+#include <gcc-plugin.h>
+#include <plugin-version.h>
+#include <tree.h>
+#include <basic-block.h>
+#include <diagnostic.h>
+#include <gimple.h>
+#include <tree-pass.h>
+#include <context.h>
+#include <function.h>
+#include <gimple-iterator.h>
+#include <c-family/c-pragma.h>
+#include <vec.h>
+#include <bitmap.h>
+#include <queue>
+
+// ========== VARIABLES GLOBALES ========== //
+
+int plugin_is_GPL_compatible;
+
+// Mode debug (affichage des informations de débogage)
+bool debug_mode = true;
+
+/* Enumération des codes des opérations collectives MPI potentielles à vérifier */
+enum mpi_collective_code
+{
+#define DEFMPICOLLECTIVES(CODE, NAME) CODE,
+#include "MPI_collectives.def"
+    LAST_AND_UNUSED_MPI_COLLECTIVE_CODE
+#undef DEFMPICOLLECTIVES
+};
+
+/* Tableau de noms des opérations collectives MPI potentielles à vérifier */
+#define DEFMPICOLLECTIVES(CODE, NAME) NAME,
+const char *const mpi_collective_name[] = {
+#include "MPI_collectives.def"
+};
+#undef DEFMPICOLLECTIVES
+
+// Vecteur contenant la liste des fonctions à vérifier issue de la directive #pragma ProjetCA mpicoll_check
+vec<tree> *fun_vec;
+
+// ========== //
+
+// ========== PRAGMA ========== //
+
+// Affichage du vecteur (variable globale) des fonctions à vérifier
+static void print_fun_vec()
+{
+    tree x;
+    printf("fun_vec contains %i element(s):", fun_vec->length());
+    for (int i = 0; fun_vec->iterate(i, &x); i++)
+        printf(" %s,", IDENTIFIER_POINTER(x));
+    printf("\n");
+}
+
+// Traitement de la directive #pragma ProjetCA mpicoll_check
+static void handle_pragma_mpicoll_check(cpp_reader *)
+{
+    location_t loc;
+    enum cpp_ttype token;
+    tree x;
+    bool close_paren_needed_p = false;
+
+    // Erreur si la directive est placée au sein d'une fonction
+    if (cfun)
+    {
+        error_at(cfun->function_start_locus, "%<#pragma ProjetCA mpicoll_check%> is not allowed inside functions");
+        return;
+    }
+
+    token = pragma_lex(&x, &loc);
+    // Si la directive est suivie d'une parenthèse ouvrante, on cherche une liste de noms de fonctions de la forme (fun1,fun2,fun3,...)
+    // Sinon, on s'attend au nom d'une seule fonction
+    if (token == CPP_OPEN_PAREN)
+    {
+        close_paren_needed_p = true;
+        token = pragma_lex(&x, &loc);
+    }
+
+    // Si le premier token (ou suivant la parenthèse) n'est pas un nom, on signale une erreur
+    if (token != CPP_NAME)
+        error_at(loc, "%<#pragma ProjetCA mpicoll_check%> is not a valid name");
+    else
+    {
+        do
+        {
+            // On émet un avertissement si le nom d'une fonction est présent plusieurs fois dans l'ensemble des directives #pragma ProjetCA mpicoll_check
+            if (fun_vec->contains(x))
+                warning_at(loc, 0, "%<#pragma ProjetCA mpicoll_check%> already contains the function %<%s%>", IDENTIFIER_POINTER(x));
+            // Sinon, on ajoute la fonction au vecteur
+            else
+                fun_vec->safe_push(x);
+
+            // On parcourt la liste de noms de fonctions séparés par des virgules
+            token = pragma_lex(&x, &loc);
+            while (token == CPP_COMMA)
+                token = pragma_lex(&x, &loc);
+        } while (token == CPP_NAME);
+
+        // On vérifie que la liste de noms de fonctions est bien terminée par une parenthèse fermante
+        if (close_paren_needed_p)
+        {
+            if (token == CPP_CLOSE_PAREN)
+                token = pragma_lex(&x, &loc);
+            else
+                error_at(loc, "%<#pragma ProjetCA mpicoll_check%> does not have a final %<)%>");
+        }
+
+        if (token != CPP_EOF)
+        {
+            error_at(loc, "%<#pragma ProjetCA mpicoll_check%> string is badly formed");
+            return;
+        }
+
+        if (debug_mode)
+            print_fun_vec();
+    }
+}
+
+// Enregistrement de la directive #pragma ProjetCA mpicoll_check
+static void register_pragma_mpicoll_check(void *event_data, void *data)
+{
+    c_register_pragma("ProjetCA", "mpicoll_check", handle_pragma_mpicoll_check);
+}
+
+// Opérations de clôture de la directive #pragma ProjetCA mpicoll_check
+static void clear_pragma_mpicoll_check(void *event_data, void *data)
+{
+    tree x;
+    // On émet un avertissement pour chaque fonction présente dans la directive qui n'a pas été appelée durant les passes
+    for (int i = 0; fun_vec->iterate(i, &x); i++)
+        warning(0, "%<#pragma ProjetCA mpicoll_check%> contains the function %<%s%> which does not seem defined", IDENTIFIER_POINTER(x));
+
+    // On libère le vecteur
+    fun_vec->release();
+}
+
+// ========== //
+
+// ========== UTILS ========== //
+
+// Récupération du code de l'opération collective MPI associée à l'instruction courante
+// Si l'instruction courante n'est pas une opération collective MPI présente dans la liste, on renvoie LAST_AND_UNUSED_MPI_COLLECTIVE_CODE
+enum mpi_collective_code get_mpi_collective_code(gimple *stmt)
+{
+    if (is_gimple_call(stmt))
+    {
+        const char *callee_name;
+
+        callee_name = IDENTIFIER_POINTER(DECL_NAME(gimple_call_fndecl(stmt)));
+
+        for (int i = 0; i < LAST_AND_UNUSED_MPI_COLLECTIVE_CODE; i++)
+        {
+            if (strcmp(callee_name, mpi_collective_name[i]) == 0)
+            {
+                return mpi_collective_code(i);
+            }
+        }
+    }
+
+    return LAST_AND_UNUSED_MPI_COLLECTIVE_CODE;
+}
+
+// Séparation des blocks contenant plusieurs appels MPI
+void split_blocks_with_multiple_mpi_calls(function *fun)
+{
+    basic_block bb;
+
+    // On parcourt tous les basic blocks de la fonction
+    FOR_EACH_BB_FN(bb, fun)
+    {
+        gimple *old_stmt = NULL;
+
+        for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+        {
+            gimple *stmt = gsi_stmt(gsi);
+
+            mpi_collective_code stmt_code = get_mpi_collective_code(stmt);
+
+            // On repère les instructions courantes qui sont des fonctions MPI collective présentes dans la liste
+            if (stmt_code != LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+            {
+                // Si on a déjà repéré une instruction MPI collective dans le basic block courant, on crée un nouveau basic block
+                if (old_stmt != NULL)
+                    split_block(bb, old_stmt);
+                old_stmt = stmt;
+            }
+        }
+    }
+}
+
+bitmap_head *generate_new_cfg_edges(function *fun)
+{
+    bitmap_head *new_cfg_edges = XNEWVEC(bitmap_head, n_basic_blocks_for_fn(fun));
+    basic_block src = ENTRY_BLOCK_PTR_FOR_FN(fun);
+    bitmap *visited_blocks;
+    visited_blocks = XNEWVEC(bitmap, n_basic_blocks_for_fn(fun));
+    edge e;
+    basic_block bb;
+
+    // On initialise le bitmap des arcs du nouveau CFG
+    FOR_EACH_BB_FN(bb, fun)
+    {
+        bitmap_initialize(&new_cfg_edges[bb->index], &bitmap_default_obstack);
+    }
+
+    // On initialise le bitmap des bb déjà visités
+    bitmap_initialize(*visited_blocks, &bitmap_default_obstack);
+
+    // On marque le bloc d'entrée comme visité
+    bitmap_set_bit(*visited_blocks, src->index);
+
+    // On parcourt le CFG à partir du bloc d'entrée
+    std::queue<basic_block> q;
+    // Ajout du bloc d'entrée dans la file
+    q.push(src);
+
+    // Tant que la file n'est pas vide, on traite le premier élément de la file
+    // On ajoute les arcs sortants dont le bloc de destination n'a pas encore été visité
+    while (!q.empty())
+    {
+        basic_block bb = q.front();
+        q.pop();
+
+        edge_iterator ei;
+        FOR_EACH_EDGE(e, ei, bb->succs)
+        {
+            basic_block succ = e->dest;
+
+            if (!bitmap_bit_p(*visited_blocks, succ->index))
+            {
+                bitmap_set_bit(&new_cfg_edges[bb->index], succ->index);
+                bitmap_set_bit(*visited_blocks, succ->index);
+                q.push(succ);
+            }
+        }
+    }
+
+    // On libère le bitmap des bb déjà visités
+    bitmap_clear(*visited_blocks);
+
+    return new_cfg_edges;
+}
+
+// Calcul du rang maximal des bb d'une fonction
+static int get_max_rank(function *fun, int *ranks)
+{
+    int max_rank = 0;
+    for (int i = 0; i < n_basic_blocks_for_fn(fun); i++)
+    {
+        if (ranks[i] > max_rank)
+        {
+            max_rank = ranks[i];
+        }
+    }
+
+    return max_rank;
+}
+
+// ========== //
+
+// ========== GRAPHVIZ ========== //
+
+// Création du nom du fichier .dot à partir du nom de la fonction et d'un suffixe
+static char *cfgviz_generate_filename(function *fun, const char *suffix)
+{
+    char *target_filename;
+
+    target_filename = (char *)xmalloc(1024 * sizeof(char));
+
+    snprintf(target_filename, 1024, "%s_%s_%d_%s.dot",
+             current_function_name(),
+             LOCATION_FILE(fun->function_start_locus),
+             LOCATION_LINE(fun->function_start_locus),
+             suffix);
+
+    return target_filename;
+}
+
+// Export de la représentation du CFG d'une fonction dans un descriptor de fichier
+static void cfgviz_internal_dump(function *fun, FILE *out)
+{
+    basic_block bb;
+
+    fprintf(out, "Digraph G{\n");
+
+    FOR_ALL_BB_FN(bb, cfun)
+    {
+        fprintf(out, "%d [label=\"BB %d", bb->index, bb->index);
+
+        gimple_stmt_iterator gsi;
+        gimple *stmt;
+        gsi = gsi_start_bb(bb);
+        stmt = gsi_stmt(gsi);
+
+        /* Itération sur les instructions du bloc */
+        for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+        {
+            stmt = gsi_stmt(gsi);
+
+            enum mpi_collective_code returned_code = get_mpi_collective_code(stmt);
+
+            if (returned_code != LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+            {
+                fprintf(out, " \\n %s", mpi_collective_name[returned_code]);
+            }
+        }
+
+        fprintf(out, "\" shape=ellipse]\n");
+
+        edge_iterator eit;
+        edge e;
+
+        // Représentation des arcs sortants
+        FOR_EACH_EDGE(e, eit, bb->succs)
+        {
+            const char *label = "";
+            if (e->flags == EDGE_TRUE_VALUE)
+                label = "true";
+            else if (e->flags == EDGE_FALSE_VALUE)
+                label = "false";
+
+            fprintf(out, "%d -> %d [color=red label=\"%s\"]\n",
+                    bb->index, e->dest->index, label);
+        }
+    }
+
+    fprintf(out, "}\n");
+}
+
+// Export de la représentation du CFG d'une fonction dans un fichier .dot
+void cfgviz_dump(function *fun, const char *suffix)
+{
+    char *target_filename;
+    FILE *out;
+
+    target_filename = cfgviz_generate_filename(fun, suffix);
+
+    printf("Generating CFG of function %s in file <%s>\n",
+           current_function_name(), target_filename);
+
+    out = fopen(target_filename, "w");
+
+    cfgviz_internal_dump(fun, out);
+
+    fclose(out);
+    free(target_filename);
+}
+
+// ========== //
+
+// ========== DOMINANCE ========== //
+
+// Calcul de la post dominance d'un ensemble de basic blocks
+bitmap get_post_dominance_for_a_set(bitmap_head *set, function *fun, bitmap_head *pd)
+{
+    bitmap_initialize(pd, &bitmap_default_obstack);
+
+    // Pour chaque bb de l'ensemble, on récupère tous les bb post-dominés par celui-ci
+    basic_block bb;
+    FOR_ALL_BB_FN(bb, fun)
+    {
+        if (bitmap_bit_p(set, bb->index))
+        {
+            auto_vec<basic_block> pd_blocks = get_all_dominated_blocks(CDI_POST_DOMINATORS, bb);
+            for (unsigned int i = 0; i < pd_blocks.length(); i++)
+            {
+                bitmap_set_bit(pd, pd_blocks[i]->index);
+            }
+        }
+    }
+
+    // On garde les bb dont au moins un successeur est post-dominé par tous les bb de l'ensemble
+    FOR_ALL_BB_FN(bb, fun)
+    {
+        edge e;
+        edge_iterator ei;
+        int total = 0;
+        int succ_n = 0;
+        FOR_EACH_EDGE(e, ei, bb->succs)
+        {
+            basic_block succ = e->dest;
+            if (bitmap_bit_p(pd, succ->index))
+                succ_n++;
+
+            total++;
+        }
+        if (total > 0 && succ_n == total)
+            bitmap_set_bit(pd, bb->index);
+    }
+
+    return pd;
+}
+
+// Calcul de la frontière de post dominance d'un ensemble de basic blocks
+bitmap get_post_dominance_frontier_for_a_set(bitmap_head *set, function *fun, bitmap_head *pd)
+{
+    bitmap_head pd2;
+    bitmap_initialize(pd, &bitmap_default_obstack);
+
+    // On récupère la post dominance de l'ensemble
+    get_post_dominance_for_a_set(set, fun, &pd2);
+
+    // On garde les noeuds qui ne sont pas post-dominés par l'ensemble mais dont au moins un successeur l'est
+    basic_block bb;
+    FOR_ALL_BB_FN(bb, fun)
+    {
+        edge e;
+        edge_iterator ei;
+        FOR_EACH_EDGE(e, ei, bb->succs)
+        {
+            basic_block succ = e->dest;
+            if (bitmap_bit_p(&pd2, succ->index) && !bitmap_bit_p(&pd2, bb->index))
+            {
+                bitmap_set_bit(pd, bb->index);
+            }
+        }
+    }
+
+    return pd;
+}
+
+// ========== //
+
+// ========== PASS ========== //
+
+const pass_data pass_mpicoll_check_data = {
+    GIMPLE_PASS,
+    "MPICOLL_CHECK",
+    OPTGROUP_NONE,
+    TV_OPTIMIZE,
+    0,
+    0,
+    0,
+    0,
+    0,
+};
+
+class pass_mpicoll_check : public gimple_opt_pass
+{
+public:
+    pass_mpicoll_check(gcc::context *ctxt) : gimple_opt_pass(pass_mpicoll_check_data, ctxt) {}
+
+    pass_mpicoll_check *clone() { return new pass_mpicoll_check(g); }
+
+    bool gate(function *fun)
+    {
+        bool pass_enabled = false;
+
+        tree x;
+        unsigned int i = 0;
+        // On parcourt le vecteur des fonctions à vérifier
+        while (!pass_enabled && i < fun_vec->length())
+        {
+            fun_vec->iterate(i, &x);
+            i++;
+            // Si la fonction courante est présente dans le vecteur, on l'enlève du vecteur et on active la passe
+            if (strcmp(IDENTIFIER_POINTER(x), function_name(fun)) == 0)
+            {
+                fun_vec->unordered_remove(i - 1);
+                pass_enabled = true;
+            }
+        }
+
+        if (pass_enabled && debug_mode)
+            printf("Executing mpicoll_check pass for the function %s\n", function_name(fun));
+
+        return pass_enabled;
+    }
+
+    unsigned int execute(function *fun)
+    {
+        // Export du CFG de la fonction avant la séparation des blocs contenant plusieurs appels MPI
+        if (debug_mode)
+            cfgviz_dump(fun, "before_split");
+
+        // Séparation des blocs contenant plusieurs appels MPI
+        split_blocks_with_multiple_mpi_calls(fun);
+
+        // Export du CFG de la fonction après la séparation des blocs contenant plusieurs appels MPI
+        if (debug_mode)
+            cfgviz_dump(fun, "after_split");
+
+        // Calcul des informations de post-dominance
+        calculate_dominance_info(CDI_POST_DOMINATORS);
+
+        // Création du nouveau CFG en retirant les arcs retour
+        bitmap_head *new_cfg_edges = generate_new_cfg_edges(fun);
+
+        // Définition d'une structure pour stocker les informations de rang
+        struct bb_with_rank
+        {
+            basic_block bb;
+            int rank;
+        };
+
+        basic_block bb;
+
+        std::queue<bb_with_rank> q;
+        bb_with_rank bbr;
+
+        bbr.bb = ENTRY_BLOCK_PTR_FOR_FN(fun);
+        bbr.rank = 0;
+        q.push(bbr);
+
+        // Tableaux pour stocker les informations de rang et d'appel de chaque bb
+        int calls[n_basic_blocks_for_fn(fun)];
+        int ranks[n_basic_blocks_for_fn(fun)];
+
+        // On parcourt l'ensemble des basic blocks de l'entrée vers la sortie
+        while (!q.empty())
+        {
+            bbr = q.front();
+            q.pop();
+
+            gimple_stmt_iterator gsi;
+            mpi_collective_code c = LAST_AND_UNUSED_MPI_COLLECTIVE_CODE;
+
+            // Si le bb contient une instruction MPI, on sort de la boucle pour lui attribuer un rang
+            for (gsi = gsi_start_bb(bbr.bb); !gsi_end_p(gsi); gsi_next(&gsi))
+            {
+                gimple *stmt = gsi_stmt(gsi);
+                c = get_mpi_collective_code(stmt);
+                if (c != LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+                    break;
+            }
+
+            calls[bbr.bb->index] = c;
+
+            // Si le bb contient un appel MPI, on augmente d'un son rang par rapport à celui du prédécesseur
+            // Sinon, on garde le même rang et on continue
+            if (c != LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+                ranks[bbr.bb->index] = bbr.rank + 1;
+            else
+                ranks[bbr.bb->index] = bbr.rank;
+
+            FOR_ALL_BB_FN(bb, fun)
+            {
+                // On ajoute les successeurs du bb courant dans la file en leur donnant le même rang
+                if (bitmap_bit_p(&new_cfg_edges[bbr.bb->index], bb->index))
+                {
+                    bb_with_rank bbr2;
+                    bbr2.bb = bb;
+                    bbr2.rank = ranks[bbr.bb->index];
+                    q.push(bbr2);
+                }
+            }
+        }
+
+        // Récupération du rang maximal
+        int max_rank = get_max_rank(fun, ranks);
+
+        // Initialisation d'une matrice de bitmaps de taille nombre_appels_differents * rang_maximum pour avoir tous les ensembles possibles
+        bitmap_head **sets = XNEWVEC(bitmap_head *, max_rank);
+
+        // Initialisation des bitmaps
+        for (int i = 0; i < max_rank; i++)
+        {
+            sets[i] = XNEWVEC(bitmap_head, LAST_AND_UNUSED_MPI_COLLECTIVE_CODE);
+            for (unsigned int j = 0; j < LAST_AND_UNUSED_MPI_COLLECTIVE_CODE; j++)
+            {
+                bitmap_initialize(&sets[i][j], &bitmap_default_obstack);
+            }
+        }
+
+        // Remplissage des bitmaps avec les index des bb compris dans les ensembles correspondants
+        FOR_ALL_BB_FN(bb, fun)
+        {
+            if (calls[bb->index] != LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+            {
+                bitmap_set_bit(&sets[ranks[bb->index] - 1][calls[bb->index]], bb->index);
+            }
+        }
+
+        // Pour chaque ensemble possible de notre matrice, on récupère la frontière de post dominance
+        for (int i = 0; i < max_rank; i++)
+        {
+            for (unsigned int j = 0; j < LAST_AND_UNUSED_MPI_COLLECTIVE_CODE; j++)
+            {
+                bitmap_head pd;
+                int target_rank = 0;
+                get_post_dominance_frontier_for_a_set(&sets[i][j], fun, &pd);
+
+                // Si la frontière de post dominance n'est pas vide, on émet un avertissement pour deadlock
+                // Cela signifie que certains chemins du CFG ne passent pas forcément par cette collective MPI
+                // Certains processus peuvent donc être bloqués en attendant que les autres processus atteignent cette collective MPI à un autre moment
+                if (!bitmap_empty_p(&pd))
+                {
+                    // On émet un avertissement en indiquant la collective concernée dans la fonction
+                    warning(0, "The MPI collective %<%s%> (rank %d) differs between process (possible deadlock)", mpi_collective_name[j], i + 1);
+                    target_rank = i + 1;
+
+                    bitmap_head temp;
+                    bitmap_initialize(&temp, &bitmap_default_obstack);
+                    // On calcule la frontière de post-dominance itérée jusqu'à ce qu'elle soit stable pour trouver l'origine du problème
+                    do
+                    {
+                        bitmap_copy(&temp, &pd);
+                        get_post_dominance_frontier_for_a_set(&temp, fun, &pd);
+                    } while (!bitmap_empty_p(&pd));
+
+                    // Notre frontière de post-dominance itérée est stable, on peut donc récupérer et indiquer le basic block contenant l'instruction à partir de laquelle on observe des divergences
+                    for (int i = 0; i < n_basic_blocks_for_fn(fun); i++)
+                    {
+                        if (bitmap_bit_p(&temp, i))
+                        {
+                            bb = BASIC_BLOCK_FOR_FN(fun, i);
+
+                            // On parcourt les statements du basic block pour trouver la première instruction non MPI qui pourrait créer la divergence
+                            gimple_stmt_iterator gsi;
+                            gimple *stmt;
+                            for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+                            {
+                                stmt = gsi_stmt(gsi);
+                                if (get_mpi_collective_code(stmt) == LAST_AND_UNUSED_MPI_COLLECTIVE_CODE)
+                                {
+                                    warning_at(gimple_location(stmt), 0, "The deadlock origin for the MPI collective %<%s%> (rank %d) is probably here", mpi_collective_name[j], target_rank);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        free_dominance_info(CDI_POST_DOMINATORS);
+
+        return 0;
+    }
+};
+
+// ========== //
+
+// ========== PLUGIN ========== //
+
+// Initialisation du plugin
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+    // On crée le vecteur qui contiendra la liste des fonctions à vérifier issue de la directive #pragma ProjetCA mpicoll_check
+    fun_vec = new vec<tree>;
+    fun_vec->create(0);
+
+    struct register_pass_info pass_info;
+
+    // On vérifie que la version de GCC est compatible avec le plugin
+    if (!plugin_default_version_check(version, &gcc_version))
+        return 1;
+
+    pass_mpicoll_check p(g);
+    pass_info.pass = &p;
+    pass_info.reference_pass_name = "cfg";
+    pass_info.ref_pass_instance_number = 0;
+    pass_info.pos_op = PASS_POS_INSERT_AFTER;
+
+    register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
+
+    register_callback(plugin_info->base_name, PLUGIN_PRAGMAS, register_pragma_mpicoll_check, NULL);
+
+    register_callback(plugin_info->base_name, PLUGIN_FINISH, clear_pragma_mpicoll_check, NULL);
+
+    return 0;
+}
+
+// ========== //
\ No newline at end of file