@@ -2653,57 +2653,78 @@ struct CoordinateOpConversion
2653
2653
return mlir::isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(type);
2654
2654
}
2655
2655
2656
- // / Check whether this form of `!fir.coordinate_of` is supported. These
2657
- // / additional checks are required, because we are not yet able to convert
2658
- // / all valid forms of `!fir.coordinate_of`.
2659
- // / TODO: Either implement the unsupported cases or extend the verifier
2660
- // / in FIROps.cpp instead.
2661
- static bool supportedCoordinate (mlir::Type type, mlir::ValueRange coors) {
2662
- const std::size_t numOfCoors = coors.size ();
2663
- std::size_t i = 0 ;
2664
- bool subEle = false ;
2665
- bool ptrEle = false ;
2666
- for (; i < numOfCoors; ++i) {
2667
- mlir::Value nxtOpnd = coors[i];
2668
- if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(type)) {
2669
- subEle = true ;
2670
- i += arrTy.getDimension () - 1 ;
2671
- type = arrTy.getEleTy ();
2672
- } else if (auto recTy = mlir::dyn_cast<fir::RecordType>(type)) {
2673
- subEle = true ;
2674
- type = recTy.getType (getFieldNumber (recTy, nxtOpnd));
2675
- } else if (auto tupTy = mlir::dyn_cast<mlir::TupleType>(type)) {
2676
- subEle = true ;
2677
- type = tupTy.getType (getConstantIntValue (nxtOpnd));
2678
- } else {
2679
- ptrEle = true ;
2680
- }
2681
- }
2682
- if (ptrEle)
2683
- return (!subEle) && (numOfCoors == 1 );
2684
- return subEle && (i >= numOfCoors);
2685
- }
2656
+ // Helper structure to analyze the CoordinateOp path and decide if and how
2657
+ // the GEP should be generated for it.
2658
+ struct ShapeAnalysis {
2659
+ bool hasKnownShape;
2660
+ bool columnIsDeferred;
2661
+ };
2686
2662
2687
2663
// / Walk the abstract memory layout and determine if the path traverses any
2688
2664
// / array types with unknown shape. Return true iff all the array types have a
2689
2665
// / constant shape along the path.
2690
- static bool arraysHaveKnownShape (mlir::Type type, mlir::ValueRange coors) {
2691
- for (std::size_t i = 0 , sz = coors.size (); i < sz; ++i) {
2692
- mlir::Value nxtOpnd = coors[i];
2666
+ // / TODO: move the verification logic into the verifier.
2667
+ static std::optional<ShapeAnalysis>
2668
+ arraysHaveKnownShape (mlir::Type type, fir::CoordinateOp coor) {
2669
+ fir::CoordinateIndicesAdaptor indices = coor.getIndices ();
2670
+ auto begin = indices.begin ();
2671
+ bool hasKnownShape = true ;
2672
+ bool columnIsDeferred = false ;
2673
+ for (auto it = begin, end = indices.end (); it != end;) {
2693
2674
if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(type)) {
2694
- if (fir::sequenceWithNonConstantShape (arrTy))
2695
- return false ;
2696
- i += arrTy.getDimension () - 1 ;
2675
+ bool addressingStart = (it == begin);
2676
+ unsigned arrayDim = arrTy.getDimension ();
2677
+ for (auto dimExtent : llvm::enumerate (arrTy.getShape ())) {
2678
+ if (dimExtent.value () == fir::SequenceType::getUnknownExtent ()) {
2679
+ hasKnownShape = false ;
2680
+ if (addressingStart && dimExtent.index () + 1 == arrayDim) {
2681
+ // If this point was reached, the raws of the first array have
2682
+ // constant extents.
2683
+ columnIsDeferred = true ;
2684
+ } else {
2685
+ // One of the array dimension that is not the column of the first
2686
+ // array has dynamic extent. It will not possible to do
2687
+ // code generation for the CoordinateOp if the base is not a
2688
+ // fir.box containing the value of that extent.
2689
+ return ShapeAnalysis{false , false };
2690
+ }
2691
+ }
2692
+ // There may be less operands than the array size if the
2693
+ // fir.coordinate_of result is not an element but a sub-array.
2694
+ if (it != end)
2695
+ ++it;
2696
+ }
2697
2697
type = arrTy.getEleTy ();
2698
- } else if (auto strTy = mlir::dyn_cast<fir::RecordType>(type)) {
2699
- type = strTy.getType (getFieldNumber (strTy, nxtOpnd));
2698
+ continue ;
2699
+ }
2700
+ if (auto strTy = mlir::dyn_cast<fir::RecordType>(type)) {
2701
+ auto intAttr = llvm::dyn_cast<mlir::IntegerAttr>(*it);
2702
+ if (!intAttr) {
2703
+ mlir::emitError (coor.getLoc (),
2704
+ " expected field name in fir.coordinate_of" );
2705
+ return std::nullopt;
2706
+ }
2707
+ type = strTy.getType (intAttr.getInt ());
2700
2708
} else if (auto strTy = mlir::dyn_cast<mlir::TupleType>(type)) {
2701
- type = strTy.getType (getConstantIntValue (nxtOpnd));
2702
- } else {
2703
- return true ;
2709
+ auto value = llvm::dyn_cast<mlir::Value>(*it);
2710
+ if (!value) {
2711
+ mlir::emitError (
2712
+ coor.getLoc (),
2713
+ " expected constant value to address tuple in fir.coordinate_of" );
2714
+ return std::nullopt;
2715
+ }
2716
+ type = strTy.getType (getConstantIntValue (value));
2717
+ } else if (auto charType = mlir::dyn_cast<fir::CharacterType>(type)) {
2718
+ // Addressing character in string. Fortran strings degenerate to arrays
2719
+ // in LLVM, so they are handled like arrays of characters here.
2720
+ if (charType.getLen () == fir::CharacterType::unknownLen ())
2721
+ return ShapeAnalysis{false , true };
2722
+ type = fir::CharacterType::getSingleton (charType.getContext (),
2723
+ charType.getFKind ());
2704
2724
}
2725
+ ++it;
2705
2726
}
2706
- return true ;
2727
+ return ShapeAnalysis{hasKnownShape, columnIsDeferred} ;
2707
2728
}
2708
2729
2709
2730
private:
@@ -2754,36 +2775,43 @@ struct CoordinateOpConversion
2754
2775
mlir::LLVM::IntegerOverflowFlags nsw =
2755
2776
mlir::LLVM::IntegerOverflowFlags::nsw;
2756
2777
2757
- for (unsigned i = 1 , last = operands.size (); i < last; ++i) {
2778
+ int nextIndexValue = 1 ;
2779
+ fir::CoordinateIndicesAdaptor indices = coor.getIndices ();
2780
+ for (auto it = indices.begin (), end = indices.end (); it != end;) {
2758
2781
if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2759
- if (i != 1 )
2782
+ if (it != indices. begin () )
2760
2783
TODO (loc, " fir.array nested inside other array and/or derived type" );
2761
2784
// Applies byte strides from the box. Ignore lower bound from box
2762
2785
// since fir.coordinate_of indexes are zero based. Lowering takes care
2763
2786
// of lower bound aspects. This both accounts for dynamically sized
2764
2787
// types and non contiguous arrays.
2765
2788
auto idxTy = lowerTy ().indexType ();
2766
2789
mlir::Value off = genConstantIndex (loc, idxTy, rewriter, 0 );
2767
- for ( unsigned index = i, lastIndex = i + arrTy.getDimension ();
2768
- index < lastIndex ; ++index ) {
2769
- mlir::Value stride = getStrideFromBox (loc, boxTyPair, operands[ 0 ],
2770
- index - i , rewriter);
2790
+ unsigned arrayDim = arrTy.getDimension ();
2791
+ for ( unsigned dim = 0 ; dim < arrayDim && it != end ; ++dim, ++it ) {
2792
+ mlir::Value stride =
2793
+ getStrideFromBox (loc, boxTyPair, operands[ 0 ], dim , rewriter);
2771
2794
auto sc = rewriter.create <mlir::LLVM::MulOp>(
2772
- loc, idxTy, operands[index ], stride, nsw);
2795
+ loc, idxTy, operands[nextIndexValue + dim ], stride, nsw);
2773
2796
off = rewriter.create <mlir::LLVM::AddOp>(loc, idxTy, sc, off, nsw);
2774
2797
}
2798
+ nextIndexValue += arrayDim;
2775
2799
resultAddr = rewriter.create <mlir::LLVM::GEPOp>(
2776
2800
loc, llvmPtrTy, byteTy, resultAddr,
2777
2801
llvm::ArrayRef<mlir::LLVM::GEPArg>{off});
2778
- i += arrTy.getDimension () - 1 ;
2779
2802
cpnTy = arrTy.getEleTy ();
2780
2803
} else if (auto recTy = mlir::dyn_cast<fir::RecordType>(cpnTy)) {
2781
- mlir::Value nxtOpnd = operands[i];
2782
- cpnTy = recTy.getType (getFieldNumber (recTy, nxtOpnd));
2804
+ auto intAttr = llvm::dyn_cast<mlir::IntegerAttr>(*it);
2805
+ if (!intAttr)
2806
+ return mlir::emitError (loc,
2807
+ " expected field name in fir.coordinate_of" );
2808
+ int fieldIndex = intAttr.getInt ();
2809
+ ++it;
2810
+ cpnTy = recTy.getType (fieldIndex);
2783
2811
auto llvmRecTy = lowerTy ().convertType (recTy);
2784
2812
resultAddr = rewriter.create <mlir::LLVM::GEPOp>(
2785
2813
loc, llvmPtrTy, llvmRecTy, resultAddr,
2786
- llvm::ArrayRef<mlir::LLVM::GEPArg>{0 , nxtOpnd });
2814
+ llvm::ArrayRef<mlir::LLVM::GEPArg>{0 , fieldIndex });
2787
2815
} else {
2788
2816
fir::emitFatalError (loc, " unexpected type in coordinate_of" );
2789
2817
}
@@ -2801,92 +2829,71 @@ struct CoordinateOpConversion
2801
2829
2802
2830
// Component Type
2803
2831
mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy (baseObjectTy);
2804
- bool hasSubdimension = hasSubDimensions (cpnTy);
2805
- bool columnIsDeferred = !hasSubdimension;
2806
-
2807
- if (!supportedCoordinate (cpnTy, operands.drop_front (1 )))
2808
- TODO (loc, " unsupported combination of coordinate operands" );
2809
-
2810
- const bool hasKnownShape =
2811
- arraysHaveKnownShape (cpnTy, operands.drop_front (1 ));
2812
-
2813
- // If only the column is `?`, then we can simply place the column value in
2814
- // the 0-th GEP position.
2815
- if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2816
- if (!hasKnownShape) {
2817
- const unsigned sz = arrTy.getDimension ();
2818
- if (arraysHaveKnownShape (arrTy.getEleTy (),
2819
- operands.drop_front (1 + sz))) {
2820
- fir::SequenceType::ShapeRef shape = arrTy.getShape ();
2821
- bool allConst = true ;
2822
- for (unsigned i = 0 ; i < sz - 1 ; ++i) {
2823
- if (shape[i] < 0 ) {
2824
- allConst = false ;
2825
- break ;
2826
- }
2827
- }
2828
- if (allConst)
2829
- columnIsDeferred = true ;
2830
- }
2831
- }
2832
- }
2832
+
2833
+ const std::optional<ShapeAnalysis> shapeAnalysis =
2834
+ arraysHaveKnownShape (cpnTy, coor);
2835
+ if (!shapeAnalysis)
2836
+ return mlir::failure ();
2833
2837
2834
2838
if (fir::hasDynamicSize (fir::unwrapSequenceType (cpnTy)))
2835
2839
return mlir::emitError (
2836
2840
loc, " fir.coordinate_of with a dynamic element size is unsupported" );
2837
2841
2838
- if (hasKnownShape || columnIsDeferred) {
2842
+ if (shapeAnalysis-> hasKnownShape || shapeAnalysis-> columnIsDeferred ) {
2839
2843
llvm::SmallVector<mlir::LLVM::GEPArg> offs;
2840
- if (hasKnownShape && hasSubdimension ) {
2844
+ if (shapeAnalysis-> hasKnownShape ) {
2841
2845
offs.push_back (0 );
2842
2846
}
2847
+ // Else, only the column is `?` and we can simply place the column value
2848
+ // in the 0-th GEP position.
2849
+
2843
2850
std::optional<int > dims;
2844
2851
llvm::SmallVector<mlir::Value> arrIdx;
2845
- for (std::size_t i = 1 , sz = operands.size (); i < sz; ++i) {
2846
- mlir::Value nxtOpnd = operands[i];
2847
-
2848
- if (!cpnTy)
2849
- return mlir::emitError (loc, " invalid coordinate/check failed" );
2850
-
2851
- // check if the i-th coordinate relates to an array
2852
- if (dims) {
2853
- arrIdx.push_back (nxtOpnd);
2854
- int dimsLeft = *dims;
2855
- if (dimsLeft > 1 ) {
2856
- dims = dimsLeft - 1 ;
2857
- continue ;
2858
- }
2859
- cpnTy = mlir::cast<fir::SequenceType>(cpnTy).getElementType ();
2860
- // append array range in reverse (FIR arrays are column-major)
2861
- offs.append (arrIdx.rbegin (), arrIdx.rend ());
2862
- arrIdx.clear ();
2863
- dims.reset ();
2852
+ int nextIndexValue = 1 ;
2853
+ for (auto index : coor.getIndices ()) {
2854
+ if (auto intAttr = llvm::dyn_cast<mlir::IntegerAttr>(index )) {
2855
+ // Addressing derived type component.
2856
+ auto recordType = llvm::dyn_cast<fir::RecordType>(cpnTy);
2857
+ if (!recordType)
2858
+ return mlir::emitError (
2859
+ loc,
2860
+ " fir.coordinate base type is not consistent with operands" );
2861
+ int fieldId = intAttr.getInt ();
2862
+ cpnTy = recordType.getType (fieldId);
2863
+ offs.push_back (fieldId);
2864
2864
continue ;
2865
2865
}
2866
- if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2867
- int d = arrTy.getDimension () - 1 ;
2868
- if (d > 0 ) {
2869
- dims = d;
2870
- arrIdx.push_back (nxtOpnd);
2871
- continue ;
2866
+ // Value index (addressing array, tuple, or complex part).
2867
+ mlir::Value indexValue = operands[nextIndexValue++];
2868
+ if (auto tupTy = mlir::dyn_cast<mlir::TupleType>(cpnTy)) {
2869
+ cpnTy = tupTy.getType (getConstantIntValue (indexValue));
2870
+ offs.push_back (indexValue);
2871
+ } else {
2872
+ if (!dims) {
2873
+ if (auto arrayType = llvm::dyn_cast<fir::SequenceType>(cpnTy)) {
2874
+ // Starting addressing array or array component.
2875
+ dims = arrayType.getDimension ();
2876
+ cpnTy = arrayType.getElementType ();
2877
+ }
2878
+ }
2879
+ if (dims) {
2880
+ arrIdx.push_back (indexValue);
2881
+ if (--(*dims) == 0 ) {
2882
+ // Append array range in reverse (FIR arrays are column-major).
2883
+ offs.append (arrIdx.rbegin (), arrIdx.rend ());
2884
+ arrIdx.clear ();
2885
+ dims.reset ();
2886
+ }
2887
+ } else {
2888
+ offs.push_back (indexValue);
2872
2889
}
2873
- cpnTy = mlir::cast<fir::SequenceType>(cpnTy).getElementType ();
2874
- offs.push_back (nxtOpnd);
2875
- continue ;
2876
2890
}
2877
-
2878
- // check if the i-th coordinate relates to a field
2879
- if (auto recTy = mlir::dyn_cast<fir::RecordType>(cpnTy))
2880
- cpnTy = recTy.getType (getFieldNumber (recTy, nxtOpnd));
2881
- else if (auto tupTy = mlir::dyn_cast<mlir::TupleType>(cpnTy))
2882
- cpnTy = tupTy.getType (getConstantIntValue (nxtOpnd));
2883
- else
2884
- cpnTy = nullptr ;
2885
-
2886
- offs.push_back (nxtOpnd);
2887
2891
}
2888
- if (dims)
2892
+ // It is possible the fir.coordinate_of result is a sub-array, in which
2893
+ // case there may be some "unfinished" array indices to reverse and push.
2894
+ if (!arrIdx.empty ())
2889
2895
offs.append (arrIdx.rbegin (), arrIdx.rend ());
2896
+
2890
2897
mlir::Value base = operands[0 ];
2891
2898
mlir::Value retval = genGEP (loc, llvmObjectTy, rewriter, base, offs);
2892
2899
rewriter.replaceOp (coor, retval);
0 commit comments