@@ -63,6 +63,7 @@ template <typename T> class Folder {
63
63
64
64
Expr<T> CSHIFT (FunctionRef<T> &&);
65
65
Expr<T> EOSHIFT (FunctionRef<T> &&);
66
+ Expr<T> PACK (FunctionRef<T> &&);
66
67
Expr<T> RESHAPE (FunctionRef<T> &&);
67
68
68
69
private:
@@ -580,7 +581,7 @@ template <typename T> Expr<T> Folder<T>::CSHIFT(FunctionRef<T> &&funcRef) {
580
581
if (j != zbDim) {
581
582
if (array->shape ()[j] != shift->shape ()[k]) {
582
583
context_.messages ().Say (
583
- " Invalid 'shift=' argument in CSHIFT; extent on dimension %d is %jd but must be %jd" _err_en_US,
584
+ " Invalid 'shift=' argument in CSHIFT: extent on dimension %d is %jd but must be %jd" _err_en_US,
584
585
k + 1 , static_cast <std::intmax_t >(shift->shape ()[k]),
585
586
static_cast <std::intmax_t >(array->shape ()[j]));
586
587
ok = false ;
@@ -653,6 +654,9 @@ template <typename T> Expr<T> Folder<T>::EOSHIFT(FunctionRef<T> &&funcRef) {
653
654
static_cast <std::intmax_t >(*dim));
654
655
} else if (shift->Rank () > 0 && shift->Rank () != array->Rank () - 1 ) {
655
656
// message already emitted from intrinsic look-up
657
+ } else if (boundary && boundary->Rank () > 0 &&
658
+ boundary->Rank () != array->Rank () - 1 ) {
659
+ // ditto
656
660
} else {
657
661
int rank{array->Rank ()};
658
662
int zbDim{static_cast <int >(*dim) - 1 };
@@ -663,15 +667,23 @@ template <typename T> Expr<T> Folder<T>::EOSHIFT(FunctionRef<T> &&funcRef) {
663
667
if (j != zbDim) {
664
668
if (array->shape ()[j] != shift->shape ()[k]) {
665
669
context_.messages ().Say (
666
- " Invalid 'shift=' argument in EOSHIFT; extent on dimension %d is %jd but must be %jd" _err_en_US,
670
+ " Invalid 'shift=' argument in EOSHIFT: extent on dimension %d is %jd but must be %jd" _err_en_US,
667
671
k + 1 , static_cast <std::intmax_t >(shift->shape ()[k]),
668
672
static_cast <std::intmax_t >(array->shape ()[j]));
669
673
ok = false ;
670
674
}
671
- if (boundary && array->shape ()[j] != boundary->shape ()[k]) {
675
+ ++k;
676
+ }
677
+ }
678
+ }
679
+ if (boundary && boundary->Rank () > 0 ) {
680
+ int k{0 };
681
+ for (int j{0 }; j < rank; ++j) {
682
+ if (j != zbDim) {
683
+ if (array->shape ()[j] != boundary->shape ()[k]) {
672
684
context_.messages ().Say (
673
- " Invalid 'boundary=' argument in EOSHIFT; extent on dimension %d is %jd but must be %jd" _err_en_US,
674
- k + 1 , static_cast <std::intmax_t >(shift ->shape ()[k]),
685
+ " Invalid 'boundary=' argument in EOSHIFT: extent on dimension %d is %jd but must be %jd" _err_en_US,
686
+ k + 1 , static_cast <std::intmax_t >(boundary ->shape ()[k]),
675
687
static_cast <std::intmax_t >(array->shape ()[j]));
676
688
ok = false ;
677
689
}
@@ -726,6 +738,70 @@ template <typename T> Expr<T> Folder<T>::EOSHIFT(FunctionRef<T> &&funcRef) {
726
738
return MakeInvalidIntrinsic (std::move (funcRef));
727
739
}
728
740
741
+ template <typename T> Expr<T> Folder<T>::PACK(FunctionRef<T> &&funcRef) {
742
+ auto args{funcRef.arguments ()};
743
+ CHECK (args.size () == 3 );
744
+ const auto *array{UnwrapConstantValue<T>(args[0 ])};
745
+ const auto *vector{UnwrapConstantValue<T>(args[2 ])};
746
+ auto convertedMask{Fold (context_,
747
+ ConvertToType<LogicalResult>(
748
+ Expr<SomeLogical>{DEREF (UnwrapExpr<Expr<SomeLogical>>(args[1 ]))}))};
749
+ const auto *mask{UnwrapConstantValue<LogicalResult>(convertedMask)};
750
+ if (!array || !mask || (args[2 ] && !vector)) {
751
+ return Expr<T>{std::move (funcRef)};
752
+ }
753
+ // Arguments are constant.
754
+ ConstantSubscript arrayElements{GetSize (array->shape ())};
755
+ ConstantSubscript truths{0 };
756
+ ConstantSubscripts maskAt{mask->lbounds ()};
757
+ if (mask->Rank () == 0 ) {
758
+ if (mask->At (maskAt).IsTrue ()) {
759
+ truths = arrayElements;
760
+ }
761
+ } else if (array->shape () != mask->shape ()) {
762
+ // Error already emitted from intrinsic processing
763
+ return MakeInvalidIntrinsic (std::move (funcRef));
764
+ } else {
765
+ for (ConstantSubscript j{0 }; j < arrayElements;
766
+ ++j, mask->IncrementSubscripts (maskAt)) {
767
+ if (mask->At (maskAt).IsTrue ()) {
768
+ ++truths;
769
+ }
770
+ }
771
+ }
772
+ std::vector<Scalar<T>> resultElements;
773
+ ConstantSubscripts arrayAt{array->lbounds ()};
774
+ ConstantSubscript resultSize{truths};
775
+ if (vector) {
776
+ resultSize = vector->shape ().at (0 );
777
+ if (resultSize < truths) {
778
+ context_.messages ().Say (
779
+ " Invalid 'vector=' argument in PACK: the 'mask=' argument has %jd true elements, but the vector has only %jd elements" _err_en_US,
780
+ static_cast <std::intmax_t >(truths),
781
+ static_cast <std::intmax_t >(resultSize));
782
+ return MakeInvalidIntrinsic (std::move (funcRef));
783
+ }
784
+ }
785
+ for (ConstantSubscript j{0 }; j < truths;) {
786
+ if (mask->At (maskAt).IsTrue ()) {
787
+ resultElements.push_back (array->At (arrayAt));
788
+ ++j;
789
+ }
790
+ array->IncrementSubscripts (arrayAt);
791
+ mask->IncrementSubscripts (maskAt);
792
+ }
793
+ if (vector) {
794
+ ConstantSubscripts vectorAt{vector->lbounds ()};
795
+ vectorAt.at (0 ) += truths;
796
+ for (ConstantSubscript j{truths}; j < resultSize; ++j) {
797
+ resultElements.push_back (vector->At (vectorAt));
798
+ ++vectorAt[0 ];
799
+ }
800
+ }
801
+ return Expr<T>{PackageConstant<T>(std::move (resultElements), *array,
802
+ ConstantSubscripts{static_cast <ConstantSubscript>(resultSize)})};
803
+ }
804
+
729
805
template <typename T> Expr<T> Folder<T>::RESHAPE(FunctionRef<T> &&funcRef) {
730
806
auto args{funcRef.arguments ()};
731
807
CHECK (args.size () == 4 );
@@ -863,10 +939,12 @@ Expr<T> FoldOperation(FoldingContext &context, FunctionRef<T> &&funcRef) {
863
939
return Folder<T>{context}.CSHIFT (std::move (funcRef));
864
940
} else if (name == " eoshift" ) {
865
941
return Folder<T>{context}.EOSHIFT (std::move (funcRef));
942
+ } else if (name == " pack" ) {
943
+ return Folder<T>{context}.PACK (std::move (funcRef));
866
944
} else if (name == " reshape" ) {
867
945
return Folder<T>{context}.RESHAPE (std::move (funcRef));
868
946
}
869
- // TODO: eoshift, pack, spread, unpack, transpose
947
+ // TODO: spread, unpack, transpose
870
948
// TODO: extends_type_of, same_type_as
871
949
if constexpr (!std::is_same_v<T, SomeDerived>) {
872
950
return FoldIntrinsicFunction (context, std::move (funcRef));
0 commit comments