@@ -66,6 +66,11 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
66
66
return lowerTy ().convertType (ty);
67
67
}
68
68
69
+ mlir::Type getVoidPtrType () const {
70
+ return mlir::LLVM::LLVMPointerType::get (
71
+ mlir::IntegerType::get (&lowerTy ().getContext (), 8 ));
72
+ }
73
+
69
74
mlir::LLVM::ConstantOp
70
75
genI32Constant (mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
71
76
int value) const {
@@ -126,6 +131,17 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
126
131
return rewriter.create <mlir::LLVM::LoadOp>(loc, ty, p);
127
132
}
128
133
134
+ mlir::Value
135
+ loadStrideFromBox (mlir::Location loc, mlir::Value box, unsigned dim,
136
+ mlir::ConversionPatternRewriter &rewriter) const {
137
+ auto idxTy = lowerTy ().indexType ();
138
+ auto c0 = genConstantOffset (loc, rewriter, 0 );
139
+ auto cDims = genConstantOffset (loc, rewriter, kDimsPosInBox );
140
+ auto dimValue = genConstantIndex (loc, idxTy, rewriter, dim);
141
+ return loadFromOffset (loc, box, c0, cDims, dimValue, kDimStridePos , idxTy,
142
+ rewriter);
143
+ }
144
+
129
145
// / Read base address from a fir.box. Returned address has type ty.
130
146
mlir::Value
131
147
loadBaseAddrFromBox (mlir::Location loc, mlir::Type ty, mlir::Value box,
@@ -188,6 +204,12 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
188
204
return type;
189
205
}
190
206
207
+ // Return LLVM type of the base address given the LLVM type
208
+ // of the related descriptor (lowered fir.box type).
209
+ static mlir::Type getBaseAddrTypeFromBox (mlir::Type type) {
210
+ return getBoxEleTy (type, {kAddrPosInBox });
211
+ }
212
+
191
213
template <typename ... ARGS>
192
214
mlir::LLVM::GEPOp genGEP (mlir::Location loc, mlir::Type ty,
193
215
mlir::ConversionPatternRewriter &rewriter,
@@ -2004,6 +2026,168 @@ struct InsertOnRangeOpConversion
2004
2026
}
2005
2027
};
2006
2028
2029
+ // / XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
2030
+ // / shifted etc. array.
2031
+ // / (See the static restriction on coordinate_of.) array_coor determines the
2032
+ // / coordinate (location) of a specific element.
2033
+ struct XArrayCoorOpConversion
2034
+ : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
2035
+ using FIROpAndTypeConversion::FIROpAndTypeConversion;
2036
+
2037
+ mlir::LogicalResult
2038
+ doRewrite (fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
2039
+ mlir::ConversionPatternRewriter &rewriter) const override {
2040
+ auto loc = coor.getLoc ();
2041
+ mlir::ValueRange operands = adaptor.getOperands ();
2042
+ unsigned rank = coor.getRank ();
2043
+ assert (coor.indices ().size () == rank);
2044
+ assert (coor.shape ().empty () || coor.shape ().size () == rank);
2045
+ assert (coor.shift ().empty () || coor.shift ().size () == rank);
2046
+ assert (coor.slice ().empty () || coor.slice ().size () == 3 * rank);
2047
+ mlir::Type idxTy = lowerTy ().indexType ();
2048
+ mlir::Value one = genConstantIndex (loc, idxTy, rewriter, 1 );
2049
+ mlir::Value prevExt = one;
2050
+ mlir::Value zero = genConstantIndex (loc, idxTy, rewriter, 0 );
2051
+ mlir::Value offset = zero;
2052
+ const bool isShifted = !coor.shift ().empty ();
2053
+ const bool isSliced = !coor.slice ().empty ();
2054
+ const bool baseIsBoxed = coor.memref ().getType ().isa <fir::BoxType>();
2055
+
2056
+ auto indexOps = coor.indices ().begin ();
2057
+ auto shapeOps = coor.shape ().begin ();
2058
+ auto shiftOps = coor.shift ().begin ();
2059
+ auto sliceOps = coor.slice ().begin ();
2060
+ // For each dimension of the array, generate the offset calculation.
2061
+ for (unsigned i = 0 ; i < rank;
2062
+ ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3 ) {
2063
+ mlir::Value index =
2064
+ integerCast (loc, rewriter, idxTy, operands[coor.indicesOffset () + i]);
2065
+ mlir::Value lb = isShifted ? integerCast (loc, rewriter, idxTy,
2066
+ operands[coor.shiftOffset () + i])
2067
+ : one;
2068
+ mlir::Value step = one;
2069
+ bool normalSlice = isSliced;
2070
+ // Compute zero based index in dimension i of the element, applying
2071
+ // potential triplets and lower bounds.
2072
+ if (isSliced) {
2073
+ mlir::Value ub = *(sliceOps + 1 );
2074
+ normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp ());
2075
+ if (normalSlice)
2076
+ step = integerCast (loc, rewriter, idxTy, *(sliceOps + 2 ));
2077
+ }
2078
+ auto idx = rewriter.create <mlir::LLVM::SubOp>(loc, idxTy, index, lb);
2079
+ mlir::Value diff =
2080
+ rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, idx, step);
2081
+ if (normalSlice) {
2082
+ mlir::Value sliceLb =
2083
+ integerCast (loc, rewriter, idxTy, operands[coor.sliceOffset () + i]);
2084
+ auto adj = rewriter.create <mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
2085
+ diff = rewriter.create <mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
2086
+ }
2087
+ // Update the offset given the stride and the zero based index `diff`
2088
+ // that was just computed.
2089
+ if (baseIsBoxed) {
2090
+ // Use stride in bytes from the descriptor.
2091
+ mlir::Value stride =
2092
+ loadStrideFromBox (loc, adaptor.getOperands ()[0 ], i, rewriter);
2093
+ auto sc = rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
2094
+ offset = rewriter.create <mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
2095
+ } else {
2096
+ // Use stride computed at last iteration.
2097
+ auto sc = rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
2098
+ offset = rewriter.create <mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
2099
+ // Compute next stride assuming contiguity of the base array
2100
+ // (in element number).
2101
+ auto nextExt =
2102
+ integerCast (loc, rewriter, idxTy, operands[coor.shapeOffset () + i]);
2103
+ prevExt =
2104
+ rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
2105
+ }
2106
+ }
2107
+
2108
+ // Add computed offset to the base address.
2109
+ if (baseIsBoxed) {
2110
+ // Working with byte offsets. The base address is read from the fir.box.
2111
+ // and need to be casted to i8* to do the pointer arithmetic.
2112
+ mlir::Type baseTy =
2113
+ getBaseAddrTypeFromBox (adaptor.getOperands ()[0 ].getType ());
2114
+ mlir::Value base =
2115
+ loadBaseAddrFromBox (loc, baseTy, adaptor.getOperands ()[0 ], rewriter);
2116
+ mlir::Type voidPtrTy = getVoidPtrType ();
2117
+ base = rewriter.create <mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2118
+ llvm::SmallVector<mlir::Value> args{base, offset};
2119
+ auto addr = rewriter.create <mlir::LLVM::GEPOp>(loc, voidPtrTy, args);
2120
+ if (coor.subcomponent ().empty ()) {
2121
+ rewriter.replaceOpWithNewOp <mlir::LLVM::BitcastOp>(coor, baseTy, addr);
2122
+ return success ();
2123
+ }
2124
+ auto casted = rewriter.create <mlir::LLVM::BitcastOp>(loc, baseTy, addr);
2125
+ args.clear ();
2126
+ args.push_back (casted);
2127
+ args.push_back (zero);
2128
+ if (!coor.lenParams ().empty ()) {
2129
+ // If type parameters are present, then we don't want to use a GEPOp
2130
+ // as below, as the LLVM struct type cannot be statically defined.
2131
+ TODO (loc, " derived type with type parameters" );
2132
+ }
2133
+ // TODO: array offset subcomponents must be converted to LLVM's
2134
+ // row-major layout here.
2135
+ for (auto i = coor.subcomponentOffset (); i != coor.indicesOffset (); ++i)
2136
+ args.push_back (operands[i]);
2137
+ rewriter.replaceOpWithNewOp <mlir::LLVM::GEPOp>(coor, baseTy, args);
2138
+ return success ();
2139
+ }
2140
+
2141
+ // The array was not boxed, so it must be contiguous. offset is therefore an
2142
+ // element offset and the base type is kept in the GEP unless the element
2143
+ // type size is itself dynamic.
2144
+ mlir::Value base;
2145
+ if (coor.subcomponent ().empty ()) {
2146
+ // No subcomponent.
2147
+ if (!coor.lenParams ().empty ()) {
2148
+ // Type parameters. Adjust element size explicitly.
2149
+ auto eleTy = fir::dyn_cast_ptrEleTy (coor.getType ());
2150
+ assert (eleTy && " result must be a reference-like type" );
2151
+ if (fir::characterWithDynamicLen (eleTy)) {
2152
+ assert (coor.lenParams ().size () == 1 );
2153
+ auto bitsInChar = lowerTy ().getKindMap ().getCharacterBitsize (
2154
+ eleTy.cast <fir::CharacterType>().getFKind ());
2155
+ auto scaling = genConstantIndex (loc, idxTy, rewriter, bitsInChar / 8 );
2156
+ auto scaledBySize =
2157
+ rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
2158
+ auto length =
2159
+ integerCast (loc, rewriter, idxTy,
2160
+ adaptor.getOperands ()[coor.lenParamsOffset ()]);
2161
+ offset = rewriter.create <mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
2162
+ length);
2163
+ } else {
2164
+ TODO (loc, " compute size of derived type with type parameters" );
2165
+ }
2166
+ }
2167
+ // Cast the base address to a pointer to T.
2168
+ base = rewriter.create <mlir::LLVM::BitcastOp>(loc, ty,
2169
+ adaptor.getOperands ()[0 ]);
2170
+ } else {
2171
+ // Operand #0 must have a pointer type. For subcomponent slicing, we
2172
+ // want to cast away the array type and have a plain struct type.
2173
+ mlir::Type ty0 = adaptor.getOperands ()[0 ].getType ();
2174
+ auto ptrTy = ty0.dyn_cast <mlir::LLVM::LLVMPointerType>();
2175
+ assert (ptrTy && " expected pointer type" );
2176
+ mlir::Type eleTy = ptrTy.getElementType ();
2177
+ while (auto arrTy = eleTy.dyn_cast <mlir::LLVM::LLVMArrayType>())
2178
+ eleTy = arrTy.getElementType ();
2179
+ auto newTy = mlir::LLVM::LLVMPointerType::get (eleTy);
2180
+ base = rewriter.create <mlir::LLVM::BitcastOp>(loc, newTy,
2181
+ adaptor.getOperands ()[0 ]);
2182
+ }
2183
+ SmallVector<mlir::Value> args = {base, offset};
2184
+ for (auto i = coor.subcomponentOffset (); i != coor.indicesOffset (); ++i)
2185
+ args.push_back (operands[i]);
2186
+ rewriter.replaceOpWithNewOp <mlir::LLVM::GEPOp>(coor, ty, args);
2187
+ return success ();
2188
+ }
2189
+ };
2190
+
2007
2191
//
2008
2192
// Primitive operations on Complex types
2009
2193
//
@@ -2431,8 +2615,8 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2431
2615
ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
2432
2616
SliceOpConversion, StoreOpConversion, StringLitOpConversion,
2433
2617
SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
2434
- UndefOpConversion, UnreachableOpConversion, XEmboxOpConversion ,
2435
- ZeroOpConversion>(typeConverter);
2618
+ UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion ,
2619
+ XEmboxOpConversion, ZeroOpConversion>(typeConverter);
2436
2620
mlir::populateStdToLLVMConversionPatterns (typeConverter, pattern);
2437
2621
mlir::arith::populateArithmeticToLLVMConversionPatterns (typeConverter,
2438
2622
pattern);
0 commit comments