Компилятор C-DVM |
Содержание
2
Последовательность компиляции
3
Компиляция конструкций C-DVM
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.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.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.1 Директива и поддиректива REMOTE_ACCESS
3.4.2 Директива REMOTE_GROUP
3.4.3 Директива PREFETCH
3.4.4 Директива RESET
3.4.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.1 Создание и удаление распределенных массивов
3.6.2 Статические распределенные массивы
3.6.3 Доступ к распределенным данным
3.6.4 Собственные вычисления
3.6.5 Инициализация и завершение параллельного выполнения
3.6.6 Функции ввода-вывода
3.7.1 Анализатор производительности. Циклы
3.7.2 Анализатор производительности. Интервалы
3.7.3 Отладчик. Трассировка данных
3.7.4 Отладчик. Трассировка вычислений
3.7.5 Пoследовательный код
C-DVM является расширением языка СИ специальными аннотациями для задания параллельного выполнения программы. Аннотации называются DVM-директивами. Компилятор C-DVM транслирует аннотированную программу в SPMD программу, которая содержит вызовы системы поддержки DVM (RTL).
Кроме чисто параллельного кода компилятор должен уметь cоздавать расширенный отладочный код для использования возможностей анализатора производительности (PPPA) и отладчика, а также последовательный код (без вызовов RTL и, тем самым, без распараллеливания) с такими же отладочными расширениями.
Для распараллеливания компилятор должен распознавать следующие четыре типа конcтрукций и выполнять соответствующие действия и преобразования программы:
- создание и уничтожение распределенных массивов;
- доступ к распределенным данным;
- функции ввода-вывода;
- инициализация и завершение параллельного выполнения;
- собственные вычисления;
- последовательные циклы.
Для анализатора производительности компилятор должен обрабатывать:
Эти действия реализуются вызовами соответствующих функций анализатора.
Для отладчика компилятор должен обеспечить:
Все это реализуется вызовами соответствующих функций отладчика. Точка регистрации инициализированных переменных определяется компилятором.
Режим последовательного выполнения нужен для получения временных характеристик исходной программы и "эталонной" трассировки для отладки в режиме сравнения трассировки. В этом режиме все DVM-директивы игнорируются за исключением следующих:
Компиляция C-DVM программы выполняется в следующей последовательности.
Для удобства и большей гибкости сгенерированная программа не содержит прямых вызовов функций RTL. Она содержит макрокоманды со всей необходимой информацией, скрывающие низкоуровневые детали интерфейса RTL. Окончательная генерация выполняется препроцессором СИ с использованием макроопределений, содержащихся в файле cdvm_c.h.
Необходимость преобразования программы для параллельного выполнения вызвана распределением данных и вычислений.
Распределение данных состоит в разбиении массивов на части и размещении этих частей в локальной памяти разных процессоров. На каждом процессоре RTL определяет размер локальной части (с учетом теневых граней) и выделяет память для неё. Для программы эта локальная часть массива доступна через хендлер массива. Следовательно, исходные последовательные операторы для создания массива и доступа к его элементам должны быть найдены в исходном коде и заменены.
Распределение вычислений состоит в разбиении индексного пространства цикла на части и выполнения на разных процессорах разных множеств витков цикла. На каждом процессоре локальная часть параллельного цикла описывается дескриптором цикла. Т.о. заголовки цикла должны быть преобразованы.
В этом разделе описаны эти и другие преобразования конструкций C-DVM, выполняемые компилятором.
Контекст и синтаксис.
DVM( ["*"] DISTRIBUTE [ format...] [ ONTO target ] [ ; SHADOW-clause ] [ ; TEMPLATE-clause ] ) C-declaration ;
Выход компилятора.
long array-id [ rank+1 ];
Замечание. Исходное описание заменено. Вся прочая информация из описания и директивы будет использоваться при генерации других конструкций и при распознавании ссылок к распределенным данным.
Контекст и синтаксис.
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);
Контекст и синтаксис.
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);
Контекст и синтаксис.
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); }
Контекст и синтаксис.
DVM(["*"] ALIGN [ "["dummy-var"]"... ] WITH base "["align-expr"]"... [ ; SHADOW-clause ] ) C-declaration ;
Выход компилятора.
long array-id [ rank+1 ];
Замечание. Исходное описание заменено. Вся прочая информация из описания и директивы будет использоваться при генерации других конструкций и при распознавании ссылок к распределенным данным.
Контекст и синтаксис.
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); }
Контекст и синтаксис.
DVM(DISTRIBUTE ... ; TEMPLATE [ "["size"]"... ] ) void * template-id ;
Выход компилятора.
AMViewRef template-id;
Замечание. Исходное описание заменено. Форматы распределения будут использованы при создании темплейта. Если размер (size) задан, то создание будет неявным.
Контекст и синтаксис.
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.
Контекст и синтаксис.
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);}
Контекст и синтаксис.
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) ), )
Контекст и синтаксис.
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))
Контекст и синтаксис.
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);
Контекст и синтаксис.
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);
Контекст и синтаксис.
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;
Контекст и синтаксис.
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_()
Контекст и синтаксис.
DVM(PARALLEL "["var"]" ON task-id "["var"]") DO(var, ..., ..., ...) { C-statements }
Выход компилятора.
for(var=0; ...) if(DVM_RUN(task,var)) { statements DVM_STOP(); }
Контекст и синтаксис.
DVM( DISTRIBUTE | ALIGN ... ; SHADOW "["widths"]"... )
Замечание. В точке описания ничего не генерируется. Компилятор сохраняет значения widths как максимальную ширину граней. Эти значения используются при создании массива.
Контекст и синтаксис.
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)
Контекст и синтаксис.
DVM(SHADOW_GROUP) void * sh-group-id;
Выход компилятора.
ShadowGroupRef sh-group-id;
Замечание. Исходное описание заменено.
Контекст и синтаксис.
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; }
Контекст и синтаксис.
DVM(SHADOW_START sh-group-id);
Выход компилятора.
DVM_SHADOW_START(sg);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_SHADOW_START(sg) расширяется в
strtsh_(&sg)
Контекст и синтаксис.
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)
Контекст и синтаксис.
DVM(SHADOW_WAIT sh-group-id);
Выход компилятора.
DVM_SHADOW_WAIT(sg);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_SHADOW_WAIT(sg) расширяется в
waitsh_(&sg)
Контекст и синтаксис.
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)
Контекст и синтаксис.
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); }
Контекст и синтаксис.
DVM(REMOTE_GROUP) void * ra-group-id;
Выход компилятора.
RegularAccessGroupRef ra-group-id; long RMG_ra-group-id;
Замечание. Исходное описание заменено. Для операций PREFETCH и RESET требуется вспомогательная переменная, управляющая операциями обновления буферов.
Контекст и синтаксис.
DVM(PREFETCH ra-group-id );
Выход компилятора.
DVM_PREFETCH(rg);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_PREFETCH(rg) расширяется в
if(rg==0) {RMG_##rg=0;} else {loadbg_(&rg, 1); RMG_##rg=1; }
Контекст и синтаксис.
DVM(RESET ra-group-id );
Выход компилятора.
DVM_RESET(rg);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_RESET(rg) расширяется в
delbg_(&rg); rg=0; RMG_##rg=0;
Удаленные ссылки заменяются на ссылки к соответствующему буферу.
Контекст и синтаксис.
DVM(REDUCTION_GROUP) void * red-group-id;
Выход компилятора.
RedGroupRef red-group-id;
Замечание. Исходное описание заменено.
Контекст и синтаксис.
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);} }
Контекст и синтаксис.
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)
Контекст и синтаксис.
DVM(REDUCTION_START red-group-id);
Выход компилятора.
DVM_REDUCTION_START(red-group-id);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REDUCTION_START(rg) расширяется в
strtrd_((RedGroupRef*) &rg)
Контекст и синтаксис.
DVM(REDUCTION_WAIT red-group-id);
Выход компилятора.
DVM_REDUCTION_WAIT(red-group-id);
Замечание. Выполнимая директива конвертируется в оператор. Макрокоманда DVM_REDUCTION_WAIT(rg) расширяется в
waitrd_((RedGroupRef*) &rg); delrg_((RedGroupRef*) &rg); rg=0;
Контекст и синтаксис.
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));
Контекст и синтаксис.
DVM(DISTRIBUTE | ALIGN...) element-type array-id "["const-dim"]"...;
Выход компилятора. Стандартная последовательность создания массива как и в случае malloc.
Замечание. Для глобальных описаний неявный malloc вставляется в начало функции main. Для локальных -- перед первым оператором блока.
Контекст и синтаксис. Обычные ссылки на элементы массивов array[ind1]...[indr] с распределенным array. Допускается также специальная форма ссылок в виде макрокоманд array(ind1,...,indr) для моделирования динамических массивов.
Выход компилятора.
DAElm<r>(type,array-id,ind1,...indr)
Замечание. Это макрокоманды RTL.
Контекст и синтаксис.
lhs=rhs; // assignement
Выход компилятора.
if(DVM_ISLOCAL(lhs)) { lhs = rhs ; } DVM_ENDLOCAL();
Замечание. Оператор
собственных вычислений это
присваивание распределенному
массиву в нераспределенной ветки
программы. Оно должно
"охраняться" проверкой
локальности элемента.
Макрокоманда DVM_ISLOCAL(a,r,ind)
расширяется в
tstelm_(a, ind)
Макрокоманда DVM_ENDLOCAL() расширяется в
dskpbl_()
Контекст и синтаксис.
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);}
Компиляция функций ввода-вывода сводится к переименованию функции iofun на ее RTL аналог dvm_iofun. Единственным исключением являются функции fread() и fwrite(), когда они применяются к распределенному массиву. В это случае массив читается или пишется целиком. Остальные параметры игнорируются.
Контекст и синтаксис.
[ 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);
Контекст и синтаксис.
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 )
Контекст и синтаксис. Любая ссылка на обычную или распределенную переменную 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. --
Необычный порядок вычисления
операции-запятая.
Контекст и синтаксис. Любой цикл или конструкция 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);
Генерация последовательной программы задается параметром -s командной строки. Все DVM-директивы игнорируются за исключением следующих:
Заметим, что препроцессорные операторы #define должны оставаться на месте в отличие от параллельного кода, в котором они должны переноситься в начало файла.