Skip to content

Commit 538552d

Browse files
committed
update codegen
1 parent e0cd978 commit 538552d

File tree

16 files changed

+223
-220
lines changed

16 files changed

+223
-220
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct DebuggingResource
5151
};
5252

5353
class CoordinateIndicesAdaptor;
54+
using IntOrValue = llvm::PointerUnion<mlir::IntegerAttr, mlir::Value>;
5455

5556
} // namespace fir
5657

@@ -60,7 +61,6 @@ class CoordinateIndicesAdaptor;
6061
namespace fir {
6162
class CoordinateIndicesAdaptor {
6263
public:
63-
using IntOrValue = llvm::PointerUnion<mlir::IntegerAttr, mlir::Value>;
6464
using value_type = IntOrValue;
6565

6666
CoordinateIndicesAdaptor(mlir::DenseI32ArrayAttr fieldIndices,

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,10 +1748,16 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoMemoryEffect]> {
17481748
Unlike LLVM's GEP instruction, one cannot stride over the outermost
17491749
reference; therefore, the leading 0 index must be omitted.
17501750

1751+
This operation can be used to index derived type fields, in which case
1752+
the operand is the name of the index field.
1753+
17511754
```
17521755
%i = ... : index
17531756
%h = ... : !fir.heap<!fir.array<100 x f32>>
17541757
%p = fir.coordinate_of %h, %i : (!fir.heap<!fir.array<100 x f32>>, index) -> !fir.ref<f32>
1758+
1759+
%d = ... : !fir.ref<!fir.type<t{field1:i32, field2:f32}>>
1760+
%f = fir.coordinate_of %d, field2 : (!fir.ref<!fir.type<t{field1:i32, field2:f32}>>) -> !fir.ref<f32>
17551761
```
17561762

17571763
In the example, `%p` will be a pointer to the `%i`-th f32 value in the
@@ -1772,7 +1778,9 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoMemoryEffect]> {
17721778

17731779
let builders = [
17741780
OpBuilder<(ins "mlir::Type":$resultType,
1775-
"mlir::Value":$ref, "mlir::ValueRange":$coor)>
1781+
"mlir::Value":$ref, "mlir::ValueRange":$coor)>,
1782+
OpBuilder<(ins "mlir::Type":$resultType,
1783+
"mlir::Value":$ref, "llvm::ArrayRef<fir::IntOrValue>":$coor)>
17761784
];
17771785
let extraClassDeclaration = [{
17781786
constexpr static int32_t kDynamicIndex = std::numeric_limits<int32_t>::min();

flang/lib/Lower/OpenMP/Utils.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,12 @@ mlir::Value createParentSymAndGenIntermediateMaps(
354354
// type.
355355
if (fir::RecordType recordType = mlir::dyn_cast<fir::RecordType>(
356356
fir::unwrapPassByRefType(curValue.getType()))) {
357-
mlir::Value idxConst = firOpBuilder.createIntegerConstant(
358-
clauseLocation, firOpBuilder.getIndexType(),
359-
indices[currentIndicesIdx]);
360-
mlir::Type memberTy =
361-
recordType.getTypeList().at(indices[currentIndicesIdx]).second;
357+
fir::IntOrValue idxConst = mlir::IntegerAttr::get(
358+
firOpBuilder.getI32Type(), indices[currentIndicesIdx]);
359+
mlir::Type memberTy = recordType.getType(indices[currentIndicesIdx]);
362360
curValue = firOpBuilder.create<fir::CoordinateOp>(
363361
clauseLocation, firOpBuilder.getRefType(memberTy), curValue,
364-
idxConst);
362+
llvm::SmallVector<fir::IntOrValue, 1>{idxConst});
365363

366364
// Skip mapping and the subsequent load if we're the final member or not
367365
// a type with a descriptor such as a pointer/allocatable. If we're a

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 130 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,57 +2653,78 @@ struct CoordinateOpConversion
26532653
return mlir::isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(type);
26542654
}
26552655

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+
};
26862662

26872663
/// Walk the abstract memory layout and determine if the path traverses any
26882664
/// array types with unknown shape. Return true iff all the array types have a
26892665
/// 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;) {
26932674
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+
}
26972697
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());
27002708
} 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());
27042724
}
2725+
++it;
27052726
}
2706-
return true;
2727+
return ShapeAnalysis{hasKnownShape, columnIsDeferred};
27072728
}
27082729

27092730
private:
@@ -2754,36 +2775,43 @@ struct CoordinateOpConversion
27542775
mlir::LLVM::IntegerOverflowFlags nsw =
27552776
mlir::LLVM::IntegerOverflowFlags::nsw;
27562777

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;) {
27582781
if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2759-
if (i != 1)
2782+
if (it != indices.begin())
27602783
TODO(loc, "fir.array nested inside other array and/or derived type");
27612784
// Applies byte strides from the box. Ignore lower bound from box
27622785
// since fir.coordinate_of indexes are zero based. Lowering takes care
27632786
// of lower bound aspects. This both accounts for dynamically sized
27642787
// types and non contiguous arrays.
27652788
auto idxTy = lowerTy().indexType();
27662789
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);
27712794
auto sc = rewriter.create<mlir::LLVM::MulOp>(
2772-
loc, idxTy, operands[index], stride, nsw);
2795+
loc, idxTy, operands[nextIndexValue + dim], stride, nsw);
27732796
off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off, nsw);
27742797
}
2798+
nextIndexValue += arrayDim;
27752799
resultAddr = rewriter.create<mlir::LLVM::GEPOp>(
27762800
loc, llvmPtrTy, byteTy, resultAddr,
27772801
llvm::ArrayRef<mlir::LLVM::GEPArg>{off});
2778-
i += arrTy.getDimension() - 1;
27792802
cpnTy = arrTy.getEleTy();
27802803
} 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);
27832811
auto llvmRecTy = lowerTy().convertType(recTy);
27842812
resultAddr = rewriter.create<mlir::LLVM::GEPOp>(
27852813
loc, llvmPtrTy, llvmRecTy, resultAddr,
2786-
llvm::ArrayRef<mlir::LLVM::GEPArg>{0, nxtOpnd});
2814+
llvm::ArrayRef<mlir::LLVM::GEPArg>{0, fieldIndex});
27872815
} else {
27882816
fir::emitFatalError(loc, "unexpected type in coordinate_of");
27892817
}
@@ -2801,92 +2829,71 @@ struct CoordinateOpConversion
28012829

28022830
// Component Type
28032831
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();
28332837

28342838
if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy)))
28352839
return mlir::emitError(
28362840
loc, "fir.coordinate_of with a dynamic element size is unsupported");
28372841

2838-
if (hasKnownShape || columnIsDeferred) {
2842+
if (shapeAnalysis->hasKnownShape || shapeAnalysis->columnIsDeferred) {
28392843
llvm::SmallVector<mlir::LLVM::GEPArg> offs;
2840-
if (hasKnownShape && hasSubdimension) {
2844+
if (shapeAnalysis->hasKnownShape) {
28412845
offs.push_back(0);
28422846
}
2847+
// Else, only the column is `?` and we can simply place the column value
2848+
// in the 0-th GEP position.
2849+
28432850
std::optional<int> dims;
28442851
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);
28642864
continue;
28652865
}
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);
28722889
}
2873-
cpnTy = mlir::cast<fir::SequenceType>(cpnTy).getElementType();
2874-
offs.push_back(nxtOpnd);
2875-
continue;
28762890
}
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);
28872891
}
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())
28892895
offs.append(arrIdx.rbegin(), arrIdx.rend());
2896+
28902897
mlir::Value base = operands[0];
28912898
mlir::Value retval = genGEP(loc, llvmObjectTy, rewriter, base, offs);
28922899
rewriter.replaceOp(coor, retval);

0 commit comments

Comments
 (0)