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