Компилятор C-DVM
Предварительный дизайн
* 22 June 2000 *


Содержание

1 Назначение компилятора

1.1 Распараллеливание
1.2 Отладочные расширения

2 Последовательность компиляции
3 Компиляция конструкций C-DVM

3.1 Распределение данных

3.1.1 Директива DISTRIBUTE
3.1.2 Формат распределения GENBLOCK
3.1.3 Спецификация ONTO
3.1.4 Директива REDISTRIBUTE
3.1.5 Директива ALIGN
3.1.6 Директива REALIGN
3.1.7 Поддиректива TEMPLATE
3.1.8 Директива CREATE_TEMPLATE

3.2 Распределение вычислений (циклы и задачи)

3.2.1 Директива PARALLEL
3.2.2 Поддиректива ACROSS
3.2.3 Директива PROCESSORS и функция NUMBER_OF_PROCESSORS()
3.2.4 Директива TASK
3.2.5 Директива MAP
3.2.6 Директива TASK_REGION
3.2.7 Конструкция ON-block
3.2.8 Конструкция ON-loop

3.3 Теневые грани

3.3.1 Поддиректива SHADOW
3.3.2 Поддиректива SHADOW_RENEW
3.3.3 Директива SHADOW_GROUP
3.3.4 Директива CREATE_SHADOW_GROUP
3.3.5 Директива SHADOW_START
3.3.6 Поддиректива SHADOW_START
3.3.7 Директива SHADOW_WAIT
3.3.8 Поддиректива SHADOW_WAIT

3.4 Удаленный доступ

3.4.1 Директива и поддиректива REMOTE_ACCESS
3.4.2 Директива REMOTE_GROUP
3.4.3 Директива PREFETCH
3.4.4 Директива RESET
3.4.5 Удаленные ссылки

3.5 Редукционные операции

3.5.1 Директива REDUCTION_GROUP
3.5.2 Поддиректива REDUCTION
3.5.3 Редукционные переменные и операции
3.5.4 Директива REDUCTION_START
3.5.5 Директива REDUCTION_WAIT

3.6 Неявные конструкции

3.6.1 Создание и удаление распределенных массивов
3.6.2 Статические распределенные массивы
3.6.3 Доступ к распределенным данным
3.6.4 Собственные вычисления
3.6.5 Инициализация и завершение параллельного выполнения
3.6.6 Функции ввода-вывода

3.7 Отладочные расширения

3.7.1 Анализатор производительности. Циклы
3.7.2 Анализатор производительности. Интервалы
3.7.3 Отладчик. Трассировка данных
3.7.4 Отладчик. Трассировка вычислений
3.7.5 Пoследовательный код


1 Назначение компилятора

C-DVM является расширением языка СИ специальными аннотациями для задания параллельного выполнения программы. Аннотации называются DVM-директивами. Компилятор C-DVM транслирует аннотированную программу в SPMD программу, которая содержит вызовы системы поддержки DVM (RTL).

Кроме чисто параллельного кода компилятор должен уметь cоздавать расширенный отладочный код для использования возможностей анализатора производительности (PPPA) и отладчика, а также последовательный код (без вызовов RTL и, тем самым, без распараллеливания) с такими же отладочными расширениями.

1.1 Распараллеливание

Для распараллеливания компилятор должен распознавать следующие четыре типа конcтрукций и выполнять соответствующие действия и преобразования программы:

1.2 Отладочные расширения

Для анализатора производительности компилятор должен обрабатывать:

Эти действия реализуются вызовами соответствующих функций анализатора.

Для отладчика компилятор должен обеспечить:

Все это реализуется вызовами соответствующих функций отладчика. Точка регистрации инициализированных переменных определяется компилятором.

Режим последовательного выполнения нужен для получения временных характеристик исходной программы и "эталонной" трассировки для отладки в режиме сравнения трассировки. В этом режиме все DVM-директивы игнорируются за исключением следующих:

2 Последовательность компиляции

Компиляция C-DVM программы выполняется в следующей последовательности.

Для удобства и большей гибкости сгенерированная программа не содержит прямых вызовов функций RTL. Она содержит макрокоманды со всей необходимой информацией, скрывающие низкоуровневые детали интерфейса RTL. Окончательная генерация выполняется препроцессором СИ с использованием макроопределений, содержащихся в файле cdvm_c.h.

3 Компиляция конструкций C-DVM

Необходимость преобразования программы для параллельного выполнения вызвана распределением данных и вычислений.

Распределение данных состоит в разбиении массивов на части и размещении этих частей в локальной памяти разных процессоров. На каждом процессоре RTL определяет размер локальной части (с учетом теневых граней) и выделяет память для неё. Для программы эта локальная часть массива доступна через хендлер массива. Следовательно, исходные последовательные операторы для создания массива и доступа к его элементам должны быть найдены в исходном коде и заменены.

Распределение вычислений состоит в разбиении индексного пространства цикла на части и выполнения на разных процессорах разных множеств витков цикла. На каждом процессоре локальная часть параллельного цикла описывается дескриптором цикла. Т.о. заголовки цикла должны быть преобразованы.

В этом разделе описаны эти и другие преобразования конструкций C-DVM, выполняемые компилятором.

3.1 Распределение данных

3.1.1 Директива DISTRIBUTE

Контекст и синтаксис. 

    DVM( ["*"] DISTRIBUTE [ format...] [ ONTO target ]
            [ ; SHADOW-clause ] [ ; TEMPLATE-clause ] )
            C-declaration ;

Выход компилятора. 

    long array-id [ rank+1 ];

Замечание.  Исходное описание заменено. Вся прочая информация из описания и директивы будет использоваться при генерации других конструкций и при распознавании ссылок к распределенным данным.

3.1.2 Формат распределения GENBLOCK

Контекст и синтаксис. 

DVM(DISTRIBUTE ... "[" GENBLOCK( int-array ) "]"... )
DVM(REDISTRIBUTE ... "[" GENBLOCK( int-array ) "]"... )

Выход компилятора. 

    DVM_GENBLOCK(am,ps,k,gbs);

Замечание.  Эта макрокоманда генерируется не в точке описания, а в общей последовательности (явного или неявного) создания массива. Макрокоманда DVM_GENBLOCK(am,ps,k,gbs) расширяется в

    DVM_AM=am? am : getam_();
    DVM_PS=ps? ps : getps_(NULL);
    genbli_(&DVM_PS, &DVM_AM, (AddrType*) gbs, k);

3.1.3 Спецификация ONTO

Контекст и синтаксис. 

    DVM(DISTRIBUTE ... ONTO target ... )

Выход компилятора. 

    DVM_ONTO(ps,k,ls,hs)

Замечание.  Эта макрокоманда генерируется не в точке описания, а в общей последовательности (явного или неявного) создания массива. Она создает процессорную подсистему, которая будет использоваться вместо текущей (используемой по умолчанию). Макрокоманда DVM_ONTO(ps,k,ls,hs) расширяется в

    DVM_PS=ps;
    DVM_PS=crtps_(&DVM_PS,  ls, hs,  DVM_0000);

3.1.4 Директива REDISTRIBUTE

Контекст и синтаксис. 

    DVM(REDISTRIBUTE array format... [ NEW ] ) ;

Выход компилятора. 

    DVM_REDISTRIBUTE(amv,ps,k,axs,new);

Замечание.  Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REDISTRIBUTE(amv,ps,k,axs,new) расширяется в

    {DVM_PS=ps;
    redis_((AMViewRef*) amv, &DVM_PS, k, axs, 0, new);
    }

3.1.5 Директива ALIGN

Контекст и синтаксис. 

    DVM(["*"] ALIGN [ "["dummy-var"]"... ]
            WITH base "["align-expr"]"...
            [ ; SHADOW-clause ] )
            C-declaration ;

Выход компилятора. 

    long array-id [ rank+1 ];

Замечание.  Исходное описание заменено. Вся прочая информация из описания и директивы будет использоваться при генерации других конструкций и при распознавании ссылок к распределенным данным.

3.1.6 Директива REALIGN

Контекст и синтаксис. 

    DVM( REALIGN array "["dummy-var"]"...
            WITH base "["align-expr"]"... ) ;

Выход компилятора. 

    DVM_REALIGN(arr,base,k,i,a,b,new);

Замечание.  Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REALIGN(arr,base,k,i,a,b,new) расширяется в

    {realn_(arr, (PatternRef*)(base), i, a, b, new);
    }

3.1.7 Поддиректива TEMPLATE

Контекст и синтаксис. 

    DVM(DISTRIBUTE ... ; TEMPLATE [ "["size"]"... ] )
            void * template-id ;

Выход компилятора. 

    AMViewRef template-id;

Замечание.  Исходное описание заменено. Форматы распределения будут использованы при создании темплейта. Если размер (size) задан, то создание будет неявным.

3.1.8 Директива CREATE_TEMPLATE

Контекст и синтаксис. 

    DVM(CREATE_TEMPLATE template-id "["size"]"... ) ;

Выход компилятора. 

    DVM_CREATE_TEMPLATE(am,t,r,di);
    DVM_DISTRIBUTE(amv,ps,k,axs);

Замечание.  Выполнимая директива конвертируется в оператор. Макрокоманда DVM_CREATE_TEMPLATE(am,t,r,di) расширяется в

    {if(am==0) DVM_AM=getam_();
    else DVM_AM=am;
    t=crtamv_( (AMRef*)DVM_AM, r, di, 0);
    }

Макрокоманда DVM_DISTRIBUTE(amv,ps,k,axs) расширяется в

    {DVM_PS=ps;
    DVM_AMV=amv;
    distr_( &DVM_AMV, &DVM_PS, k, axs, 0);
    }

Эти макрокоманды генерируются также для создания и распределения неявного темплейта для любого массива со спецификацией DISTRIBUTE.

3.2 Распределение вычислений (циклы и задачи)

3.2.1 Директива PARALLEL

Контекст и синтаксис. 

    DVM ( PARALLEL "["loop-var"]"...
        ON base "["align_expr"]"...
        [ ; sub-directives]... )
        loop-nest

Выход компилятора. 

    {
        [ dvm_create_rg ]
    DVM_PARALLEL(n,r);
        [ other sub-directives... ]
    DVM_DO_ON((n,r,vs,ls,hs,ss,base,rb,is,as,bs);
        [ dvm_reduction or dvm_reduction20 ]
    {
    DVM_DOPL(n)
    loop-headers DVM_FOR...
    {
        loop-body
    }
    }
        [ end_reduction ]
    DVM_END_PARALLEL(n);
    }

Замечание.  Макрокоманда DVM_PARALLEL(n,r) расширяется в

    {long DVM_LO##n[r],
        DVM_HI##n[r],
        DVM_ST##n[r];
    LoopRef DVM_LP##n;
    DVM_LP##n=crtpl_(DVM_A0(r))

Макрокоманда Макрокоманда DVM_DO_ON(n,r,vs,ls,hs,ss,base,rb,is,as,bs) расширяется в

    mappl_(&DVM_LP##n,  (PatternRef*)(base),
        is, as, bs, vs,  1,
        ls, hs, ss, DVM_LO##n, DVM_HI##n, DVM_ST##n);

Макрокоманда DVM_DOPL(n) расширяется в

    while(dopl_(&DVM_LP##n))

Макрокоманда DVM_FOR(n,v,k,lh) расширяется в

for(v=DVM_LO##n[k]; v<=DVM_HI##n[k]; v+=DVM_ST##n[k])

Макрокоманда DVM_REDBLACK(n,v,k,e,lh) расширяется в

for(v=DVM_LO##n[k]+(DVM_LO##n[k]+e)%2;v<=DVM_HI##n[k];v+=2)

Макрокоманда DVM_END_PARALLEL(n) расширяется в

    endpl_(&DVM_LP##n);}

3.2.2 Поддиректива ACROSS

Контекст и синтаксис. 

    DVM ( PARALLEL ... ; ACROSS array "["widths"]"... )

Выход компилятора. 

     dvm_parallel ... sub_directives
    DVM_ACROSS(loopid, (
        DVM_ACROSS_SH(a,k,ls,hs,corner)  // for each renewee
        ...
        ))
    { dvm_dopl
      loop-headers...
      loop-body
    }
    DVM_END_ACROSS()
    [ end_reduction ]
    dvm_end_parallel

Замечание. Макрокоманда DVM_ACROSS(loopid,shads) расширяется в

    {ShadowGroupRef DVM_LSG;
    ShadowGroupRef DVM_HSG;
    int DVM_LorH;
    DVM_LSG=crtshg_(0);
    DVM_HSG=crtshg_(0);
    DVM_LorH=1;
    shads;
    strtsh_(&DVM_HSG);
    waitsh_(&DVM_HSG);
    delshg_(&DVM_HSG);
    DVM_LorH=0;
    shads;
    recvsh_(&DVM_LSG);
    waitsh_(&DVM_LSG);

Макрокоманда DVM_END_ACROSS() расширяется в

    sendsh_(&DVM_LSG);
    waitsh_(&DVM_LSG);
    delshg_(&DVM_LSG);
    }

Макрокоманда DVM_ACROSS_SH(a,k,ls,hs,corner) расширяется в

    ((DVM_LorH ?
    inssh_(&DVM_HSG, a, 0, hs, corner)
    :inssh_(&DVM_LSG, a, ls, 0, corner) ),
    )

3.2.3 Директива PROCESSORS и функция NUMBER_OF_PROCESSORS()

Контекст и синтаксис. 

    DVM(PROCESSORS "["dim"]"...) void * proc_id ;

Выход компилятора. 

    PSRef proc_id;
    ...
    DVM_PROCESSORS(Iproc_id),r,dims);

Замечание.  Исходное описание заменено. Макрокоманда генерируется не в точке описания, а в общей последовательности неявных операций. Макрокоманда DVM_PROCESSORS(proc,r,dims) расширяется в

    {DVM_PS=getps_(NULL);
    proc=psview_(&DVM_PS, r, dims, 0);
    }

Макрокоманда NUMBER_OF_PROCESSORS() расширяется в

    (DVM_PS=getps_(NULL), getsiz_((ObjectRef*)&DVM_PS,0))

3.2.4 Директива TASK

Контекст и синтаксис. 

    DVM(TASK) void * task-id "["size"]"

Выход компилятора. 

    AMViewRef AMV_task-id;
    PSRef  task-id [ size ]={0};
    ...
    DVM_TASK(task-id,n);

Замечание. Исходное описание заменено. Макрокоманда генерируется не в точке описания, а в общей последовательности неявных операций.Макрокоманда DVM_TASK(id,n) расширяется в

    AMV_##id=crtamv_(getam_(), 1, n, 0);

3.2.5 Директива MAP

Контекст и синтаксис. 

    DVM(MAP task-id"["task_ind"]" ONTO proc-section );

Выход компилятора. 

    DVM_MAP(task,ind, [ DVM_ONTO(ps,k,ls,hs) ]) ;

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_MAP(task,ind,ps) расширяется в

    ps;
    task[ind]=DVM_PS;
    mapam_(getamr_(&AMV_##task,ind), &DVM_PS);

3.2.6 Директива TASK_REGION

Контекст и синтаксис. 

    DVM(TASK_REGION task-id)
    {
        ON-block... |  ON-loop
    }

Выход компилятора. 

    {DVM_TASKREGION(no,task);
    ...
    }

Замечание. Макрокоманда DVM_TASKREGION(no,task) расширяется в

    AMViewRef AMV_0;
    AMViewRef DVM_LP##no=AMV_##task;

3.2.7 Конструкция ON-block

Контекст и синтаксис. 

    DVM(ON task-id "["task-ind"]")
    {   C-statements   }

Выход компилятора. 

    if(DVM_RUN(task,ind))
        { statements
        DVM_STOP();
        }

Замечание. Макрокоманда DVM_RUN(task,ind) расширяется в

    runam_(getamr_(&AMV_##task,ind))

Макрокоманда DVM_STOP() расширяется в

    stopam_()

3.2.8 Конструкция ON-loop

Контекст и синтаксис. 

    DVM(PARALLEL "["var"]" ON task-id "["var"]")
    DO(var, ..., ..., ...)
        {   C-statements   }

Выход компилятора. 

    for(var=0; ...)
    if(DVM_RUN(task,var))
        { statements
        DVM_STOP();
        }

3.3 Теневые грани

3.3.1 Поддиректива SHADOW

Контекст и синтаксис. 

    DVM( DISTRIBUTE | ALIGN ...
             ; SHADOW "["widths"]"... )

Замечание.  В точке описания ничего не генерируется. Компилятор сохраняет значения widths как максимальную ширину граней. Эти значения используются при создании массива.

3.3.2 Поддиректива SHADOW_RENEW

Контекст и синтаксис. 

    DVM(PARALLEL ... ; SHADOW_RENEW renewee... ... )
    renewee ::=  array [ "["widhs"]"... ] [ CORNER ]

Выход компилятора. 

    DVM_SHADOW_RENEW(loop-number,
        (DVM_SHADOWS(a,k,ls,hs,corner), // for each renewee
        ...
        ))

Замечание. Это cокращение для последовательности операторов (директив) "CREATE_SHADOW_GROUP; SHADOW_START; SHADOW_WAIT;" с временной группой границ, выполненной перед циклом. Макрокоманда DVM_SHADOW_RENEW(n,das) расширяется в

    {ShadowGroupRef DVM_SG=crtshg_(0);
    das;
    strtsh_(&DVM_SG);
    waitsh_(&DVM_SG);
    delshg_(&DVM_SG); }

Макрокоманда DVM_SHADOWS(a,k,ls,hs,corner) расширяется в

    inssh_(&DVM_SG, a, ls, hs, corner)

3.3.3 Директива SHADOW_GROUP

Контекст и синтаксис. 

    DVM(SHADOW_GROUP) void * sh-group-id;

Выход компилятора. 

    ShadowGroupRef sh-group-id;

Замечание. Исходное описание заменено.

3.3.4 Директива CREATE_SHADOW_GROUP

Контекст и синтаксис. 

    DVM(CREATE_SHADOW_GROUP sh-group-id : renewee... );

Выход компилятора. 

    DVM_CREATE_SHADOW_GROUP( sh-group-id,
        (DVM_SHADOWS(a,k,ls,hs,corner), // for each renewee
        ...
        ))

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_CREATE_SHADOW_GROUP(sg,shads) расширяется в

    {ShadowGroupRef DVM_SG;
    if(sg!=0) delshg_(&sg);
    DVM_SG=crtshg_(0);
    shads;
    sg=DVM_SG;
    }

3.3.5 Директива SHADOW_START

Контекст и синтаксис. 

    DVM(SHADOW_START sh-group-id);

Выход компилятора. 

    DVM_SHADOW_START(sg);

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_SHADOW_START(sg) расширяется в

    strtsh_(&sg)

3.3.6 Поддиректива SHADOW_START

Контекст и синтаксис. 

    DVM(PARALLEL ... ; SHADOW_START sh-group-id ... ) ...

Выход компилятора. 

    DVM_PAR_SHADOW_START(n,sg); // in loop header

Замечание. Макрокоманда DVM_PAR_SHADOW_START(n,sg) расширяется в

    exfrst_(&DVM_LP##n,&sg)

3.3.7 Директива SHADOW_WAIT

Контекст и синтаксис. 

    DVM(SHADOW_WAIT sh-group-id);

Выход компилятора. 

    DVM_SHADOW_WAIT(sg);

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_SHADOW_WAIT(sg) расширяется в

    waitsh_(&sg)

3.3.8 Поддиректива SHADOW_WAIT

Контекст и синтаксис. 

    DVM(PARALLEL ... ; SHADOW_WAIT sh-group-id ...) ...

Выход компилятора. 

    DVM_PAR_SHADOW_WAIT(n,sg); // in loop header

Замечание. Макрокоманда DVM_PAR_SHADOW_WAIT(n,sg) расширяется в

    imlast_(&DVM_LP##n,&sg)

3.4 Удаленный доступ

3.4.1 Директива и поддиректива REMOTE_ACCESS

Контекст и синтаксис. 

    DVM(REMOTE_ACCESS ra-reference...)
        C-statement
    DVM(PARALLEL ... ;
        REMOTE_ACCESS [ ra-group : ] ra-reference...
        ...) ...
    ra-reference ::= array [ "["[expr]"]"... ]

Выход компилятора. 

    DVM_BLOCK_BEG();
    DVM_REMOTE20(arr,buf,k,as,bs);
    statements using remote referencies
    DVM_BLOCK_END();

Замечание. Макрокоманда DVM_REMOTE20(arr,buf,k,as,bs) расширяется в

    {static long buf[2*k+2];
    crtrbl_(arr, buf, NULL, 0, NULL, 1, as, bs);
    loadrb_(buf, 1);
    waitrb_(buf);}

Макрокоманда DVM_REMOTE20G(n,rg,arr,buf,k,is,as,bs) расширяется в

    if(RMG_##rg==1) {waitbg_(&rg); RMG_##rg=2;}
    if(RMG_##rg==0)
        {crtrbl_(arr, buf, NULL, 1, &DVM_LP##n, is, as, bs);
        loadrb_(buf, 1);
        waitrb_(buf);
        if(rg==0) {rg=crtbg_(1, 1);}
        insrb_(&rg, buf);
        }

3.4.2 Директива REMOTE_GROUP

Контекст и синтаксис. 

    DVM(REMOTE_GROUP) void * ra-group-id;

Выход компилятора. 

    RegularAccessGroupRef ra-group-id;
    long  RMG_ra-group-id;

Замечание. Исходное описание заменено. Для операций PREFETCH и RESET требуется вспомогательная переменная, управляющая операциями обновления буферов.

3.4.3 Директива PREFETCH

Контекст и синтаксис. 

    DVM(PREFETCH ra-group-id );

Выход компилятора. 

    DVM_PREFETCH(rg);

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_PREFETCH(rg) расширяется в

    if(rg==0) {RMG_##rg=0;}
    else {loadbg_(&rg, 1);
        RMG_##rg=1;
        }

3.4.4 Директива RESET

Контекст и синтаксис. 

    DVM(RESET ra-group-id );

Выход компилятора. 

    DVM_RESET(rg);

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_RESET(rg) расширяется в

    delbg_(&rg);
    rg=0;
    RMG_##rg=0;

3.4.5 Удаленные ссылки

Удаленные ссылки заменяются на ссылки к соответствующему буферу.

3.5 Редукционные операции

3.5.1 Директива REDUCTION_GROUP

Контекст и синтаксис. 

    DVM(REDUCTION_GROUP) void * red-group-id;

Выход компилятора. 

    RedGroupRef red-group-id;

Замечание. Исходное описание заменено.

3.5.2 Поддиректива REDUCTION

Контекст и синтаксис. 

    DVM( PARALLEL | TASK_REGION ... ;
        REDUCTION [ red-group-id : ] red-operation...
        ... ) ...

Выход компилятора. 

    DVM_CREATE_RG(rg, (
        DVM_RVAL(...) | DVM_RLOC(...)  // for each operation
        ...
        ));
        loop creation and mapping
    DVM_REDUCTION20(loopid,rg);       // insert to the group
        loop headers and body
    [ DVM_END_REDUCTION(); ]          // synchronous reduction

Замечание. Макрокоманда DVM_CREATE_RG(rg,rvs) расширяется в

    if(rg==0) rg=crtrg_(1,1);
    (void)rvs;

Макрокоманда DVM_REDUCTION(loopid,rvs) расширяется в

    { RedGroupRef DVM_RG;
    LoopRef DVM_LP0=0;
    PSSpaceRef DVM_PSSpace=DVM_LP##loopid;
    DVM_RG=crtrg_(1, 1);
    (void)rvs;
    DVM_INSERT_RV();

Макрокоманда DVM_REDUCTION20(loopid, rg) расширяется в

    { RedGroupRef DVM_RG=rg;
    LoopRef DVM_LP0=0;
    PSSpaceRef DVM_PSSpace=DVM_LP##loopid;
    DVM_INSERT_RV();
    rg=DVM_RG;}

Макрокоманда DVM_INSERT_RV() расширяется в

    while(CDVM_TOP!=CDVM_BOTTOM) {
    insred_( &DVM_RG, (RedRef*)CDVM_TOP, &DVM_PSSpace, 1);
    }

Макрокоманда DVM_END_REDUCTION() расширяется в

    {strtrd_(&DVM_RG);
    waitrd_(&DVM_RG);
    delrg_(&DVM_RG);}
    }

3.5.3 Редукционные переменные и операции

Контекст и синтаксис. 

    DVM(...; REDUCTION ... MAX(red-var) ... )
    DVM(...; REDUCTION ... MIN(red-var) ... )
    DVM(...; REDUCTION ... SUM(red-var) ... )
    DVM(...; REDUCTION ... PROD(red-var) ... )
    DVM(...; REDUCTION ... AND(red-var) ... )
    DVM(...; REDUCTION ... OR(red-var) ... )
    DVM(...; REDUCTION ... MAXLOC(red-var,loc-var) ... )
    DVM(...; REDUCTION ... MINLOC(red-var,loc-var) ... )

Выход компилятора. 

    DVM_RVAR(rf_MAX,var,t,l)
    DVM_RVAR(rf_MIN,var,t,l)
    DVM_RVAR(rf_SUM,var,t,l)
    DVM_RVAR(rf_PROD,var,t,l)
    DVM_RVAR(rf_AND,var,t,l)
    DVM_RVAR(rf_OR,var,t,l)
    DVM_RLOC(rf_MAX,var,t,l,loc-var)
    DVM_RLOC(rf_MIN,var,t,l,loc-var)

Замечание. Параметр t -- это код типа переменной (rt_INT, rt_LONG, rt_FLOAT, rt_DOUBLE). Параметр l -- это число элементов в red-var (если это массив) или 1. Макрокоманда DVM_RVAR(f,v,t,l) расширяется в

    crtred_(f, &(v), t, l, 0, 0, 1)

Макрокоманда DVM_RLOC(f,v,t,l,loc) расширяется в

    crtred_(f, &(v), t, l, &(loc), sizeof(loc), 1)

3.5.4 Директива REDUCTION_START

Контекст и синтаксис. 

    DVM(REDUCTION_START red-group-id);

Выход компилятора. 

    DVM_REDUCTION_START(red-group-id);

Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REDUCTION_START(rg) расширяется в

    strtrd_((RedGroupRef*) &rg)

3.5.5 Директива REDUCTION_WAIT

Контекст и синтаксис. 

    DVM(REDUCTION_WAIT red-group-id);

Выход компилятора. 

    DVM_REDUCTION_WAIT(red-group-id);

Замечание.  Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REDUCTION_WAIT(rg) расширяется в

    waitrd_((RedGroupRef*) &rg);
    delrg_((RedGroupRef*) &rg);
    rg=0;

3.6 Неявные конструкции

3.6.1 Создание и удаление распределенных массивов

Контекст и синтаксис. 

    array = malloc(dim1 *...* dimr * elem-size);
    free( array );

Выход компилятора. Генерируются все или часть следующих операторов в зависимости от описания массива array.

  [ DVM_CREATE_TEMPLATE(am,t,r,di); // implicit template   ]
  [ DVM_ONTO(ps,k,ls,hs);           // target system       ]
  [ DVM_DISTRIBUTE(amv,ps,k,axs);   // distribute template ]
  [ DVM_GENBLOCK(am,ps,k,gbs);      // GENBLOCK parameters ]
    DVM_MALLOC(arr,r,len,dim,lw,hw,redis) // initialize array handler
  [ DVM_ALIGN(arr,base,k,i,a,b)     // align with template ]

Замечание. Макрокоманда DVM_MALLOC(arr,r,len,dim,lw,hw,redis) расширяется в

    {crtda_( arr, 0, NULL, r, len, dim, 0, redis, lw, hw );
    }

Макрокоманда DVM_ALIGN(arr,base,k,i,a,b) расширяется в

    {align_( arr, &(base), i, a, b);
    }

Макрокоманда DVM_FREE(arr) расширяется в

    (delda_(arr));

3.6.2 Статические распределенные массивы

Контекст и синтаксис. 

    DVM(DISTRIBUTE | ALIGN...)
        element-type array-id "["const-dim"]"...;

Выход компилятора. Стандартная последовательность создания массива как и в случае malloc.

Замечание.  Для глобальных описаний неявный malloc вставляется в начало функции main. Для локальных -- перед первым оператором блока.

3.6.3 Доступ к распределенным данным

Контекст и синтаксис.  Обычные ссылки на элементы массивов array[ind1]...[indr] с распределенным array. Допускается также специальная форма ссылок в виде макрокоманд array(ind1,...,indr) для моделирования динамических массивов.

Выход компилятора. 

    DAElm<r>(type,array-id,ind1,...indr)

Замечание. Это макрокоманды RTL.

3.6.4 Собственные вычисления

Контекст и синтаксис. 

        lhs=rhs; // assignement

Выход компилятора. 

    if(DVM_ISLOCAL(lhs)) {
        lhs = rhs ; }
    DVM_ENDLOCAL();

Замечание. Оператор собственных вычислений это присваивание распределенному массиву в нераспределенной ветки программы. Оно должно "охраняться" проверкой локальности элемента.
Макрокоманда DVM_ISLOCAL(a,r,ind) расширяется в

    tstelm_(a, ind)

Макрокоманда DVM_ENDLOCAL() расширяется в

    dskpbl_()

3.6.5 Инициализация и завершение параллельного выполнения

Контекст и синтаксис. 

    int main( int argc, char ** arg)
    {
        declarations...
        first-statement
        ...
        [ exit(rc); ]
        ...
        return rc;
    }

Выход компилятора. 

    int main( int argn, char ** args)
    {
        declarations...
        DVM_INIT(0,argn,args); // initialization of RTL
        [ implicit static array creation ]
        [ tracing of initialized variables ]
        [ other implicit actions ]
        first-statement
        ...
        [ DVM_EXIT(rc); ]  // exit through RTL
        ...
        DVM_RETURN(rc);    // exit through RTL
    }

Замечание. Для генерации корректной программы функция main должна принимать параметры командной строки (которые затем будут переданы RTL) и должна завершаться оператором return или exit. Макрокоманда DVM_INIT(argn,args) расширяется в

    {rtl_init(0L,argn,args);
    }

Макрокоманда DVM_RETURN(r) расширяется в

    {lexit_(r);}

Макрокоманда DVM_EXIT(r) расширяется в

    {lexit_(r);}

3.6.6 Функции ввода-вывода

Компиляция функций ввода-вывода сводится к переименованию функции iofun на ее RTL аналог dvm_iofun. Единственным исключением являются функции fread() и fwrite(), когда они применяются к распределенному массиву. В это случае массив читается или пишется целиком. Остальные параметры игнорируются.

3.7 Отладочные расширения

3.7.1 Анализатор производительности. Циклы

Контекст и синтаксис. 

    [ DVM(PARALLEL... ) ]
        DO(var,first,last,step)    // or
        FOR(var,times)
            loop-body

Выход компилятора. 

    BPLOOP(n)  // for parallel loop or
    BSLOOP(n)  // for sequential loop
        code for loop
    ELOOP(n)

Замечание. Параметр n это порядковый номер цикла для идентификации парных команд.Множество циклов, для которых генерируются эти макрокоманды, зависит от параметров командной строки (-e1 ... -e4).
Макрокоманда DVM_BPLOOP(n) расширяется в

    bploop_(n);

Макрокоманда DVM_BSLOOP(n) расширяется в

    bsloop_(n);

Макрокоманда DVM_ELOOP(n) расширяется в

    eloop_(n, line);

3.7.2 Анализатор производительности. Интервалы

Контекст и синтаксис. 

    DVM(INTERVAL  [ int-expr ] )
    { C-statements }

Выход компилятора. 

    DVM_BINTER(n,v)
      { code for statements }
    DVM_EINTER(n)

Замечание. Параметр n это порядковый номер цикла для идентификации парных команд. Если int-expr отсутствует, то параметр v будет иметь некоторое стандартное значение. Макрокоманда DVM_BINTER(n,v) расширяется в

    binter_(n, v)

Макрокоманда DVM_EINTER(n) расширяется в

    einter_(n,line )

3.7.3 Отладчик. Трассировка данных

Контекст и синтаксис.  Любая ссылка на обычную или распределенную переменную var в операторах СИ или инициализация переменной.

Выход компилятора. 

    DVM_STVA(type,rt,var,base,rhs)  // lh-side of assignement
    DVM_LDV(type,rt,var,base)  // for read access
    DVM_STV(type,rt,var,base)  // to register initialization

Замечание. Множество ссылок, для которых генерируются эти макрокоманды, зависит от параметров командной строки (-d1 ... -d4). Макрокоманда DVM_LDV(type,rt,var,base) расширяется в

    *(type*) ( ( DVM2A((long)&(var),rt) &&
    dldv_(&CDVM_TOP[1],
        (AddrType *)&CDVM_TOP[0],
        (long *) base, #var, -1) && 0) ? 0 :
    )

Макрокоманда DVM_STV(type,rt,var,base) расширяется в

    ( DVM2A((long)&(var), rt),
    dprstv_(&CDVM_TOP[1], (AddrType *)&CDVM_TOP[0],
    (long *) base, #var, -1),
    dstv_())

Макрокоманда DVM_STVA(type,rt,var,base,rhs) расширяется в

    ( DVM2A((long)&(var), rt),
    dprstv_(&CDVM_TOP[1], (AddrType *)&CDVM_TOP[0],
    (long *) base, #var, -1),
    (*(type *)(CDVM_TOP[0]) = rhs),
    dstv_())

Такая ужасная конструкция появилась в результе попытки переноса под MS Visual-C 5.0. -- Необычный порядок вычисления операции-запятая.

3.7.4 Отладчик. Трассировка вычислений

Контекст и синтаксис.  Любой цикл или конструкция TASK_REGION.

Выход компилятора. 

        parallel loop creation
    DVM_PLOOP(n,r,ls,hs,ss)   // or DVM_SLOOP(n)
        loop-headers
    DVM_ITER(r,vars)
        code for loop body
    DVM_ENDLOOP(n)

для цикла или

    DVM_BTASK(n)     // in TASK_REGION header
        ...
    DVM_ETASK(n)
        ON-block or ON-loop body
        ...
    DVM_NTASK(ind)   // end of TASK_REGION construct

для конструкции TASK_REGION.

Замечание.  Макрокоманда DVM_PLOOP(n,r,ls,hs,ss) расширяется в

    dbegpl_(r, n, ls, hs, ss);

Параметры те же, что задавались при создании цикла.
Макрокоманда DVM_SLOOP(n) расширяется в

    dbegsl_(n);

Макрокоманда DVM_ENDLOOP(n) расширяется в

    dendl_(n, line);

Макрокоманда DVM_ITER(r,vars) расширяется в

    diter_(vars, NULL );

Макрокоманда DVM_BTASK(n) расширяется в

    dbegtr_(n);

Макрокоманда DVM_ETASK(n) расширяется в

    dendl_(n, );

Макрокоманда DVM_NTASK(ind) расширяется в

    diter_(ind, 0);

3.7.5 Пoследовательный код

Генерация последовательной программы задается параметром -s командной строки. Все DVM-директивы игнорируются за исключением следующих:

Заметим, что препроцессорные операторы #define должны оставаться на месте в отличие от параллельного кода, в котором они должны переноситься в начало файла.