/*    TEMPL1
TESTING template CLAUSE */

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

static void templ111();
static void templ121();

static void ansyes(const char tname[]);
static void ansno(const char tname[]);

static int NL = 1000;
static int ER = 10000;
static int erri, i, j, ia, ib, ic, ja, jb, jc, k;

int main(int an, char **as)
{
    printf("=== START OF TEMPL1 ======================\n");
    /* TEMPLATE A1[BLOCK]   ALIGN B1[i] WITH A1[i + 4]
                            ALIGN C1[i] WITH A1[2*i + 4] */
    templ111();
    /* TEMPLATE A1[BLOCK]   ALIGN B1[][i]  WITH A1[i]
                            ALIGN C1[i][] WITH A1[2*i + 1] */
    templ121();
    printf("=== END OF TEMPL1 ========================\n");
    return 0;
}

/* ---------------------------------------------TEMPL111*/
/* TEMPLATE A1[BLOCK]   ALIGN B1[i] WITH A1[i + 4]
                        ALIGN C1[i] WITH A1[2*i + 4] */
void templ111()
{
    #define AN1 14
    #define BN1 8
    #define CN1 4
    int k1i = 1, k2i = 0, li = 4;
    int kc1i = 2, kc2i = 0, lci = 4;
    char tname[] = "templ111 ";

    #pragma dvm template[AN1] distribute[block]
    void *A1;
    #pragma dvm array align([i] with A1[k1i * i + li])
    int B1[BN1];
    #pragma dvm array align([i] with A1[kc1i * i + lci])
    int C1[CN1];

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
        #pragma dvm parallel([i] on B1[i])
        for (i = 0; i < BN1; i++)
                B1[i] = i;

        #pragma dvm parallel([i] on C1[i])
        for (i = 0; i < CN1; i++)
                C1[i] = i;

        #pragma dvm parallel([i] on A1[i]) private(ib, erri, ic)
        for (i = 0; i < AN1; i++)
        {
            if (((i-li) == (((i-li)/k1i) * k1i)) &&
                    (((i-li)/k1i) >= 0) &&
                    (((i-li)/k1i) < BN1))
            {
                ib = (i-li)/k1i;
                if (B1[ib] != (ib))
                    erri = i;
            }
            if (((i-lci) == (((i-lci)/kc1i) * kc1i)) &&
                    (((i-lci)/kc1i) >= 0) &&
                    (((i-lci)/kc1i) < CN1))
            {
                ic = (i-lci)/kc1i;
                if (C1[ic] != (ic))
                    erri = i;
            }
        }

    }
    #pragma dvm get_actual(erri)

    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);

    #undef AN1
    #undef BN1
    #undef CN1
}

/* ---------------------------------------------TEMPL121*/
/* TEMPLATE A1[BLOCK]   ALIGN B1[][i] WITH A1[i]
                        ALIGN C1[i][] WITH A1[2*i + 1] */
void templ121()
{
    int AN1 = 9;
    int BN1 = 8;
    int BN2 = 8;
    int CN1 = 4;
    int CN2 = 4;

    int k1i = 1, k2i = 0, li = 0;
    int kc1i = 2, kc2i = 0, lci = 1;

    char tname[] = "templ121 ";

    #pragma dvm template[AN1] distribute[block]
    void *A1;
    #pragma dvm array
    int (*B2)[BN2];
    #pragma dvm array
    int (*C2)[CN2];

    B2 = malloc(sizeof(int[BN1][BN2]));
    C2 = malloc(sizeof(int[CN1][CN2]));
    #pragma dvm realign(B2[][i] with A1[k1i * i + li])
    #pragma dvm realign(C2[i][] with A1[kc1i * i + lci])

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
    #pragma dvm parallel([i][j] on B2[i][j])
    for (i = 0; i < BN1; i++)
        for(j = 0; j < BN2; j++)
            B2[i][j] = i*NL + j;

    #pragma dvm parallel([i][j] on C2[i][j])
    for (i = 0; i < CN1; i++)
        for(j = 0; j < CN2; j++)
            C2[i][j] = i*NL + j;


    #pragma dvm parallel([i] on A1[i]) private(j, ib, jb, erri, jc, ic, k)
    for (i = 0; i < AN1; i++)
    {
        for (j = 0; j < BN1; j++)
        {
            if (((i-li) == (((i-li)/k1i) * k1i)) &&
                    (((i-li)/k1i) >= 0) &&
                    (((i-li)/k1i) < BN2))
            {
                ib = j;
                jb = (i-li)/k1i;
                if (B2[ib][jb] != ib*NL + jb)
                    erri = i*NL/10 + j;
            }
        }
        for (k = 0; k < CN2; k++)
        {
            if (((i-lci) == (((i-lci)/kc1i) * kc1i)) &&
                    (((i-lci)/kc1i) >= 0) &&
                    (((i-lci)/kc1i) < CN1))
            {
                jc = k;
                ic = (i-lci)/kc1i;
                if (C2[ic][jc] != (ic*NL + jc))
                    erri = i*NL/10 + j;
            }
        }
    }
    }

    #pragma dvm get_actual(erri)

    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);

    free(B2);
    free(C2);
}

void ansyes(const char name[])
{
    printf("%s  -  complete\n", name);
}

void ansno(const char name[])
{
    printf("%s  -  ***error\n", name);
}
