Oops, the Michael Ferguson bug bit me and I forgot the patch. Attached now.

-Brad


On Fri, 24 Jan 2014, Brad Chamberlain wrote:


Hi Chapel Devs --

This is a request for a proposed change to the interpretation of Chapel programs, which anyone invested in the language should give a quick look at and then respond to two questions below. There's also a patch to implement the change (which I'll need a reviewer for as soon as we verify that we have consensus on it).

For some time now, Chapel has permitted a domain to be specified either
by naming it, e.g.:

        const D = {1..n};
        const DistD = D dmapped Block(...);
        forall i in DistD ...

or by wrapping it in an extraneous set of curly brackets:

        const D = {1..n};
        const DistD = {D} dmapped Block(...);
        forall i in {DistD} ...


The reasons for this are somewhat obscure (and arguably indefensible), but relate to (1) a precedent set in ZPL, (2) the days when we used square brackets for domain literals, and (3) to the use of anonymous domains in array declarations without curly brackets (i.e., a pure implementation of Chapel would require

        var A: [{1..n, 1..n}] real;

rather than permitting the shorthand:

        var A: [1..n, 1..n] real;


I'd forgotten about this anomaly until doing cleanup on iterations over anonymous domains the other week when I encountered some instances of it. Over lunch, Vass pointed out that cleaning this up should be fairly easy so I took it on as a five-minute fix (TM).

I'm proposing that instead, we interpret {D} (where 'D' is a domain) as an associative domain of domain values, containing one index 'D' which seems more consistent with the current language definition.

In implementing this, I also realized for the first time (or re-realized something I'd forgotten), that as an extension to the sugaring of anonymous domains in array declarations, that we permit:

        var A: [1, 2, 4] real;

to mean "A is declared over an anonymous associative domain {1, 2, 4}. I'm not sure whether this is a good thing or not. I think the argument for sugaring this case is weaker since programmers from C and Fortran won't have a corresponding concept that they'll expect to work in Chapel, and I think in this case the curly brackets make the intention clearer:

        var A: [{1, 2, 4}] real;

That said, my patch does not impact this behavior -- it's more a question for future five-minute fixes (TM) because it would be similarly straightforward.

So, the two questions are:

1) Should we interpret {D} as an anonymous associative domain of domains
  rather than simply a reference to domain 'D'?

2) Should we require curly brackets for anonymous domains in array
  types that are not rectangular / defined by a list of ranges?

And if you're not interested in reviewing the patch, you can stop there.

-----

The heart of the patch is a simple change: We have traditionally supported a routine, chpl__buildDomainExpr() which creates a domain from whatever is passed it. One of the overloads took a domain and simply returned it which is what caused '{D}' to evaluate to 'D'. So the idea behind this change is to remove that overload.

A little more work is required, however, because the same call is used to build the domain for an array type like '[D] real' and in this case, we want to permit a domain like 'D' to be used. So what I did was to split
this call into two calls:

        chpl__buildDomainExpr() : does what it has, but without the domain
                                  overload now

        chpl_ensureDomainExpr() : used in the array type signature context
                                  to make sure that the expression is a
                                  domain.  In this context, if the thing
                                  is a domain, we simply return it.  In
                                  all other cases, we forward the args to
                                  chpl__buildDomainExpr()

From there, the only other change was to switch calls to chpl__buildDomainExpr() in the array type signature case (which was most of them) over to chpl__ensureDomainExpr(), and to rewrite any tests that were relying on '{D}' evaluating to 'D'.

I also added a test to demonstrate the "anonymous associative domain in an array declaration" issue for consideration.

Note that to only permit rectangular domains to have their curly brackets dropped in the array declaration context, we'd simply need to restrict the type signatures permitted for chpl_ensureDomainExpr(), I believe. And we could generate an error overload for the other cases.

Thanks,
-Brad

Index: test/release/examples/benchmarks/ssca2/SSCA2_Modules/SSCA2_kernels.chpl
===================================================================
--- test/release/examples/benchmarks/ssca2/SSCA2_Modules/SSCA2_kernels.chpl	(revision 22577)
+++ test/release/examples/benchmarks/ssca2/SSCA2_Modules/SSCA2_kernels.chpl	(working copy)
@@ -169,7 +169,7 @@
   config const defaultNumTPVs = 16;
   config var numTPVs = min(defaultNumTPVs, numLocales);
   // Would be nice to use PriavteDist, but aliasing is not supported (yet)
-  const PrivateSpace = {LocaleSpace} dmapped Block(boundingBox={LocaleSpace});
+  const PrivateSpace = LocaleSpace dmapped Block(boundingBox=LocaleSpace);
 
   // ==================================================================
   //                              KERNEL 4
@@ -244,8 +244,8 @@
           TPVLocales[t] = Locales[((t-1)/numTPVs)/numLocales];
         }
       }
-      const TPVLocaleSpace = {TPVSpace} dmapped Block(boundingBox={TPVSpace},
-                                                      targetLocales=TPVLocales);
+      const TPVLocaleSpace = TPVSpace dmapped Block(boundingBox=TPVSpace,
+                                                    targetLocales=TPVLocales);
 
       // There will be numTPVs copies of the temps, thus throttling the
       // number of starting vertices being considered simultaneously.
Index: test/distributions/diten/Dimensional.chpl
===================================================================
--- test/distributions/diten/Dimensional.chpl	(revision 22577)
+++ test/distributions/diten/Dimensional.chpl	(working copy)
@@ -168,7 +168,7 @@
   var localeDom: domain(nDims) = {0..#nLocRows, 0..#nLocCols};
   var locales: [localeDom] locale;
 
-  for (i,j) in {localeDom} do
+  for (i,j) in localeDom do
     locales(i,j) = Locales((i*nLocCols + j)%numLocales);
 
   var dims: nDims*DimensionDistributor = (new Cyclic(1), new Cyclic(2));
Index: test/studies/ssca2/rachels/SSCA2_kernels.chpl
===================================================================
--- test/studies/ssca2/rachels/SSCA2_kernels.chpl	(revision 22577)
+++ test/studies/ssca2/rachels/SSCA2_kernels.chpl	(working copy)
@@ -171,7 +171,7 @@
   config const defaultNumTPVs = 16;
   config var numTPVs = min(defaultNumTPVs, numLocales);
   // Would be nice to use PriavteDist, but aliasing is not supported (yet)
-  const PrivateSpace = {LocaleSpace} dmapped Block(boundingBox={LocaleSpace});
+  const PrivateSpace = LocaleSpace dmapped Block(boundingBox=LocaleSpace);
 
   // ==================================================================
   //                              KERNEL 4
@@ -240,8 +240,8 @@
         TPVLocales[t] = Locales[_computeChunkStartEnd(numLocales,
                                                       numTPVs, t+1)[1]-1];
       }
-      const TPVLocaleSpace = {TPVSpace} dmapped Block(boundingBox={TPVSpace},
-                                                      targetLocales=TPVLocales);
+      const TPVLocaleSpace = TPVSpace dmapped Block(boundingBox=TPVSpace,
+                                                    targetLocales=TPVLocales);
 
       // There will be numTPVs copies of the temps, thus throttling the
       // number of starting vertices being considered simultaneously.
Index: test/studies/parsec/blackscholes_promote.chpl
===================================================================
--- test/studies/parsec/blackscholes_promote.chpl	(revision 22577)
+++ test/studies/parsec/blackscholes_promote.chpl	(working copy)
@@ -128,7 +128,7 @@
 				data.r, data.v, data.t, otype);
 	}
 	if ERR_CHK then
-		numError = + reduce [i in {Dom}] errChk(i, data(i).DGrefval, prices(i));
+		numError = + reduce [i in Dom] errChk(i, data(i).DGrefval, prices(i));
 }
 
 proc main() {
Index: test/studies/hpcc/HPL/stonea/serial/hplExample3.chpl
===================================================================
--- test/studies/hpcc/HPL/stonea/serial/hplExample3.chpl	(revision 22577)
+++ test/studies/hpcc/HPL/stonea/serial/hplExample3.chpl	(working copy)
@@ -98,8 +98,8 @@
                        (ABlkDmn.dim(2))((blkCol-1)*blkSize+1..#blkSize)};
         const bBlkD = {(ABlkDmn.dim(1))((blkRow-1)*blkSize+1..#blkSize),
                        (ADmn.dim(2))((blkCol-1)*blkSize+1..#blkSize)};
-        const cBlkD = {ADmn[(blkRow-1)*blkSize+1..#aBlkD.dim(1).length,
-                            (blkCol-1)*blkSize+1..#bBlkD.dim(2).length]};
+        const cBlkD = ADmn[(blkRow-1)*blkSize+1..#aBlkD.dim(1).length,
+                           (blkCol-1)*blkSize+1..#bBlkD.dim(2).length];
 
         local {
             dgemm(
@@ -235,11 +235,11 @@
         const trailingCols   = blk+crntBlkSize..ACols.high;
         const unfactoredCols = blk..ACols.high;
 
-        var tl = {A.domain[blockRange, blockRange]};
-        var tr = {A.domain[blockRange, trailingCols]};
-        var bl = {A.domain[trailingRows, blockRange]};
-        var br = {A.domain[trailingRows, trailingCols]};
-        var l  = {A.domain[unfactoredRows, blockRange]};
+        var tl = A.domain[blockRange, blockRange];
+        var tr = A.domain[blockRange, trailingCols];
+        var bl = A.domain[trailingRows, blockRange];
+        var br = A.domain[trailingRows, trailingCols];
+        var l  = A.domain[unfactoredRows, blockRange];
         
         // Now that we've sliced and diced A properly do the blocked-LU
         // computation:
Index: test/arrays/bradc/anonAssoc.chpl
===================================================================
--- test/arrays/bradc/anonAssoc.chpl	(revision 0)
+++ test/arrays/bradc/anonAssoc.chpl	(revision 0)
@@ -0,0 +1,11 @@
+var x: [1, 2, 4] string;
+
+x[1] = "one";
+x[2] = "two";
+x[4] = "four";
+
+writeln("x[1] is ", x[1]);
+writeln("x[4] is ", x[4]);
+writeln("x[2] is ", x[2]);
+
+x[3] = "three";
Index: test/arrays/bradc/anonAssoc.good
===================================================================
--- test/arrays/bradc/anonAssoc.good	(revision 0)
+++ test/arrays/bradc/anonAssoc.good	(revision 0)
@@ -0,0 +1,4 @@
+x[1] is one
+x[4] is four
+x[2] is two
+anonAssoc.chpl:11: error: halt reached - array index out of bounds: 3
Index: test/parallel/taskPar/rachels/Barrier.chpl
===================================================================
--- test/parallel/taskPar/rachels/Barrier.chpl	(revision 22577)
+++ test/parallel/taskPar/rachels/Barrier.chpl	(working copy)
@@ -15,7 +15,7 @@
 use BlockDist;
 
 // use this instead of a PrivateDist for performance reasons (PrivateDists are expensive!)
-const PrivateSpace = {LocaleSpace} dmapped Block(boundingBox={LocaleSpace});
+const PrivateSpace = LocaleSpace dmapped Block(boundingBox=LocaleSpace);
 
 record Barrier {
   param reusable = true;
Index: modules/internal/ChapelArray.chpl
===================================================================
--- modules/internal/ChapelArray.chpl	(revision 22577)
+++ modules/internal/ChapelArray.chpl	(working copy)
@@ -349,9 +349,6 @@
   //
   // Support for domain expressions, e.g., {1..3, 1..3}
   //
-  proc chpl__buildDomainExpr(x: domain)
-    return x;
-  
   proc chpl__buildDomainExpr(ranges: range(?) ...?rank) {
     for param i in 2..rank do
       if ranges(1).idxType != ranges(i).idxType then
@@ -383,6 +380,17 @@
   
       return D; 
   }
+
+  //
+  // Support for domain expressions within array types, e.g. [1..n], [D]
+  //
+  proc chpl__ensureDomainExpr(x: domain) {
+    return x;
+  }
+
+  proc chpl__ensureDomainExpr(x...) {
+    return chpl__buildDomainExpr((...x));
+  }
   
   //
   // Support for distributed domain expression e.g. {1..3, 1..3} dmapped Dist()
Index: compiler/AST/build.cpp
===================================================================
--- compiler/AST/build.cpp	(revision 22577)
+++ compiler/AST/build.cpp	(working copy)
@@ -171,16 +171,16 @@
     if (indexCall->numActuals() != 1)
       USR_FATAL(iterator, "invalid index expression");
     return new CallExpr("chpl__buildArrayRuntimeType",
-             new CallExpr("chpl__buildDomainExpr", iterator),
+             new CallExpr("chpl__ensureDomainExpr", iterator),
              eltType, indexCall->get(1)->remove(),
-             new CallExpr("chpl__buildDomainExpr", iterator->copy()));
+             new CallExpr("chpl__ensureDomainExpr", iterator->copy()));
   } else {
     CallExpr* call = toCallExpr(iterator);
     if (call->numActuals() == 1 && isDefExpr(call->get(1))) {
       return new CallExpr("chpl__buildArrayRuntimeType", call->get(1)->remove(), eltType);
     } else
       return new CallExpr("chpl__buildArrayRuntimeType",
-               new CallExpr("chpl__buildDomainExpr", iterator), eltType);
+               new CallExpr("chpl__ensureDomainExpr", iterator), eltType);
   }
 }
 
@@ -710,7 +710,7 @@
   // counting domains within runtime array types
   thenStmt->insertAtTail(new CallExpr(PRIM_MOVE, domain,
                            new CallExpr("chpl__autoCopy",
-                             new CallExpr("chpl__buildDomainExpr",
+                             new CallExpr("chpl__ensureDomainExpr",
                                           iteratorExpr->copy()))));
   if (hasSpecifiedIndices) {
     // we want to swap something like the below commented-out
Index: compiler/AST/expr.cpp
===================================================================
--- compiler/AST/expr.cpp	(revision 22577)
+++ compiler/AST/expr.cpp	(working copy)
@@ -3370,7 +3370,7 @@
         argList.last()->prettyPrint(o);
         unusual = true;
       } else if (strcmp(expr->unresolved,
-                        "chpl__buildDomainExpr") == 0) {
+                        "chpl__ensureDomainExpr") == 0) {
         unusual = true;
         for_alist(expr, argList) {
           if (expr != argList.first()) {
Index: compiler/parser/chapel.ypp
===================================================================
--- compiler/parser/chapel.ypp	(revision 22577)
+++ compiler/parser/chapel.ypp	(working copy)
@@ -340,7 +340,7 @@
 | TLSBR expr_ls TRSBR stmt
     {
       if ($2->argList.length > 1)
-        $$ = buildForallLoopStmt(NULL, new CallExpr("chpl__buildDomainExpr", $2), new BlockStmt($4));
+        $$ = buildForallLoopStmt(NULL, new CallExpr("chpl__ensureDomainExpr", $2), new BlockStmt($4));
       else
         $$ = buildForallLoopStmt(NULL, $2->get(1)->remove(), new BlockStmt($4));
     }
@@ -806,7 +806,7 @@
 opt_reindex_expr:
     { $$ = NULL; }
 | TCOLON TLSBR expr_ls TRSBR
-    { $$ = new CallExpr("chpl__buildDomainExpr", $3); }
+    { $$ = new CallExpr("chpl__ensureDomainExpr", $3); }
 ;
 
 opt_type:
@@ -835,19 +835,19 @@
 array_type:
   TLSBR expr_ls TRSBR type_level_expr
     { $$ = new CallExpr("chpl__buildArrayRuntimeType",
-             new CallExpr("chpl__buildDomainExpr", $2), $4); 
+             new CallExpr("chpl__ensureDomainExpr", $2), $4); 
     }
 | TLSBR expr_ls TRSBR array_type
     { $$ = new CallExpr("chpl__buildArrayRuntimeType",
-             new CallExpr("chpl__buildDomainExpr", $2), $4); 
+             new CallExpr("chpl__ensureDomainExpr", $2), $4); 
     }
 | TLSBR expr_ls TIN expr TRSBR type_level_expr
     { 
       if ($2->argList.length != 1)
         USR_FATAL($4, "invalid index expression");
       $$ = new CallExpr("chpl__buildArrayRuntimeType",
-             new CallExpr("chpl__buildDomainExpr", $4), $6, $2->get(1)->remove(),
-             new CallExpr("chpl__buildDomainExpr", $4->copy()));
+             new CallExpr("chpl__ensureDomainExpr", $4), $6, $2->get(1)->remove(),
+             new CallExpr("chpl__ensureDomainExpr", $4->copy()));
     }
 | error  {printf("bad array type specification"); clean_exit(1); }
 ;
@@ -984,7 +984,7 @@
 | TLSBR expr_ls TRSBR expr %prec TFOR
     {
       if ($2->argList.length > 1)
-        $$ = buildForallLoopExpr(NULL, new CallExpr("chpl__buildDomainExpr", $2), $4, NULL, true);
+        $$ = buildForallLoopExpr(NULL, new CallExpr("chpl__ensureDomainExpr", $2), $4, NULL, true);
       else
         $$ = buildForallLoopExpr(NULL, $2->get(1)->remove(), $4, NULL, true);
     }
Index: compiler/passes/normalize.cpp
===================================================================
--- compiler/passes/normalize.cpp	(revision 22577)
+++ compiler/passes/normalize.cpp	(working copy)
@@ -867,12 +867,6 @@
       CallExpr* call = toCallExpr(arg->typeExpr->body.tail);
       // Not sure why we select the tail here....
 
-      //if (call && call->isNamed("chpl__buildDomainExpr")) {
-        //CallExpr* arrayTypeCall = new CallExpr("chpl__buildArrayRuntimeType");
-        //call->insertBefore(arrayTypeCall);
-        //arrayTypeCall->insertAtTail(call->remove());
-        //call = arrayTypeCall;
-      //}
       if (call && call->isNamed("chpl__buildArrayRuntimeType")) {
         // We are building an array type.
         bool noDomain = (isSymExpr(call->get(1))) ? toSymExpr(call->get(1))->var == gNil : false;
------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today. 
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers

Reply via email to