4.4 对准 |
在这里我们详细描述怎样确定哑参所根本对准的模板:
首先,模板不是通过子程序参数接口传递的。仅当通过宿主关联或使用关联使得模板在调用者和被调子程序中都能访问到时,哑参及其相应的实参才可以被对准到同一模板上。
在任何其它的情况中,哑参所对准的模板总是不同于实参所对准的模板,虽然该模板可能是实参模板的一个拷贝。在过程的出口,一种HPF实现是安排实参与调用前它所对准的同一模板对准。
哑参的模板可以以下面三种方式的某一种获得:
.如果哑参在ALIGN指令中作为对准子显式出现,则如果对准目标(align-target)是一个模板的话,哑参的模板就是该对准目标;否则其模板是哑参所根本对准的模板。
.如果哑参不是显式对准的并且不具有INHERIT属性(见下面的4.4.2节),则模板与哑元具有相同的形状和边界;我们将其称之为哑参的自然模板。(这样,4.3节中的所有例子使用的都是自然模板)
.如果哑参不是显式对准的但具有INHERIT属性,则模板根据下列规则从实参中继承:
—如果实参是一个整个数组,则哑参的模板是实参所根本对准的模板的拷贝。
—如果实参是数组A的一个数组区域且任何一个下标都不是向量下标,则哑参的模板是A所根本对准的模板的拷贝。
—如果实参是任何其它的表达式,则语言处理器可以任意选择模板的形状和分配(因此程序员对其分配一无所知)
在所有这些情况中,我们说哑参具有一个继承属性。
INHERIT指令指明哑参应以与实参对准相同的方式被对准到相应实参模板的拷贝上。
H401 inherit-directive is INHERIT inheritee-list
H402 inheritee is object-name
约束:一个继承子(inheritee)必须是一个哑参。
约束:一个继承子不能是一个对准子
约束:一个继承子不能是一个分配子。
对用户的建议:在所认可的扩展中对于指针放松了这三个约束中的第一个(见7.8节)(对用户的建议结束)
INHERIT指令导致所命名的子程序哑参具有INHERIT属性。只有哑参可以具有INHERIT属性。一个对象不能既具有INHERIT属性由具有ALIGN属性。INHERIT指令仅能出现在作用域单元的说明部分。
如果一个哑参具有TARGET属性且没有显式映射属性,则隐含假定它具有INHERIT属性。(见4.7节)
INHERIT属性指明哑参的模板应通过建立实参模板的拷贝来继承。而且,对于具有INHERIT属性的参数不能出现显式映射指令:INHERIT属性暗示对于继承的模板其分配方式是:DISTRIBUTE * ONTO *。这样最后的效果是告诉编译器将数据完全放在它原来所在的位置,并且不试图对实参进行重映射。哑参将以与实参完全相同的方式被映射;为正确工作,子程序必须以这种方式编译而不管实参是怎样被映射到抽象处理器上。
注意如果A是一个数组哑参,则指令
!HPF$ INHERIT A
比下面的指令更一般化
!HPF$ DISTRIBUTE A * ONTO *
这是由于下面的原因:INHERIT指令指明A所对准的(继承的)模板以* ONTO *方式分配,但是A可能以一些复杂的方式与该模板对准。另一方面,DISTRIBUTE指明A与其自然模板对准,该模板依次以* ONTO *方式分配。
例如下面的代码是不允许的:
!HPF$ PROCESSORS P(2)
REAL, DIMENSION(100) :: A
!HPF$ DISTRIBUTE (BLOCK) ONTO P :: A
CALL FOO(A(1:50))
...
SUBROUTINE FOO(D)
REAL, DIMENSION(50) :: D
!HPF$ DISTRIBUTE D * &不合法
D的抄写性分配是不合法的,这是因为D的自然模板不是以BLOCK方式分配的。另一方面,用下面的指令代替该非法指令就是合理的:
!HPF$ INHERIT D
这是一个使用INHERIT的直接例子:
REAL DOUGH(100)
!HPF$ DISTRIBUTE DOUGH(BLOCK(10))
CALL PROBATE(DOUGH(7:23:2))
...
SOUBROUTINE PROBATE(BREAD)
REAL BREAD(9)
!HPF$ INHERIT BREAD
BREAD的继承模板具有形状[100];元素BREAD(I)与继承模板的元素5+2*I对准,且该模板的分配方式是BLOCK(10)。
可以很容易构成更复杂的例子。记住继承模板可以与哑参具有不同的维数,它甚至可以与实参具有不同的维数。例如,某程序可能包括下列代码:
REAL A(100,100)
!HPF$ TEMPLATE T(100,100,100)
!HPF$ DISTRIBUTE T(BLOCK,CYCLIC,*)
!HPF$ ALIGN A(I,J) WITH T(J,3,I)
CALL SUBR(A(:,7))
...
SUBROUTINE SUBR(D)
REAL D(100)
!HPF$ INHERIT D
在这种情况下,哑参D的维数是1。它对应于二维实参A的一维区域,而A依次又与一个三维模板T的二维区域对准。D的模板是此三维模板的一个拷贝。D与这个继承模板的区域(7,3,:)对准。这样,哑参D的“可见”维被以*方式分配,但是如果调用语句是下面的形式
CALL SUBR(A(7,:))
则哑参的“可见”维将以BLOCK方式分配。
在align-spec的开始有无星号同dist-format子句中有无星号具有同样的意义:它分别指明ALIGN指令是描述性的还是指示性的。
如果将一个不以*开始的align-spec应用到一个哑参上,则意味着此哑参将在子程序的入口处被强制具有指定的对准。这样就可以要求调用者或子程序对实参的数据或一个拷贝进行临时重映射。
注意,哑参也可以用作一个对准目标(align-target).
SUBROUTINE NICHOLAS(TSAR,CZAR)
REAL, DIMENSION(1918) :: TSAR,CZAR
!HPF$ INHERIT :: TSAR
!HPF$ ALIGN WITH TSAR :: CZAR
在本例中,第一个哑参,TSAR,保持与相应的实参对准,而第二个哑参,CAAR,被强制与第一个哑参对准。如果两个实参都已对准,则运行时不需要数据的重映射。如果他们没对准,则将要发生一些重映射。
如果align-spec以*开始,则alignee必须是一个哑参。*表明程序员相信实参已经具有了指定的对准,并且在运行时无须对其重映射。(同前面一样,不要求程序员的信念一定是正确的,如果有必要的话编译器必须产生重映射,就象指示性对准一样)例如,如果在上面的例子中,将对准指令修改为
!HPF$ ALIGN WITH *TSAR :: CZAR
则程序员建立这样一个信念:对应于TSAR的实参不必要进行重映射。
不允许简单地说“ALIGN WITH *”;一个对准目标必须紧跟一个星号。(说“接受任何对准”的正确方式是INHERIT)
如果一个哑参没有显式ALIGN或DISTRIBUTE属性,则编译器提供一个隐式对准和分配说明,该说明无须任何“声明星号”即可被显式描述。
如果不使用INHERIT,则有必要保证哑参的显式对准在子程序边界不会发生任何重映射。这里是一个例子:
LOGICAL FRUG(128)
!HPF$ PROCESSORS DANCE_FLOOR(16)
!HPF$ DISTRIBUTE (BLOCK) ONTO DANCE_FLOOR::FRUG
CALL TERPSICHORE(FRUG(1:40:3))
数组区域FRUG(1:40:3)以下列方式映射到抽象处理器上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 | 25 | ||||||||||||||
10 | 34 | ||||||||||||||
19 | |||||||||||||||
4 | 28 | ||||||||||||||
13 | 37 | ||||||||||||||
22 | |||||||||||||||
7 | 31 | ||||||||||||||
16 | 40 |
首先假定子程序TERPSICHORE的接口看起来是这样的:
SUBROUTINE TERPSICHORE(FOXTROT)
LOGICAL FOXTROT(:)
!HPF$ INHERIT FOXTROT
FOXTROT的模板是整个数组FRUG的模板的一个拷贝,该模板具有128个元素。该模板被映射成这种形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 | 65 | 73 | 81 | 89 | 97 | 105 | 113 | 121 |
2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 | 66 | 74 | 82 | 90 | 98 | 106 | 114 | 122 |
3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 | 67 | 75 | 83 | 91 | 99 | 107 | 115 | 123 |
4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 | 68 | 76 | 84 | 92 | 100 | 108 | 116 | 124 |
5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 | 69 | 77 | 85 | 93 | 101 | 109 | 117 | 125 |
6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 | 70 | 78 | 86 | 94 | 102 | 110 | 118 | 126 |
7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 | 71 | 79 | 87 | 95 | 103 | 111 | 119 | 127 |
8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 104 | 112 | 120 | 128 |
FOXTROT(I)与模板的元素3*I-2对准。
另一方面假定PERPSICHORE的接口看起来是这样的:
SUBROUTINE TERPSICHORE(FOXTROT)
LOGICAL FOXTROT(:)
!HPF$ DISTRIBUTE FOXTROT(BLOCK)
在这种情况下,FOXTROT的模板是它的自然模板;它的大小同FOXTROT一样,都是14。实参FRUG(1:40:3)以这种方式被映射到16个处理器中:
抽象处理器 FRUG的元素
1 1,2,3
2 4,5,6
3 7,8
4 9,10,11
5 12,13,14
6-16 无
也就是说,哑参元素的原始位置(在实参的模板中)如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 | 9 | ||||||||||||||
4 | 12 | ||||||||||||||
7 | |||||||||||||||
2 | 10 | ||||||||||||||
5 | 13 | ||||||||||||||
8 | |||||||||||||||
3 | 11 | ||||||||||||||
6 | 14 |
这种分布(3个元素在第一个处理器上,3个在第二个上,2个在第三个上,3个在第四个上,...)不能正确描述为BLOCK分配。因此调用时将发生重映射。
在不使用INHERIT的情况下,通过将哑参与大小为128的分配块的模板显式对准,可以避免重映射:
SUBROUTINE TERPSICHORE(FOXTROT)
LOGICAL FOXTROT(:)
!HPF$ PROCESSORS DANCE_FLOOR(16)
!HPF$ TEMPLATE, DISTRIBUTE(BLOCK) ONTO DANCE_FLOOR::GURF(128)
!HPF$ ALIGN FOXTROT(J) WITH GURF(3*J-2)
对用户的建议:这一技术的优点是,在使用它的地方,它可以为编译器提供更多的信息;这一信息通常可用于产生更有效的代码。(对用户的建议结束)
Copyright: NPACT |