Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][OpenMP] Duplicate the utils needed by DoConcurrentConversion #88

Merged
merged 1 commit into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions flang/lib/Optimizer/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ add_flang_library(FIRTransforms
FunctionAttr.cpp
DebugTypeGenerator.cpp
DoConcurrentConversion.cpp
# TODO Find a cleaner solution for this. This is a workaround to expose
# `Utils.cpp` so that it be used the `DoConcurrentConversion` pass. We should
# probably split this is a shared lib.
../../Lower/OpenMP/Utils.cpp

DEPENDS
FIRDialect
Expand Down
110 changes: 109 additions & 1 deletion flang/lib/Optimizer/Transforms/DoConcurrentConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//

#include "flang/Lower/OpenMP/Utils.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
Expand Down Expand Up @@ -35,6 +34,115 @@ namespace fir {

#define DEBUG_TYPE "fopenmp-do-concurrent-conversion"

namespace Fortran {
namespace lower {
namespace omp {
mlir::omp::MapInfoOp
createMapInfoOp(mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name,
llvm::ArrayRef<mlir::Value> bounds,
llvm::ArrayRef<mlir::Value> members,
mlir::DenseIntElementsAttr membersIndex, uint64_t mapType,
mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
bool partialMap = false) {
if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) {
baseAddr = builder.create<fir::BoxAddrOp>(loc, baseAddr);
retTy = baseAddr.getType();
}

mlir::TypeAttr varType = mlir::TypeAttr::get(
llvm::cast<mlir::omp::PointerLikeType>(retTy).getElementType());

mlir::omp::MapInfoOp op = builder.create<mlir::omp::MapInfoOp>(
loc, retTy, baseAddr, varType, varPtrPtr, members, membersIndex, bounds,
builder.getIntegerAttr(builder.getIntegerType(64, false), mapType),
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),
builder.getStringAttr(name), builder.getBoolAttr(partialMap));

return op;
}

mlir::Value calculateTripCount(fir::FirOpBuilder &builder, mlir::Location loc,
const mlir::omp::CollapseClauseOps &ops) {
using namespace mlir::arith;
assert(ops.loopLBVar.size() == ops.loopUBVar.size() &&
ops.loopLBVar.size() == ops.loopStepVar.size() &&
!ops.loopLBVar.empty() && "Invalid bounds or step");

// Get the bit width of an integer-like type.
auto widthOf = [](mlir::Type ty) -> unsigned {
if (mlir::isa<mlir::IndexType>(ty)) {
return mlir::IndexType::kInternalStorageBitWidth;
}
if (auto tyInt = mlir::dyn_cast<mlir::IntegerType>(ty)) {
return tyInt.getWidth();
}
llvm_unreachable("Unexpected type");
};

// For a type that is either IntegerType or IndexType, return the
// equivalent IntegerType. In the former case this is a no-op.
auto asIntTy = [&](mlir::Type ty) -> mlir::IntegerType {
if (ty.isIndex()) {
return mlir::IntegerType::get(ty.getContext(), widthOf(ty));
}
assert(ty.isIntOrIndex() && "Unexpected type");
return mlir::cast<mlir::IntegerType>(ty);
};

// For two given values, establish a common signless IntegerType
// that can represent any value of type of x and of type of y,
// and return the pair of x, y converted to the new type.
auto unifyToSignless =
[&](fir::FirOpBuilder &b, mlir::Value x,
mlir::Value y) -> std::pair<mlir::Value, mlir::Value> {
auto tyX = asIntTy(x.getType()), tyY = asIntTy(y.getType());
unsigned width = std::max(widthOf(tyX), widthOf(tyY));
auto wideTy = mlir::IntegerType::get(b.getContext(), width,
mlir::IntegerType::Signless);
return std::make_pair(b.createConvert(loc, wideTy, x),
b.createConvert(loc, wideTy, y));
};

// Start with signless i32 by default.
auto tripCount = builder.createIntegerConstant(loc, builder.getI32Type(), 1);

for (auto [origLb, origUb, origStep] :
llvm::zip(ops.loopLBVar, ops.loopUBVar, ops.loopStepVar)) {
auto tmpS0 = builder.createIntegerConstant(loc, origStep.getType(), 0);
auto [step, step0] = unifyToSignless(builder, origStep, tmpS0);
auto reverseCond =
builder.create<CmpIOp>(loc, CmpIPredicate::slt, step, step0);
auto negStep = builder.create<SubIOp>(loc, step0, step);
mlir::Value absStep =
builder.create<SelectOp>(loc, reverseCond, negStep, step);

auto [lb, ub] = unifyToSignless(builder, origLb, origUb);
auto start = builder.create<SelectOp>(loc, reverseCond, ub, lb);
auto end = builder.create<SelectOp>(loc, reverseCond, lb, ub);

mlir::Value range = builder.create<SubIOp>(loc, end, start);
auto rangeCond =
builder.create<CmpIOp>(loc, CmpIPredicate::slt, end, start);
std::tie(range, absStep) = unifyToSignless(builder, range, absStep);
// numSteps = (range /u absStep) + 1
auto numSteps = builder.create<AddIOp>(
loc, builder.create<DivUIOp>(loc, range, absStep),
builder.createIntegerConstant(loc, range.getType(), 1));

auto trip0 = builder.createIntegerConstant(loc, numSteps.getType(), 0);
auto loopTripCount =
builder.create<SelectOp>(loc, rangeCond, trip0, numSteps);
auto [totalTC, thisTC] = unifyToSignless(builder, tripCount, loopTripCount);
tripCount = builder.create<MulIOp>(loc, totalTC, thisTC);
}

return tripCount;
}
} // namespace omp
} // namespace lower
} // namespace Fortran

namespace {
class DoConcurrentConversion : public mlir::OpConversionPattern<fir::DoLoopOp> {
public:
Expand Down