6 changes: 4 additions & 2 deletions flang/include/flang/Optimizer/CodeGen/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ struct NameUniquer;

/// Prerequiste pass for code gen. Perform intermediate rewrites to perform
/// the code gen (to LLVM-IR dialect) conversion.
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass();
std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass(
CodeGenRewriteOptions Options = CodeGenRewriteOptions{});

/// FirTargetRewritePass options.
struct TargetRewriteOptions {
Expand Down Expand Up @@ -88,7 +89,8 @@ void populateFIRToLLVMConversionPatterns(fir::LLVMTypeConverter &converter,
fir::FIRToLLVMPassOptions &options);

/// Populate the pattern set with the PreCGRewrite patterns.
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns);
void populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare);

// declarative passes
#define GEN_PASS_REGISTRATION
Expand Down
4 changes: 3 additions & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace fir {
std::unique_ptr<mlir::Pass> createAffineDemotionPass();
std::unique_ptr<mlir::Pass>
createArrayValueCopyPass(fir::ArrayValueCopyOptions options = {});
std::unique_ptr<mlir::Pass> createCFGConversionPassWithNSW();
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
std::unique_ptr<mlir::Pass>
createExternalNameConversionPass(bool appendUnderscore);
Expand Down Expand Up @@ -89,7 +90,8 @@ createFunctionAttrPass(FunctionAttrTypes &functionAttr, bool noInfsFPMath,
bool noSignedZerosFPMath, bool unsafeFPMath);

void populateCfgConversionRewrites(mlir::RewritePatternSet &patterns,
bool forceLoopToExecuteOnce = false);
bool forceLoopToExecuteOnce = false,
bool setNSW = false);

// declarative passes
#define GEN_PASS_REGISTRATION
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def CFGConversion : Pass<"cfg-conversion"> {
let options = [
Option<"forceLoopToExecuteOnce", "always-execute-loop-body", "bool",
/*default=*/"false",
"force the body of a loop to execute at least once">
"force the body of a loop to execute at least once">,
Option<"setNSW", "set-nsw", "bool",
/*default=*/"false",
"set nsw on loop variable increment">
];
}

Expand Down
24 changes: 16 additions & 8 deletions flang/include/flang/Tools/CLOptions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,14 @@ static void addCanonicalizerPassWithoutRegionSimplification(
pm.addPass(mlir::createCanonicalizerPass(config));
}

inline void addCfgConversionPass(mlir::PassManager &pm) {
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversion);
inline void addCfgConversionPass(
mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
if (config.NSWOnLoopVarInc)
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversionPassWithNSW);
else
addNestedPassToAllTopLevelOperationsConditionally(
pm, disableCfgConversion, fir::createCFGConversion);
}

inline void addAVC(
Expand All @@ -169,9 +174,11 @@ inline void addMemoryAllocationOpt(mlir::PassManager &pm) {
}

#if !defined(FLANG_EXCLUDE_CODEGEN)
inline void addCodeGenRewritePass(mlir::PassManager &pm) {
addPassConditionally(
pm, disableCodeGenRewrite, fir::createFirCodeGenRewritePass);
inline void addCodeGenRewritePass(mlir::PassManager &pm, bool preserveDeclare) {
fir::CodeGenRewriteOptions options;
options.preserveDeclare = preserveDeclare;
addPassConditionally(pm, disableCodeGenRewrite,
[&]() { return fir::createFirCodeGenRewritePass(options); });
}

inline void addTargetRewritePass(mlir::PassManager &pm) {
Expand Down Expand Up @@ -290,7 +297,7 @@ inline void createDefaultFIROptimizerPassPipeline(
pm.addPass(fir::createAliasTagsPass());

// convert control flow to CFG form
fir::addCfgConversionPass(pm);
fir::addCfgConversionPass(pm, pc);
pm.addPass(mlir::createConvertSCFToCFPass());

pm.addPass(mlir::createCanonicalizerPass(config));
Expand Down Expand Up @@ -353,7 +360,8 @@ inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
MLIRToLLVMPassPipelineConfig config, llvm::StringRef inputFilename = {}) {
fir::addBoxedProcedurePass(pm);
addNestedPassToAllTopLevelOperations(pm, fir::createAbstractResultOpt);
fir::addCodeGenRewritePass(pm);
fir::addCodeGenRewritePass(
pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
fir::addTargetRewritePass(pm);
fir::addExternalNameConversionPass(pm, config.Underscoring);
fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);
Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Tools/CrossToolHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
bool NoSignedZerosFPMath =
false; ///< Set no-signed-zeros-fp-math attribute for functions.
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
bool NSWOnLoopVarInc = false; ///< Add nsw flag to loop variable increments.
};

struct OffloadModuleOpts {
Expand Down
6 changes: 6 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,12 @@ bool CompilerInvocation::createFromArgs(
invoc.loweringOpts.setNoPPCNativeVecElemOrder(true);
}

// -flang-experimental-integer-overflow
if (args.hasArg(
clang::driver::options::OPT_flang_experimental_integer_overflow)) {
invoc.loweringOpts.setNSWOnLoopVarInc(true);
}

// Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
// -Rpass-analysis. This will be used later when processing and outputting the
// remarks generated by LLVM in ExecuteCompilerInvocation.cpp.
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,9 @@ void CodeGenAction::generateLLVMIR() {
config.VScaleMax = vsr->second;
}

if (ci.getInvocation().getLoweringOpts().getNSWOnLoopVarInc())
config.NSWOnLoopVarInc = true;

// Create the pass pipeline
fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
(void)mlir::applyPassManagerCLOptions(pm);
Expand Down
12 changes: 9 additions & 3 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
assert(!incrementLoopNestInfo.empty() && "empty loop nest");
mlir::Location loc = toLocation();
mlir::arith::IntegerOverflowFlags flags{};
if (getLoweringOptions().getNSWOnLoopVarInc())
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
builder->getContext(), flags);
for (auto it = incrementLoopNestInfo.rbegin(),
rend = incrementLoopNestInfo.rend();
it != rend; ++it) {
Expand All @@ -2021,15 +2026,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
builder->setInsertionPointToEnd(info.doLoop.getBody());
llvm::SmallVector<mlir::Value, 2> results;
results.push_back(builder->create<mlir::arith::AddIOp>(
loc, info.doLoop.getInductionVar(), info.doLoop.getStep()));
loc, info.doLoop.getInductionVar(), info.doLoop.getStep(),
iofAttr));
// Step loopVariable to help optimizations such as vectorization.
// Induction variable elimination will clean up as necessary.
mlir::Value step = builder->createConvert(
loc, info.getLoopVariableType(), info.doLoop.getStep());
mlir::Value loopVar =
builder->create<fir::LoadOp>(loc, info.loopVariable);
results.push_back(
builder->create<mlir::arith::AddIOp>(loc, loopVar, step));
builder->create<mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
builder->create<fir::ResultOp>(loc, results);
builder->setInsertionPointAfter(info.doLoop);
// The loop control variable may be used after the loop.
Expand All @@ -2054,7 +2060,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
if (info.hasRealControl)
value = builder->create<mlir::arith::AddFOp>(loc, value, step);
else
value = builder->create<mlir::arith::AddIOp>(loc, value, step);
value = builder->create<mlir::arith::AddIOp>(loc, value, step, iofAttr);
builder->create<fir::StoreOp>(loc, value, info.loopVariable);

genBranch(info.headerBlock);
Expand Down
9 changes: 7 additions & 2 deletions flang/lib/Lower/IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,11 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
Fortran::lower::StatementContext stmtCtx;
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
mlir::Location loc = converter.getCurrentLocation();
mlir::arith::IntegerOverflowFlags flags{};
if (converter.getLoweringOptions().getNSWOnLoopVarInc())
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr =
mlir::arith::IntegerOverflowFlagsAttr::get(builder.getContext(), flags);
makeNextConditionalOn(builder, loc, checkResult, ok, inLoop);
const auto &itemList = std::get<0>(ioImpliedDo.t);
const auto &control = std::get<1>(ioImpliedDo.t);
Expand Down Expand Up @@ -965,7 +970,7 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
genItemList(ioImpliedDo);
builder.setInsertionPointToEnd(doLoopOp.getBody());
mlir::Value result = builder.create<mlir::arith::AddIOp>(
loc, doLoopOp.getInductionVar(), doLoopOp.getStep());
loc, doLoopOp.getInductionVar(), doLoopOp.getStep(), iofAttr);
builder.create<fir::ResultOp>(loc, result);
builder.setInsertionPointAfter(doLoopOp);
// The loop control variable may be used after the loop.
Expand Down Expand Up @@ -1007,7 +1012,7 @@ static void genIoLoop(Fortran::lower::AbstractConverter &converter,
mlir::OpResult iterateResult = builder.getBlock()->back().getResult(0);
mlir::Value inductionResult0 = iterWhileOp.getInductionVar();
auto inductionResult1 = builder.create<mlir::arith::AddIOp>(
loc, inductionResult0, iterWhileOp.getStep());
loc, inductionResult0, iterWhileOp.getStep(), iofAttr);
auto inductionResult = builder.create<mlir::arith::SelectOp>(
loc, iterateResult, inductionResult1, inductionResult0);
llvm::SmallVector<mlir::Value> results = {inductionResult, iterateResult};
Expand Down
213 changes: 95 additions & 118 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Large diffs are not rendered by default.

113 changes: 53 additions & 60 deletions flang/lib/Lower/OpenMP/ClauseProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,44 +47,43 @@ namespace omp {
/// construct.
class ClauseProcessor {
public:
ClauseProcessor(Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semaCtx,
ClauseProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
const List<Clause> &clauses)
: converter(converter), semaCtx(semaCtx), clauses(clauses) {}

// 'Unique' clauses: They can appear at most once in the clause list.
bool processCollapse(
mlir::Location currentLocation, Fortran::lower::pft::Evaluation &eval,
mlir::omp::CollapseClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &iv) const;
bool
processCollapse(mlir::Location currentLocation, lower::pft::Evaluation &eval,
mlir::omp::CollapseClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &iv) const;
bool processDefault() const;
bool processDevice(Fortran::lower::StatementContext &stmtCtx,
bool processDevice(lower::StatementContext &stmtCtx,
mlir::omp::DeviceClauseOps &result) const;
bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;
bool processFinal(Fortran::lower::StatementContext &stmtCtx,
bool processFinal(lower::StatementContext &stmtCtx,
mlir::omp::FinalClauseOps &result) const;
bool
processHasDeviceAddr(mlir::omp::HasDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool processHasDeviceAddr(
mlir::omp::HasDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSymbols) const;
bool processHint(mlir::omp::HintClauseOps &result) const;
bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
bool processNowait(mlir::omp::NowaitClauseOps &result) const;
bool processNumTeams(Fortran::lower::StatementContext &stmtCtx,
bool processNumTeams(lower::StatementContext &stmtCtx,
mlir::omp::NumTeamsClauseOps &result) const;
bool processNumThreads(Fortran::lower::StatementContext &stmtCtx,
bool processNumThreads(lower::StatementContext &stmtCtx,
mlir::omp::NumThreadsClauseOps &result) const;
bool processOrdered(mlir::omp::OrderedClauseOps &result) const;
bool processPriority(Fortran::lower::StatementContext &stmtCtx,
bool processPriority(lower::StatementContext &stmtCtx,
mlir::omp::PriorityClauseOps &result) const;
bool processProcBind(mlir::omp::ProcBindClauseOps &result) const;
bool processSafelen(mlir::omp::SafelenClauseOps &result) const;
bool processSchedule(Fortran::lower::StatementContext &stmtCtx,
bool processSchedule(lower::StatementContext &stmtCtx,
mlir::omp::ScheduleClauseOps &result) const;
bool processSimdlen(mlir::omp::SimdlenClauseOps &result) const;
bool processThreadLimit(Fortran::lower::StatementContext &stmtCtx,
bool processThreadLimit(lower::StatementContext &stmtCtx,
mlir::omp::ThreadLimitClauseOps &result) const;
bool processUntied(mlir::omp::UntiedClauseOps &result) const;

Expand All @@ -98,12 +97,11 @@ class ClauseProcessor {
processEnter(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
mlir::omp::IfClauseOps &result) const;
bool
processIsDevicePtr(mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool processIsDevicePtr(
mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSymbols) const;
bool
processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;

Expand All @@ -113,35 +111,32 @@ class ClauseProcessor {
// They may be used later on to create the block_arguments for some of the
// target directives that require it.
bool processMap(
mlir::Location currentLocation, Fortran::lower::StatementContext &stmtCtx,
mlir::Location currentLocation, lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *mapSyms =
nullptr,
llvm::SmallVectorImpl<const semantics::Symbol *> *mapSyms = nullptr,
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs = nullptr,
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes = nullptr) const;
bool processReduction(
mlir::Location currentLocation, mlir::omp::ReductionClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> *reductionTypes = nullptr,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *reductionSyms =
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSyms =
nullptr) const;
bool processSectionsReduction(mlir::Location currentLocation,
mlir::omp::ReductionClauseOps &result) const;
bool processTo(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
bool
processUseDeviceAddr(mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&useDeviceSyms) const;
bool
processUseDevicePtr(mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&useDeviceSyms) const;
bool processUseDeviceAddr(
mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;
bool processUseDevicePtr(
mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;

template <typename T>
bool processMotionClauses(Fortran::lower::StatementContext &stmtCtx,
bool processMotionClauses(lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result);

// Call this method for these clauses that should be supported but are not
Expand All @@ -162,36 +157,34 @@ class ClauseProcessor {
/// `nullptr` if not present. If more than one instance is expected, use
/// `findRepeatableClause` instead.
template <typename T>
const T *
findUniqueClause(const Fortran::parser::CharBlock **source = nullptr) const;
const T *findUniqueClause(const parser::CharBlock **source = nullptr) const;

/// Call `callbackFn` for each occurrence of the given clause. Return `true`
/// if at least one instance was found.
template <typename T>
bool findRepeatableClause(
std::function<void(const T &, const Fortran::parser::CharBlock &source)>
std::function<void(const T &, const parser::CharBlock &source)>
callbackFn) const;

/// Set the `result` to a new `mlir::UnitAttr` if the clause is present.
template <typename T>
bool markClauseOccurrence(mlir::UnitAttr &result) const;

Fortran::lower::AbstractConverter &converter;
Fortran::semantics::SemanticsContext &semaCtx;
lower::AbstractConverter &converter;
semantics::SemanticsContext &semaCtx;
List<Clause> clauses;
};

template <typename T>
bool ClauseProcessor::processMotionClauses(
Fortran::lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result) {
std::map<const Fortran::semantics::Symbol *,
bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result) {
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>>
parentMemberIndices;
llvm::SmallVector<const Fortran::semantics::Symbol *> mapSymbols;
llvm::SmallVector<const semantics::Symbol *> mapSymbols;

bool clauseFound = findRepeatableClause<T>(
[&](const T &clause, const Fortran::parser::CharBlock &source) {
[&](const T &clause, const parser::CharBlock &source) {
mlir::Location clauseLocation = converter.genLocation(source);
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();

Expand All @@ -209,9 +202,9 @@ bool ClauseProcessor::processMotionClauses(
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;

Fortran::lower::AddrAndBoundsInfo info =
Fortran::lower::gatherDataOperandAddrAndBounds<
mlir::omp::MapBoundsOp, mlir::omp::MapBoundsType>(
lower::AddrAndBoundsInfo info =
lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
mlir::omp::MapBoundsType>(
converter, firOpBuilder, semaCtx, stmtCtx, *object.id(),
object.ref(), clauseLocation, asFortran, bounds,
treatIndexAsSection);
Expand Down Expand Up @@ -277,8 +270,8 @@ ClauseProcessor::findClause(ClauseIterator begin, ClauseIterator end) {
}

template <typename T>
const T *ClauseProcessor::findUniqueClause(
const Fortran::parser::CharBlock **source) const {
const T *
ClauseProcessor::findUniqueClause(const parser::CharBlock **source) const {
ClauseIterator it = findClause<T>(clauses.begin(), clauses.end());
if (it != clauses.end()) {
if (source)
Expand All @@ -290,8 +283,8 @@ const T *ClauseProcessor::findUniqueClause(

template <typename T>
bool ClauseProcessor::findRepeatableClause(
std::function<void(const T &, const Fortran::parser::CharBlock &source)>
callbackFn) const {
std::function<void(const T &, const parser::CharBlock &source)> callbackFn)
const {
bool found = false;
ClauseIterator nextIt, endIt = clauses.end();
for (ClauseIterator it = clauses.begin(); it != endIt; it = nextIt) {
Expand Down
7 changes: 3 additions & 4 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,8 @@ Object makeObject(const parser::OmpObject &object,
return makeObject(std::get<parser::Designator>(object.u), semaCtx);
}

std::optional<Object>
getBaseObject(const Object &object,
Fortran::semantics::SemanticsContext &semaCtx) {
std::optional<Object> getBaseObject(const Object &object,
semantics::SemanticsContext &semaCtx) {
// If it's just the symbol, then there is no base.
if (!object.id())
return std::nullopt;
Expand Down Expand Up @@ -1211,7 +1210,7 @@ UsesAllocators make(const parser::OmpClause::UsesAllocators &inp,
// Write: empty
} // namespace clause

Clause makeClause(const Fortran::parser::OmpClause &cls,
Clause makeClause(const parser::OmpClause &cls,
semantics::SemanticsContext &semaCtx) {
return std::visit(
[&](auto &&s) {
Expand Down
7 changes: 3 additions & 4 deletions flang/lib/Lower/OpenMP/Clauses.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,8 @@ std::optional<ResultTy> maybeApply(FuncTy &&func,
return std::move(func(*arg));
}

std::optional<Object>
getBaseObject(const Object &object,
Fortran::semantics::SemanticsContext &semaCtx);
std::optional<Object> getBaseObject(const Object &object,
semantics::SemanticsContext &semaCtx);

namespace clause {
using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>;
Expand Down Expand Up @@ -262,7 +261,7 @@ Clause makeClause(llvm::omp::Clause id, Specific &&specific,
return Clause(typename Clause::BaseT{id, specific}, source);
}

Clause makeClause(const Fortran::parser::OmpClause &cls,
Clause makeClause(const parser::OmpClause &cls,
semantics::SemanticsContext &semaCtx);

List<Clause> makeClauses(const parser::OmpClauseList &clauses,
Expand Down
148 changes: 67 additions & 81 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace omp {

void DataSharingProcessor::processStep1(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
collectSymbolsForPrivatization();
collectDefaultSymbols();
collectImplicitSymbols();
Expand Down Expand Up @@ -57,14 +57,14 @@ void DataSharingProcessor::processStep2(mlir::Operation *op, bool isLoop) {
}

void DataSharingProcessor::insertDeallocs() {
for (const Fortran::semantics::Symbol *sym : privatizedSymbols)
if (Fortran::semantics::IsAllocatable(sym->GetUltimate())) {
for (const semantics::Symbol *sym : privatizedSymbols)
if (semantics::IsAllocatable(sym->GetUltimate())) {
if (!useDelayedPrivatization) {
converter.createHostAssociateVarCloneDealloc(*sym);
return;
}

Fortran::lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
assert(hsb && "Host symbol box not found");
mlir::Type symType = hsb.getAddr().getType();
mlir::Location symLoc = hsb.getAddr().getLoc();
Expand All @@ -91,33 +91,32 @@ void DataSharingProcessor::insertDeallocs() {
}
}

void DataSharingProcessor::cloneSymbol(const Fortran::semantics::Symbol *sym) {
void DataSharingProcessor::cloneSymbol(const semantics::Symbol *sym) {
// Privatization for symbols which are pre-determined (like loop index
// variables) happen separately, for everything else privatize here.
if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
if (sym->test(semantics::Symbol::Flag::OmpPreDetermined))
return;
bool success = converter.createHostAssociateVarClone(*sym);
(void)success;
assert(success && "Privatization failed due to existing binding");
}

void DataSharingProcessor::copyFirstPrivateSymbol(
const Fortran::semantics::Symbol *sym,
mlir::OpBuilder::InsertPoint *copyAssignIP) {
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate))
const semantics::Symbol *sym, mlir::OpBuilder::InsertPoint *copyAssignIP) {
if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate))
converter.copyHostAssociateVar(*sym, copyAssignIP);
}

void DataSharingProcessor::copyLastPrivateSymbol(
const Fortran::semantics::Symbol *sym,
const semantics::Symbol *sym,
[[maybe_unused]] mlir::OpBuilder::InsertPoint *lastPrivIP) {
if (sym->test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
if (sym->test(semantics::Symbol::Flag::OmpLastPrivate))
converter.copyHostAssociateVar(*sym, lastPrivIP);
}

void DataSharingProcessor::collectOmpObjectListSymbol(
const omp::ObjectList &objects,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet) {
llvm::SetVector<const semantics::Symbol *> &symbolSet) {
for (const omp::Object &object : objects)
symbolSet.insert(object.id());
}
Expand Down Expand Up @@ -150,9 +149,9 @@ bool DataSharingProcessor::needBarrier() {
// initialization of firstprivate variables and post-update of lastprivate
// variables.
// Emit implicit barrier for linear clause. Maybe on somewhere else.
for (const Fortran::semantics::Symbol *sym : privatizedSymbols) {
if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate) &&
sym->test(Fortran::semantics::Symbol::Flag::OmpLastPrivate))
for (const semantics::Symbol *sym : privatizedSymbols) {
if (sym->test(semantics::Symbol::Flag::OmpFirstPrivate) &&
sym->test(semantics::Symbol::Flag::OmpLastPrivate))
return true;
}
return false;
Expand Down Expand Up @@ -238,26 +237,26 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
}
}

static const Fortran::parser::CharBlock *
getSource(const Fortran::semantics::SemanticsContext &semaCtx,
const Fortran::lower::pft::Evaluation &eval) {
const Fortran::parser::CharBlock *source = nullptr;
static const parser::CharBlock *
getSource(const semantics::SemanticsContext &semaCtx,
const lower::pft::Evaluation &eval) {
const parser::CharBlock *source = nullptr;

auto ompConsVisit = [&](const Fortran::parser::OpenMPConstruct &x) {
std::visit(Fortran::common::visitors{
[&](const Fortran::parser::OpenMPSectionsConstruct &x) {
auto ompConsVisit = [&](const parser::OpenMPConstruct &x) {
std::visit(common::visitors{
[&](const parser::OpenMPSectionsConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPLoopConstruct &x) {
[&](const parser::OpenMPLoopConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPBlockConstruct &x) {
[&](const parser::OpenMPBlockConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPCriticalConstruct &x) {
[&](const parser::OpenMPCriticalConstruct &x) {
source = &std::get<0>(x.t).source;
},
[&](const Fortran::parser::OpenMPAtomicConstruct &x) {
[&](const parser::OpenMPAtomicConstruct &x) {
std::visit([&](const auto &x) { source = &x.source; },
x.u);
},
Expand All @@ -266,27 +265,20 @@ getSource(const Fortran::semantics::SemanticsContext &semaCtx,
x.u);
};

eval.visit(Fortran::common::visitors{
[&](const Fortran::parser::OpenMPConstruct &x) { ompConsVisit(x); },
[&](const Fortran::parser::OpenMPDeclarativeConstruct &x) {
source = &x.source;
},
[&](const Fortran::parser::OmpEndLoopDirective &x) {
source = &x.source;
},
eval.visit(common::visitors{
[&](const parser::OpenMPConstruct &x) { ompConsVisit(x); },
[&](const parser::OpenMPDeclarativeConstruct &x) { source = &x.source; },
[&](const parser::OmpEndLoopDirective &x) { source = &x.source; },
[&](const auto &x) {},
});

return source;
}

void DataSharingProcessor::collectSymbolsInNestedRegions(
Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *>
&symbolsInNestedRegions) {
for (Fortran::lower::pft::Evaluation &nestedEval :
eval.getNestedEvaluations()) {
lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions) {
for (lower::pft::Evaluation &nestedEval : eval.getNestedEvaluations()) {
if (nestedEval.hasNestedEvaluations()) {
if (nestedEval.isConstruct())
// Recursively look for OpenMP constructs within `nestedEval`'s region
Expand All @@ -307,46 +299,45 @@ void DataSharingProcessor::collectSymbolsInNestedRegions(
// Later, in current context, all symbols in the set
// `defaultSymbols` - `symbolsInNestedRegions` will be privatized.
void DataSharingProcessor::collectSymbols(
Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbols) {
semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbols) {
// Collect all scopes associated with 'eval'.
llvm::SetVector<const Fortran::semantics::Scope *> clauseScopes;
std::function<void(const Fortran::semantics::Scope *)> collectScopes =
[&](const Fortran::semantics::Scope *scope) {
llvm::SetVector<const semantics::Scope *> clauseScopes;
std::function<void(const semantics::Scope *)> collectScopes =
[&](const semantics::Scope *scope) {
clauseScopes.insert(scope);
for (const Fortran::semantics::Scope &child : scope->children())
for (const semantics::Scope &child : scope->children())
collectScopes(&child);
};
const Fortran::parser::CharBlock *source =
const parser::CharBlock *source =
clauses.empty() ? getSource(semaCtx, eval) : &clauses.front().source;
const Fortran::semantics::Scope *curScope = nullptr;
const semantics::Scope *curScope = nullptr;
if (source && !source->empty()) {
curScope = &semaCtx.FindScope(*source);
collectScopes(curScope);
}
// Collect all symbols referenced in the evaluation being processed,
// that matches 'flag'.
llvm::SetVector<const Fortran::semantics::Symbol *> allSymbols;
llvm::SetVector<const semantics::Symbol *> allSymbols;
converter.collectSymbolSet(eval, allSymbols, flag,
/*collectSymbols=*/true,
/*collectHostAssociatedSymbols=*/true);
llvm::SetVector<const Fortran::semantics::Symbol *> symbolsInNestedRegions;
llvm::SetVector<const semantics::Symbol *> symbolsInNestedRegions;
collectSymbolsInNestedRegions(eval, flag, symbolsInNestedRegions);
// Filter-out symbols that must not be privatized.
bool collectImplicit = flag == Fortran::semantics::Symbol::Flag::OmpImplicit;
auto isPrivatizable = [](const Fortran::semantics::Symbol &sym) -> bool {
return !Fortran::semantics::IsProcedure(sym) &&
!sym.GetUltimate().has<Fortran::semantics::DerivedTypeDetails>() &&
!sym.GetUltimate().has<Fortran::semantics::NamelistDetails>() &&
!Fortran::semantics::IsImpliedDoIndex(sym.GetUltimate());
bool collectImplicit = flag == semantics::Symbol::Flag::OmpImplicit;
auto isPrivatizable = [](const semantics::Symbol &sym) -> bool {
return !semantics::IsProcedure(sym) &&
!sym.GetUltimate().has<semantics::DerivedTypeDetails>() &&
!sym.GetUltimate().has<semantics::NamelistDetails>() &&
!semantics::IsImpliedDoIndex(sym.GetUltimate());
};
for (const auto *sym : allSymbols) {
assert(curScope && "couldn't find current scope");
if (isPrivatizable(*sym) && !symbolsInNestedRegions.contains(sym) &&
!privatizedSymbols.contains(sym) &&
!sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined) &&
(collectImplicit ||
!sym->test(Fortran::semantics::Symbol::Flag::OmpImplicit)) &&
!sym->test(semantics::Symbol::Flag::OmpPreDetermined) &&
(collectImplicit || !sym->test(semantics::Symbol::Flag::OmpImplicit)) &&
clauseScopes.contains(&sym->owner()))
symbols.insert(sym);
}
Expand All @@ -358,10 +349,9 @@ void DataSharingProcessor::collectDefaultSymbols() {
if (const auto *defaultClause =
std::get_if<omp::clause::Default>(&clause.u)) {
if (defaultClause->v == DataSharingAttribute::Private)
collectSymbols(Fortran::semantics::Symbol::Flag::OmpPrivate,
defaultSymbols);
collectSymbols(semantics::Symbol::Flag::OmpPrivate, defaultSymbols);
else if (defaultClause->v == DataSharingAttribute::Firstprivate)
collectSymbols(Fortran::semantics::Symbol::Flag::OmpFirstPrivate,
collectSymbols(semantics::Symbol::Flag::OmpFirstPrivate,
defaultSymbols);
}
}
Expand All @@ -370,16 +360,15 @@ void DataSharingProcessor::collectDefaultSymbols() {
void DataSharingProcessor::collectImplicitSymbols() {
// There will be no implicit symbols when a default clause is present.
if (defaultSymbols.empty())
collectSymbols(Fortran::semantics::Symbol::Flag::OmpImplicit,
implicitSymbols);
collectSymbols(semantics::Symbol::Flag::OmpImplicit, implicitSymbols);
}

void DataSharingProcessor::privatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
for (const Fortran::semantics::Symbol *sym : privatizedSymbols) {
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
for (const semantics::Symbol *sym : privatizedSymbols) {
if (const auto *commonDet =
sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) {
sym->detailsIf<semantics::CommonBlockDetails>()) {
for (const auto &mem : commonDet->objects())
doPrivatize(&*mem, clauseOps, privateSyms);
} else
Expand All @@ -389,9 +378,9 @@ void DataSharingProcessor::privatize(

void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {
insertLastPrivateCompare(op);
for (const Fortran::semantics::Symbol *sym : privatizedSymbols)
for (const semantics::Symbol *sym : privatizedSymbols)
if (const auto *commonDet =
sym->detailsIf<Fortran::semantics::CommonBlockDetails>()) {
sym->detailsIf<semantics::CommonBlockDetails>()) {
for (const auto &mem : commonDet->objects()) {
copyLastPrivateSymbol(&*mem, &lastPrivIP);
}
Expand All @@ -402,36 +391,34 @@ void DataSharingProcessor::copyLastPrivatize(mlir::Operation *op) {

void DataSharingProcessor::defaultPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
for (const Fortran::semantics::Symbol *sym : defaultSymbols)
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
for (const semantics::Symbol *sym : defaultSymbols)
doPrivatize(sym, clauseOps, privateSyms);
}

void DataSharingProcessor::implicitPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
for (const Fortran::semantics::Symbol *sym : implicitSymbols)
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
for (const semantics::Symbol *sym : implicitSymbols)
doPrivatize(sym, clauseOps, privateSyms);
}

void DataSharingProcessor::doPrivatize(
const Fortran::semantics::Symbol *sym,
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms) {
const semantics::Symbol *sym, mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms) {
if (!useDelayedPrivatization) {
cloneSymbol(sym);
copyFirstPrivateSymbol(sym);
return;
}

Fortran::lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
lower::SymbolBox hsb = converter.lookupOneLevelUpSymbol(*sym);
assert(hsb && "Host symbol box not found");

mlir::Type symType = hsb.getAddr().getType();
mlir::Location symLoc = hsb.getAddr().getLoc();
std::string privatizerName = sym->name().ToString() + ".privatizer";
bool isFirstPrivate =
sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate);
bool isFirstPrivate = sym->test(semantics::Symbol::Flag::OmpFirstPrivate);

mlir::omp::PrivateClauseOp privatizerOp = [&]() {
auto moduleOp = firOpBuilder.getModule();
Expand Down Expand Up @@ -468,8 +455,7 @@ void DataSharingProcessor::doPrivatize(
hlfir::translateToExtendedValue(
symLoc, firOpBuilder, hlfir::Entity{allocRegion.getArgument(0)},
/*contiguousHint=*/
Fortran::evaluate::IsSimplyContiguous(
*sym, converter.getFoldingContext()))
evaluate::IsSimplyContiguous(*sym, converter.getFoldingContext()))
.first;

symTable->addSymbol(*sym, localExV);
Expand Down
66 changes: 31 additions & 35 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,65 +37,61 @@ class DataSharingProcessor {
mlir::OpBuilder::InsertPoint insPt;
mlir::Value loopIV;
// Symbols in private, firstprivate, and/or lastprivate clauses.
llvm::SetVector<const Fortran::semantics::Symbol *> privatizedSymbols;
llvm::SetVector<const Fortran::semantics::Symbol *> defaultSymbols;
llvm::SetVector<const Fortran::semantics::Symbol *> implicitSymbols;
llvm::DenseMap<const Fortran::semantics::Symbol *, mlir::omp::PrivateClauseOp>
llvm::SetVector<const semantics::Symbol *> privatizedSymbols;
llvm::SetVector<const semantics::Symbol *> defaultSymbols;
llvm::SetVector<const semantics::Symbol *> implicitSymbols;
llvm::DenseMap<const semantics::Symbol *, mlir::omp::PrivateClauseOp>
symToPrivatizer;
Fortran::lower::AbstractConverter &converter;
Fortran::semantics::SemanticsContext &semaCtx;
lower::AbstractConverter &converter;
semantics::SemanticsContext &semaCtx;
fir::FirOpBuilder &firOpBuilder;
omp::List<omp::Clause> clauses;
Fortran::lower::pft::Evaluation &eval;
lower::pft::Evaluation &eval;
bool useDelayedPrivatization;
Fortran::lower::SymMap *symTable;
lower::SymMap *symTable;

bool needBarrier();
void
collectSymbols(Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbols);
void collectSymbols(semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbols);
void collectSymbolsInNestedRegions(
Fortran::lower::pft::Evaluation &eval,
Fortran::semantics::Symbol::Flag flag,
llvm::SetVector<const Fortran::semantics::Symbol *>
&symbolsInNestedRegions);
lower::pft::Evaluation &eval, semantics::Symbol::Flag flag,
llvm::SetVector<const semantics::Symbol *> &symbolsInNestedRegions);
void collectOmpObjectListSymbol(
const omp::ObjectList &objects,
llvm::SetVector<const Fortran::semantics::Symbol *> &symbolSet);
llvm::SetVector<const semantics::Symbol *> &symbolSet);
void collectSymbolsForPrivatization();
void insertBarrier();
void collectDefaultSymbols();
void collectImplicitSymbols();
void privatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
void privatize(mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms);
void defaultPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms);
void implicitPrivatize(
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
void doPrivatize(
const Fortran::semantics::Symbol *sym,
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *privateSyms);
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms);
void
doPrivatize(const semantics::Symbol *sym,
mlir::omp::PrivateClauseOps *clauseOps,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms);
void copyLastPrivatize(mlir::Operation *op);
void insertLastPrivateCompare(mlir::Operation *op);
void cloneSymbol(const Fortran::semantics::Symbol *sym);
void cloneSymbol(const semantics::Symbol *sym);
void
copyFirstPrivateSymbol(const Fortran::semantics::Symbol *sym,
copyFirstPrivateSymbol(const semantics::Symbol *sym,
mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr);
void copyLastPrivateSymbol(const Fortran::semantics::Symbol *sym,
void copyLastPrivateSymbol(const semantics::Symbol *sym,
mlir::OpBuilder::InsertPoint *lastPrivIP);
void insertDeallocs();

public:
DataSharingProcessor(Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semaCtx,
DataSharingProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
const List<Clause> &clauses,
Fortran::lower::pft::Evaluation &eval,
lower::pft::Evaluation &eval,
bool useDelayedPrivatization = false,
Fortran::lower::SymMap *symTable = nullptr)
lower::SymMap *symTable = nullptr)
: hasLastPrivateOp(false), converter(converter), semaCtx(semaCtx),
firOpBuilder(converter.getFirOpBuilder()), clauses(clauses), eval(eval),
useDelayedPrivatization(useDelayedPrivatization), symTable(symTable) {}
Expand All @@ -111,9 +107,9 @@ class DataSharingProcessor {
// Step2 performs the copying for lastprivates and requires knowledge of the
// MLIR operation to insert the last private update. Step2 adds
// dealocation code as well.
void processStep1(mlir::omp::PrivateClauseOps *clauseOps = nullptr,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
*privateSyms = nullptr);
void processStep1(
mlir::omp::PrivateClauseOps *clauseOps = nullptr,
llvm::SmallVectorImpl<const semantics::Symbol *> *privateSyms = nullptr);
void processStep2(mlir::Operation *op, bool isLoop);

void setLoopIV(mlir::Value iv) {
Expand Down
1,063 changes: 470 additions & 593 deletions flang/lib/Lower/OpenMP/OpenMP.cpp

Large diffs are not rendered by default.

52 changes: 21 additions & 31 deletions flang/lib/Lower/OpenMP/ReductionProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ ReductionProcessor::ReductionIdentifier ReductionProcessor::getReductionType(

bool ReductionProcessor::supportedIntrinsicProcReduction(
const omp::clause::ProcedureDesignator &pd) {
Fortran::semantics::Symbol *sym = pd.v.id();
if (!sym->GetUltimate().attrs().test(Fortran::semantics::Attr::INTRINSIC))
semantics::Symbol *sym = pd.v.id();
if (!sym->GetUltimate().attrs().test(semantics::Attr::INTRINSIC))
return false;
auto redType = llvm::StringSwitch<bool>(getRealName(sym).ToString())
.Case("max", true)
Expand Down Expand Up @@ -180,7 +180,7 @@ ReductionProcessor::getReductionInitValue(mlir::Location loc, mlir::Type type,
case ReductionIdentifier::NEQV:
if (auto cplxTy = mlir::dyn_cast<fir::ComplexType>(type)) {
mlir::Type realTy =
Fortran::lower::convertReal(builder.getContext(), cplxTy.getFKind());
lower::convertReal(builder.getContext(), cplxTy.getFKind());
mlir::Value initRe = builder.createRealConstant(
loc, realTy, getOperationIdentity(redId, loc));
mlir::Value initIm = builder.createRealConstant(loc, realTy, 0);
Expand Down Expand Up @@ -657,36 +657,27 @@ mlir::omp::DeclareReductionOp ReductionProcessor::createDeclareReduction(
return decl;
}

// TODO: By-ref vs by-val reductions are currently toggled for the whole
// operation (possibly effecting multiple reduction variables).
// This could cause a problem with openmp target reductions because
// by-ref trivial types may not be supported.
bool ReductionProcessor::doReductionByRef(
const llvm::SmallVectorImpl<mlir::Value> &reductionVars) {
if (reductionVars.empty())
return false;
static bool doReductionByRef(mlir::Value reductionVar) {
if (forceByrefReduction)
return true;

for (mlir::Value reductionVar : reductionVars) {
if (auto declare =
mlir::dyn_cast<hlfir::DeclareOp>(reductionVar.getDefiningOp()))
reductionVar = declare.getMemref();
if (auto declare =
mlir::dyn_cast<hlfir::DeclareOp>(reductionVar.getDefiningOp()))
reductionVar = declare.getMemref();

if (!fir::isa_trivial(fir::unwrapRefType(reductionVar.getType())))
return true;

if (!fir::isa_trivial(fir::unwrapRefType(reductionVar.getType())))
return true;
}
return false;
}

void ReductionProcessor::addDeclareReduction(
mlir::Location currentLocation,
Fortran::lower::AbstractConverter &converter,
mlir::Location currentLocation, lower::AbstractConverter &converter,
const omp::clause::Reduction &reduction,
llvm::SmallVectorImpl<mlir::Value> &reductionVars,
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
*reductionSymbols) {
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSymbols) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();

if (std::get<std::optional<omp::clause::Reduction::ReductionModifier>>(
Expand Down Expand Up @@ -716,7 +707,7 @@ void ReductionProcessor::addDeclareReduction(
// should happen byref
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
for (const Object &object : objectList) {
const Fortran::semantics::Symbol *symbol = object.id();
const semantics::Symbol *symbol = object.id();
if (reductionSymbols)
reductionSymbols->push_back(symbol);
mlir::Value symVal = converter.getSymbolAddress(*symbol);
Expand All @@ -731,8 +722,7 @@ void ReductionProcessor::addDeclareReduction(
// information needed to iterate over the array
if (mlir::isa<fir::SequenceType>(eleType)) {
// For Host associated symbols, use `SymbolBox` instead
Fortran::lower::SymbolBox symBox =
converter.lookupOneLevelUpSymbol(*symbol);
lower::SymbolBox symBox = converter.lookupOneLevelUpSymbol(*symbol);
hlfir::Entity entity{symBox.getAddr()};
entity = genVariableBox(currentLocation, builder, entity);
mlir::Value box = entity.getBase();
Expand Down Expand Up @@ -764,8 +754,8 @@ void ReductionProcessor::addDeclareReduction(
"reduction input var is a reference");

reductionVars.push_back(symVal);
reduceVarByRef.push_back(doReductionByRef(symVal));
}
const bool isByRef = doReductionByRef(reductionVars);

if (const auto &redDefinedOp =
std::get_if<omp::clause::DefinedOperator>(&redOperator.u)) {
Expand All @@ -787,7 +777,7 @@ void ReductionProcessor::addDeclareReduction(
break;
}

for (mlir::Value symVal : reductionVars) {
for (auto [symVal, isByRef] : llvm::zip(reductionVars, reduceVarByRef)) {
auto redType = mlir::cast<fir::ReferenceType>(symVal.getType());
const auto &kindMap = firOpBuilder.getKindMap();
if (mlir::isa<fir::LogicalType>(redType.getEleTy()))
Expand All @@ -811,7 +801,7 @@ void ReductionProcessor::addDeclareReduction(
*reductionIntrinsic)) {
ReductionProcessor::ReductionIdentifier redId =
ReductionProcessor::getReductionType(*reductionIntrinsic);
for (mlir::Value symVal : reductionVars) {
for (auto [symVal, isByRef] : llvm::zip(reductionVars, reduceVarByRef)) {
auto redType = mlir::cast<fir::ReferenceType>(symVal.getType());
if (!redType.getEleTy().isIntOrIndexOrFloat())
TODO(currentLocation,
Expand All @@ -828,12 +818,12 @@ void ReductionProcessor::addDeclareReduction(
}
}

const Fortran::semantics::SourceName
ReductionProcessor::getRealName(const Fortran::semantics::Symbol *symbol) {
const semantics::SourceName
ReductionProcessor::getRealName(const semantics::Symbol *symbol) {
return symbol->GetUltimate().name();
}

const Fortran::semantics::SourceName
const semantics::SourceName
ReductionProcessor::getRealName(const omp::clause::ProcedureDesignator &pd) {
return getRealName(pd.v.id());
}
Expand Down
17 changes: 7 additions & 10 deletions flang/lib/Lower/OpenMP/ReductionProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,12 @@ class ReductionProcessor {
static bool
supportedIntrinsicProcReduction(const omp::clause::ProcedureDesignator &pd);

static const Fortran::semantics::SourceName
getRealName(const Fortran::semantics::Symbol *symbol);
static const semantics::SourceName
getRealName(const semantics::Symbol *symbol);

static const Fortran::semantics::SourceName
static const semantics::SourceName
getRealName(const omp::clause::ProcedureDesignator &pd);

static bool
doReductionByRef(const llvm::SmallVectorImpl<mlir::Value> &reductionVars);

static std::string getReductionName(llvm::StringRef name,
const fir::KindMapping &kindMap,
mlir::Type ty, bool isByRef);
Expand Down Expand Up @@ -124,13 +121,13 @@ class ReductionProcessor {
/// Creates a reduction declaration and associates it with an OpenMP block
/// directive.
static void addDeclareReduction(
mlir::Location currentLocation,
Fortran::lower::AbstractConverter &converter,
mlir::Location currentLocation, lower::AbstractConverter &converter,
const omp::clause::Reduction &reduction,
llvm::SmallVectorImpl<mlir::Value> &reductionVars,
llvm::SmallVectorImpl<bool> &reduceVarByRef,
llvm::SmallVectorImpl<mlir::Attribute> &reductionDeclSymbols,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
*reductionSymbols = nullptr);
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSymbols =
nullptr);
};

template <typename FloatOp, typename IntegerOp>
Expand Down
100 changes: 46 additions & 54 deletions flang/lib/Lower/OpenMP/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,22 @@ int64_t getCollapseValue(const List<Clause> &clauses) {
}

void genObjectList(const ObjectList &objects,
Fortran::lower::AbstractConverter &converter,
lower::AbstractConverter &converter,
llvm::SmallVectorImpl<mlir::Value> &operands) {
for (const Object &object : objects) {
const Fortran::semantics::Symbol *sym = object.id();
const semantics::Symbol *sym = object.id();
assert(sym && "Expected Symbol");
if (mlir::Value variable = converter.getSymbolAddress(*sym)) {
operands.push_back(variable);
} else if (const auto *details =
sym->detailsIf<Fortran::semantics::HostAssocDetails>()) {
sym->detailsIf<semantics::HostAssocDetails>()) {
operands.push_back(converter.getSymbolAddress(details->symbol()));
converter.copySymbolBinding(details->symbol(), *sym);
}
}
}

mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
mlir::Type getLoopVarType(lower::AbstractConverter &converter,
std::size_t loopVarTypeSize) {
// OpenMP runtime requires 32-bit or 64-bit loop variables.
loopVarTypeSize = loopVarTypeSize * 8;
Expand All @@ -85,24 +85,21 @@ mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
return converter.getFirOpBuilder().getIntegerType(loopVarTypeSize);
}

Fortran::semantics::Symbol *
getIterationVariableSymbol(const Fortran::lower::pft::Evaluation &eval) {
return eval.visit(Fortran::common::visitors{
[&](const Fortran::parser::DoConstruct &doLoop) {
semantics::Symbol *
getIterationVariableSymbol(const lower::pft::Evaluation &eval) {
return eval.visit(common::visitors{
[&](const parser::DoConstruct &doLoop) {
if (const auto &maybeCtrl = doLoop.GetLoopControl()) {
using LoopControl = Fortran::parser::LoopControl;
using LoopControl = parser::LoopControl;
if (auto *bounds = std::get_if<LoopControl::Bounds>(&maybeCtrl->u)) {
static_assert(
std::is_same_v<decltype(bounds->name),
Fortran::parser::Scalar<Fortran::parser::Name>>);
static_assert(std::is_same_v<decltype(bounds->name),
parser::Scalar<parser::Name>>);
return bounds->name.thing.symbol;
}
}
return static_cast<Fortran::semantics::Symbol *>(nullptr);
},
[](auto &&) {
return static_cast<Fortran::semantics::Symbol *>(nullptr);
return static_cast<semantics::Symbol *>(nullptr);
},
[](auto &&) { return static_cast<semantics::Symbol *>(nullptr); },
});
}

Expand Down Expand Up @@ -139,12 +136,11 @@ createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
}

static int
getComponentPlacementInParent(const Fortran::semantics::Symbol *componentSym) {
const auto *derived =
componentSym->owner()
.derivedTypeSpec()
->typeSymbol()
.detailsIf<Fortran::semantics::DerivedTypeDetails>();
getComponentPlacementInParent(const semantics::Symbol *componentSym) {
const auto *derived = componentSym->owner()
.derivedTypeSpec()
->typeSymbol()
.detailsIf<semantics::DerivedTypeDetails>();
assert(derived &&
"expected derived type details when processing component symbol");
for (auto [placement, name] : llvm::enumerate(derived->componentNames()))
Expand All @@ -155,7 +151,7 @@ getComponentPlacementInParent(const Fortran::semantics::Symbol *componentSym) {

static std::optional<Object>
getComponentObject(std::optional<Object> object,
Fortran::semantics::SemanticsContext &semaCtx) {
semantics::SemanticsContext &semaCtx) {
if (!object)
return std::nullopt;

Expand All @@ -176,7 +172,7 @@ getComponentObject(std::optional<Object> object,
static void
generateMemberPlacementIndices(const Object &object,
llvm::SmallVectorImpl<int> &indices,
Fortran::semantics::SemanticsContext &semaCtx) {
semantics::SemanticsContext &semaCtx) {
auto compObj = getComponentObject(object, semaCtx);
while (compObj) {
indices.push_back(getComponentPlacementInParent(compObj->id()));
Expand All @@ -189,16 +185,14 @@ generateMemberPlacementIndices(const Object &object,

void addChildIndexAndMapToParent(
const omp::Object &object,
std::map<const Fortran::semantics::Symbol *,
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
mlir::omp::MapInfoOp &mapOp,
Fortran::semantics::SemanticsContext &semaCtx) {
std::optional<Fortran::evaluate::DataRef> dataRef =
ExtractDataRef(object.designator);
mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx) {
std::optional<evaluate::DataRef> dataRef = ExtractDataRef(object.designator);
assert(dataRef.has_value() &&
"DataRef could not be extracted during mapping of derived type "
"cannot proceed");
const Fortran::semantics::Symbol *parentSym = &dataRef->GetFirstSymbol();
const semantics::Symbol *parentSym = &dataRef->GetFirstSymbol();
assert(parentSym && "Could not find parent symbol during lower of "
"a component member in OpenMP map clause");
llvm::SmallVector<int> indices;
Expand Down Expand Up @@ -236,14 +230,14 @@ static mlir::DenseIntElementsAttr createDenseElementsAttrFromIndices(
llvm::SmallVector<int64_t> shape;
calculateShapeAndFillIndices(shape, memberPlacementData);

llvm::SmallVector<int> indicesFlattened = std::accumulate(
memberPlacementData.begin(), memberPlacementData.end(),
llvm::SmallVector<int>(),
[](llvm::SmallVector<int> &x, OmpMapMemberIndicesData y) {
x.insert(x.end(), y.memberPlacementIndices.begin(),
y.memberPlacementIndices.end());
return x;
});
llvm::SmallVector<int> indicesFlattened =
std::accumulate(memberPlacementData.begin(), memberPlacementData.end(),
llvm::SmallVector<int>(),
[](llvm::SmallVector<int> &x, OmpMapMemberIndicesData y) {
x.insert(x.end(), y.memberPlacementIndices.begin(),
y.memberPlacementIndices.end());
return x;
});

return mlir::DenseIntElementsAttr::get(
mlir::VectorType::get(shape,
Expand All @@ -252,11 +246,11 @@ static mlir::DenseIntElementsAttr createDenseElementsAttrFromIndices(
}

void insertChildMapInfoIntoParent(
Fortran::lower::AbstractConverter &converter,
std::map<const Fortran::semantics::Symbol *,
lower::AbstractConverter &converter,
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapOperands,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &mapSyms,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms,
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes,
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs) {
for (auto indices : parentMemberIndices) {
Expand Down Expand Up @@ -323,30 +317,28 @@ void insertChildMapInfoIntoParent(
}
}

Fortran::semantics::Symbol *
getOmpObjectSymbol(const Fortran::parser::OmpObject &ompObject) {
Fortran::semantics::Symbol *sym = nullptr;
semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject) {
semantics::Symbol *sym = nullptr;
std::visit(
Fortran::common::visitors{
[&](const Fortran::parser::Designator &designator) {
common::visitors{
[&](const parser::Designator &designator) {
if (auto *arrayEle =
Fortran::parser::Unwrap<Fortran::parser::ArrayElement>(
designator)) {
parser::Unwrap<parser::ArrayElement>(designator)) {
// Use getLastName to retrieve the arrays symbol, this will
// provide the farthest right symbol (the last) in a designator,
// i.e. providing something like the following:
// "dtype1%dtype2%array[2:10]", will result in "array"
sym = GetLastName(arrayEle->base).symbol;
} else if (auto *structComp = Fortran::parser::Unwrap<
Fortran::parser::StructureComponent>(designator)) {
sym = structComp->component.symbol;
} else if (const Fortran::parser::Name *name =
Fortran::semantics::getDesignatorNameIfDataRef(
} else if (auto *structComp =
parser::Unwrap<parser::StructureComponent>(
designator)) {
sym = structComp->component.symbol;
} else if (const parser::Name *name =
semantics::getDesignatorNameIfDataRef(designator)) {
sym = name->symbol;
}
},
[&](const Fortran::parser::Name &name) { sym = name.symbol; }},
[&](const parser::Name &name) { sym = name.symbol; }},
ompObject.u);
return sym;
}
Expand Down
24 changes: 11 additions & 13 deletions flang/lib/Lower/OpenMP/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ class AbstractConverter;
namespace omp {

using DeclareTargetCapturePair =
std::pair<mlir::omp::DeclareTargetCaptureClause,
const Fortran::semantics::Symbol &>;
std::pair<mlir::omp::DeclareTargetCaptureClause, const semantics::Symbol &>;

// A small helper structure for keeping track of a component members MapInfoOp
// and index data when lowering OpenMP map clauses. Keeps track of the
Expand All @@ -69,36 +68,35 @@ createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,

void addChildIndexAndMapToParent(
const omp::Object &object,
std::map<const Fortran::semantics::Symbol *,
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
mlir::omp::MapInfoOp &mapOp, Fortran::semantics::SemanticsContext &semaCtx);
mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx);

void insertChildMapInfoIntoParent(
Fortran::lower::AbstractConverter &converter,
std::map<const Fortran::semantics::Symbol *,
lower::AbstractConverter &converter,
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapOperands,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &mapSyms,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms,
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes,
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs);

mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
mlir::Type getLoopVarType(lower::AbstractConverter &converter,
std::size_t loopVarTypeSize);

Fortran::semantics::Symbol *
getIterationVariableSymbol(const Fortran::lower::pft::Evaluation &eval);
semantics::Symbol *
getIterationVariableSymbol(const lower::pft::Evaluation &eval);

void gatherFuncAndVarSyms(
const ObjectList &objects, mlir::omp::DeclareTargetCaptureClause clause,
llvm::SmallVectorImpl<DeclareTargetCapturePair> &symbolAndClause);

int64_t getCollapseValue(const List<Clause> &clauses);

Fortran::semantics::Symbol *
getOmpObjectSymbol(const Fortran::parser::OmpObject &ompObject);
semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject);

void genObjectList(const ObjectList &objects,
Fortran::lower::AbstractConverter &converter,
lower::AbstractConverter &converter,
llvm::SmallVectorImpl<mlir::Value> &operands);

} // namespace omp
Expand Down
157 changes: 63 additions & 94 deletions flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ static bool isDummyArgument(mlir::Value v) {
if (!blockArg)
return false;

mlir::Block *owner = blockArg.getOwner();
if (!owner->isEntryBlock() ||
!mlir::isa<mlir::FunctionOpInterface>(owner->getParentOp()))
return false;
return true;
auto *owner{blockArg.getOwner()};
return owner->isEntryBlock() &&
mlir::isa<mlir::FunctionOpInterface>(owner->getParentOp());
}

/// Temporary function to skip through all the no op operations
Expand All @@ -58,12 +56,17 @@ static mlir::Value getOriginalDef(mlir::Value v) {
namespace fir {

void AliasAnalysis::Source::print(llvm::raw_ostream &os) const {
if (auto v = llvm::dyn_cast<mlir::Value>(u))
if (auto v = llvm::dyn_cast<mlir::Value>(origin.u))
os << v;
else if (auto gbl = llvm::dyn_cast<mlir::SymbolRefAttr>(u))
else if (auto gbl = llvm::dyn_cast<mlir::SymbolRefAttr>(origin.u))
os << gbl;
os << " SourceKind: " << EnumToString(kind);
os << " Type: " << valueType << " ";
if (origin.isData) {
os << " following data ";
} else {
os << " following box reference ";
}
attributes.Dump(os, EnumToString);
}

Expand All @@ -80,6 +83,19 @@ bool AliasAnalysis::Source::isTargetOrPointer() const {
attributes.test(Attribute::Target);
}

bool AliasAnalysis::Source::isDummyArgument() const {
if (auto v = origin.u.dyn_cast<mlir::Value>()) {
return ::isDummyArgument(v);
}
return false;
}

bool AliasAnalysis::Source::isData() const { return origin.isData; }
bool AliasAnalysis::Source::isBoxData() const {
return mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(valueType)) &&
origin.isData;
}

bool AliasAnalysis::Source::isRecordWithPointerComponent() const {
auto eleTy = fir::dyn_cast_ptrEleTy(valueType);
if (!eleTy)
Expand All @@ -92,70 +108,35 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
auto lhsSrc = getSource(lhs);
auto rhsSrc = getSource(rhs);
bool approximateSource = lhsSrc.approximateSource || rhsSrc.approximateSource;
LLVM_DEBUG(llvm::dbgs() << "AliasAnalysis::alias\n";
LLVM_DEBUG(llvm::dbgs() << "\nAliasAnalysis::alias\n";
llvm::dbgs() << " lhs: " << lhs << "\n";
llvm::dbgs() << " lhsSrc: " << lhsSrc << "\n";
llvm::dbgs() << " rhs: " << rhs << "\n";
llvm::dbgs() << " rhsSrc: " << rhsSrc << "\n";
llvm::dbgs() << "\n";);
llvm::dbgs() << " rhsSrc: " << rhsSrc << "\n";);

// Indirect case currently not handled. Conservatively assume
// it aliases with everything
if (lhsSrc.kind > SourceKind::Direct || rhsSrc.kind > SourceKind::Direct) {
if (lhsSrc.kind >= SourceKind::Indirect ||
rhsSrc.kind >= SourceKind::Indirect) {
return AliasResult::MayAlias;
}

// SourceKind::Direct is set for the addresses wrapped in a global boxes.
// ie: fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
// Though nothing is known about them, they would only alias with targets or
// pointers
bool directSourceToNonTargetOrPointer = false;
if (lhsSrc.u != rhsSrc.u || lhsSrc.kind != rhsSrc.kind) {
if ((lhsSrc.kind == SourceKind::Direct && !rhsSrc.isTargetOrPointer()) ||
(rhsSrc.kind == SourceKind::Direct && !lhsSrc.isTargetOrPointer()))
directSourceToNonTargetOrPointer = true;
}

if (lhsSrc.kind == SourceKind::Direct ||
rhsSrc.kind == SourceKind::Direct) {
if (!directSourceToNonTargetOrPointer)
return AliasResult::MayAlias;
}

if (lhsSrc.kind == rhsSrc.kind) {
if (lhsSrc.u == rhsSrc.u) {
if (lhsSrc.origin == rhsSrc.origin) {
LLVM_DEBUG(llvm::dbgs()
<< " aliasing because same source kind and origin\n");
if (approximateSource)
return AliasResult::MayAlias;
return AliasResult::MustAlias;
}

// Two host associated accesses may overlap due to an equivalence.
if (lhsSrc.kind == SourceKind::HostAssoc)
if (lhsSrc.kind == SourceKind::HostAssoc) {
LLVM_DEBUG(llvm::dbgs() << " aliasing because of host association\n");
return AliasResult::MayAlias;

// Allocate and global memory address cannot physically alias
if (lhsSrc.kind == SourceKind::Allocate ||
lhsSrc.kind == SourceKind::Global)
return AliasResult::NoAlias;

// Dummy TARGET/POINTER arguments may alias.
if (lhsSrc.isTargetOrPointer() && rhsSrc.isTargetOrPointer())
return AliasResult::MayAlias;

// Box for POINTER component inside an object of a derived type
// may alias box of a POINTER object, as well as boxes for POINTER
// components inside two objects of derived types may alias.
if ((lhsSrc.isRecordWithPointerComponent() && rhsSrc.isTargetOrPointer()) ||
(rhsSrc.isRecordWithPointerComponent() && lhsSrc.isTargetOrPointer()) ||
(lhsSrc.isRecordWithPointerComponent() &&
rhsSrc.isRecordWithPointerComponent()))
return AliasResult::MayAlias;

return AliasResult::NoAlias;
}
}

assert(lhsSrc.kind != rhsSrc.kind && "memory source kinds must be different");

Source *src1, *src2;
if (lhsSrc.kind < rhsSrc.kind) {
src1 = &lhsSrc;
Expand Down Expand Up @@ -186,17 +167,22 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
}

// Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
if (src1->isTargetOrPointer() && src2->isTargetOrPointer())
if (src1->isTargetOrPointer() && src2->isTargetOrPointer() &&
src1->isData() == src2->isData()) {
LLVM_DEBUG(llvm::dbgs() << " aliasing because of target or pointer\n");
return AliasResult::MayAlias;
}

// Box for POINTER component inside an object of a derived type
// may alias box of a POINTER object, as well as boxes for POINTER
// components inside two objects of derived types may alias.
if ((src1->isRecordWithPointerComponent() && src2->isTargetOrPointer()) ||
(src2->isRecordWithPointerComponent() && src1->isTargetOrPointer()) ||
(src1->isRecordWithPointerComponent() &&
src2->isRecordWithPointerComponent()))
src2->isRecordWithPointerComponent())) {
LLVM_DEBUG(llvm::dbgs() << " aliasing because of pointer components\n");
return AliasResult::MayAlias;
}

return AliasResult::NoAlias;
}
Expand Down Expand Up @@ -262,7 +248,10 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
mlir::Type ty;
bool breakFromLoop{false};
bool approximateSource{false};
bool followBoxAddr{mlir::isa<fir::BaseBoxType>(v.getType())};
bool followBoxData{mlir::isa<fir::BaseBoxType>(v.getType())};
bool isBoxRef{fir::isa_ref_type(v.getType()) &&
mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(v.getType()))};
bool followingData = !isBoxRef;
mlir::SymbolRefAttr global;
Source::Attributes attributes;
while (defOp && !breakFromLoop) {
Expand All @@ -282,34 +271,32 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
v = op->getOperand(0);
defOp = v.getDefiningOp();
if (mlir::isa<fir::BaseBoxType>(v.getType()))
followBoxAddr = true;
followBoxData = true;
})
.Case<fir::ArrayCoorOp, fir::CoordinateOp>([&](auto op) {
v = op->getOperand(0);
defOp = v.getDefiningOp();
if (mlir::isa<fir::BaseBoxType>(v.getType()))
followBoxAddr = true;
followBoxData = true;
approximateSource = true;
})
.Case<fir::EmboxOp, fir::ReboxOp>([&](auto op) {
if (followBoxAddr) {
if (followBoxData) {
v = op->getOperand(0);
defOp = v.getDefiningOp();
} else
breakFromLoop = true;
})
.Case<fir::LoadOp>([&](auto op) {
if (followBoxAddr && mlir::isa<fir::BaseBoxType>(op.getType())) {
// For now, support the load of an argument or fir.address_of
// TODO: generalize to all operations (in particular fir.alloca and
// fir.allocmem)
auto def = getOriginalDef(op.getMemref());
if (isDummyArgument(def) ||
def.template getDefiningOp<fir::AddrOfOp>()) {
v = def;
defOp = v.getDefiningOp();
return;
}
// If the load is from a leaf source, return the leaf. Do not track
// through indirections otherwise.
// TODO: Add support to fir.alloca and fir.allocmem
auto def = getOriginalDef(op.getMemref());
if (isDummyArgument(def) ||
def.template getDefiningOp<fir::AddrOfOp>()) {
v = def;
defOp = v.getDefiningOp();
return;
}
// No further tracking for addresses loaded from memory for now.
type = SourceKind::Indirect;
Expand All @@ -318,36 +305,18 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
.Case<fir::AddrOfOp>([&](auto op) {
// Address of a global scope object.
ty = v.getType();

// When the global is a
// fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>>
// or
// fir.global @_QMpointersEp : !fir.box<!fir.heap<f32>>
//
// and when following through the wrapped address, capture
// the fact that there is nothing known about it. Therefore setting
// the source to Direct.
//
// When not following the wrapped address, then consider the address
// of the box, which has nothing to do with the wrapped address and
// lies in the global memory space.
if (followBoxAddr &&
mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(ty)))
type = SourceKind::Direct;
else
type = SourceKind::Global;
type = SourceKind::Global;

auto globalOpName = mlir::OperationName(
fir::GlobalOp::getOperationName(), defOp->getContext());
if (fir::valueHasFirAttribute(
v, fir::GlobalOp::getTargetAttrName(globalOpName)))
attributes.set(Attribute::Target);

// TODO: Take followBoxAddr into account when setting the pointer
// TODO: Take followBoxData into account when setting the pointer
// attribute
if (Source::isPointerReference(ty))
attributes.set(Attribute::Pointer);

global = llvm::cast<fir::AddrOfOp>(op).getSymbol();
breakFromLoop = true;
})
Expand Down Expand Up @@ -393,7 +362,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
// MustAlias after going through a designate operation
approximateSource = true;
if (mlir::isa<fir::BaseBoxType>(v.getType()))
followBoxAddr = true;
followBoxData = true;
})
.Default([&](auto op) {
defOp = nullptr;
Expand All @@ -412,10 +381,10 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
attributes.set(Attribute::Pointer);
}

if (type == SourceKind::Global || type == SourceKind::Direct)
return {global, type, ty, attributes, approximateSource};

return {v, type, ty, attributes, approximateSource};
if (type == SourceKind::Global) {
return {{global, followingData}, type, ty, attributes, approximateSource};
}
return {{v, followingData}, type, ty, attributes, approximateSource};
}

} // namespace fir
2 changes: 1 addition & 1 deletion flang/lib/Optimizer/CodeGen/CGOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down
50 changes: 36 additions & 14 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#include "flang/Optimizer/CodeGen/CodeGen.h"

#include "CGOps.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"
#include "flang/Optimizer/CodeGen/FIROpPatterns.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
Expand Down Expand Up @@ -170,6 +170,28 @@ genAllocationScaleSize(OP op, mlir::Type ity,
return nullptr;
}

namespace {
struct DeclareOpConversion : public fir::FIROpConversion<fir::cg::XDeclareOp> {
public:
using FIROpConversion::FIROpConversion;
mlir::LogicalResult
matchAndRewrite(fir::cg::XDeclareOp declareOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
auto memRef = adaptor.getOperands()[0];
if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(declareOp.getLoc())) {
if (auto varAttr =
mlir::dyn_cast_or_null<mlir::LLVM::DILocalVariableAttr>(
fusedLoc.getMetadata())) {
rewriter.create<mlir::LLVM::DbgDeclareOp>(memRef.getLoc(), memRef,
varAttr, nullptr);
}
}
rewriter.replaceOp(declareOp, memRef);
return mlir::success();
}
};
} // namespace

namespace {
/// convert to LLVM IR dialect `alloca`
struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
Expand Down Expand Up @@ -3714,19 +3736,19 @@ void fir::populateFIRToLLVMConversionPatterns(
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
HasValueOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
MulcOpConversion, NegcOpConversion, NoReassocOpConversion,
SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
ShiftOpConversion, SliceOpConversion, StoreOpConversion,
StringLitOpConversion, SubcOpConversion, TypeDescOpConversion,
TypeInfoOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
UndefOpConversion, UnreachableOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DeclareOpConversion,
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
InsertValueOpConversion, IsPresentOpConversion, LenParamIndexOpConversion,
LoadOpConversion, MulcOpConversion, NegcOpConversion,
NoReassocOpConversion, SelectCaseOpConversion, SelectOpConversion,
SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
StoreOpConversion, StringLitOpConversion, SubcOpConversion,
TypeDescOpConversion, TypeInfoOpConversion, UnboxCharOpConversion,
UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
UnrealizedConversionCastOpConversion, XArrayCoorOpConversion,
XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(converter,
options);
Expand Down
49 changes: 41 additions & 8 deletions flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

#include "flang/Optimizer/CodeGen/CodeGen.h"

#include "CGOps.h"
#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down Expand Up @@ -270,13 +270,43 @@ class ArrayCoorConversion : public mlir::OpRewritePattern<fir::ArrayCoorOp> {
};

class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
bool preserveDeclare;

public:
using OpRewritePattern::OpRewritePattern;
DeclareOpConversion(mlir::MLIRContext *ctx, bool preserveDecl)
: OpRewritePattern(ctx), preserveDeclare(preserveDecl) {}

mlir::LogicalResult
matchAndRewrite(fir::DeclareOp declareOp,
mlir::PatternRewriter &rewriter) const override {
rewriter.replaceOp(declareOp, declareOp.getMemref());
if (!preserveDeclare) {
rewriter.replaceOp(declareOp, declareOp.getMemref());
return mlir::success();
}
auto loc = declareOp.getLoc();
llvm::SmallVector<mlir::Value> shapeOpers;
llvm::SmallVector<mlir::Value> shiftOpers;
if (auto shapeVal = declareOp.getShape()) {
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
populateShape(shapeOpers, shapeOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
else if (auto shiftOp =
mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp()))
populateShift(shiftOpers, shiftOp);
else
return mlir::failure();
}
// FIXME: Add FortranAttrs and CudaAttrs
auto xDeclOp = rewriter.create<fir::cg::XDeclareOp>(
loc, declareOp.getType(), declareOp.getMemref(), shapeOpers, shiftOpers,
declareOp.getTypeparams(), declareOp.getDummyScope(),
declareOp.getUniqName());
LLVM_DEBUG(llvm::dbgs()
<< "rewriting " << declareOp << " to " << xDeclOp << '\n');
rewriter.replaceOp(declareOp, xDeclOp.getOperation()->getResults());
return mlir::success();
}
};
Expand All @@ -297,6 +327,7 @@ class DummyScopeOpConversion

class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
public:
CodeGenRewrite(fir::CodeGenRewriteOptions opts) : Base(opts) {}
void runOnOperation() override final {
mlir::ModuleOp mod = getOperation();

Expand All @@ -314,7 +345,7 @@ class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
mlir::cast<fir::BaseBoxType>(embox.getType()).getEleTy()));
});
mlir::RewritePatternSet patterns(&context);
fir::populatePreCGRewritePatterns(patterns);
fir::populatePreCGRewritePatterns(patterns, preserveDeclare);
if (mlir::failed(
mlir::applyPartialConversion(mod, target, std::move(patterns)))) {
mlir::emitError(mlir::UnknownLoc::get(&context),
Expand All @@ -330,12 +361,14 @@ class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {

} // namespace

std::unique_ptr<mlir::Pass> fir::createFirCodeGenRewritePass() {
return std::make_unique<CodeGenRewrite>();
std::unique_ptr<mlir::Pass>
fir::createFirCodeGenRewritePass(fir::CodeGenRewriteOptions Options) {
return std::make_unique<CodeGenRewrite>(Options);
}

void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns) {
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
bool preserveDeclare) {
patterns.insert<EmboxConversion, ArrayCoorConversion, ReboxConversion,
DeclareOpConversion, DummyScopeOpConversion>(
patterns.getContext());
DummyScopeOpConversion>(patterns.getContext());
patterns.add<DeclareOpConversion>(patterns.getContext(), preserveDeclare);
}
17 changes: 10 additions & 7 deletions flang/lib/Optimizer/Transforms/AddAliasTags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
source.kind == fir::AliasAnalysis::SourceKind::Argument) {
LLVM_DEBUG(llvm::dbgs().indent(2)
<< "Found reference to dummy argument at " << *op << "\n");
std::string name = getFuncArgName(source.u.get<mlir::Value>());
std::string name = getFuncArgName(source.origin.u.get<mlir::Value>());
if (!name.empty())
tag = state.getFuncTree(func).dummyArgDataTree.getTag(name);
else
Expand All @@ -155,18 +155,20 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,

// TBAA for global variables
} else if (enableGlobals &&
source.kind == fir::AliasAnalysis::SourceKind::Global) {
mlir::SymbolRefAttr glbl = source.u.get<mlir::SymbolRefAttr>();
source.kind == fir::AliasAnalysis::SourceKind::Global &&
!source.isBoxData()) {
mlir::SymbolRefAttr glbl = source.origin.u.get<mlir::SymbolRefAttr>();
const char *name = glbl.getRootReference().data();
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global " << name
<< " at " << *op << "\n");
tag = state.getFuncTree(func).globalDataTree.getTag(name);

// TBAA for SourceKind::Direct
} else if (enableDirect &&
source.kind == fir::AliasAnalysis::SourceKind::Direct) {
if (source.u.is<mlir::SymbolRefAttr>()) {
mlir::SymbolRefAttr glbl = source.u.get<mlir::SymbolRefAttr>();
source.kind == fir::AliasAnalysis::SourceKind::Global &&
source.isBoxData()) {
if (source.origin.u.is<mlir::SymbolRefAttr>()) {
mlir::SymbolRefAttr glbl = source.origin.u.get<mlir::SymbolRefAttr>();
const char *name = glbl.getRootReference().data();
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to direct " << name
<< " at " << *op << "\n");
Expand All @@ -182,7 +184,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
} else if (enableLocalAllocs &&
source.kind == fir::AliasAnalysis::SourceKind::Allocate) {
std::optional<llvm::StringRef> name;
mlir::Operation *sourceOp = source.u.get<mlir::Value>().getDefiningOp();
mlir::Operation *sourceOp =
source.origin.u.get<mlir::Value>().getDefiningOp();
if (auto alloc = mlir::dyn_cast_or_null<fir::AllocaOp>(sourceOp))
name = alloc.getUniqName();
else if (auto alloc = mlir::dyn_cast_or_null<fir::AllocMemOp>(sourceOp))
Expand Down
60 changes: 56 additions & 4 deletions flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "flang/Common/Version.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/CodeGen/CGOps.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down Expand Up @@ -45,13 +46,59 @@ namespace fir {
namespace {

class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
void handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen);

public:
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
void runOnOperation() override;
};

static uint32_t getLineFromLoc(mlir::Location loc) {
uint32_t line = 1;
if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
line = fileLoc.getLine();
return line;
}

} // namespace

void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scopeAttr,
fir::DebugTypeGenerator &typeGen) {
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
auto result = fir::NameUniquer::deconstruct(declOp.getUniqName());

if (result.first != fir::NameUniquer::NameKind::VARIABLE)
return;

// Only accept local variables.
if (result.second.procs.empty())
return;

// FIXME: There may be cases where an argument is processed a bit before
// DeclareOp is generated. In that case, DeclareOp may point to an
// intermediate op and not to BlockArgument. We need to find those cases and
// walk the chain to get to the actual argument.

unsigned argNo = 0;
if (auto Arg = llvm::dyn_cast<mlir::BlockArgument>(declOp.getMemref()))
argNo = Arg.getArgNumber() + 1;

auto tyAttr = typeGen.convertType(fir::unwrapRefType(declOp.getType()),
fileAttr, scopeAttr, declOp.getLoc());

auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
context, scopeAttr, mlir::StringAttr::get(context, result.second.name),
fileAttr, getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0,
tyAttr);
declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
}

void AddDebugInfoPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
Expand Down Expand Up @@ -144,14 +191,19 @@ void AddDebugInfoPass::runOnOperation() {
subprogramFlags =
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
}
unsigned line = 1;
if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l))
line = funcLoc.getLine();

unsigned line = getLineFromLoc(l);
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, fileAttr, funcName, fullName,
funcFileAttr, line, line, subprogramFlags, subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));

// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
return;

funcOp.walk([&](fir::cg::XDeclareOp declOp) {
handleDeclareOp(declOp, fileAttr, spAttr, typeGen);
});
});
}

Expand Down
44 changes: 34 additions & 10 deletions flang/lib/Optimizer/Transforms/ControlFlowConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,19 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgLoopConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
CfgLoopConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce, bool setNSW)
: mlir::OpRewritePattern<fir::DoLoopOp>(ctx),
forceLoopToExecuteOnce(forceLoopToExecuteOnce) {}
forceLoopToExecuteOnce(forceLoopToExecuteOnce), setNSW(setNSW) {}

mlir::LogicalResult
matchAndRewrite(DoLoopOp loop,
mlir::PatternRewriter &rewriter) const override {
auto loc = loop.getLoc();
mlir::arith::IntegerOverflowFlags flags{};
if (setNSW)
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
rewriter.getContext(), flags);

// Create the start and end blocks that will wrap the DoLoopOp with an
// initalizer and an end point
Expand Down Expand Up @@ -104,7 +109,7 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {
rewriter.setInsertionPointToEnd(lastBlock);
auto iv = conditionalBlock->getArgument(0);
mlir::Value steppedIndex =
rewriter.create<mlir::arith::AddIOp>(loc, iv, step);
rewriter.create<mlir::arith::AddIOp>(loc, iv, step, iofAttr);
assert(steppedIndex && "must be a Value");
auto lastArg = conditionalBlock->getNumArguments() - 1;
auto itersLeft = conditionalBlock->getArgument(lastArg);
Expand Down Expand Up @@ -142,14 +147,15 @@ class CfgLoopConv : public mlir::OpRewritePattern<fir::DoLoopOp> {

private:
bool forceLoopToExecuteOnce;
bool setNSW;
};

/// Convert `fir.if` to control-flow
class CfgIfConv : public mlir::OpRewritePattern<fir::IfOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgIfConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
CfgIfConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce, bool setNSW)
: mlir::OpRewritePattern<fir::IfOp>(ctx) {}

mlir::LogicalResult
Expand Down Expand Up @@ -214,13 +220,19 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
public:
using OpRewritePattern::OpRewritePattern;

CfgIterWhileConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce)
: mlir::OpRewritePattern<fir::IterWhileOp>(ctx) {}
CfgIterWhileConv(mlir::MLIRContext *ctx, bool forceLoopToExecuteOnce,
bool setNSW)
: mlir::OpRewritePattern<fir::IterWhileOp>(ctx), setNSW(setNSW) {}

mlir::LogicalResult
matchAndRewrite(fir::IterWhileOp whileOp,
mlir::PatternRewriter &rewriter) const override {
auto loc = whileOp.getLoc();
mlir::arith::IntegerOverflowFlags flags{};
if (setNSW)
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
rewriter.getContext(), flags);

// Start by splitting the block containing the 'fir.do_loop' into two parts.
// The part before will get the init code, the part after will be the end
Expand Down Expand Up @@ -248,7 +260,8 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
auto *terminator = lastBodyBlock->getTerminator();
rewriter.setInsertionPointToEnd(lastBodyBlock);
auto step = whileOp.getStep();
mlir::Value stepped = rewriter.create<mlir::arith::AddIOp>(loc, iv, step);
mlir::Value stepped =
rewriter.create<mlir::arith::AddIOp>(loc, iv, step, iofAttr);
assert(stepped && "must be a Value");

llvm::SmallVector<mlir::Value> loopCarried;
Expand Down Expand Up @@ -305,17 +318,23 @@ class CfgIterWhileConv : public mlir::OpRewritePattern<fir::IterWhileOp> {
rewriter.replaceOp(whileOp, args);
return success();
}

private:
bool setNSW;
};

/// Convert FIR structured control flow ops to CFG ops.
class CfgConversion : public fir::impl::CFGConversionBase<CfgConversion> {
public:
using CFGConversionBase<CfgConversion>::CFGConversionBase;

CfgConversion(bool setNSW) { this->setNSW = setNSW; }

void runOnOperation() override {
auto *context = &this->getContext();
mlir::RewritePatternSet patterns(context);
fir::populateCfgConversionRewrites(patterns, this->forceLoopToExecuteOnce);
fir::populateCfgConversionRewrites(patterns, this->forceLoopToExecuteOnce,
this->setNSW);
mlir::ConversionTarget target(*context);
target.addLegalDialect<mlir::affine::AffineDialect,
mlir::cf::ControlFlowDialect, FIROpsDialect,
Expand All @@ -337,7 +356,12 @@ class CfgConversion : public fir::impl::CFGConversionBase<CfgConversion> {

/// Expose conversion rewriters to other passes
void fir::populateCfgConversionRewrites(mlir::RewritePatternSet &patterns,
bool forceLoopToExecuteOnce) {
bool forceLoopToExecuteOnce,
bool setNSW) {
patterns.insert<CfgLoopConv, CfgIfConv, CfgIterWhileConv>(
patterns.getContext(), forceLoopToExecuteOnce);
patterns.getContext(), forceLoopToExecuteOnce, setNSW);
}

std::unique_ptr<mlir::Pass> fir::createCFGConversionPassWithNSW() {
return std::make_unique<CfgConversion>(true);
}
10 changes: 5 additions & 5 deletions flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m)
LLVM_DEBUG(llvm::dbgs() << "DITypeAttr generator\n");
}

static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return mlir::LLVM::DIBasicTypeAttr::get(
context, llvm::dwarf::DW_TAG_base_type, "void", 32, 1);
}

static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
mlir::StringAttr name,
unsigned bitSize,
Expand All @@ -37,6 +32,11 @@ static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context,
context, llvm::dwarf::DW_TAG_base_type, name, bitSize, decoding);
}

static mlir::LLVM::DITypeAttr genPlaceholderType(mlir::MLIRContext *context) {
return genBasicType(context, mlir::StringAttr::get(context, "integer"), 32,
llvm::dwarf::DW_ATE_signed);
}

mlir::LLVM::DITypeAttr
DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope,
Expand Down
37 changes: 24 additions & 13 deletions flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@

// arg2 is a reference to a pointer. Modifying arg2 could
// modify a target with a pointer component
// CHECK-DAG: func.region0#0 <-> func.region0#2: MayAlias
// CHECK-DAG: func.region0#1 <-> func.region0#2: MayAlias
// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg2.load#0 <-> func.region0#1: MayAlias

// However, the address wrapped by arg2, can alias with any target or
// pointer arguments
// CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias
// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MustAlias
// CHECK-DAG: arg2.load#0 <-> arg2.addr#0: MustAlias
// CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias

func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
Expand Down Expand Up @@ -80,7 +80,7 @@ func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %a
%14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
fir.store %14 to %4 : !fir.ref<!fir.ptr<f32>>

%15 = fir.load %arg2 : !fir.ref<!fir.box<!fir.ptr<f32>>>
%15 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
%16 = fir.box_addr %15 {test.ptr = "arg2.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
return
}
Expand All @@ -99,10 +99,12 @@ func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %a
// CHECK-DAG: func.region0#1 <-> func.region0#2: MayAlias

// They can also modify targets that have pointer components
// CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias
// CHECK-DAG: func.region0#0 <-> func.region0#2: MayAlias
// CHECK-DAG: arg1.load#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias

func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>>, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {
%0 = fir.load %arg1 {test.ptr = "arg1.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
%1 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
return
}

Expand Down Expand Up @@ -141,14 +143,14 @@ func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %
// alias with the wrapped scalar _QFEvar2. We meant box_addr of _QMpointersEp
// CHECK-DAG: p#0 <-> box.addr#0: NoAlias

// TODO: Still need to handle more gracefully the difference between !fir.ref<!fir.box<>> and !fir.box<>
// CHECK-DAG: box.addr#0 <-> func.region0#0: MayAlias
// Handling gracefully the difference between !fir.ref<!fir.box<>> and !fir.box<>
// CHECK-DAG: box.addr#0 <-> func.region0#0: NoAlias

// var2, although it is a target, cannot alias with p
// A modification of p would only make them point to a new target but not modify it
// CHECK-DAG: var2#0 <-> p#0: NoAlias
// It can alias with p1, if p1 is a pointer component
// CHECK-DAG: var2#0 <-> func.region0#0: MayAlias
// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias
// It is the same as box.addr
// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias

Expand All @@ -173,6 +175,7 @@ fir.global internal @_QFEvar2 target : f32 {
}

func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
%3 = fir.load %arg0 {test.ptr = "arg0.load"}: !fir.ref<!fir.box<!fir.ptr<f32>>>
%4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
%5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
%6 = fir.embox %4 : (!fir.ref<f32>) -> !fir.box<!fir.ptr<f32>>
Expand Down Expand Up @@ -214,10 +217,17 @@ func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name =
// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#0: NoAlias
// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#1: NoAlias

// CHECK-DAG: var2#0 <-> func.region0#0: MayAlias
// CHECK-DAG: var2_fir#0 <-> func.region0#0: MayAlias
// CHECK-DAG: var2_hlfir#0 <-> func.region0#0: MayAlias
// CHECK-DAG: var2_hlfir#1 <-> func.region0#0: MayAlias
// The data cannot alias with the box references
// CHECK-DAG: var2#0 <-> func.region0#0: NoAlias
// CHECK-DAG: var2_fir#0 <-> func.region0#0: NoAlias
// CHECK-DAG: var2_hlfir#0 <-> func.region0#0: NoAlias
// CHECK-DAG: var2_hlfir#1 <-> func.region0#0: NoAlias

// But it can alias with the box's own data
// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias
// CHECK-DAG: arg0.load#0 <-> var2_fir#0: MayAlias
// CHECK-DAG: arg0.load#0 <-> var2_hlfir#0: MayAlias
// CHECK-DAG: arg0.load#0 <-> var2_hlfir#1: MayAlias

// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
// CHECK-DAG: var2#0 <-> box.addr_fir#0: MustAlias
Expand Down Expand Up @@ -255,6 +265,7 @@ fir.global internal @_QFEvar2 target : f32 {
}

func.func @_QFPtest4(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
%3 = fir.load %arg0 {test.ptr = "arg0.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
%4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
%fir_decl_var2 = fir.declare %4 {uniq_name = "var2_fir", test.ptr = "var2_fir"}: (!fir.ref<f32>) -> !fir.ref<f32>
%hlfir_decl_var2:2 = hlfir.declare %4 {uniq_name = "var2_hlfir", test.ptr = "var2_hlfir"}: (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Analysis/AliasAnalysis/alias-analysis-3.fir
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
// FIXME: a's box cannot alias with raw reference to f32 (x), so MayAlias below must be NoAlias:
// CHECK: a#0 <-> func.region0#1: MayAlias

// FIXME: pointer_dummy's box cannot alias with raw reference to f32 (x), so MayAlias below must be NoAlias:
// CHECK: func.region0#0 <-> func.region0#1: MayAlias
// pointer_dummy's box cannot alias with raw reference to f32 (x)
// CHECK: func.region0#0 <-> func.region0#1: NoAlias

fir.global @_QMmEa : !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}> {
%0 = fir.undefined !fir.type<_QMmTt{pointer_component:!fir.box<!fir.ptr<f32>>}>
Expand Down
Loading