@@ -62,6 +62,7 @@ template <typename T> class Folder {
62
62
Constant<T> *Folding (std::optional<ActualArgument> &);
63
63
64
64
Expr<T> CSHIFT (FunctionRef<T> &&);
65
+ Expr<T> EOSHIFT (FunctionRef<T> &&);
65
66
Expr<T> RESHAPE (FunctionRef<T> &&);
66
67
67
68
private:
@@ -619,6 +620,112 @@ template <typename T> Expr<T> Folder<T>::CSHIFT(FunctionRef<T> &&funcRef) {
619
620
return MakeInvalidIntrinsic (std::move (funcRef));
620
621
}
621
622
623
+ template <typename T> Expr<T> Folder<T>::EOSHIFT(FunctionRef<T> &&funcRef) {
624
+ auto args{funcRef.arguments ()};
625
+ CHECK (args.size () == 4 );
626
+ const auto *array{UnwrapConstantValue<T>(args[0 ])};
627
+ const auto *shiftExpr{UnwrapExpr<Expr<SomeInteger>>(args[1 ])};
628
+ auto dim{GetInt64ArgOr (args[3 ], 1 )};
629
+ if (!array || !shiftExpr || !dim) {
630
+ return Expr<T>{std::move (funcRef)};
631
+ }
632
+ // Apply type conversions to the shift= and boundary= arguments.
633
+ auto convertedShift{Fold (context_,
634
+ ConvertToType<SubscriptInteger>(Expr<SomeInteger>{*shiftExpr}))};
635
+ const auto *shift{UnwrapConstantValue<SubscriptInteger>(convertedShift)};
636
+ if (!shift) {
637
+ return Expr<T>{std::move (funcRef)};
638
+ }
639
+ const Constant<T> *boundary{nullptr };
640
+ std::optional<Expr<SomeType>> convertedBoundary;
641
+ if (const auto *boundaryExpr{UnwrapExpr<Expr<SomeType>>(args[2 ])}) {
642
+ convertedBoundary = Fold (context_,
643
+ ConvertToType (array->GetType (), Expr<SomeType>{*boundaryExpr}));
644
+ boundary = UnwrapExpr<Constant<T>>(convertedBoundary);
645
+ if (!boundary) {
646
+ return Expr<T>{std::move (funcRef)};
647
+ }
648
+ }
649
+ // Arguments are constant
650
+ if (*dim < 1 || *dim > array->Rank ()) {
651
+ context_.messages ().Say (
652
+ " Invalid 'dim=' argument (%jd) in EOSHIFT" _err_en_US,
653
+ static_cast <std::intmax_t >(*dim));
654
+ } else if (shift->Rank () > 0 && shift->Rank () != array->Rank () - 1 ) {
655
+ // message already emitted from intrinsic look-up
656
+ } else {
657
+ int rank{array->Rank ()};
658
+ int zbDim{static_cast <int >(*dim) - 1 };
659
+ bool ok{true };
660
+ if (shift->Rank () > 0 ) {
661
+ int k{0 };
662
+ for (int j{0 }; j < rank; ++j) {
663
+ if (j != zbDim) {
664
+ if (array->shape ()[j] != shift->shape ()[k]) {
665
+ context_.messages ().Say (
666
+ " Invalid 'shift=' argument in EOSHIFT; extent on dimension %d is %jd but must be %jd" _err_en_US,
667
+ k + 1 , static_cast <std::intmax_t >(shift->shape ()[k]),
668
+ static_cast <std::intmax_t >(array->shape ()[j]));
669
+ ok = false ;
670
+ }
671
+ if (boundary && array->shape ()[j] != boundary->shape ()[k]) {
672
+ 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]),
675
+ static_cast <std::intmax_t >(array->shape ()[j]));
676
+ ok = false ;
677
+ }
678
+ ++k;
679
+ }
680
+ }
681
+ }
682
+ if (ok) {
683
+ std::vector<Scalar<T>> resultElements;
684
+ ConstantSubscripts arrayAt{array->lbounds ()};
685
+ ConstantSubscript dimLB{arrayAt[zbDim]};
686
+ ConstantSubscript dimExtent{array->shape ()[zbDim]};
687
+ ConstantSubscripts shiftAt{shift->lbounds ()};
688
+ ConstantSubscripts boundaryAt;
689
+ if (boundary) {
690
+ boundaryAt = boundary->lbounds ();
691
+ }
692
+ for (auto n{GetSize (array->shape ())}; n > 0 ; n -= dimExtent) {
693
+ ConstantSubscript shiftCount{shift->At (shiftAt).ToInt64 ()};
694
+ for (ConstantSubscript j{0 }; j < dimExtent; ++j) {
695
+ ConstantSubscript zbAt{shiftCount + j};
696
+ if (zbAt >= 0 && zbAt < dimExtent) {
697
+ arrayAt[zbDim] = dimLB + zbAt;
698
+ resultElements.push_back (array->At (arrayAt));
699
+ } else if (boundary) {
700
+ resultElements.push_back (boundary->At (boundaryAt));
701
+ } else if constexpr (T::category == TypeCategory::Integer ||
702
+ T::category == TypeCategory::Real ||
703
+ T::category == TypeCategory::Complex ||
704
+ T::category == TypeCategory::Logical) {
705
+ resultElements.emplace_back ();
706
+ } else if constexpr (T::category == TypeCategory::Character) {
707
+ auto len{static_cast <std::size_t >(array->LEN ())};
708
+ typename Scalar<T>::value_type space{' ' };
709
+ resultElements.emplace_back (len, space);
710
+ } else {
711
+ DIE (" no derived type boundary" );
712
+ }
713
+ }
714
+ arrayAt[zbDim] = dimLB + dimExtent - 1 ;
715
+ array->IncrementSubscripts (arrayAt);
716
+ shift->IncrementSubscripts (shiftAt);
717
+ if (boundary) {
718
+ boundary->IncrementSubscripts (boundaryAt);
719
+ }
720
+ }
721
+ return Expr<T>{PackageConstant<T>(
722
+ std::move (resultElements), *array, array->shape ())};
723
+ }
724
+ }
725
+ // Invalid, prevent re-folding
726
+ return MakeInvalidIntrinsic (std::move (funcRef));
727
+ }
728
+
622
729
template <typename T> Expr<T> Folder<T>::RESHAPE(FunctionRef<T> &&funcRef) {
623
730
auto args{funcRef.arguments ()};
624
731
CHECK (args.size () == 4 );
@@ -754,6 +861,8 @@ Expr<T> FoldOperation(FoldingContext &context, FunctionRef<T> &&funcRef) {
754
861
const std::string name{intrinsic->name };
755
862
if (name == " cshift" ) {
756
863
return Folder<T>{context}.CSHIFT (std::move (funcRef));
864
+ } else if (name == " eoshift" ) {
865
+ return Folder<T>{context}.EOSHIFT (std::move (funcRef));
757
866
} else if (name == " reshape" ) {
758
867
return Folder<T>{context}.RESHAPE (std::move (funcRef));
759
868
}
0 commit comments