diff --git a/compiler/AST/primitive.cpp b/compiler/AST/primitive.cpp index 31c8854bb839..29248f224a48 100644 --- a/compiler/AST/primitive.cpp +++ b/compiler/AST/primitive.cpp @@ -1070,6 +1070,8 @@ initPrimitive() { prim_def(PRIM_MAYBE_LOCAL_ARR_ELEM, "may be local array element", returnInfoUnknown); prim_def(PRIM_MAYBE_AGGREGATE_ASSIGN, "may be aggregated assignment", returnInfoUnknown); + prim_def(PRIM_PROTO_SLICE_ASSIGN, "assign proto slices", returnInfoVoid); + prim_def(PRIM_ERROR, "error", returnInfoVoid, true); prim_def(PRIM_WARNING, "warning", returnInfoVoid, true); prim_def(PRIM_WHEN, "when case expressions", returnInfoVoid); diff --git a/compiler/include/arrayViewElision.h b/compiler/include/arrayViewElision.h new file mode 100644 index 000000000000..cae12de7da60 --- /dev/null +++ b/compiler/include/arrayViewElision.h @@ -0,0 +1,88 @@ +/* + * Copyright 2020-2024 Hewlett Packard Enterprise Development LP + * Copyright 2004-2019 Cray Inc. + * Other additional copyright holders may be indicated within. + * + * The entirety of this work is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CallExpr.h" +#include "stmt.h" +#include "symbol.h" + +// interface for normalize +void arrayViewElision(); + +class ArrayViewElisionTransformer { +public: + ArrayViewElisionTransformer() = delete; + ArrayViewElisionTransformer(CallExpr* origCall); + + inline bool candidate() const { return candidate_; } + + void transform(); + +private: + CallExpr* origCall_; + CallExpr* origLhs_; + CallExpr* origRhs_; + + bool candidate_; + + bool exprSuitableForProtoSlice(CallExpr* e, bool isLhs); + CallExpr* genCreateProtoSlice(CallExpr* call); +}; + +// interface for prefold +class ArrayViewElisionPrefolder { +public: + ArrayViewElisionPrefolder() = delete; + ArrayViewElisionPrefolder(CallExpr* call); + ~ArrayViewElisionPrefolder(); + + inline CondStmt* condStmt() const { return condStmt_; } + inline bool supported() const { return supported_; } + inline BlockStmt* staticCheckBlock() const { return staticCheckBlock_; } + + CallExpr* getReplacement(); + void report(); + void updateAndFoldConditional(); + +private: + CallExpr* call_; + Symbol* lhsBase_; + Symbol* rhsBase_; + CallExpr* newProtoSliceLhs_; + CallExpr* newProtoSliceRhs_; + CondStmt* condStmt_; + Symbol* tmpCondFlag_; + bool supported_; + BlockStmt* staticCheckBlock_; + + // support for report-array-view-elision + std::string lhsBaseType_; + std::string rhsBaseType_; + + std::vector lhsIndexExprTypes_; + std::vector rhsIndexExprTypes_; + + void findCondStmt(); + void findProtoSlices(); + bool handleOneProtoSlice(bool isLhs); + bool canAssign() const; + CallExpr* findOneProtoSliceCall(Expr* e); + Symbol* getFlagReplacement(); +}; + diff --git a/compiler/include/driver.h b/compiler/include/driver.h index 08d1c0fe307b..b32671eede6c 100644 --- a/compiler/include/driver.h +++ b/compiler/include/driver.h @@ -68,6 +68,9 @@ extern bool fReportAutoLocalAccess; extern bool fAutoAggregation; extern bool fReportAutoAggregation; +extern bool fArrayViewElision; +extern bool fReportArrayViewElision; + extern bool fNoRemoteValueForwarding; extern bool fNoInferConstRefs; extern bool fNoRemoteSerialization; diff --git a/compiler/main/driver.cpp b/compiler/main/driver.cpp index abcb5d0213e1..9650ad65f39d 100644 --- a/compiler/main/driver.cpp +++ b/compiler/main/driver.cpp @@ -215,6 +215,9 @@ bool fReportAutoLocalAccess= false; bool fAutoAggregation = false; bool fReportAutoAggregation= false; +bool fArrayViewElision = true; +bool fReportArrayViewElision = false; + bool printPasses = false; FILE* printPassesFile = NULL; @@ -1274,6 +1277,8 @@ static ArgumentDescription arg_desc[] = { {"auto-aggregation", ' ', NULL, "Enable [disable] automatically aggregating remote accesses in foralls", "N", &fAutoAggregation, "CHPL_AUTO_AGGREGATION", NULL}, + {"array-view-elision", ' ', NULL, "Enable [disable] array view elision", "N", &fArrayViewElision, "CHPL_DISABLE_ARRAY_VIEW_ELISION", NULL}, + {"", ' ', NULL, "Run-time Semantic Check Options", NULL, NULL, NULL, NULL}, {"checks", ' ', NULL, "Enable [disable] all following run-time checks", "n", &fNoChecks, "CHPL_CHECKS", setChecks}, {"bounds-checks", ' ', NULL, "Enable [disable] bounds checking", "n", &fNoBoundsChecks, "CHPL_BOUNDS_CHECKING", NULL}, @@ -1403,6 +1408,7 @@ static ArgumentDescription arg_desc[] = { {"report-optimized-on", ' ', NULL, "Print information about on clauses that have been optimized for potential fast remote fork operation", "F", &fReportOptimizedOn, NULL, NULL}, {"report-auto-local-access", ' ', NULL, "Enable compiler logs for auto local access optimization", "N", &fReportAutoLocalAccess, "CHPL_REPORT_AUTO_LOCAL_ACCESS", NULL}, {"report-auto-aggregation", ' ', NULL, "Enable compiler logs for automatic aggregation", "N", &fReportAutoAggregation, "CHPL_REPORT_AUTO_AGGREGATION", NULL}, + {"report-array-view-elision", ' ', NULL, "Enable compiler logs for array view elision", "N", &fReportArrayViewElision, "CHPL_REPORT_ARRAY_VIEW_ELISION", NULL}, {"report-optimized-forall-unordered-ops", ' ', NULL, "Show which statements in foralls have been converted to unordered operations", "F", &fReportOptimizeForallUnordered, NULL, NULL}, {"report-promotion", ' ', NULL, "Print information about scalar promotion", "F", &fReportPromotion, NULL, NULL}, {"report-scalar-replace", ' ', NULL, "Print scalar replacement stats", "F", &fReportScalarReplace, NULL, NULL}, diff --git a/compiler/optimizations/CMakeLists.txt b/compiler/optimizations/CMakeLists.txt index 5ba45dbeb253..0e775877729f 100644 --- a/compiler/optimizations/CMakeLists.txt +++ b/compiler/optimizations/CMakeLists.txt @@ -15,6 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. set(SRCS + arrayViewElision.cpp bulkCopyRecords.cpp copyPropagation.cpp deadCodeElimination.cpp diff --git a/compiler/optimizations/Makefile.share b/compiler/optimizations/Makefile.share index 7d74f9f0d583..1c9b953534f0 100644 --- a/compiler/optimizations/Makefile.share +++ b/compiler/optimizations/Makefile.share @@ -17,6 +17,7 @@ # limitations under the License. OPTIMIZATIONS_SRCS = \ + arrayViewElision.cpp \ bulkCopyRecords.cpp \ copyPropagation.cpp \ deadCodeElimination.cpp \ diff --git a/compiler/optimizations/arrayViewElision.cpp b/compiler/optimizations/arrayViewElision.cpp new file mode 100644 index 000000000000..0605ba9e0e93 --- /dev/null +++ b/compiler/optimizations/arrayViewElision.cpp @@ -0,0 +1,445 @@ +/* + * Copyright 2020-2024 Hewlett Packard Enterprise Development LP + * Copyright 2004-2019 Cray Inc. + * Other additional copyright holders may be indicated within. + * + * The entirety of this work is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "arrayViewElision.h" +#include "global-ast-vecs.h" +#include "passes.h" +#include "resolution.h" + +// Array View Elision (AVE) aims to optimize assignments involving array views. +// Currently, this is limited to: +// +// slice = slice, and +// rank-change = rank-change +// +// This is mostly out of abundance of caution and could be extended to +// assignments involving arrays, too +// +// The gist of the implementation is based on eliding array views from +// operations such as the ones above. Note that this implies that the following +// cannot be covered: +// +// ref slice = A[1..5]; +// slice = A[6..10]; +// +// As determining whether `slice` can be dropped is more complicated than I +// could bite at the moment. So, both sides of the assignments must be +// array-view generating expressions for this optimization to fire. +// +// There are two parts of this optimization: +// +// 1. Pre-normalize (ArrayViewElisionTransformer is the type doing this) +// +// Given a statement like +// +// A[x] = B[y]; +// +// we generate +// +// param array_view_elision: bool; // will be replaced during resolution +// if (array_view_elision) { +// var protoSlice1 = chpl__createProtoSlice(A, x); +// var protoSlice2 = chpl__createProtoSlice(B, y); +// +// __primitive(PRIM_PROTO_SLICE_ASSIGN, protoSlice1, protoSlice2); +// } +// else { +// A[x] = B[y]; +// } +// +// Here the "protoSlice" has type `chpl__protoSlice`. See +// modules/internal/ChapelArrayViewElision.chpl for the details of that type. +// The main purpose of that type is to represent the expression that would +// create an array view. But avoid doing that. +// +// 2. During prefold (ArrayViewElisionPrefolder is the type doing this) +// +// Operation revolves around `PRIM_PROTO_SLICE_ASSIGN`. The +// ArrayViewElisionPrefolder is in charge of finding the other relevant AST (the +// CondStmt, the protoSlice temps etc) and transforming the conditional. +// +// Statically, chpl__ave_exprCanBeProtoSlice is called on both protoSlices to +// make sure that the module code is OK with creating protoSlices out of those +// expressions. We also check whether two protoSlices can be assigned to one +// another. This is done by chpl__ave_protoSlicesSupportAssignment. If `fLocal`, +// that's sufficient. Calls to that function are inserted, resolved, the result +// is collected, and finally the calls are removed. At that point, we drop the +// `array_view_elision` flag completely, and replace it with `true` or `false`, +// after which the conditional statement is constant-folded. +// +// If not `fLocal`, we also call `chpl_bothLocal` an replace the flag with the +// result of that. Note that this is a dynamic check, meaning that the +// conditional will not be removed. +// +// This optimization is on-by-default. It can be controlled with +// `--[no-]array-view-elision`. Additionally, there's also +// `--report-array-view-elision` flag to enable some output during compilation +// to help with understanding what's optimized and what's not. + + +ArrayViewElisionTransformer::ArrayViewElisionTransformer(CallExpr* origCall): + origCall_(origCall) { + + origLhs_ = toCallExpr(origCall_->get(1)); + origRhs_ = toCallExpr(origCall_->get(2)); + + // one side is not a call + // TODO this should be relaxed for `array=view` or vice versa + if (origLhs_ == nullptr || origRhs_ == nullptr) { + candidate_ = false; + return; + } + + // calls have different number of actuals + // TODO this should be relaxed for `slice=rank-change` or vice versa + if (origLhs_->numActuals() != origRhs_->numActuals()) { + candidate_ = false; + return; + } + + // further analysis per call + if ( !(exprSuitableForProtoSlice(origLhs_, /*isLhs*/ true) && + exprSuitableForProtoSlice(origRhs_, /*isLhs*/ false)) ) { + candidate_ = false; + return; + } + + candidate_ = true; +} + +void ArrayViewElisionTransformer::transform() { + INT_ASSERT(candidate_); + + SET_LINENO(origCall_); + + CallExpr* lhsPSCall = genCreateProtoSlice(origLhs_); + CallExpr* rhsPSCall = genCreateProtoSlice(origRhs_); + + // arrayview elision placeholder + VarSymbol* placeholder = new VarSymbol("array_view_elision_flag", dtBool); + placeholder->addFlag(FLAG_ARRAY_VIEW_ELISION_FLAG); + + origCall_->insertBefore(new DefExpr(placeholder, gFalse)); + + BlockStmt* thenBlock = new BlockStmt(); + VarSymbol* lhsPS = new VarSymbol("lhs_proto_slice"); + VarSymbol* rhsPS = new VarSymbol("rhs_proto_slice"); + + thenBlock->insertAtTail(new DefExpr(lhsPS, lhsPSCall)); + thenBlock->insertAtTail(new DefExpr(rhsPS, rhsPSCall)); + thenBlock->insertAtTail(new CallExpr(PRIM_PROTO_SLICE_ASSIGN, lhsPS, + rhsPS)); + + BlockStmt* elseBlock = new BlockStmt(); + + CondStmt* cond = new CondStmt(new SymExpr(placeholder), thenBlock, + elseBlock); + + origCall_->insertBefore(cond); + elseBlock->insertAtTail(origCall_->remove()); +} + + + +bool ArrayViewElisionTransformer::exprSuitableForProtoSlice(CallExpr* call, + bool isLhs) { + if (SymExpr* callBase = toSymExpr(call->baseExpr)) { + if (!isFnSymbol(callBase->symbol()) && + (!isLhs || !callBase->symbol()->isConstant())) { + // we avoid touching const lhs, otherwise this optimization causes the + // const checking error to point at the internal code rather than users. + return true; + } + } + return false; +} + +CallExpr* ArrayViewElisionTransformer::genCreateProtoSlice(CallExpr* call) { + INT_ASSERT(call); + + SymExpr* base = toSymExpr(call->baseExpr); + INT_ASSERT(base); + + const bool isConst = base->symbol()->isConstant(); + + const char* factory = isConst ? "chpl__createConstProtoSlice" : + "chpl__createProtoSlice"; + + CallExpr* ret = new CallExpr(factory, base->copy()); + for_actuals(actual, call) { + ret->insertAtTail(actual->copy()); + } + + return ret; +} + + +void arrayViewElision() { + if (!fArrayViewElision) return; + + for_alive_in_Vec (CallExpr, call, gCallExprs) { + if (FnSymbol* parentFn = toFnSymbol(call->parentSymbol)) { + if (parentFn->hasFlag(FLAG_NO_ARRAY_VIEW_ELISION)) { + continue; + } + } + + if (call->getModule()->modTag == MOD_USER) { + if (call->isNamed("=")) { + ArrayViewElisionTransformer transformer(call); + + if (transformer.candidate()) { + transformer.transform(); + } + } + } + } +} + +ArrayViewElisionPrefolder::ArrayViewElisionPrefolder(CallExpr* call): + call_(call), + newProtoSliceLhs_(nullptr), + newProtoSliceRhs_(nullptr), + condStmt_(nullptr), + supported_(false), + staticCheckBlock_(nullptr) { + + findProtoSlices(); + INT_ASSERT(newProtoSliceLhs_); + INT_ASSERT(newProtoSliceRhs_); + + + // this is just a temporary block. we add some AST in it, resolve and then + // remove them. I cannot be sure if those operations could leave any AST in. + // So, when we destroy this helper, we'll remove this block just to be sure. + staticCheckBlock_ = new BlockStmt(); + + BlockStmt* parentBlock = toBlockStmt(call->parentExpr); + parentBlock->insertAtHead(staticCheckBlock_); + + supported_ = handleOneProtoSlice(/* isLhs */ true) && + handleOneProtoSlice(/* isLhs */ false) && + canAssign(); + + findCondStmt(); + INT_ASSERT(condStmt_); +} + +ArrayViewElisionPrefolder::~ArrayViewElisionPrefolder() { + staticCheckBlock_->remove(); + tmpCondFlag_->getSingleDef()->getStmtExpr()->remove(); + tmpCondFlag_->defPoint->remove(); +} + +CallExpr* ArrayViewElisionPrefolder::getReplacement() { + return new CallExpr("=", call_->get(1)->copy(), call_->get(2)->copy()); +} + +Symbol* ArrayViewElisionPrefolder::getFlagReplacement() { + if (!supported_) { + // we can't optimize + return gFalse; + } + else if (fLocal) { + // no need to check anything else, we can determine this statically + return gTrue; + } + else { + INT_ASSERT(lhsBase_); + INT_ASSERT(rhsBase_); + // we need to check if the arrays are on the same locale at run time + CallExpr* localeCheck = new CallExpr("chpl__bothLocal", lhsBase_, rhsBase_); + + VarSymbol* flagTmp = newTemp(dtBool); + DefExpr* flagDef = new DefExpr(flagTmp); + + condStmt_->insertBefore(flagDef); + condStmt_->insertBefore(new CallExpr(PRIM_MOVE, flagTmp, localeCheck)); + + resolveExpr(localeCheck); + resolveExpr(flagDef); + return flagTmp; + } +} + +void ArrayViewElisionPrefolder::updateAndFoldConditional() { + condStmt_->condExpr->replace(new SymExpr(getFlagReplacement())); + condStmt_->foldConstantCondition(/*addEndOfStatement*/ false); +} + +void ArrayViewElisionPrefolder::report() { + if (!fReportArrayViewElision) return; + if (ModuleSymbol* mod = call_->getModule()) { + // if there's no user module, getModule could return null + if (mod->modTag != MOD_USER) return; + } + + std::string isSupported = supported() ? "supported" : "not supported"; + std::string isDynamic = (supported() && !fLocal) ? + " (dynamic locality check required)" : + ""; + std::cout << "ArrayViewElision " << isSupported << isDynamic << " " << + call_->stringLoc() << std::endl; + + std::cout << "\t" << "lhsBaseType: " << lhsBaseType_ << std::endl; + std::cout << "\t" << "lhsIndexingExprs: " << std::endl; + for (auto typeName: lhsIndexExprTypes_) { + std::cout << "\t\t" << typeName << std::endl; + } + + std::cout << "\t" << "rhsBaseType: " << rhsBaseType_ << std::endl; + std::cout << "\t" << "rhsIndexingExprs: " << std::endl; + for (auto typeName: rhsIndexExprTypes_) { + std::cout << "\t\t" << typeName << std::endl; + } + + std::cout << std::endl; +} + +bool ArrayViewElisionPrefolder::handleOneProtoSlice(bool isLhs) { + CallExpr* call = isLhs ? newProtoSliceLhs_ : newProtoSliceRhs_; + + INT_ASSERT(call->isNamed("chpl__createProtoSlice") || + call->isNamed("chpl__createConstProtoSlice")); + + // stash some information while working on the call + if (fReportArrayViewElision) { + std::string& baseType = isLhs ? lhsBaseType_ : rhsBaseType_; + std::vector& indexExprTypes = isLhs ? lhsIndexExprTypes_ : + rhsIndexExprTypes_; + + bool baseRecorded = false; + for_actuals (actual, call) { + std::string typeName = std::string(actual->typeInfo()->symbol->name); + if (!baseRecorded) { + baseType = typeName; + baseRecorded = true; + } + else { + indexExprTypes.push_back(typeName); + } + } + } + + CallExpr* typeCheck = new CallExpr("chpl__ave_exprCanBeProtoSlice"); + for_actuals (actual, call) { + INT_ASSERT(isSymExpr(actual)); + typeCheck->insertAtTail(actual->copy()); + } + + VarSymbol* tmp = newTemp("call_tmp", dtBool); + DefExpr* flagDef = new DefExpr(tmp, typeCheck); + + staticCheckBlock_->insertAtTail(flagDef); + + resolveExpr(typeCheck); + resolveExpr(flagDef); + + bool ret = (toSymExpr(flagDef->init)->symbol() == gTrue); + + flagDef->remove(); + + // record the base symbol here for further checks + Symbol*& baseToCapture = isLhs ? lhsBase_ : rhsBase_; + baseToCapture = toSymExpr(call->get(1))->symbol(); + + return ret; +} + +// make sure we don't try to optimize A[3, 1..3] = B[1..3, 3]. +// because the current optimization works by strength-reducing that to use +// slices : A[3..3, 1..3] = B[1..3, 3..3]. That's not a valid assignment as +// opposed to what the user wrote. +bool ArrayViewElisionPrefolder::canAssign() const { + CallExpr* canAssign = new CallExpr("chpl__ave_protoSlicesSupportAssignment", + call_->get(1)->copy(), + call_->get(2)->copy()); + + VarSymbol* tmp = newTemp("call_tmp", dtBool); + DefExpr* flagDef = new DefExpr(tmp, canAssign); + + staticCheckBlock_->insertAtTail(flagDef); + + resolveExpr(canAssign); + resolveExpr(flagDef); + + bool ret = (toSymExpr(flagDef->init)->symbol() == gTrue); + + flagDef->remove(); + + return ret; +} + +// e must be the lhs or rhs of PRIM_ASSIGN_PROTO_SLICES +// returns the `chpl__createProtoSlice call +CallExpr* ArrayViewElisionPrefolder::findOneProtoSliceCall(Expr* e) { + SymExpr* symExpr = toSymExpr(e); + INT_ASSERT(symExpr); + + Symbol* sym = symExpr->symbol(); + CallExpr* tmpMove = toCallExpr(sym->getSingleDef()->getStmtExpr()); + INT_ASSERT(tmpMove && tmpMove->isPrimitive(PRIM_MOVE)); + + SymExpr* tmpSymExpr = toSymExpr(tmpMove->get(2)); + INT_ASSERT(tmpSymExpr); + + Symbol* tmpSym = tmpSymExpr->symbol(); + CallExpr* move = toCallExpr(tmpSym->getSingleDef()->getStmtExpr()); + INT_ASSERT(move && move->isPrimitive(PRIM_MOVE)); + + return toCallExpr(move->get(2)); +} + +void ArrayViewElisionPrefolder::findProtoSlices() { + //nprint_view(call_); + newProtoSliceLhs_ = findOneProtoSliceCall(call_->get(1)); + newProtoSliceRhs_ = findOneProtoSliceCall(call_->get(2)); +} + +void ArrayViewElisionPrefolder::findCondStmt() { + Expr* cur = call_; + while (cur) { + if (CondStmt* condStmt = toCondStmt(cur)) { + if (SymExpr* condExpr = toSymExpr(condStmt->condExpr)) { + if (condExpr->symbol()->hasFlag(FLAG_ARRAY_VIEW_ELISION_FLAG)) { + tmpCondFlag_ = condExpr->symbol(); + condStmt_ = condStmt; + break; + } + else { + // this is an unknown conditional, this shouldn't have happened + INT_FATAL(call_, + "unexpected syntax tree generated by arrayview elision"); + } + } + } + + cur = cur->parentExpr; + } + + if (condStmt_ == nullptr) { + // where is the conditional? + INT_FATAL(call_, + "unexpected syntax tree generated by arrayview elision"); + } +} + diff --git a/compiler/optimizations/forallOptimizations.cpp b/compiler/optimizations/forallOptimizations.cpp index 725f18c745f2..10d902ccb06e 100644 --- a/compiler/optimizations/forallOptimizations.cpp +++ b/compiler/optimizations/forallOptimizations.cpp @@ -146,6 +146,7 @@ void doPreNormalizeArrayOptimizations() { const bool anyAnalysisNeeded = fAutoLocalAccess || fAutoAggregation || !fNoFastFollowers; + if (anyAnalysisNeeded) { forv_expanding_Vec(ForallStmt, forall, gForallStmts) { if (!fNoFastFollowers) { diff --git a/compiler/passes/normalize.cpp b/compiler/passes/normalize.cpp index 031a0fd0fa92..d951d2f4fc40 100644 --- a/compiler/passes/normalize.cpp +++ b/compiler/passes/normalize.cpp @@ -26,6 +26,7 @@ #include "baseAST.h" #include "passes.h" +#include "arrayViewElision.h" #include "astutil.h" #include "build.h" #include "DecoratedClassType.h" @@ -172,6 +173,8 @@ void normalize() { insertModuleInit(); + arrayViewElision(); + doPreNormalizeArrayOptimizations(); moveAndCheckInterfaceConstraints(); diff --git a/compiler/resolution/preFold.cpp b/compiler/resolution/preFold.cpp index cf4cbb0f285d..3f89ef8c27c6 100644 --- a/compiler/resolution/preFold.cpp +++ b/compiler/resolution/preFold.cpp @@ -20,6 +20,7 @@ #include "preFold.h" +#include "arrayViewElision.h" #include "astutil.h" #include "buildDefaultFunctions.h" #include "fcf-support.h" @@ -916,6 +917,24 @@ static Expr* preFoldPrimOp(CallExpr* call) { break; } + case PRIM_PROTO_SLICE_ASSIGN: { + ArrayViewElisionPrefolder assignment(call); + + if (assignment.supported()) { + retval = assignment.getReplacement(); + call->replace(retval); + } + else { + retval = new CallExpr(PRIM_NOOP); + assignment.condStmt()->insertBefore(retval); + } + + assignment.report(); + assignment.updateAndFoldConditional(); + + break; + } + case PRIM_CALL_RESOLVES: case PRIM_CALL_AND_FN_RESOLVES: case PRIM_METHOD_CALL_RESOLVES: diff --git a/frontend/include/chpl/uast/PragmaList.h b/frontend/include/chpl/uast/PragmaList.h index beebfe3c067f..40bc535af7b6 100644 --- a/frontend/include/chpl/uast/PragmaList.h +++ b/frontend/include/chpl/uast/PragmaList.h @@ -52,6 +52,11 @@ PRAGMA(ALIASING_ARRAY, ypr, "aliasing array", ncm) // can alias the same scopes as 'this' PRAGMA(ALIAS_SCOPE_FROM_THIS, ypr, "alias scope from this", ncm) +// Added to the condExpr of a static ArrayView Elision conditional. Should +// disappear after resolution +PRAGMA(ARRAY_VIEW_ELISION_FLAG, npr, "static flag for array view elision", ncm) +PRAGMA(NO_ARRAY_VIEW_ELISION, ypr, "no array view elision", ncm) + // This flag is used in scalarReplace.cpp to determine if an assignment of a ref // has an allocator as the RHS. If so, then it is not creating an alias, since // the allocator function does not retain a reference to the referenced object. diff --git a/frontend/include/chpl/uast/prim-ops-list.h b/frontend/include/chpl/uast/prim-ops-list.h index 1285e1c2bae0..aaeb75586e99 100644 --- a/frontend/include/chpl/uast/prim-ops-list.h +++ b/frontend/include/chpl/uast/prim-ops-list.h @@ -230,6 +230,8 @@ PRIMITIVE_R(MAYBE_LOCAL_THIS, "may be local access") PRIMITIVE_R(MAYBE_LOCAL_ARR_ELEM, "may be local array element") PRIMITIVE_R(MAYBE_AGGREGATE_ASSIGN, "may be aggregated assignment") +PRIMITIVE_R(PROTO_SLICE_ASSIGN, "assign proto slices") + PRIMITIVE_R(ERROR, "error") PRIMITIVE_R(WARNING, "warning") PRIMITIVE_R(WHEN, "when case expressions") diff --git a/frontend/lib/resolution/prims.cpp b/frontend/lib/resolution/prims.cpp index 173c5080b276..606e4e1d0d00 100644 --- a/frontend/lib/resolution/prims.cpp +++ b/frontend/lib/resolution/prims.cpp @@ -1696,6 +1696,7 @@ CallResolutionResult resolvePrimCall(Context* context, case PRIM_MAYBE_LOCAL_THIS: case PRIM_MAYBE_LOCAL_ARR_ELEM: case PRIM_MAYBE_AGGREGATE_ASSIGN: + case PRIM_PROTO_SLICE_ASSIGN: case PRIM_BLOCK_PARAM_LOOP: case PRIM_BLOCK_WHILEDO_LOOP: case PRIM_BLOCK_DOWHILE_LOOP: diff --git a/man/chpl.rst b/man/chpl.rst index 769e1a9a42a5..86fea582e56c 100644 --- a/man/chpl.rst +++ b/man/chpl.rst @@ -467,6 +467,12 @@ OPTIONS Enable [disable] optimization of the last statement in forall statements to use aggregated communication. This optimization is disabled by default. +.. _man-array-view-elision: + +**\--[no-]array-view-elision** + + Enable [disable] an optimization eliding array views in some statements. + *Run-time Semantic Check Options* .. _man-checks: diff --git a/modules/dists/DSIUtil.chpl b/modules/dists/DSIUtil.chpl index efbc4977d83a..aa16ee241999 100644 --- a/modules/dists/DSIUtil.chpl +++ b/modules/dists/DSIUtil.chpl @@ -498,6 +498,8 @@ private proc asap1(arg) { if isSubtype(arg.type, BaseDom) then return asapTuple(arg.dsiDims()); if isSubtype(arg.type, BaseArr) then return asapTuple(arg.dom.dsiDims()); compilerError("asap1: unsupported argument type ", arg.type:string); + return false; // otherwise we get resolution errors before the compilerError + // above } // asapP1 = All Strides Are Positive - Param - 1 arg diff --git a/modules/internal/ChapelArray.chpl b/modules/internal/ChapelArray.chpl index 3bfb63429131..0d586bcb1814 100644 --- a/modules/internal/ChapelArray.chpl +++ b/modules/internal/ChapelArray.chpl @@ -34,6 +34,7 @@ module ChapelArray { use CTypes; use ChapelPrivatization; use ChplConfig only compiledForSingleLocale, CHPL_LOCALE_MODEL; + use ChapelArrayViewElision; public use ChapelDomain; // Explicitly use a processor atomic, as most calls to this function are @@ -511,7 +512,7 @@ module ChapelArray { param isDRView = chpl__isArrayView(value) && chpl__getActualArray(value).isDefaultRectangular(); return isDR || isDRView; } else { - compilerError("Invalid argument for chpl__isDROrDRView"); + return false; } } @@ -2066,7 +2067,7 @@ module ChapelArray { } } - proc chpl__serializeAssignment(a: [], b) param { + proc chpl__serializeAssignment(a, b) param { if a.rank != 1 && isRange(b) then return true; @@ -2091,7 +2092,7 @@ module ChapelArray { } // This must be a param function - proc chpl__compatibleForBulkTransfer(a:[], b:[], param kind:_tElt) param { + proc chpl__compatibleForBulkTransfer(a, b, param kind:_tElt) param { if !useBulkTransfer then return false; if a.eltType != b.eltType then return false; if kind==_tElt.move then return true; @@ -2141,10 +2142,12 @@ module ChapelArray { proc chpl__supportedDataTypeForBulkTransfer(x) param do return true; @chpldoc.nodoc - proc checkArrayShapesUponAssignment(a: [], b: [], forSwap = false) { + proc checkArrayShapesUponAssignment(a, b, forSwap = false) { if a.isRectangular() && b.isRectangular() { - const aDims = a._value.dom.dsiDims(), - bDims = b._value.dom.dsiDims(); + const aDims = if isProtoSlice(a) then a.dims() + else a._value.dom.dsiDims(); + const bDims = if isProtoSlice(b) then b.dims() + else b._value.dom.dsiDims(); compilerAssert(aDims.size == bDims.size); for param i in 0..aDims.size-1 { if aDims(i).sizeAs(uint) != bDims(i).sizeAs(uint) then @@ -2159,8 +2162,7 @@ module ChapelArray { } pragma "find user line" - @chpldoc.nodoc - inline operator =(ref a: [], b:[]) { + private inline proc arrayOrProtoSliceAssign(ref a, b) { if a.rank != b.rank then compilerError("rank mismatch in array assignment"); @@ -2169,7 +2171,18 @@ module ChapelArray { // default initializer is a forall expr. E.g. arrayInClassRecord.chpl. return; - if a._value == b._value { + var eqVals: bool; + if isArray(a) && isArray(b) { + eqVals = (a._value == b._value); + } + else if isProtoSlice(a) && isProtoSlice(b) { + eqVals = (a == b); // default record comparison should cover it + } + else { + compilerError("Internal error: cross-type assignments are not supported"); + } + + if eqVals then { // Do nothing for A = A but we could generate a warning here // since it is probably unintended. We need this check here in order // to avoid memcpy(x,x) which happens inside doiBulkTransfer. @@ -2186,6 +2199,19 @@ module ChapelArray { chpl__uncheckedArrayTransfer(a, b, kind=_tElt.assign); } + + pragma "find user line" + @chpldoc.nodoc + inline operator =(ref a: [], b: []) { + arrayOrProtoSliceAssign(a, b); + } + + pragma "find user line" + @chpldoc.nodoc + inline operator =(ref a: chpl__protoSlice, b: chpl__protoSlice) { + arrayOrProtoSliceAssign(a, b); + } + // what kind of transfer to do for each element? @chpldoc.nodoc enum _tElt { @@ -2293,32 +2319,46 @@ module ChapelArray { } pragma "find user line" - inline proc chpl__uncheckedArrayTransfer(ref a: [], b:[], param kind) { + inline proc chpl__uncheckedArrayTransfer(ref a, b, param kind) { + use ChapelShortArrayTransfer; - var done = false; - if !chpl__serializeAssignment(a, b) { - if chpl__compatibleForBulkTransfer(a, b, kind) { - done = chpl__bulkTransferArray(a, b); + if chpl__serializeAssignment(a, b) { + chpl__transferArray(a, b, kind); + } + else if chpl__staticCheckShortArrayTransfer(a, b) && + chpl__dynamicCheckShortArrayTransfer(a, b) { + chpl__transferArray(a, b, kind, alwaysSerialize=true); + } + else if chpl__compatibleForBulkTransfer(a, b, kind) { + if chpl__bulkTransferArray(a, b) { + chpl__initAfterBulkTransfer(a, kind); } - else if chpl__compatibleForWidePtrBulkTransfer(a, b, kind) { - done = chpl__bulkTransferPtrArray(a, b); + else { + chpl__transferArray(a, b, kind); } - // If we did a bulk transfer, it just bit copied, so need to - // run copy initializer still - if done { - if kind==_tElt.initCopy && !isPODType(a.eltType) { - initCopyAfterTransfer(a); - } else if kind==_tElt.move && (isSubtype(a.eltType, _array) || - isSubtype(a.eltType, _domain)) { - fixEltRuntimeTypesAfterTransfer(a); - } + } + else if chpl__compatibleForWidePtrBulkTransfer(a, b, kind) { + if chpl__bulkTransferPtrArray(a, b) { + chpl__initAfterBulkTransfer(a, kind); + } + else { + chpl__transferArray(a, b, kind); } } - if !done { + else { chpl__transferArray(a, b, kind); } } + inline proc chpl__initAfterBulkTransfer(ref a, param kind) { + if kind==_tElt.initCopy && !isPODType(a.eltType) { + initCopyAfterTransfer(a); + } else if kind==_tElt.move && (isSubtype(a.eltType, _array) || + isSubtype(a.eltType, _domain)) { + fixEltRuntimeTypesAfterTransfer(a); + } + } + proc chpl__compatibleForWidePtrBulkTransfer(a, b, param kind=_tElt.assign) param { if !useBulkPtrTransfer then return false; @@ -2359,11 +2399,21 @@ module ChapelArray { inline proc chpl__bulkTransferArray(ref a: [?AD], b : [?BD]) { return chpl__bulkTransferArray(a, AD, b, BD); } - inline proc chpl__bulkTransferArray(ref a: [], AD : domain, const ref b: [], BD : domain) { + + inline proc chpl__bulkTransferArray(ref a: chpl__protoSlice, + b: chpl__protoSlice) { + if debugBulkTransfer { + chpl_debug_writeln("Performing protoSlice bulk transfer"); + } + return chpl__bulkTransferArray(a.ptrToArr.deref(), a.domOrRange, + b.ptrToArr.deref(), b.domOrRange); + } + inline proc chpl__bulkTransferArray(ref a: [], AD, const ref b: [], BD) { return chpl__bulkTransferArray(a._value, AD, b._value, BD); } - inline proc chpl__bulkTransferArray(destClass, destDom : domain, srcClass, srcDom : domain) { + + inline proc chpl__bulkTransferArray(destClass, destView, srcClass, srcView) { var success = false; inline proc bulkTransferDebug(msg:string) { @@ -2380,21 +2430,21 @@ module ChapelArray { // TODO: should we attempt other bulk transfer methods if one fails? // if Reflection.canResolveMethod(destClass, "doiBulkTransferFromKnown", - destDom, srcClass, srcDom) { + destView, srcClass, srcView) { bulkTransferDebug("attempting doiBulkTransferFromKnown"); - success = destClass.doiBulkTransferFromKnown(destDom, srcClass, srcDom); + success = destClass.doiBulkTransferFromKnown(destView, srcClass, srcView); } else if Reflection.canResolveMethod(srcClass, "doiBulkTransferToKnown", - srcDom, destClass, destDom) { + srcView, destClass, destView) { bulkTransferDebug("attempting doiBulkTransferToKnown"); - success = srcClass.doiBulkTransferToKnown(srcDom, destClass, destDom); + success = srcClass.doiBulkTransferToKnown(srcView, destClass, destView); } else if Reflection.canResolveMethod(destClass, "doiBulkTransferFromAny", - destDom, srcClass, srcDom) { + destView, srcClass, srcView) { bulkTransferDebug("attempting doiBulkTransferFromAny"); - success = destClass.doiBulkTransferFromAny(destDom, srcClass, srcDom); + success = destClass.doiBulkTransferFromAny(destView, srcClass, srcView); } else if Reflection.canResolveMethod(srcClass, "doiBulkTransferToAny", - srcDom, destClass, destDom) { + srcView, destClass, destView) { bulkTransferDebug("attempting doiBulkTransferToAny"); - success = srcClass.doiBulkTransferToAny(srcDom, destClass, destDom); + success = srcClass.doiBulkTransferToAny(srcView, destClass, destView); } if success then @@ -2407,8 +2457,9 @@ module ChapelArray { pragma "find user line" pragma "ignore transfer errors" - inline proc chpl__transferArray(ref a: [], const ref b, - param kind=_tElt.assign) lifetime a <= b { + inline proc chpl__transferArray(ref a, const ref b, + param kind=_tElt.assign, + param alwaysSerialize=false) lifetime a <= b { if (a.eltType == b.type || _isPrimitiveType(a.eltType) && _isPrimitiveType(b.type)) { @@ -2436,7 +2487,7 @@ module ChapelArray { aa = b; } } - } else if chpl__serializeAssignment(a, b) { + } else if alwaysSerialize || chpl__serializeAssignment(a, b) { if kind==_tElt.move { if needsInitWorkaround(a.eltType) { for (ai, bb) in zip(a.domain, b) { diff --git a/modules/internal/ChapelArrayViewElision.chpl b/modules/internal/ChapelArrayViewElision.chpl new file mode 100644 index 000000000000..43c596aff91a --- /dev/null +++ b/modules/internal/ChapelArrayViewElision.chpl @@ -0,0 +1,462 @@ +/* + * Copyright 2020-2024 Hewlett Packard Enterprise Development LP + * Copyright 2004-2019 Cray Inc. + * Other additional copyright holders may be indicated within. + * + * The entirety of this work is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module ChapelArrayViewElision { + use ChapelBase only iterKind; + use ChapelRange; + use DefaultRectangular; + use CTypes; + use ChapelArray only _validRankChangeArgs; + + // + // compiler interface + // + // Calls to these functions are inserted by the compiler. See + // compiler/optimizations/arrayViewElision.cpp for how the compiler makes use + // of these functions. + + proc chpl__createProtoSlice(ref Arr, slicingExprs ...) + where chpl__createProtoSliceArgCheck(Arr, slicingExprs) { + + if slicingExprs.size == 1 then + return new chpl__protoSlice(isConst=false, c_addrOf(Arr), + slicingExprs[0]); + else + return new chpl__protoSlice(isConst=false, c_addrOf(Arr), slicingExprs); + } + + proc chpl__createConstProtoSlice(const ref Arr, slicingExprs ...) + where chpl__createProtoSliceArgCheck(Arr, slicingExprs) { + + if slicingExprs.size == 1 { + return new chpl__protoSlice(isConst=true, c_addrOfConst(Arr), + slicingExprs[0]); + } + else + return new chpl__protoSlice(isConst=true, c_addrOfConst(Arr), + slicingExprs); + } + + // catch-all: nothing here is supported, just pretend creating a proto slice. + // The branch where this call is will be dropped during resolution. We just + // want to avoid resolution errors before that happens + proc chpl__createProtoSlice(x, slicingExprs... ) { + return new chpl__protoSlice(); + } + + // catch-all: nothing here is supported, just pretend creating a proto slice. + // The branch where this call is will be dropped during resolution. We just + // want to avoid resolution errors before that happens + proc chpl__createConstProtoSlice(x, slicingExprs... ) { + return new chpl__protoSlice(); + } + + proc chpl__ave_exprCanBeProtoSlice(base, idxExprs...) param: bool { + return chpl__ave_baseTypeSupports(base) && + chpl__ave_idxExprsSupport(base.idxType, (...idxExprs)); + } + + proc chpl__ave_protoSlicesSupportAssignment(a: chpl__protoSlice, + b: chpl__protoSlice) param: bool { + if a.isRankChange != b.isRankChange then return false; //or assert? + + if !a.isRankChange then return true; // nothing else to check + + // we want to check that if there are integrals in the original slicing + // expressions, they are at the same rank. In other words, if we are working + // with rank-changes, we want to make sure that the collapsed dims on both + // sides match + type aType = a.slicingExprType; + type bType = b.slicingExprType; + compilerAssert(a.slicingExprType.size == b.slicingExprType.size); + for param i in 0..1 { + if isDomain(ranges) then + return ranges; + else + return {(...ranges)}; + } + + inline proc dims() { + if chpl__isTupleOfRanges(this.ranges) { + return ranges; + } + else if isDomain(this.ranges) { + return ranges.dims(); + } + else if isRange(this.ranges) { + return (ranges,); + } + else { + compilerError("Unhandled case in chpl__protoSlice.dims()"); + } + } + + inline proc rank param { return ptrToArr.deref().rank; } + inline proc eltType type { return ptrToArr.deref().eltType; } + inline proc _value { return ptrToArr.deref()._value; } + + inline proc sizeAs(type t) where rank==1 { + return ranges.sizeAs(t); + } + + inline proc sizeAs(type t) { + if isDomain(this.ranges) { + return ranges.sizeAs(t); + } + else { + var size = 1:t; + for param r in 0.. b; } + + // check if both arguments are local without `.locale` or `here` + proc chpl__bothLocal(const ref a, const ref b) { + extern proc chpl_equals_localeID(const ref x, const ref y): bool; + + const aLoc = __primitive("_wide_get_locale", a._value); + const bLoc = __primitive("_wide_get_locale", b._value); + + return chpl_equals_localeID(aLoc, bLoc) && + chpl_equals_localeID(aLoc, here_id); + } } diff --git a/modules/internal/ChapelDomain.chpl b/modules/internal/ChapelDomain.chpl index b0908938a383..98a5c8bc45ea 100644 --- a/modules/internal/ChapelDomain.chpl +++ b/modules/internal/ChapelDomain.chpl @@ -57,6 +57,27 @@ module ChapelDomain { return new _domain(nullPid, value, _unowned=true); } + @chpldoc.nodoc + proc tupleOfRangesSlice(base, slice) where chpl__isTupleOfRanges(base) && + chpl__isTupleOfRanges(slice) { + + if base.size != slice.size then + compilerError("tuple size mismatch in tupleOfRangesSlice"); + + param rank = base.size; + + proc resultStrides(param dim = 0) param do return + if dim == rank-1 then ( base(dim)[slice(dim)] ).strides + else chpl_strideUnion( ( base(dim)[slice(dim)] ).strides, + resultStrides(dim+1) ); + + var r: rank*range(base[0].idxType, boundKind.both, resultStrides()); + for param i in 0..rank-1 { + r(i) = base(i)[slice(i)]; + } + return r; + } + // Run-time type support // // NOTE: the bodies of functions marked with runtime type init fn (such as @@ -175,6 +196,7 @@ module ChapelDomain { // proc chpl__isTupleOfRanges(tup) param { + if !isTuple(tup) then return false; for param i in 0..tup.size-1 { if !isRangeType(tup(i).type) then return false; @@ -1317,17 +1339,7 @@ module ChapelDomain { @chpldoc.nodoc proc this(ranges...rank) where chpl__isTupleOfRanges(ranges) { - const myDims = dims(); - - proc resultStrides(param dim = 0) param do return - if dim == rank-1 then ( myDims(dim)[ranges(dim)] ).strides - else chpl_strideUnion( ( myDims(dim)[ranges(dim)] ).strides, - resultStrides(dim+1) ); - - var r: rank*range(_value.idxType, boundKind.both, resultStrides()); - for param i in 0..rank-1 { - r(i) = myDims(i)[ranges(i)]; - } + const r = tupleOfRangesSlice(dims(), ranges); return new _domain(distribution, rank, _value.idxType, r(0).strides, r); } diff --git a/modules/internal/ChapelShortArrayTransfer.chpl b/modules/internal/ChapelShortArrayTransfer.chpl new file mode 100644 index 000000000000..1a24480b0258 --- /dev/null +++ b/modules/internal/ChapelShortArrayTransfer.chpl @@ -0,0 +1,85 @@ +/* + * Copyright 2020-2024 Hewlett Packard Enterprise Development LP + * Copyright 2004-2019 Cray Inc. + * Other additional copyright holders may be indicated within. + * + * The entirety of this work is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a helper module to support the Short Array Transfer optimization. +// For array-to-array assignments where number of elements (or maybe the data +// size?) are below some threshold, just looping serially is more efficient +// than both parallel iteration and memcpy. + +module ChapelShortArrayTransfer { + use ChapelBase; + use ChplConfig only CHPL_LOCALE_MODEL; + + @chpldoc.nodoc + config param debugShortArrayTransfer = false; + @chpldoc.nodoc + config param disableShortArrayTransfer = false; + @chpldoc.nodoc + config param shortArrayTransferThreshold = 60; // number of elements + + + proc chpl__staticCheckShortArrayTransfer(a, b) param { + // Engin: this is the case I'm focusing on in the initial PR. This can + // definitely be loosened up... by a lot. + return !disableShortArrayTransfer && isProtoSlice(a) && isProtoSlice(b); + } + + inline proc chpl__dynamicCheckShortArrayTransfer(a, b) { + param msgHeader = " "; + param localCompilation = _local && CHPL_LOCALE_MODEL=="flat"; + const sizeOk = a.sizeAs(uint) < shortArrayTransferThreshold; + + debug("Size: ", a.sizeAs(uint), " Threshold: ", + shortArrayTransferThreshold); + if sizeOk then + debug("size qualifies"); + else + debug("size doesn't qualify"); + + if localCompilation { + return sizeOk; + } + else { + extern proc chpl_task_getRequestedSubloc(): int(32); + // No `.locale` to avoid overheads. Note that this is an optimization for + // fast-running code. Small things matter. + const bothLocal = chpl__bothLocal(a, b); + const notGpu = CHPL_LOCALE_MODEL=="flat" || + chpl_task_getRequestedSubloc() < 0; + + if bothLocal then + if notGpu then + debug("locality qualifies"); + else + debug("GPU arrays shouldn't be SAT'ed"); + else + debug("locality does not qualify"); + + return sizeOk && bothLocal && notGpu; + } + } + + private proc debug(s...) { + use ChapelDebugPrint only chpl_debug_writeln; + if debugShortArrayTransfer { + chpl_debug_writeln(" ", (...s)); + } + } +} diff --git a/modules/internal/ChapelStandard.chpl b/modules/internal/ChapelStandard.chpl index 3e10bd091846..662acb8dd374 100644 --- a/modules/internal/ChapelStandard.chpl +++ b/modules/internal/ChapelStandard.chpl @@ -76,6 +76,7 @@ module ChapelStandard { public use ChapelContext; public use ChapelStaticVars; public use ChapelRemoteVars; + public use ChapelArrayViewElision; // Standard modules. public use Types as Types; diff --git a/modules/internal/ChapelTuple.chpl b/modules/internal/ChapelTuple.chpl index 9d5ad4e6cb95..f9180ecf8d8f 100644 --- a/modules/internal/ChapelTuple.chpl +++ b/modules/internal/ChapelTuple.chpl @@ -148,6 +148,7 @@ module ChapelTuple { // pragma "compiler generated" pragma "last resort" + pragma "no array view elision" @chpldoc.nodoc inline operator =(ref x: _tuple, pragma "intent ref maybe const formal" y: _tuple) diff --git a/modules/internal/DefaultRectangular.chpl b/modules/internal/DefaultRectangular.chpl index c18760142245..04c7bbd245ea 100644 --- a/modules/internal/DefaultRectangular.chpl +++ b/modules/internal/DefaultRectangular.chpl @@ -1622,51 +1622,64 @@ module DefaultRectangular { } } - iter chpl__serialViewIter(arr, viewDom) ref - where chpl__isDROrDRView(arr) { + // This is specialized to avoid overheads of calling dsiAccess() + iter chpl__serialViewIter1D(arr, viewRange) ref + where chpl__isDROrDRView(arr) { + param useCache = chpl__isArrayView(arr) && arr.shouldUseIndexCache(); var info = if useCache then arr.indexCache else if arr.isSliceArrayView() then arr.arr else arr; - if arr.rank == 1 { - // This is specialized to avoid overheads of calling dsiAccess() - if viewDom.hasUnitStride() { - // Ideally we would like to be able to do something like - // "for i in first..last by step". However, right now that would - // result in a strided iterator which isn't as optimized. It would - // also add a range initializer, which in tight loops is pretty - // expensive. Instead we use a direct range iterator that is - // optimized for positively strided ranges. It should be just as fast - // as directly using a "c for loop", but it contains code check for - // overflow and invalid strides as well as the ability to use a less - // optimized iteration method if users are concerned about range - // overflow. - - const first = info.getDataIndex(viewDom.dsiLow); - const second = info.getDataIndex(chpl__intToIdx(viewDom.idxType, chpl__idxToInt(viewDom.dsiLow)+1)); - const step = (second-first); - const last = first + (viewDom.dsiNumIndices:step.type-1) * step; - foreach i in chpl_direct_pos_stride_range_iter(first, last, step) with (ref info) { - yield info.theData(i); - } - } else { - type vdIntIdxType = chpl__idxTypeToIntIdxType(viewDom.idxType); - const viewDomDim = viewDom.dsiDim(0), - stride = viewDomDim.stride: vdIntIdxType, - start = viewDomDim.first, - second = info.getDataIndex(chpl__intToIdx(viewDom.idxType, viewDomDim.firstAsInt + stride)); - var first = info.getDataIndex(start); - const step = (second-first).safeCast(int); - var last = first + (viewDomDim.sizeAs(int)-1) * step; + if viewRange.hasUnitStride() { + // Ideally we would like to be able to do something like + // "for i in first..last by step". However, right now that would + // result in a strided iterator which isn't as optimized. It would + // also add a range initializer, which in tight loops is pretty + // expensive. Instead we use a direct range iterator that is + // optimized for positively strided ranges. It should be just as fast + // as directly using a "c for loop", but it contains code check for + // overflow and invalid strides as well as the ability to use a less + // optimized iteration method if users are concerned about range + // overflow. + + const first = info.getDataIndex(viewRange.low); + const second = info.getDataIndex(chpl__intToIdx(viewRange.idxType, chpl__idxToInt(viewRange.low)+1)); + const step = (second-first); + const last = first + (viewRange.size:step.type-1) * step; + foreach i in chpl_direct_pos_stride_range_iter(first, last, step) + with (ref info) { + yield info.theData(i); + } + } else { + type vdIntIdxType = chpl__idxTypeToIntIdxType(viewRange.idxType); + const stride = viewRange.stride: vdIntIdxType, + start = viewRange.first, + second = info.getDataIndex(chpl__intToIdx(viewRange.idxType, viewRange.firstAsInt + stride)); - if step < 0 then - last <=> first; + var first = info.getDataIndex(start); + const step = (second-first).safeCast(int); + var last = first + (viewRange.sizeAs(int)-1) * step; - var data = info.theData; - foreach i in first..last by step do - yield data(i); - } + if step < 0 then + last <=> first; + + var data = info.theData; + foreach i in first..last by step do + yield data(i); + } + + } + + iter chpl__serialViewIter(arr, viewDom) ref + where chpl__isDROrDRView(arr) { + param useCache = chpl__isArrayView(arr) && arr.shouldUseIndexCache(); + var info = if useCache then arr.indexCache + else if arr.isSliceArrayView() then arr.arr + else arr; + if arr.rank == 1 { + foreach elem in chpl__serialViewIter1D(arr, viewDom.dsiDim[0]) do + yield elem; } else if useCache { foreach i in viewDom { const dataIdx = info.getDataIndex(i); @@ -1978,6 +1991,25 @@ module DefaultRectangular { dsiSerialReadWrite(f); } + inline proc DefaultRectangularArr.isDataContiguous(dom: domain) { + return isDataContiguous(dom._value); + } + + // This is very conservative. + inline proc DefaultRectangularArr.isDataContiguous(dom: range) { + if rank != 1 then return false; + + if debugDefaultDistBulkTransfer then + chpl_debug_writeln("isDataContiguous(): off=", off, " blk=", blk); + + if blk(rank-1) != 1 then return false; + + if debugDefaultDistBulkTransfer then + chpl_debug_writeln("\tYES!"); + + return true; + } + // This is very conservative. proc DefaultRectangularArr.isDataContiguous(dom) { if debugDefaultDistBulkTransfer then @@ -1998,7 +2030,7 @@ module DefaultRectangular { } private proc _canDoSimpleTransfer(A, aView, B, bView) { - if !A.isDataContiguous(aView._value) || !B.isDataContiguous(bView._value) { + if !A.isDataContiguous(aView) || !B.isDataContiguous(bView) { if debugDefaultDistBulkTransfer then chpl_debug_writeln("isDataContiguous return False"); return false; @@ -2049,15 +2081,29 @@ module DefaultRectangular { param rank = A.rank; type idxType = A.idxType; - const Adims = aView.dims(); var Alo: rank*aView.idxType; - for param i in 0..rank-1 do - Alo(i) = Adims(i).first; - const Bdims = bView.dims(); + if isDomain(aView) { + const Adims = aView.dims(); + for param i in 0..rank-1 do + Alo(i) = Adims(i).first; + } + else if isRange(aView) { + Alo(0) = aView.first; + } + else { + compilerError("Unexpected type"); + } + var Blo: rank*B.idxType; + if isDomain(bView) { + const Bdims = bView.dims(); for param i in 0..rank-1 do Blo(i) = Bdims(i).first; + } + else if isRange(bView) { + Blo(0) = bView.first; + } const len = aView.sizeAs(aView.chpl_integralIdxType).safeCast(c_size_t); @@ -2214,8 +2260,10 @@ module DefaultRectangular { writeln("Original domains :", LHS.dom.dsiDims(), " <-- ", RHS.dom.dsiDims()); } - const LeftDims = LViewDom.dims(); - const RightDims = RViewDom.dims(); + const LeftDims = if isDomain(LViewDom) then LViewDom.dims() + else (LViewDom,); + const RightDims = if isDomain(RViewDom) then RViewDom.dims() + else (RViewDom, ); const (LeftActives, RightActives, inferredRank) = bulkCommComputeActiveDims(LeftDims, RightDims); diff --git a/modules/standard/CTypes.chpl b/modules/standard/CTypes.chpl index abe8a0d2ddeb..ff0780dbab18 100644 --- a/modules/standard/CTypes.chpl +++ b/modules/standard/CTypes.chpl @@ -836,16 +836,16 @@ module CTypes { */ @chpldoc.nodoc inline proc c_ptrTo(ref arr: []): c_ptr(arr.eltType) { - if (!arr.isRectangular() || !arr.domain.distribution._value.dsiIsLayout()) then + if (!isSubtype(arr.domain._instance.type, DefaultRectangularDom)) then compilerError("Only single-locale rectangular arrays support c_ptrTo() at present"); - if (arr._value.locale != here) then - halt( - "c_ptrTo() can only be applied to an array from the locale on " + - "which it lives (array is on locale " + arr._value.locale.id:string + - ", call was made on locale " + here.id:string + ")"); - if boundsChecking { + if (arr._value.locale != here) then + halt( + "c_ptrTo() can only be applied to an array from the locale on " + + "which it lives (array is on locale " + arr._value.locale.id:string + + ", call was made on locale " + here.id:string + ")"); + if (arr.size == 0) then halt("Can't create a C pointer for an array with 0 elements."); } @@ -925,16 +925,16 @@ module CTypes { */ @chpldoc.nodoc inline proc c_ptrToConst(const arr: []): c_ptrConst(arr.eltType) { - if (!arr.isRectangular() || !arr.domain.distribution._value.dsiIsLayout()) then + if (!isSubtype(arr.domain._instance.type, DefaultRectangularDom)) then compilerError("Only single-locale rectangular arrays support c_ptrToConst() at present"); - if (arr._value.locale != here) then - halt( - "c_ptrToConst() can only be applied to an array from the locale on " + - "which it lives (array is on locale " + arr._value.locale.id:string + - ", call was made on locale " + here.id:string + ")"); - if boundsChecking { + if (arr._value.locale != here) then + halt( + "c_ptrToConst() can only be applied to an array from the locale on " + + "which it lives (array is on locale " + arr._value.locale.id:string + + ", call was made on locale " + here.id:string + ")"); + if (arr.size == 0) then halt("Can't create a C pointer for an array with 0 elements."); } @@ -996,10 +996,10 @@ module CTypes { */ @chpldoc.nodoc inline proc c_addrOf(ref arr: []) { - if (!arr.isRectangular() || !arr.domain.distribution._value.dsiIsLayout()) then + if (!isSubtype(arr.domain._instance.type, DefaultRectangularDom)) then compilerError("Only single-locale rectangular arrays support c_addrOf() at present"); - if (arr._value.locale != here) then + if (boundsChecking && arr._value.locale != here) then halt( "c_addrOf() can only be applied to an array from the locale on " + "which it lives (array is on locale " + arr._value.locale.id:string + @@ -1014,10 +1014,10 @@ module CTypes { */ @chpldoc.nodoc inline proc c_addrOfConst(const arr: []) { - if (!arr.isRectangular() || !arr.domain.distribution._value.dsiIsLayout()) then + if (!isSubtype(arr.domain._instance.type, DefaultRectangularDom)) then compilerError("Only single-locale rectangular arrays support c_addrOfConst() at present"); - if (arr._value.locale != here) then + if (boundsChecking && arr._value.locale != here) then halt( "c_addrOfConst() can only be applied to an array from the locale on " + "which it lives (array is on locale " + arr._value.locale.id:string + diff --git a/runtime/include/localeModels/flat/chpl-locale-model.h b/runtime/include/localeModels/flat/chpl-locale-model.h index 779ba55f0bc6..3636eb82a188 100644 --- a/runtime/include/localeModels/flat/chpl-locale-model.h +++ b/runtime/include/localeModels/flat/chpl-locale-model.h @@ -71,6 +71,11 @@ c_sublocid_t chpl_rt_sublocFromLocaleID(chpl_localeID_t loc) { return c_sublocid_any; } +static inline +int chpl_equals_localeID(chpl_localeID_t* loc1, chpl_localeID_t* loc2) { + return loc1->node == loc2->node; +} + // // These functions are exported from the locale model for use by // the tasking layer to convert between a full sublocale and an diff --git a/runtime/include/localeModels/gpu/chpl-locale-model.h b/runtime/include/localeModels/gpu/chpl-locale-model.h index 0a4cf6a92b66..b7f94c7d8dfc 100644 --- a/runtime/include/localeModels/gpu/chpl-locale-model.h +++ b/runtime/include/localeModels/gpu/chpl-locale-model.h @@ -71,6 +71,13 @@ c_sublocid_t chpl_rt_sublocFromLocaleID(chpl_localeID_t loc) { return loc.subloc; } +static inline +int chpl_equals_localeID(chpl_localeID_t* loc1, chpl_localeID_t* loc2) { + return loc1->node == loc2->node && + loc1->subloc == loc2->subloc; +} + + // // These functions are exported from the locale model for use by // the tasking layer to convert between a full sublocale and an diff --git a/test/compflags/bradc/help/userhelp.good b/test/compflags/bradc/help/userhelp.good index 6397f9b1f21c..a66e13a4e5dd 100644 --- a/test/compflags/bradc/help/userhelp.good +++ b/test/compflags/bradc/help/userhelp.good @@ -111,6 +111,7 @@ Optimization Control Options: automatically (dynamic only) --[no-]auto-aggregation Enable [disable] automatically aggregating remote accesses in foralls + --[no-]array-view-elision Enable [disable] array view elision Run-time Semantic Check Options: --[no-]checks Enable [disable] all following run-time diff --git a/test/compflags/ferguson/print-module-resolution.good b/test/compflags/ferguson/print-module-resolution.good index 45fd5bc24657..e967200b5381 100644 --- a/test/compflags/ferguson/print-module-resolution.good +++ b/test/compflags/ferguson/print-module-resolution.good @@ -98,6 +98,8 @@ ArrayViewReindex from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.ArrayViewReindex ChapelPrivatization from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.ChapelPrivatization +ChapelArrayViewElision + from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.ChapelArrayViewElision ChapelIO from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.ChapelDomain.FormattedIO.IO.ChapelIO Types @@ -134,6 +136,8 @@ QuickSort from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.Sort.QuickSort Sort from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.Sort +ChapelShortArrayTransfer + from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray.ChapelShortArrayTransfer ChapelArray from print-module-resolution.ChapelStandard.LocaleModel.LocaleModelHelpFlat.LocaleModelHelpSetup.DefaultRectangular.ChapelArray ChapelHashtable diff --git a/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.chpl b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.chpl new file mode 100644 index 000000000000..4bde69249911 --- /dev/null +++ b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.chpl @@ -0,0 +1,37 @@ +use Time; + +config type elemType = int; +var t: stopwatch; +config const correctness = false; +config const useLoop = false; +config const arrSize = 10; +config const totalSeconds = if correctness then 0 else 5; +config const checkGranularity = if correctness then 1 else 10000; + +var totalOps = 0; +on here.gpus[0] { + var Arr1: [1..arrSize] elemType; + var Arr2: [1..arrSize] elemType = 1; + + t.start(); + do { + for 1..checkGranularity { + Arr1[1..arrSize] = Arr2[1..arrSize]; + } + + totalOps += checkGranularity; + } while t.elapsed() < totalSeconds; + t.stop(); + + + + if correctness { + writeln(Arr1[4]); + } + else { + const memCopied: real = totalOps*arrSize*numBytes(elemType); + writef("Total time(s): %.2dr\n", t.elapsed()); + writef("Total memory copied(GB): %.5dr\n", memCopied/2**30); + writef("Sustained throughput(GB/s): %.5dr\n", memCopied/2**30/t.elapsed()); + } +} diff --git a/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.compopts b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.compopts new file mode 100644 index 000000000000..3f27f7a0bd37 --- /dev/null +++ b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.compopts @@ -0,0 +1 @@ +-sdebugBulkTransfer -sdebugShortArrayTransfer diff --git a/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.execopts b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.execopts new file mode 100644 index 000000000000..83996d2a7860 --- /dev/null +++ b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.execopts @@ -0,0 +1 @@ +--correctness=true diff --git a/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.good b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.good new file mode 100644 index 000000000000..bc832740ce44 --- /dev/null +++ b/test/gpu/native/optimizations/arrayViewElision/gpuViewElision.good @@ -0,0 +1,9 @@ + Size: 10 Threshold: 60 + size qualifies + GPU arrays shouldn't be SAT'ed +Performing protoSlice bulk transfer +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +In DefaultRectangular._simpleTransfer(): Alo=(1,), Blo=(1,), len=10, elemSize=8 +operator =(a:[],b:[]): successfully completed bulk transfer +1 diff --git a/test/optimizations/arrayViewElision/avoidExtraCalls.chpl b/test/optimizations/arrayViewElision/avoidExtraCalls.chpl new file mode 100644 index 000000000000..cfd25405b587 --- /dev/null +++ b/test/optimizations/arrayViewElision/avoidExtraCalls.chpl @@ -0,0 +1,42 @@ +{ + writeln("Test 1"); + var A: [1..10] int; + var B: [1..10] int = 1; + + proc foo() { + writeln("foo called"); + return 1..3; + } + A[foo()] = B[foo()]; + writeln(A); + writeln(); +} + +{ + writeln("Test 2"); + var A: [1..10] int; + const B: [1..10] int = 1; + + proc foo() { + writeln("foo called"); + return 1..3; + } + A[foo()] = B[foo()]; + writeln(A); + writeln(); +} + +{ + writeln("Test 3"); + var A: [1..10, 1..10] int; + var B: [1..10, 1..10] int = 1; + + proc foo() { + writeln("foo called"); + return 1..3; + } + + A[foo(), foo()] = B[foo(), foo()]; + writeln(A); + writeln(); +} diff --git a/test/optimizations/arrayViewElision/avoidExtraCalls.comm-none.good b/test/optimizations/arrayViewElision/avoidExtraCalls.comm-none.good new file mode 100644 index 000000000000..0b7b6aba6225 --- /dev/null +++ b/test/optimizations/arrayViewElision/avoidExtraCalls.comm-none.good @@ -0,0 +1,58 @@ +ArrayViewElision supported avoidExtraCalls.chpl:10 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported avoidExtraCalls.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported avoidExtraCalls.chpl:39 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +Test 1 +foo called +foo called + Size: 3 Threshold: 60 + size qualifies +1 1 1 0 0 0 0 0 0 0 + +Test 2 +foo called +foo called + Size: 3 Threshold: 60 + size qualifies +1 1 1 0 0 0 0 0 0 0 + +Test 3 +foo called +foo called +foo called +foo called + Size: 9 Threshold: 60 + size qualifies +1 1 1 0 0 0 0 0 0 0 +1 1 1 0 0 0 0 0 0 0 +1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 + diff --git a/test/optimizations/arrayViewElision/avoidExtraCalls.compopts b/test/optimizations/arrayViewElision/avoidExtraCalls.compopts new file mode 100644 index 000000000000..1facc70badbb --- /dev/null +++ b/test/optimizations/arrayViewElision/avoidExtraCalls.compopts @@ -0,0 +1 @@ +--report-array-view-elision -sdebugShortArrayTransfer diff --git a/test/optimizations/arrayViewElision/avoidExtraCalls.good b/test/optimizations/arrayViewElision/avoidExtraCalls.good new file mode 100644 index 000000000000..d0c5be8548a5 --- /dev/null +++ b/test/optimizations/arrayViewElision/avoidExtraCalls.good @@ -0,0 +1,61 @@ +ArrayViewElision supported (dynamic locality check required) avoidExtraCalls.chpl:10 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) avoidExtraCalls.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) avoidExtraCalls.chpl:39 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +Test 1 +foo called +foo called + Size: 3 Threshold: 60 + size qualifies + locality qualifies +1 1 1 0 0 0 0 0 0 0 + +Test 2 +foo called +foo called + Size: 3 Threshold: 60 + size qualifies + locality qualifies +1 1 1 0 0 0 0 0 0 0 + +Test 3 +foo called +foo called +foo called +foo called + Size: 9 Threshold: 60 + size qualifies + locality qualifies +1 1 1 0 0 0 0 0 0 0 +1 1 1 0 0 0 0 0 0 0 +1 1 1 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 + diff --git a/test/optimizations/arrayViewElision/constChecking-error.good b/test/optimizations/arrayViewElision/constChecking-error.good new file mode 100644 index 000000000000..389fe0924fc2 --- /dev/null +++ b/test/optimizations/arrayViewElision/constChecking-error.good @@ -0,0 +1 @@ +constChecking.chpl:14: error: cannot assign to const variable diff --git a/test/optimizations/arrayViewElision/constChecking-no-error.good b/test/optimizations/arrayViewElision/constChecking-no-error.good new file mode 100644 index 000000000000..020ad234dda5 --- /dev/null +++ b/test/optimizations/arrayViewElision/constChecking-no-error.good @@ -0,0 +1 @@ +0 1 1 0 0 diff --git a/test/optimizations/arrayViewElision/constChecking.chpl b/test/optimizations/arrayViewElision/constChecking.chpl new file mode 100644 index 000000000000..b043d6c66ed4 --- /dev/null +++ b/test/optimizations/arrayViewElision/constChecking.chpl @@ -0,0 +1,16 @@ +config param shouldError = false; + +if !shouldError { + var A: [1..5] int; + const B: [1..5] int = 1; + + A[2..3] = B[2..3]; + writeln(A); +} +else { + const A: [1..5] int; + const B: [1..5] int = 1; + + A[2..3] = B[2..3]; + writeln(A); +} diff --git a/test/optimizations/arrayViewElision/constChecking.compopts b/test/optimizations/arrayViewElision/constChecking.compopts new file mode 100644 index 000000000000..04b76300be9d --- /dev/null +++ b/test/optimizations/arrayViewElision/constChecking.compopts @@ -0,0 +1,2 @@ +-sshouldError=false # constChecking-no-error +-sshouldError=true # constChecking-error diff --git a/test/optimizations/arrayViewElision/distributed.chpl b/test/optimizations/arrayViewElision/distributed.chpl new file mode 100644 index 000000000000..f6ecf3378b2e --- /dev/null +++ b/test/optimizations/arrayViewElision/distributed.chpl @@ -0,0 +1,24 @@ +const Space = {1..10}; + +// not exhaustive. +{ + use BlockDist; + + const D = Space dmapped new blockDist(Space); + var A: [D] int = 1; + var B: [D] int = 2; + + A[3..5] = B[3..5]; + writeln(A); +} + +{ + use CyclicDist; + + const D = Space dmapped new cyclicDist(Space.first); + var A: [D] int = 1; + var B: [D] int = 2; + + A[3..5] = B[3..5]; + writeln(A); +} diff --git a/test/optimizations/arrayViewElision/distributed.compopts b/test/optimizations/arrayViewElision/distributed.compopts new file mode 100644 index 000000000000..4e1569775cbb --- /dev/null +++ b/test/optimizations/arrayViewElision/distributed.compopts @@ -0,0 +1 @@ +--report-array-view-elision diff --git a/test/optimizations/arrayViewElision/distributed.good b/test/optimizations/arrayViewElision/distributed.good new file mode 100644 index 000000000000..c7a73524b514 --- /dev/null +++ b/test/optimizations/arrayViewElision/distributed.good @@ -0,0 +1,16 @@ +ArrayViewElision not supported distributed.chpl:11 + lhsBaseType: [BlockDom(1,int(64),one,unmanaged DefaultDist)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: + rhsIndexingExprs: + +ArrayViewElision not supported distributed.chpl:22 + lhsBaseType: [CyclicDom(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: + rhsIndexingExprs: + +1 1 2 2 2 1 1 1 1 1 +1 1 2 2 2 1 1 1 1 1 diff --git a/test/optimizations/arrayViewElision/flags.chpl b/test/optimizations/arrayViewElision/flags.chpl new file mode 100644 index 000000000000..3ab31c0e2e4a --- /dev/null +++ b/test/optimizations/arrayViewElision/flags.chpl @@ -0,0 +1,6 @@ +var A: [1..1000] int; +var B: [1..1000] int; + +A[1..1000] = B[1..1000]; + +writeln(A[3]); diff --git a/test/optimizations/arrayViewElision/flags.compopts b/test/optimizations/arrayViewElision/flags.compopts new file mode 100644 index 000000000000..3b5fea555689 --- /dev/null +++ b/test/optimizations/arrayViewElision/flags.compopts @@ -0,0 +1,2 @@ +--array-view-elision -sdebugBulkTransfer=true # flags.opt +--no-array-view-elision -sdebugBulkTransfer=true # flags.no-opt diff --git a/test/optimizations/arrayViewElision/flags.no-opt.good b/test/optimizations/arrayViewElision/flags.no-opt.good new file mode 100644 index 000000000000..217f7cf4fbb1 --- /dev/null +++ b/test/optimizations/arrayViewElision/flags.no-opt.good @@ -0,0 +1,11 @@ +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferToKnown +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +In DefaultRectangular._simpleTransfer(): Alo=(1,), Blo=(1,), len=1000, elemSize=8 +operator =(a:[],b:[]): successfully completed bulk transfer +operator =(a:[],b:[]): successfully completed bulk transfer +operator =(a:[],b:[]): successfully completed bulk transfer +0 diff --git a/test/optimizations/arrayViewElision/flags.opt.good b/test/optimizations/arrayViewElision/flags.opt.good new file mode 100644 index 000000000000..16312e544ebc --- /dev/null +++ b/test/optimizations/arrayViewElision/flags.opt.good @@ -0,0 +1,6 @@ +Performing protoSlice bulk transfer +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +In DefaultRectangular._simpleTransfer(): Alo=(1,), Blo=(1,), len=1000, elemSize=8 +operator =(a:[],b:[]): successfully completed bulk transfer +0 diff --git a/test/optimizations/arrayViewElision/negativeStrideSlice.chpl b/test/optimizations/arrayViewElision/negativeStrideSlice.chpl new file mode 100644 index 000000000000..feba9ae53fab --- /dev/null +++ b/test/optimizations/arrayViewElision/negativeStrideSlice.chpl @@ -0,0 +1,11 @@ +var A, B: [1..10] int; + +B = 1; + +A[1..10 by 2] = B[1..10 by -2]; + +writeln(A); + +A[1..10 by -2] = B[1..10 by 2]; + +writeln(A); diff --git a/test/optimizations/arrayViewElision/negativeStrideSlice.compopts b/test/optimizations/arrayViewElision/negativeStrideSlice.compopts new file mode 100644 index 000000000000..4e1569775cbb --- /dev/null +++ b/test/optimizations/arrayViewElision/negativeStrideSlice.compopts @@ -0,0 +1 @@ +--report-array-view-elision diff --git a/test/optimizations/arrayViewElision/negativeStrideSlice.good b/test/optimizations/arrayViewElision/negativeStrideSlice.good new file mode 100644 index 000000000000..53a58a1818da --- /dev/null +++ b/test/optimizations/arrayViewElision/negativeStrideSlice.good @@ -0,0 +1,19 @@ +ArrayViewElision not supported negativeStrideSlice.chpl:5 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,positive) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,negative) + +ArrayViewElision not supported negativeStrideSlice.chpl:9 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,negative) + rhsBaseType: + rhsIndexingExprs: + +1 0 1 0 1 0 1 0 1 0 +1 1 1 1 1 1 1 1 1 1 +negativeStrideSlice.chpl:5: warning: arrays and array slices with negatively-strided dimensions are currently unsupported and may lead to unexpected behavior; compile with -snoNegativeStrideWarnings to suppress this warning; the dimension(s) are: (1..10 by -2,) +negativeStrideSlice.chpl:9: warning: arrays and array slices with negatively-strided dimensions are currently unsupported and may lead to unexpected behavior; compile with -snoNegativeStrideWarnings to suppress this warning; the dimension(s) are: (1..10 by -2,) diff --git a/test/optimizations/arrayViewElision/rankChangeFunky.chpl b/test/optimizations/arrayViewElision/rankChangeFunky.chpl new file mode 100644 index 000000000000..36154ef6fc71 --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChangeFunky.chpl @@ -0,0 +1,6 @@ +var A: [1..5, 1..5, 1..5] int = 1; +var B: [1..5, 1..5, 1..5] int = 2; + +A[1, 2, 3..12] = B[1..5, 2, 3..7]; + +writeln(A); diff --git a/test/optimizations/arrayViewElision/rankChangeFunky.compopts b/test/optimizations/arrayViewElision/rankChangeFunky.compopts new file mode 100644 index 000000000000..4e1569775cbb --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChangeFunky.compopts @@ -0,0 +1 @@ +--report-array-view-elision diff --git a/test/optimizations/arrayViewElision/rankChangeFunky.good b/test/optimizations/arrayViewElision/rankChangeFunky.good new file mode 100644 index 000000000000..8c88811a36ca --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChangeFunky.good @@ -0,0 +1,13 @@ +ArrayViewElision not supported rankChangeFunky.chpl:4 + lhsBaseType: [domain(3,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + int(64) + range(int(64),both,one) + rhsBaseType: [domain(3,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + int(64) + range(int(64),both,one) + +rankChangeFunky.chpl:4: error: rank mismatch in array assignment diff --git a/test/optimizations/arrayViewElision/rankChanges.chpl b/test/optimizations/arrayViewElision/rankChanges.chpl new file mode 100644 index 000000000000..6dede159716e --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChanges.chpl @@ -0,0 +1,20 @@ +var A: [1..5, 1..5] int = 1; +var B: [1..5, 1..5] int = 2; + +proc testAndReset() { + writeln(A); + writeln(); + A = 1; +} + +// supported: +A[3, 1..3] = B[3, 1..3]; testAndReset(); +A[1..3, 3] = B[1..3, 3]; testAndReset(); + +// supported: +A[3, ..] = B[3, ..]; testAndReset(); +A[.., 3] = B[.., 3]; testAndReset(); + +// unsupported: +A[3, 1..3] = B[1..3, 3]; testAndReset(); +A[1..3, 3] = B[3, 1..3]; testAndReset(); diff --git a/test/optimizations/arrayViewElision/rankChanges.comm-none.good b/test/optimizations/arrayViewElision/rankChanges.comm-none.good new file mode 100644 index 000000000000..5abf1cf73bd5 --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChanges.comm-none.good @@ -0,0 +1,104 @@ +ArrayViewElision supported rankChanges.chpl:11 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),both,one) + +ArrayViewElision supported rankChanges.chpl:12 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + int(64) + +ArrayViewElision supported rankChanges.chpl:15 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),neither,one) + +ArrayViewElision supported rankChanges.chpl:16 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + int(64) + +ArrayViewElision not supported rankChanges.chpl:19 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + int(64) + +ArrayViewElision not supported rankChanges.chpl:20 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),both,one) + + Size: 3 Threshold: 60 + size qualifies +1 1 1 1 1 +1 1 1 1 1 +2 2 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 3 Threshold: 60 + size qualifies +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 5 Threshold: 60 + size qualifies +1 1 1 1 1 +1 1 1 1 1 +2 2 2 2 2 +1 1 1 1 1 +1 1 1 1 1 + + Size: 5 Threshold: 60 + size qualifies +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 + +1 1 1 1 1 +1 1 1 1 1 +2 2 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + diff --git a/test/optimizations/arrayViewElision/rankChanges.compopts b/test/optimizations/arrayViewElision/rankChanges.compopts new file mode 100644 index 000000000000..1facc70badbb --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChanges.compopts @@ -0,0 +1 @@ +--report-array-view-elision -sdebugShortArrayTransfer diff --git a/test/optimizations/arrayViewElision/rankChanges.good b/test/optimizations/arrayViewElision/rankChanges.good new file mode 100644 index 000000000000..bc2abd136e59 --- /dev/null +++ b/test/optimizations/arrayViewElision/rankChanges.good @@ -0,0 +1,108 @@ +ArrayViewElision supported (dynamic locality check required) rankChanges.chpl:11 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) rankChanges.chpl:12 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + int(64) + +ArrayViewElision supported (dynamic locality check required) rankChanges.chpl:15 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),neither,one) + +ArrayViewElision supported (dynamic locality check required) rankChanges.chpl:16 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + int(64) + +ArrayViewElision not supported rankChanges.chpl:19 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + int(64) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + int(64) + +ArrayViewElision not supported rankChanges.chpl:20 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + int(64) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + int(64) + range(int(64),both,one) + + Size: 3 Threshold: 60 + size qualifies + locality qualifies +1 1 1 1 1 +1 1 1 1 1 +2 2 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 3 Threshold: 60 + size qualifies + locality qualifies +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +1 1 1 1 1 +1 1 1 1 1 +2 2 2 2 2 +1 1 1 1 1 +1 1 1 1 1 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 + +1 1 1 1 1 +1 1 1 1 1 +2 2 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + +1 1 2 1 1 +1 1 2 1 1 +1 1 2 1 1 +1 1 1 1 1 +1 1 1 1 1 + diff --git a/test/optimizations/arrayViewElision/remoteDR.chpl b/test/optimizations/arrayViewElision/remoteDR.chpl new file mode 100644 index 000000000000..a21ef15c6712 --- /dev/null +++ b/test/optimizations/arrayViewElision/remoteDR.chpl @@ -0,0 +1,9 @@ +var A: [1..10] int; + +on Locales.last { + var B: [1..10] int = 1; + + A[1..5] = B[1..5]; + + writeln(A); +} diff --git a/test/optimizations/arrayViewElision/remoteDR.comm-none.good b/test/optimizations/arrayViewElision/remoteDR.comm-none.good new file mode 100644 index 000000000000..4160b8636bee --- /dev/null +++ b/test/optimizations/arrayViewElision/remoteDR.comm-none.good @@ -0,0 +1,9 @@ +ArrayViewElision supported remoteDR.chpl:6 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +1 1 1 1 1 0 0 0 0 0 diff --git a/test/optimizations/arrayViewElision/remoteDR.compopts b/test/optimizations/arrayViewElision/remoteDR.compopts new file mode 100644 index 000000000000..6db3d3c1e9d2 --- /dev/null +++ b/test/optimizations/arrayViewElision/remoteDR.compopts @@ -0,0 +1 @@ +--report-array-view-elision -sdebugBulkTransfer diff --git a/test/optimizations/arrayViewElision/remoteDR.good b/test/optimizations/arrayViewElision/remoteDR.good new file mode 100644 index 000000000000..cb6a7321d8d6 --- /dev/null +++ b/test/optimizations/arrayViewElision/remoteDR.good @@ -0,0 +1,19 @@ +ArrayViewElision supported (dynamic locality check required) remoteDR.chpl:6 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferToKnown +operator =(a:[],b:[]): in chpl__bulkTransferArray +operator =(a:[],b:[]): attempting doiBulkTransferFromKnown +In DefaultRectangular._simpleTransfer(): Alo=(1,), Blo=(1,), len=5, elemSize=8 +operator =(a:[],b:[]): successfully completed bulk transfer +operator =(a:[],b:[]): successfully completed bulk transfer +operator =(a:[],b:[]): successfully completed bulk transfer +1 1 1 1 1 0 0 0 0 0 diff --git a/test/optimizations/arrayViewElision/remoteDR.numlocales b/test/optimizations/arrayViewElision/remoteDR.numlocales new file mode 100644 index 000000000000..0cfbf08886fc --- /dev/null +++ b/test/optimizations/arrayViewElision/remoteDR.numlocales @@ -0,0 +1 @@ +2 diff --git a/test/optimizations/arrayViewElision/slices-1d-domain.comm-none.good b/test/optimizations/arrayViewElision/slices-1d-domain.comm-none.good new file mode 100644 index 000000000000..436e02fc44e4 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-1d-domain.comm-none.good @@ -0,0 +1,52 @@ +ArrayViewElision supported slices.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + domain(1,int(64),one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + domain(1,int(64),one) + +ArrayViewElision supported slices.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + domain(1,int(64),one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + domain(1,int(64),one) + +Set first two: + Size: 2 Threshold: 60 + size qualifies +Test 1 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 2 +2 2 1 1 1 + +----------------- +Set last two: + Size: 2 Threshold: 60 + size qualifies +Test 3 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 4 +1 1 1 2 2 + +----------------- +Set all: + Size: 5 Threshold: 60 + size qualifies +Test 5 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 6 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-1d-domain.good b/test/optimizations/arrayViewElision/slices-1d-domain.good new file mode 100644 index 000000000000..8e4066c3f7f6 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-1d-domain.good @@ -0,0 +1,58 @@ +ArrayViewElision supported (dynamic locality check required) slices.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + domain(1,int(64),one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + domain(1,int(64),one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:24 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + domain(1,int(64),one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + domain(1,int(64),one) + +Set first two: + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 1 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 2 +2 2 1 1 1 + +----------------- +Set last two: + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 3 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 4 +1 1 1 2 2 + +----------------- +Set all: + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 5 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 6 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-1d-range.comm-none.good b/test/optimizations/arrayViewElision/slices-1d-range.comm-none.good new file mode 100644 index 000000000000..1c7817657a63 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-1d-range.comm-none.good @@ -0,0 +1,243 @@ +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +Set first two: + Size: 2 Threshold: 60 + size qualifies +Test 1 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 2 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 3 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 4 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 5 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 6 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 7 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies +Test 8 +2 2 1 1 1 + +----------------- +Set last two: + Size: 2 Threshold: 60 + size qualifies +Test 9 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 10 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 11 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 12 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 13 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 14 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 15 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies +Test 16 +1 1 1 2 2 + +----------------- +Set all: + Size: 5 Threshold: 60 + size qualifies +Test 17 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 18 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 19 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 20 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 21 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 22 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 23 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 24 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies +Test 25 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-1d-range.good b/test/optimizations/arrayViewElision/slices-1d-range.good new file mode 100644 index 000000000000..af3ebf7e7716 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-1d-range.good @@ -0,0 +1,268 @@ +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(1,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + rhsBaseType: [domain(1,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + +Set first two: + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 1 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 2 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 3 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 4 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 5 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 6 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 7 +2 2 1 1 1 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 8 +2 2 1 1 1 + +----------------- +Set last two: + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 9 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 10 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 11 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 12 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 13 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 14 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 15 +1 1 1 2 2 + + Size: 2 Threshold: 60 + size qualifies + locality qualifies +Test 16 +1 1 1 2 2 + +----------------- +Set all: + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 17 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 18 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 19 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 20 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 21 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 22 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 23 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 24 +2 2 2 2 2 + + Size: 5 Threshold: 60 + size qualifies + locality qualifies +Test 25 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-2d-domain.comm-none.good b/test/optimizations/arrayViewElision/slices-2d-domain.comm-none.good new file mode 100644 index 000000000000..1153a81438c4 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-2d-domain.comm-none.good @@ -0,0 +1,76 @@ +ArrayViewElision supported slices.chpl:24 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + domain(2,int(64),one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + domain(2,int(64),one) + +ArrayViewElision supported slices.chpl:24 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + domain(2,int(64),one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + domain(2,int(64),one) + +Set first two: + Size: 4 Threshold: 60 + size qualifies +Test 1 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 2 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + +----------------- +Set last two: + Size: 4 Threshold: 60 + size qualifies +Test 3 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 4 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + +----------------- +Set all: + Size: 25 Threshold: 60 + size qualifies +Test 5 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 6 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-2d-domain.good b/test/optimizations/arrayViewElision/slices-2d-domain.good new file mode 100644 index 000000000000..5a874225ce6c --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-2d-domain.good @@ -0,0 +1,82 @@ +ArrayViewElision supported (dynamic locality check required) slices.chpl:24 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + domain(2,int(64),one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + domain(2,int(64),one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:24 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + domain(2,int(64),one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + domain(2,int(64),one) + +Set first two: + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 1 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 2 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + +----------------- +Set last two: + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 3 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 4 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + +----------------- +Set all: + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 5 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 6 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-2d-range.comm-none.good b/test/optimizations/arrayViewElision/slices-2d-range.comm-none.good new file mode 100644 index 000000000000..1be0e42f42c1 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-2d-range.comm-none.good @@ -0,0 +1,371 @@ +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +ArrayViewElision supported slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +Set first two: + Size: 4 Threshold: 60 + size qualifies +Test 1 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 2 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 3 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 4 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 5 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 6 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 7 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies +Test 8 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + +----------------- +Set last two: + Size: 4 Threshold: 60 + size qualifies +Test 9 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 10 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 11 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 12 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 13 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 14 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 15 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies +Test 16 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + +----------------- +Set all: + Size: 25 Threshold: 60 + size qualifies +Test 17 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 18 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 19 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 20 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 21 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 22 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 23 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 24 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies +Test 25 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices-2d-range.good b/test/optimizations/arrayViewElision/slices-2d-range.good new file mode 100644 index 000000000000..18d1bd420fac --- /dev/null +++ b/test/optimizations/arrayViewElision/slices-2d-range.good @@ -0,0 +1,396 @@ +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),high,one) + range(int(64),high,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),both,one) + range(int(64),both,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),low,one) + range(int(64),low,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +ArrayViewElision supported (dynamic locality check required) slices.chpl:26 + lhsBaseType: [domain(2,int(64),one)] int(64) + lhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + rhsBaseType: [domain(2,int(64),one)] int(64) + rhsIndexingExprs: + range(int(64),neither,one) + range(int(64),neither,one) + +Set first two: + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 1 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 2 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 3 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 4 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 5 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 6 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 7 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 8 +2 2 1 1 1 +2 2 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 + +----------------- +Set last two: + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 9 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 10 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 11 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 12 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 13 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 14 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 15 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + + Size: 4 Threshold: 60 + size qualifies + locality qualifies +Test 16 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 1 1 +1 1 1 2 2 +1 1 1 2 2 + +----------------- +Set all: + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 17 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 18 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 19 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 20 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 21 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 22 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 23 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 24 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + + Size: 25 Threshold: 60 + size qualifies + locality qualifies +Test 25 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 +2 2 2 2 2 + +----------------- diff --git a/test/optimizations/arrayViewElision/slices.chpl b/test/optimizations/arrayViewElision/slices.chpl new file mode 100644 index 000000000000..803d941367a5 --- /dev/null +++ b/test/optimizations/arrayViewElision/slices.chpl @@ -0,0 +1,81 @@ +config param useDomain = true, rank = 1; + +proc multuplify(param rank, x) { + var ret: rank*x.type; + for param i in 0..