|
6 | 6 | //
|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 |
| -#include "flang/Lower/OpenMP/Utils.h" |
10 | 9 | #include "flang/Optimizer/Builder/FIRBuilder.h"
|
11 | 10 | #include "flang/Optimizer/Builder/Todo.h"
|
12 | 11 | #include "flang/Optimizer/Dialect/FIRDialect.h"
|
@@ -35,6 +34,115 @@ namespace fir {
|
35 | 34 |
|
36 | 35 | #define DEBUG_TYPE "fopenmp-do-concurrent-conversion"
|
37 | 36 |
|
| 37 | +namespace Fortran { |
| 38 | +namespace lower { |
| 39 | +namespace omp { |
| 40 | +mlir::omp::MapInfoOp |
| 41 | +createMapInfoOp(mlir::OpBuilder &builder, mlir::Location loc, |
| 42 | + mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name, |
| 43 | + llvm::ArrayRef<mlir::Value> bounds, |
| 44 | + llvm::ArrayRef<mlir::Value> members, |
| 45 | + mlir::DenseIntElementsAttr membersIndex, uint64_t mapType, |
| 46 | + mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy, |
| 47 | + bool partialMap = false) { |
| 48 | + if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) { |
| 49 | + baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr); |
| 50 | + retTy = baseAddr.getType(); |
| 51 | + } |
| 52 | + |
| 53 | + mlir::TypeAttr varType = mlir::TypeAttr::get( |
| 54 | + llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType()); |
| 55 | + |
| 56 | + mlir::omp::MapInfoOp op = builder.create<mlir::omp::MapInfoOp>( |
| 57 | + loc, retTy, baseAddr, varType, varPtrPtr, members, membersIndex, bounds, |
| 58 | + builder.getIntegerAttr(builder.getIntegerType(64, false), mapType), |
| 59 | + builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType), |
| 60 | + builder.getStringAttr(name), builder.getBoolAttr(partialMap)); |
| 61 | + |
| 62 | + return op; |
| 63 | +} |
| 64 | + |
| 65 | +mlir::Value calculateTripCount(fir::FirOpBuilder &builder, mlir::Location loc, |
| 66 | + const mlir::omp::CollapseClauseOps &ops) { |
| 67 | + using namespace mlir::arith; |
| 68 | + assert(ops.loopLBVar.size() == ops.loopUBVar.size() && |
| 69 | + ops.loopLBVar.size() == ops.loopStepVar.size() && |
| 70 | + !ops.loopLBVar.empty() && "Invalid bounds or step"); |
| 71 | + |
| 72 | + // Get the bit width of an integer-like type. |
| 73 | + auto widthOf = [](mlir::Type ty) -> unsigned { |
| 74 | + if (mlir::isa<mlir::IndexType>(ty)) { |
| 75 | + return mlir::IndexType::kInternalStorageBitWidth; |
| 76 | + } |
| 77 | + if (auto tyInt = mlir::dyn_cast<mlir::IntegerType>(ty)) { |
| 78 | + return tyInt.getWidth(); |
| 79 | + } |
| 80 | + llvm_unreachable("Unexpected type"); |
| 81 | + }; |
| 82 | + |
| 83 | + // For a type that is either IntegerType or IndexType, return the |
| 84 | + // equivalent IntegerType. In the former case this is a no-op. |
| 85 | + auto asIntTy = [&](mlir::Type ty) -> mlir::IntegerType { |
| 86 | + if (ty.isIndex()) { |
| 87 | + return mlir::IntegerType::get(ty.getContext(), widthOf(ty)); |
| 88 | + } |
| 89 | + assert(ty.isIntOrIndex() && "Unexpected type"); |
| 90 | + return mlir::cast<mlir::IntegerType>(ty); |
| 91 | + }; |
| 92 | + |
| 93 | + // For two given values, establish a common signless IntegerType |
| 94 | + // that can represent any value of type of x and of type of y, |
| 95 | + // and return the pair of x, y converted to the new type. |
| 96 | + auto unifyToSignless = |
| 97 | + [&](fir::FirOpBuilder &b, mlir::Value x, |
| 98 | + mlir::Value y) -> std::pair<mlir::Value, mlir::Value> { |
| 99 | + auto tyX = asIntTy(x.getType()), tyY = asIntTy(y.getType()); |
| 100 | + unsigned width = std::max(widthOf(tyX), widthOf(tyY)); |
| 101 | + auto wideTy = mlir::IntegerType::get(b.getContext(), width, |
| 102 | + mlir::IntegerType::Signless); |
| 103 | + return std::make_pair(b.createConvert(loc, wideTy, x), |
| 104 | + b.createConvert(loc, wideTy, y)); |
| 105 | + }; |
| 106 | + |
| 107 | + // Start with signless i32 by default. |
| 108 | + auto tripCount = builder.createIntegerConstant(loc, builder.getI32Type(), 1); |
| 109 | + |
| 110 | + for (auto [origLb, origUb, origStep] : |
| 111 | + llvm::zip(ops.loopLBVar, ops.loopUBVar, ops.loopStepVar)) { |
| 112 | + auto tmpS0 = builder.createIntegerConstant(loc, origStep.getType(), 0); |
| 113 | + auto [step, step0] = unifyToSignless(builder, origStep, tmpS0); |
| 114 | + auto reverseCond = |
| 115 | + builder.create<CmpIOp>(loc, CmpIPredicate::slt, step, step0); |
| 116 | + auto negStep = builder.create<SubIOp>(loc, step0, step); |
| 117 | + mlir::Value absStep = |
| 118 | + builder.create<SelectOp>(loc, reverseCond, negStep, step); |
| 119 | + |
| 120 | + auto [lb, ub] = unifyToSignless(builder, origLb, origUb); |
| 121 | + auto start = builder.create<SelectOp>(loc, reverseCond, ub, lb); |
| 122 | + auto end = builder.create<SelectOp>(loc, reverseCond, lb, ub); |
| 123 | + |
| 124 | + mlir::Value range = builder.create<SubIOp>(loc, end, start); |
| 125 | + auto rangeCond = |
| 126 | + builder.create<CmpIOp>(loc, CmpIPredicate::slt, end, start); |
| 127 | + std::tie(range, absStep) = unifyToSignless(builder, range, absStep); |
| 128 | + // numSteps = (range /u absStep) + 1 |
| 129 | + auto numSteps = builder.create<AddIOp>( |
| 130 | + loc, builder.create<DivUIOp>(loc, range, absStep), |
| 131 | + builder.createIntegerConstant(loc, range.getType(), 1)); |
| 132 | + |
| 133 | + auto trip0 = builder.createIntegerConstant(loc, numSteps.getType(), 0); |
| 134 | + auto loopTripCount = |
| 135 | + builder.create<SelectOp>(loc, rangeCond, trip0, numSteps); |
| 136 | + auto [totalTC, thisTC] = unifyToSignless(builder, tripCount, loopTripCount); |
| 137 | + tripCount = builder.create<MulIOp>(loc, totalTC, thisTC); |
| 138 | + } |
| 139 | + |
| 140 | + return tripCount; |
| 141 | +} |
| 142 | +} // namespace omp |
| 143 | +} // namespace lower |
| 144 | +} // namespace Fortran |
| 145 | + |
38 | 146 | namespace {
|
39 | 147 | class DoConcurrentConversion : public mlir::OpConversionPattern<fir::DoLoopOp> {
|
40 | 148 | public:
|
|
0 commit comments