<=C-DVM - детальный дизайн (начало)

Компилятор C-DVM. Детальный дизайн (продолжение)
* 22 June 2000 *


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

Парсер строит внутреннее представление программы. Конструктор восстанавливает внешнее представление дерева. Собственно компиляция выполняется многочисленными семантическими программами. Головная семантическая программа это функция ISWF. Она вызывается парсером дважды для каждого узла. Конкретные семантические действия зависят от кода узла (т.е. от кода синтаксического правила.) Первый (нисходящий) вызов выполняется, когда парсер пытается применить некоторое синтаксическое правило, т.е. до начала разбора конструкции. В основном это проверки контекста. (Заметим, что до разбора некоторого оператора или описания предшествующая ему DVM-директива уже разобрана. В этом случае функция Allowed проверяет совместимость директивы, оператора и контекста.) В этот момент могут быть зафиксированы ошибки:

Кроме проверки контекста могут быть выполнены и другие действия:

Второй (и последний -- восходящий) вызов выполняется, когда (и если) правило успешно сопоставлено. В этот момент вызывается соответствующая семантическая функция, которая проверит семантическую правильность конструкции и построит поддерево для выходной программы. Это описывается ниже для всех конструкций C-DVM.

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

3.1.1 Директива DISTRIBUTE

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

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

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

    long array-id [ rank+1 ];

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

Реализация. 

Функция  wfDISTRIBUTE()  проверяет только формат распределения. Остальные части директивы уже обработаны. Допустимость в данном контексте и корректность описания будет проверена позже функцими Allowed, ISWFdcltr и ISWFdecl. Ссылка на описание сохраняется в списке описаний текущей области видимости функцией addDecl.

Функция  crHandler(dd,decl)  заменяет тип и декларатор массива на тип и декларатор хендлера массива.

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

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

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

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

    DVM_GENBLOCK(am,ps,k,gbs);

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

Реализация. 

Функция  wfGENBLOCK()  проверяет параметр формата распределения GENBLOCK и выдает сообщение, если

Требуемые поддеревья строит функция  mk_genblock. Она использует функцию GENaxis(N) для построения списка адресов массивов параметров.

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

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

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

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

    DVM_ONTO(ps,k,ls,hs)

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

Реализация. 

Функция  wfONTO  проверяет ONTO-target и выдает сообщение, если

Требуемые поддеревья строит функция  crONTO и сохраняет их как атрибут "ONTO" для последующего использования.

3.1.4 Директива REDISTRIBUTE

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

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

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

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

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfREDISTRIBUTE  проверяет array и выдает сообщение, если

Требуемые поддеревья строит функция  mk_alloc2, если формат распределения не был указан в описании массива. Функция  wfREDISTRIBUTE  использует также поддеревья, построенные для ONTO и GENBLOCK.

3.1.5 Директива ALIGN

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

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

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

    long array-id [ rank+1 ];

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

Реализация. 

Функция  wfDVMind  проверяет список dummy-var и выдает сообщение, если найдены повторяющиеся переменные. Функция  wfDVMbind  проверяет список align-expr и выдает сообщение, если

Функция  wfDVMbase  проверяет base и выдает сообщение, если

Допустимость в данном контексте и корректность описания будет проверена позже функцими Allowed, ISWFdcltr и ISWFdecl. Ссылка на описание сохраняется в списке описаний текущей области видимости функцией addDecl.

Функция  crHandler(dd,decl)  заменяет тип и декларатор массива на тип и декларатор хендлера массива.

3.1.6 Директива REALIGN

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

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

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

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

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfREALIGN  проверяет array и выдает сообщение, если

Остальные части директивы проверяются как для директивы ALIGN.

Требуемые поддеревья строит функция  wfREALIGN

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

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

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

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

    AMViewRef template-id;

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что template-id описан как void *, и выдает сообщение, если это не так. Функция  wfTEMPLATE  проверяет параметр поддирективы и выдает сообщение, если ранги не совпадают.

Функция  crRef(N,type)  заменяет тип "void*" на тип "AMViewRef".

3.1.8 Директива CREATE_TEMPLATE

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

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

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

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

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLX_CRTEMP  проверяет директиву и выдает сообщение, если

Требуемые поддеревья строит функция  mk_templ(amv,dims,dir).

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);
    }

Реализация. 

Ядро директивы проверяются как для директивы ALIGN. Функция  wfDVMvar  проверяет список loop-var , сравнивая его с заголовками цикла, и выдает сообщение, если он не состоит из всех переменных цикла или содержит их не в том порядке.

Требуемые поддеревья строит функция  pLoop. Она также вставляем в нужные места оболочки параллельного цикла поддеревья, построенные для поддиректив.

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

Реализация. 

Функция  wfDVMshw()  проверяет список границ и выдает сообщение, если:

Функция  wfDVMshad()  проверяет renewee и выдает сообщение, если CORNER указан для одномерного массива (предупреждение).

Требуемые поддеревья строит функция  wfACROSS. Окончательное построение выполняется функцией Ploop, когда цикл полностью разобран. Она вставляет ранее построенное поддерево в нужное место оболочки параллельного цикла.

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

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

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

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

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

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что proc-id описан как void *, и выдает сообщение, если это не так. Функция  ISWFdclr  строит также поддерево для макрокоманды DVM_PROCESSORS и с помощью функции addIMloc сохраняет его во временном глобальном или локальном списке. Операторы будут вставлены в нужное место функцией genIMglob или genIMloc.

Функция  crRef(N,type)  заменяет тип "void*" на тип "PSRef".

3.2.4 Директива TASK

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

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

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

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

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что task-id описан как void *, и выдает сообщение, если это не так. Функция  ISWFdclr  строит также поддерево для макрокоманды DVM_TASK и с помощью функции addIMloc сохраняет его во временном глобальном или локальном списке. Операторы будут вставлены в нужное место функцией genIMglob или genIMloc

Функция  crRef(N,type)  заменяет тип "void*" на тип "PSRef" и порождает описание переменной для представления АМ AMV_.... Функция  crAMVdcltrs(N)  порождает ее декларатор.

3.2.5 Директива MAP

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

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

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

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

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Требуемые поддеревья строит функция  wfMAP, используя поддерево, построенное для предложения ONTO.

3.2.6 Директива TASK_REGION

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

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

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

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

Реализация. 

Функция  wfTASKREGION  проверяет составной оператор. Все его операторы должны быть ON-блоками, либо он должен состоять из единственного оператора -- ON-цикла. Затем эта же функция строит требуемые поддеревья, в том числе для поддирективы REDUCTION и для отладчика (опция -dx).

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

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

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

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

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

Реализация. 

Функция  wfLXItask  проверяет task-id и выдает сообщение, если он не определен или не специфицирован как TASK.

Требуемые поддеревья строит функция  mkRUNAM().

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();
        }

Реализация. 

Функция  wfLXItask  проверяет task-id и выдает сообщение, если он не определен или не специфицирован как TASK.

Требуемые поддеревья строит функция  mkRUNAM().

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

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

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

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

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

Реализация. 

Функция  wfSHADOW  проверяет список границ и выдает сообщение, если ранги не совпадают.

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;" с временной группой границ, выполненной перед циклом.

Реализация. 

Функция  wfDVMshw()  проверяет список границ и выдает сообщение, если:

Функция  wfDVMshad()  проверяет renewee и выдает сообщение, если CORNER указан для одномерного массива (предупреждение).

Требуемые поддеревья строит функция  wfSHRENEW. Окончательное построение выполняется функцией Ploop, когда цикл полностью разобран. Она вставляет ранее построенное поддерево в нужное место оболочки параллельного цикла.

3.3.3 Директива SHADOW_GROUP

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

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

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

    ShadowGroupRef sh-group-id;

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что sh-group-id описан как void *, и выдает сообщение, если это не так.

Функция  crRef(N,type)  заменяет тип "void*" на тип "ShadowGroupRef".

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
        ...
        ))

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfDVMshw()  проверяет список границ и выдает сообщение, если:

Функция  wfDVMshad()  проверяет renewee и выдает сообщение, если CORNER указан для одномерного массива (предупреждение).

Требуемые поддеревья строит функция  wfLX_CRSG. Она использует следующие функции:

3.3.6 Директива SHADOW_START

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

    DVM(SHADOW_START sh-group-id);

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

    DVM_SHADOW_START(sg);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIsg  проверяет sh-group-id и выдает сообщение, если он не определен или не специфицирован как SHADOW_GROUP.

Требуемые поддеревья строит функция  wfSHSTART().

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

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

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

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

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

Реализация. 

Функция  wfLXIsg  проверяет sh-group-id и выдает сообщение, если он не определен или не специфицирован как SHADOW_GROUP.

Требуемые поддеревья строит функция  wfSHSTART(). Окончательное построение выполняется функцией Ploop, когда цикл полностью разобран. Она вставляет ранее построенное поддерево в нужное место оболочки параллельного цикла.

3.3.8 Директива SHADOW_WAIT

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

    DVM(SHADOW_WAIT sh-group-id);

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

    DVM_SHADOW_WAIT(sg);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIsg  проверяет sh-group-id и выдает сообщение, если он не определен или не специфицирован как SHADOW_GROUP.

Требуемые поддеревья строит функция  wfSHWAIT().

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

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

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

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

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

Реализация. 

Функция  wfLXIsg  проверяет sh-group-id и выдает сообщение, если он не определен или не специфицирован как SHADOW_GROUP.

Требуемые поддеревья строит функция  wfSHWAIT(). Окончательное построение выполняется функцией Ploop, когда цикл полностью разобран. Она вставляет ранее построенное поддерево в нужное место оболочки параллельного цикла.

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();

Реализация. 

Функция  wfREMOTE()  проверяет индексные выражения и выдает сообщение, если они некорректны. Она также сохраняет информацию, необходимую для распознавания и преобразования удаленных ссылок.

Требуемые поддеревья строит функция  mk_remote(dir,oper). Она использует функции:

3.4.2 Директива REMOTE_GROUP

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

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

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

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

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что ra-group-id описан как void *, и выдает сообщение, если это не так.

Функция  crRef(N,type)  заменяет тип "void*" на тип "RegularAccessGroupRef" и порождает описание вспомогательной переменной "RMG_...". Функция  crRMGdcltrs(N)  генерирует ее декларатор.

3.4.3 Директива PREFETCH

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

    DVM(PREFETCH ra-group-id );

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

    DVM_PREFETCH(rg);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIag  проверяет ra-group-id и выдает сообщение, если он не определен или не специфицирован как REMORE_GROUP.

Требуемые поддеревья строит функция  wfPREFETCH().

3.4.4 Директива RESET

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

    DVM(RESET ra-group-id );

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

    DVM_RESET(rg);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIag  проверяет ra-group-id и выдает сообщение, если он не определен или не специфицирован как REMORE_GROUP.

Требуемые поддеревья строит функция  wfRESET().

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

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

Реализация. 

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

3.5.1 Директива REDUCTION_GROUP

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

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

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

    RedGroupRef red-group-id;

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

Реализация. 

Функция  ISWFdcltr  проверяет (кроме прочего), что red-group-id описан как void *, и выдает сообщение, если это не так.

Функция  crRef(N,type)  заменяет тип "void*" на тип "RedGroupGroupRef".

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

Реализация. 

Требуемые поддеревья строит функция  wfREDUCTION, а именно, создается список макрокоманд DVM_RVAR или DVM_RLOC для всех редукционных операций в директиве. Окончательное построение выполняется функцией Ploop, когда цикл полностью разобран. Она вставляет ранее построенное поддерево в нужное место оболочки параллельного цикла, в зависимости от того, является ли редукция синхронной или асинхронной.

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.

Реализация. 

Функция  cRG0()  строит макрокоманду DVM_RVAR или DVM_RLOC для одной операции в списке. Ее первый параметр -- имя операции -- порождается функцией rts_name(t). Функция  cRG(Ad,N)  создает список макрокоманд для всех операций в директиве.

3.5.4 Директива REDUCTION_START

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

    DVM(REDUCTION_START red-group-id);

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

    DVM_REDUCTION_START(red-group-id);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIrg  проверяет red-group-id и выдает сообщение, если он не определен или не специфицирован как REDUCTION_GROUP.

Требуемые поддеревья строит функция  wfRSTART().

3.5.5 Директива REDUCTION_WAIT

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

    DVM(REDUCTION_WAIT red-group-id);

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

    DVM_REDUCTION_WAIT(red-group-id);

Замечание.  Выполнимая директива конвертируется в оператор.

Реализация. 

Функция  wfLXIrg  проверяет red-group-id и выдает сообщение, если он не определен или не специфицирован как REDUCTION_GROUP.

Требуемые поддеревья строит функция  wfRWAIT().

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 ]

Реализация. 

Функция  ISWF  проверяет параметр malloc, левую часть присваивания и выдает сообщение, если:

Требуемые поддеревья строит функция  mk_alloc(lhs,parm). Она вызывает функции mk_templ и mk_genblock, и использует поддерево, построенное для предложения ONTO директивы DISTRIBUTE.

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

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

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

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

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

Реализация. 

Функция  ISWFdcltr  (кроме прочего) определяет, не является ли декларатор "статическим". В этом случае она строит поддерево для неявного создания и с помощью функции addIMloc сохраняет его во временном глобальном или локальном списке и выдает сообщение, если точка вставки уже пройдена. Операторы будут вставлены в нужное место функцией genIMglob или genIMloc

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

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

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

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

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

Реализация. 

Функция  ISWFaccess(N)  проверяет ссылку на распределенные данные и выдает сообщение, если

Она использует функции:

Если это корректная ссылка на элемент распределенного массива, эта же функция строит ссылку в форме, требуемой RTL. Функция  mk_datype(N,type)  порождает первый параметр макрокоманды DAElmx -- тип как идентификатор. Функция  mk_daind(N,type,lbk)  преобразует ссылку на распределенный массив в список остальных параметров макрокоманды.

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

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

        lhs=rhs; // assignement

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

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

Замечание.  Оператор собственных вычислений это присваивание распределенному массиву в нераспределенной ветки программы. Оно должно "охраняться" проверкой локальности элемента.

Реализация. 

Требуемые поддеревья строит функция  mk_local(N), когда это необходимо (т.е. если ссылка в левой части присваивания может оказаться нелокальной). Если это так, то выдается (слабое) предупреждение. (Чтобы его получить, нужно задать опцию -w.) Функция  mk_ind_list(N)  используется для создания списка индексных выражений.

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.

Реализация. 

Функция  isMain(N)  определяет, не является ли текущее определение определением функции main. Функция  Arg(N)  извлекает параметры и выдает сообщение, если если они не указаны.

Требуемые поддеревья строит функция  wfRETURN(), а также функция ISWF непосредственно перед вызовом функции genIMglob().

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

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

Реализация. 

Замена идентификаторов выполняется на шаге преобразования той же функцией pSUBST. Она использует список пар идентификаторов. Этот список строится в списковой памяти на шаге инициализации функцией RenInit(). Функция  RenPair(a,b)  записывает одну пару в список.

Список переименования содержит следующие идентификаторы:

   идентификатор СИ -- идентификатор C-DVM
        exit            DVM_EXIT
        FILE            DVMFILE
        clearerr        dvm_clearerr
        fclose          dvm_fclose
        feof            dvm_feof
        ferror          dvm_ferror
        fflush          dvm_fflush
        fgetc           dvm_fgetc
        fgetpos         dvm_fgetpos
        fgets           dvm_fgets
        fopen           dvm_fopen
        fprintf         dvm_void_fprintf
        fputc           dvm_fputc
        fputs           dvm_fputs
        fread           dvm_fread
        freopen         dvm_freopen
        fscanf          dvm_fscanf
        fseek           dvm_fseek
        fsetpos         dvm_fsetpos
        ftell           dvm_ftell
        fwrite          dvm_fwrite
        getc            dvm_getc
        getchar         dvm_getchar
        gets            dvm_gets
        printf          dvm_void_printf
        putc            dvm_putc
        putchar         dvm_putchar
        puts            dvm_puts
        rewind          dvm_rewind
        scanf           dvm_scanf
        setbuf          dvm_setbuf
        setvbuf         dvm_setvbuf
        tmpfile         dvm_tmpfile
        ungetc          dvm_ungetc
        vfprintf        dvm_void_vfprintf
        void_vprintf    dvm_void_vprintf
        vprintf         dvm_vprintf
        fgetchar        dvm_fgetchar
        fputchar        dvm_fputchar
        vfscanf         dvm_vfscanf
        vscanf          dvm_vscanf
        STDIN           DVMSTDIN
        STDOUT          DVMSTDOUT
        STDERR          DVMSTDERR
        STDAUX          DVMSTDAUX
        STDPRN          DVMSTDPRN
        remove          dvm_remove
        rename          dvm_rename
        tmpnam          dvm_tmpnam
        access          dvm_access
        unlink          dvm_unlink
        stat            dvm_stat

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).

Реализация. 

Требуемые поддеревья строит функция  Ploop() в зависимости от параметров командной строки.

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

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

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

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

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

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

Реализация. 

Требуемые поддеревья строит функция  interval(N) в зависимости от параметров командной строки.

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).

Реализация. 

Это последнее действие функции ISWFaccess, которая вызывает функцию cDTscal или cDTarr, чтобы перестроить уже построенное дерево RTL ссылки. Еще одно преобразование будет выполнено функцией stv2stva для оператора присваивания; а именно, макрокоманда будет преобразована в DVM_STVA.

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.

Реализация. 

Требуемые поддеревья строит функция  Ploop() для параллельного цикла и функция wfTASKREGION для блока TASK_REGION в зависимости от параметров командной строки.

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

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

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

Реализация. 

Опция командной строки -s сохраняется в переменной OPTs, которая управляет генерацией всех конструкций. При наличии этой опции почти все макрокоманды (с указанными выше исключениями) генерируются как пустые операторы, а все описания остаются неизменными.