FLANG
Factory.h
1//===-- Optimizer/Builder/Factory.h -----------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Templates to generate more complex code patterns in transformation passes.
10// In transformation passes, front-end information such as is available in
11// lowering is not available.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef FORTRAN_OPTIMIZER_BUILDER_FACTORY_H
16#define FORTRAN_OPTIMIZER_BUILDER_FACTORY_H
17
18#include "flang/Optimizer/Dialect/FIROps.h"
19#include "flang/Optimizer/Dialect/FIRType.h"
20#include "mlir/Dialect/Func/IR/FuncOps.h"
21#include "llvm/ADT/iterator_range.h"
22
23namespace mlir {
24class Location;
25class Value;
26} // namespace mlir
27
28namespace fir::factory {
29
30constexpr llvm::StringRef attrFortranArrayOffsets() {
31 return "Fortran.offsets";
32}
33
42template <typename B>
43void genCharacterCopy(mlir::Value src, mlir::Value srcLen, mlir::Value dst,
44 mlir::Value dstLen, B &builder, mlir::Location loc) {
45 auto srcTy =
46 mlir::cast<fir::CharacterType>(fir::dyn_cast_ptrEleTy(src.getType()));
47 auto dstTy =
48 mlir::cast<fir::CharacterType>(fir::dyn_cast_ptrEleTy(dst.getType()));
49 if (!srcLen && !dstLen && srcTy.getFKind() == dstTy.getFKind() &&
50 srcTy.getLen() == dstTy.getLen()) {
51 // same size, so just use load and store
52 auto load = builder.template create<fir::LoadOp>(loc, src);
53 builder.template create<fir::StoreOp>(loc, load, dst);
54 return;
55 }
56 auto zero = builder.template create<mlir::arith::ConstantIndexOp>(loc, 0);
57 auto one = builder.template create<mlir::arith::ConstantIndexOp>(loc, 1);
58 auto toArrayTy = [&](fir::CharacterType ty) {
59 return fir::ReferenceType::get(fir::SequenceType::get(
60 fir::SequenceType::ShapeRef{fir::SequenceType::getUnknownExtent()},
61 fir::CharacterType::getSingleton(ty.getContext(), ty.getFKind())));
62 };
63 auto toEleTy = [&](fir::ReferenceType ty) {
64 auto seqTy = mlir::cast<fir::SequenceType>(ty.getEleTy());
65 return mlir::cast<fir::CharacterType>(seqTy.getEleTy());
66 };
67 auto toCoorTy = [&](fir::ReferenceType ty) {
68 return fir::ReferenceType::get(toEleTy(ty));
69 };
70 if (!srcLen && !dstLen && srcTy.getLen() >= dstTy.getLen()) {
71 auto upper = builder.template create<mlir::arith::ConstantIndexOp>(
72 loc, dstTy.getLen() - 1);
73 auto loop = builder.template create<fir::DoLoopOp>(loc, zero, upper, one);
74 auto insPt = builder.saveInsertionPoint();
75 builder.setInsertionPointToStart(loop.getBody());
76 auto csrcTy = toArrayTy(srcTy);
77 auto csrc = builder.template create<fir::ConvertOp>(loc, csrcTy, src);
78 auto in = builder.template create<fir::CoordinateOp>(
79 loc, toCoorTy(csrcTy), csrc, loop.getInductionVar());
80 auto load = builder.template create<fir::LoadOp>(loc, in);
81 auto cdstTy = toArrayTy(dstTy);
82 auto cdst = builder.template create<fir::ConvertOp>(loc, cdstTy, dst);
83 auto out = builder.template create<fir::CoordinateOp>(
84 loc, toCoorTy(cdstTy), cdst, loop.getInductionVar());
85 mlir::Value cast =
86 srcTy.getFKind() == dstTy.getFKind()
87 ? load.getResult()
88 : builder
89 .template create<fir::ConvertOp>(loc, toEleTy(cdstTy), load)
90 .getResult();
91 builder.template create<fir::StoreOp>(loc, cast, out);
92 builder.restoreInsertionPoint(insPt);
93 return;
94 }
95 auto minusOne = [&](mlir::Value v) -> mlir::Value {
96 return builder.template create<mlir::arith::SubIOp>(
97 loc, builder.template create<fir::ConvertOp>(loc, one.getType(), v),
98 one);
99 };
100 mlir::Value len = dstLen ? minusOne(dstLen)
101 : builder
102 .template create<mlir::arith::ConstantIndexOp>(
103 loc, dstTy.getLen() - 1)
104 .getResult();
105 auto loop = builder.template create<fir::DoLoopOp>(loc, zero, len, one);
106 auto insPt = builder.saveInsertionPoint();
107 builder.setInsertionPointToStart(loop.getBody());
108 mlir::Value slen =
109 srcLen
110 ? builder.template create<fir::ConvertOp>(loc, one.getType(), srcLen)
111 .getResult()
112 : builder
113 .template create<mlir::arith::ConstantIndexOp>(loc,
114 srcTy.getLen())
115 .getResult();
116 auto cond = builder.template create<mlir::arith::CmpIOp>(
117 loc, mlir::arith::CmpIPredicate::slt, loop.getInductionVar(), slen);
118 auto ifOp = builder.template create<fir::IfOp>(loc, cond, /*withElse=*/true);
119 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
120 auto csrcTy = toArrayTy(srcTy);
121 auto csrc = builder.template create<fir::ConvertOp>(loc, csrcTy, src);
122 auto in = builder.template create<fir::CoordinateOp>(
123 loc, toCoorTy(csrcTy), csrc, loop.getInductionVar());
124 auto load = builder.template create<fir::LoadOp>(loc, in);
125 auto cdstTy = toArrayTy(dstTy);
126 auto cdst = builder.template create<fir::ConvertOp>(loc, cdstTy, dst);
127 auto out = builder.template create<fir::CoordinateOp>(
128 loc, toCoorTy(cdstTy), cdst, loop.getInductionVar());
129 mlir::Value cast =
130 srcTy.getFKind() == dstTy.getFKind()
131 ? load.getResult()
132 : builder.template create<fir::ConvertOp>(loc, toEleTy(cdstTy), load)
133 .getResult();
134 builder.template create<fir::StoreOp>(loc, cast, out);
135 builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
136 auto space = builder.template create<fir::StringLitOp>(
137 loc, toEleTy(cdstTy), llvm::ArrayRef<char>{' '});
138 auto cdst2 = builder.template create<fir::ConvertOp>(loc, cdstTy, dst);
139 auto out2 = builder.template create<fir::CoordinateOp>(
140 loc, toCoorTy(cdstTy), cdst2, loop.getInductionVar());
141 builder.template create<fir::StoreOp>(loc, space, out2);
142 builder.restoreInsertionPoint(insPt);
143}
144
147inline llvm::SmallVector<mlir::Value> getExtents(mlir::Value shapeVal) {
148 if (shapeVal)
149 if (auto *shapeOp = shapeVal.getDefiningOp()) {
150 if (auto shOp = mlir::dyn_cast<fir::ShapeOp>(shapeOp)) {
151 auto operands = shOp.getExtents();
152 return {operands.begin(), operands.end()};
153 }
154 if (auto shOp = mlir::dyn_cast<fir::ShapeShiftOp>(shapeOp)) {
155 auto operands = shOp.getExtents();
156 return {operands.begin(), operands.end()};
157 }
158 }
159 return {};
160}
161
164inline llvm::SmallVector<mlir::Value> getOrigins(mlir::Value shapeVal) {
165 if (shapeVal)
166 if (auto *shapeOp = shapeVal.getDefiningOp()) {
167 if (auto shOp = mlir::dyn_cast<fir::ShapeShiftOp>(shapeOp)) {
168 auto operands = shOp.getOrigins();
169 return {operands.begin(), operands.end()};
170 }
171 if (auto shOp = mlir::dyn_cast<fir::ShiftOp>(shapeOp)) {
172 auto operands = shOp.getOrigins();
173 return {operands.begin(), operands.end()};
174 }
175 }
176 return {};
177}
178
184template <typename B>
186originateIndices(mlir::Location loc, B &builder, mlir::Type memTy,
187 mlir::Value shapeVal, mlir::ValueRange indices) {
189 auto origins = getOrigins(shapeVal);
190 if (origins.empty()) {
191 assert(!shapeVal || mlir::isa<fir::ShapeOp>(shapeVal.getDefiningOp()));
192 auto ty = fir::dyn_cast_ptrOrBoxEleTy(memTy);
193 assert(ty && mlir::isa<fir::SequenceType>(ty));
194 auto seqTy = mlir::cast<fir::SequenceType>(ty);
195 auto one = builder.template create<mlir::arith::ConstantIndexOp>(loc, 1);
196 const auto dimension = seqTy.getDimension();
197 if (shapeVal) {
198 assert(dimension == mlir::cast<fir::ShapeOp>(shapeVal.getDefiningOp())
199 .getType()
200 .getRank());
201 }
202 for (auto i : llvm::enumerate(indices)) {
203 if (i.index() < dimension) {
204 assert(fir::isa_integer(i.value().getType()));
205 result.push_back(
206 builder.template create<mlir::arith::AddIOp>(loc, i.value(), one));
207 } else {
208 result.push_back(i.value());
209 }
210 }
211 return result;
212 }
213 const auto dimension = origins.size();
214 unsigned origOff = 0;
215 for (auto i : llvm::enumerate(indices)) {
216 if (i.index() < dimension)
217 result.push_back(builder.template create<mlir::arith::AddIOp>(
218 loc, i.value(), origins[origOff++]));
219 else
220 result.push_back(i.value());
221 }
222 return result;
223}
224
225} // namespace fir::factory
226
227#endif // FORTRAN_OPTIMIZER_BUILDER_FACTORY_H
Definition: FIRType.h:77
Definition: OpenACC.h:20
mlir::Value getLen(const ExtendedValue &exv)
Definition: BoxValue.cpp:26
mlir::Type dyn_cast_ptrEleTy(mlir::Type t)
Definition: FIRType.cpp:216
mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t)
Definition: FIRType.cpp:223
bool isa_integer(mlir::Type t)
Is t an integral type?
Definition: FIRType.h:166
@ Value
Lower argument to a value. Mainly intended for scalar arguments.
Definition: AbstractConverter.h:27