include(CMakeParseArguments)
include(AddFlang)
+if (FLANG_INCLUDE_TESTS)
+ add_compile_definitions(FLANG_INCLUDE_TESTS=1)
+endif()
add_subdirectory(include)
add_subdirectory(lib)
--- /dev/null
+//===- AliasAnalysis.h - Alias Analysis in FIR -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FIR_ANALYSIS_ALIASANALYSIS_H_
+#define FIR_ANALYSIS_ALIASANALYSIS_H_
+
+#include "mlir/Analysis/AliasAnalysis.h"
+
+namespace fir {
+
+//===----------------------------------------------------------------------===//
+// AliasAnalysis
+//===----------------------------------------------------------------------===//
+class AliasAnalysis {
+public:
+ /// Given two values, return their aliasing behavior.
+ mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs);
+
+ /// Return the modify-reference behavior of `op` on `location`.
+ mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location);
+};
+} // namespace fir
+
+#endif // FIR_ANALYSIS_ALIASANALYSIS_H_
/// intrinsic function.
Fortran::lower::ArgLoweringRule Fortran::lower::lowerIntrinsicArgumentAs(
const IntrinsicArgumentLoweringRules &rules, unsigned position) {
- assert(position < sizeof(rules.args) / sizeof(decltype(*rules.args)) &&
+ assert(position < sizeof(rules.args) / (sizeof(decltype(*rules.args))) &&
"invalid argument");
return {rules.args[position].lowerAs,
rules.args[position].handleDynamicOptional};
--- /dev/null
+//===- AliasAnalysis.cpp - Alias Analysis for FIR ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Analysis/AliasAnalysis.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// AliasAnalysis: alias
+//===----------------------------------------------------------------------===//
+
+namespace fir {
+AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
+ // This is for now a mock analysis
+ if (lhs == rhs) {
+ return AliasResult::MustAlias;
+ }
+ return AliasResult::MayAlias;
+}
+
+//===----------------------------------------------------------------------===//
+// AliasAnalysis: getModRef
+//===----------------------------------------------------------------------===//
+
+/// This is mostly inspired by MLIR::LocalAliasAnalysis with 2 notable
+/// differences 1) Regions are not handled here but will be handled by a data
+/// flow analysis to come 2) Allocate and Free effects are considered modifying
+ModRefResult AliasAnalysis::getModRef(Operation *op, Value location) {
+ MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
+ if (!interface)
+ return ModRefResult::getModAndRef();
+
+ // Build a ModRefResult by merging the behavior of the effects of this
+ // operation.
+ SmallVector<MemoryEffects::EffectInstance> effects;
+ interface.getEffects(effects);
+
+ ModRefResult result = ModRefResult::getNoModRef();
+ for (const MemoryEffects::EffectInstance &effect : effects) {
+
+ // Check for an alias between the effect and our memory location.
+ AliasResult aliasResult = AliasResult::MayAlias;
+ if (Value effectValue = effect.getValue())
+ aliasResult = alias(effectValue, location);
+
+ // If we don't alias, ignore this effect.
+ if (aliasResult.isNo())
+ continue;
+
+ // Merge in the corresponding mod or ref for this effect.
+ if (isa<MemoryEffects::Read>(effect.getEffect())) {
+ result = result.merge(ModRefResult::getRef());
+ } else {
+ result = result.merge(ModRefResult::getMod());
+ }
+ if (result.isModAndRef())
+ break;
+ }
+ return result;
+}
+} // namespace fir
--- /dev/null
+add_flang_library(FIRAnalysis
+ AliasAnalysis.cpp
+
+ DEPENDS
+ FIRBuilder
+ FIRDialect
+ FIRSupport
+
+ LINK_LIBS
+ FIRBuilder
+ FIRDialect
+ MLIRFuncDialect
+ MLIRLLVMDialect
+ MLIRMathTransforms
+ FIRSupport
+)
add_subdirectory(HLFIR)
add_subdirectory(Support)
add_subdirectory(Transforms)
+add_subdirectory(Analysis)
# Test runner infrastructure for Flang. This configures the Flang test trees
# for use by Lit, and delegates to LLVM's lit test handlers.
+add_subdirectory(lib)
llvm_canonicalize_cmake_booleans(
FLANG_BUILD_EXAMPLES
--- /dev/null
+# Exclude tests from libMLIR.so
+add_flang_library(FIRTestAnalysis
+ TestAliasAnalysis.cpp
+
+ DEPENDS
+ FIRDialect
+ FIRBuilder
+ FIRSupport
+ FIRTransforms
+ FIRAnalysis
+ ${dialect_libs}
+
+ LINK_LIBS
+ FIRDialect
+ FIRBuilder
+ FIRSupport
+ FIRTransforms
+ FIRAnalysis
+ ${dialect_libs}
+ MLIRFuncDialect
+ MLIRLLVMDialect
+ MLIRAnalysis
+ MLIRTestAnalysis
+ )
+
+target_include_directories(FIRTestAnalysis
+ PRIVATE
+ ${MLIR_MAIN_SRC_DIR}/..
+ )
\ No newline at end of file
--- /dev/null
+//===- TestAliasAnalysis.cpp - Test FIR lias analysis -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/test/lib/Analysis/TestAliasAnalysis.h"
+#include "mlir/Analysis/AliasAnalysis.h"
+#include "mlir/Pass/Pass.h"
+#include "flang/Optimizer/Analysis/AliasAnalysis.h"
+
+using namespace mlir;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// Testing AliasResult
+//===----------------------------------------------------------------------===//
+
+struct TestFIRAliasAnalysisPass
+ : public test::TestAliasAnalysisBase,
+ PassWrapper<TestFIRAliasAnalysisPass, OperationPass<>> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFIRAliasAnalysisPass)
+
+ StringRef getArgument() const final { return "test-fir-alias-analysis"; }
+ StringRef getDescription() const final {
+ return "Test alias analysis results.";
+ }
+ void runOnOperation() override {
+ mlir::AliasAnalysis aliasAnalysis(getOperation());
+ aliasAnalysis.addAnalysisImplementation(fir::AliasAnalysis());
+ runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Testing ModRefResult
+//===----------------------------------------------------------------------===//
+
+struct TestFIRAliasAnalysisModRefPass
+ : public test::TestAliasAnalysisModRefBase,
+ PassWrapper<TestFIRAliasAnalysisModRefPass, OperationPass<>> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFIRAliasAnalysisModRefPass)
+
+ StringRef getArgument() const final {
+ return "test-fir-alias-analysis-modref";
+ }
+ StringRef getDescription() const final {
+ return "Test alias analysis ModRef results.";
+ }
+ void runOnOperation() override {
+ mlir::AliasAnalysis aliasAnalysis(getOperation());
+ aliasAnalysis.addAnalysisImplementation(fir::AliasAnalysis());
+ runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
+ }
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// Pass Registration
+//===----------------------------------------------------------------------===//
+
+namespace fir {
+namespace test {
+void registerTestFIRAliasAnalysisPass() {
+ PassRegistration<TestFIRAliasAnalysisPass>();
+ PassRegistration<TestFIRAliasAnalysisModRefPass>();
+}
+} // namespace test
+} // namespace fir
\ No newline at end of file
--- /dev/null
+// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file 2>&1 | FileCheck %s
+
+// CHECK-LABEL: Testing : "_QPtest"
+// CHECK-DAG: alloca_1#0 <-> address_of#0: MayAlias
+func.func @_QPtest(%arg1: !fir.ref<i32>) {
+ %c1_i32 = arith.constant 1 : i32
+ %0 = fir.alloca () -> () {test.ptr = "alloca_1"}
+ %1 = fir.address_of(@_QPf) {test.ptr = "address_of"} : () -> i32
+ %2 = fir.convert %1 : (() -> i32) -> (() -> ())
+ %4 = fir.convert %0 : (!fir.ref<() -> ()>) -> !fir.llvm_ptr<() -> ()>
+ fir.store %2 to %4 : !fir.llvm_ptr<() -> ()>
+ %6 = fir.load %0 : !fir.ref<() -> ()>
+ fir.call @_QPs(%6) : (() -> ()) -> ()
+ return
+}
+
+// -----
+func.func private @_QPs(%arg0: () -> ())
+
+// -----
+func.func private @_QPf() -> i32
--- /dev/null
+add_subdirectory(AliasAnalysis)
--- /dev/null
+add_subdirectory(Analysis)
--- /dev/null
+
+# Excluding .cpp file from the extensions since from this level down they are used for the development
+config.suffixes = ['.c', '.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90',
+ '.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf'
+ '.CUF', '.f18', '.F18', '.f03', '.F03', '.f08', '.F08',
+ '.ll', '.fir', '.mlir']
+
llvm_update_compile_flags(fir-opt)
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+if(FLANG_INCLUDE_TESTS)
+ set(test_libs
+ FIRTestAnalysis
+ )
+endif()
+
target_link_libraries(fir-opt PRIVATE
FIRDialect
FIRSupport
FIRTransforms
FIRCodeGen
HLFIRDialect
+ FIRAnalysis
+ ${test_libs}
${dialect_libs}
# TODO: these should be transitive dependencies from a target providing
#include "flang/Optimizer/Transforms/Passes.h"
using namespace mlir;
+namespace fir {
+namespace test {
+void registerTestFIRAliasAnalysisPass();
+} // namespace test
+} // namespace fir
int main(int argc, char **argv) {
fir::support::registerMLIRPassesForFortranTools();
fir::registerOptCodeGenPasses();
fir::registerOptTransformPasses();
+#ifdef FLANG_INCLUDE_TESTS
+ fir::test::registerTestFIRAliasAnalysisPass();
+#endif
DialectRegistry registry;
fir::support::registerDialects(registry);
return failed(MlirOptMain(argc, argv, "FIR modular optimizer driver\n",
//
//===----------------------------------------------------------------------===//
+#include "TestAliasAnalysis.h"
#include "mlir/Analysis/AliasAnalysis.h"
#include "mlir/Pass/Pass.h"
llvm::errs() << "#" << result.getResultNumber();
}
+namespace mlir {
+namespace test {
+void printAliasResult(AliasResult result, Value lhs, Value rhs) {
+ printAliasOperand(lhs);
+ llvm::errs() << " <-> ";
+ printAliasOperand(rhs);
+ llvm::errs() << ": " << result << "\n";
+}
+
+/// Print the result of an alias query.
+void printModRefResult(ModRefResult result, Operation *op, Value location) {
+ printAliasOperand(op);
+ llvm::errs() << " -> ";
+ printAliasOperand(location);
+ llvm::errs() << ": " << result << "\n";
+}
+
+void TestAliasAnalysisBase::runAliasAnalysisOnOperation(
+ Operation *op, AliasAnalysis &aliasAnalysis) {
+ llvm::errs() << "Testing : " << op->getAttr("sym_name") << "\n";
+
+ // Collect all of the values to check for aliasing behavior.
+ SmallVector<Value, 32> valsToCheck;
+ op->walk([&](Operation *op) {
+ if (!op->getAttr("test.ptr"))
+ return;
+ valsToCheck.append(op->result_begin(), op->result_end());
+ for (Region ®ion : op->getRegions())
+ for (Block &block : region)
+ valsToCheck.append(block.args_begin(), block.args_end());
+ });
+
+ // Check for aliasing behavior between each of the values.
+ for (auto it = valsToCheck.begin(), e = valsToCheck.end(); it != e; ++it)
+ for (auto *innerIt = valsToCheck.begin(); innerIt != it; ++innerIt)
+ printAliasResult(aliasAnalysis.alias(*innerIt, *it), *innerIt, *it);
+}
+
+void TestAliasAnalysisModRefBase::runAliasAnalysisOnOperation(
+ Operation *op, AliasAnalysis &aliasAnalysis) {
+ llvm::errs() << "Testing : " << op->getAttr("sym_name") << "\n";
+
+ // Collect all of the values to check for aliasing behavior.
+ SmallVector<Value, 32> valsToCheck;
+ op->walk([&](Operation *op) {
+ if (!op->getAttr("test.ptr"))
+ return;
+ valsToCheck.append(op->result_begin(), op->result_end());
+ for (Region ®ion : op->getRegions())
+ for (Block &block : region)
+ valsToCheck.append(block.args_begin(), block.args_end());
+ });
+
+ // Check for aliasing behavior between each of the values.
+ for (auto &it : valsToCheck) {
+ op->walk([&](Operation *op) {
+ if (!op->getAttr("test.ptr"))
+ return;
+ printModRefResult(aliasAnalysis.getModRef(op, it), op, it);
+ });
+ }
+}
+
+} // namespace test
+} // namespace mlir
+
//===----------------------------------------------------------------------===//
// Testing AliasResult
//===----------------------------------------------------------------------===//
namespace {
struct TestAliasAnalysisPass
- : public PassWrapper<TestAliasAnalysisPass, OperationPass<>> {
+ : public test::TestAliasAnalysisBase,
+ PassWrapper<TestAliasAnalysisPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAliasAnalysisPass)
StringRef getArgument() const final { return "test-alias-analysis"; }
return "Test alias analysis results.";
}
void runOnOperation() override {
- llvm::errs() << "Testing : " << getOperation()->getAttr("sym_name") << "\n";
-
- // Collect all of the values to check for aliasing behavior.
AliasAnalysis &aliasAnalysis = getAnalysis<AliasAnalysis>();
- SmallVector<Value, 32> valsToCheck;
- getOperation()->walk([&](Operation *op) {
- if (!op->getAttr("test.ptr"))
- return;
- valsToCheck.append(op->result_begin(), op->result_end());
- for (Region ®ion : op->getRegions())
- for (Block &block : region)
- valsToCheck.append(block.args_begin(), block.args_end());
- });
-
- // Check for aliasing behavior between each of the values.
- for (auto it = valsToCheck.begin(), e = valsToCheck.end(); it != e; ++it)
- for (auto *innerIt = valsToCheck.begin(); innerIt != it; ++innerIt)
- printAliasResult(aliasAnalysis.alias(*innerIt, *it), *innerIt, *it);
- }
-
- /// Print the result of an alias query.
- void printAliasResult(AliasResult result, Value lhs, Value rhs) {
- printAliasOperand(lhs);
- llvm::errs() << " <-> ";
- printAliasOperand(rhs);
- llvm::errs() << ": " << result << "\n";
+ runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
}
};
} // namespace
namespace {
struct TestAliasAnalysisModRefPass
- : public PassWrapper<TestAliasAnalysisModRefPass, OperationPass<>> {
+ : public test::TestAliasAnalysisModRefBase,
+ PassWrapper<TestAliasAnalysisModRefPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAliasAnalysisModRefPass)
StringRef getArgument() const final { return "test-alias-analysis-modref"; }
return "Test alias analysis ModRef results.";
}
void runOnOperation() override {
- llvm::errs() << "Testing : " << getOperation()->getAttr("sym_name") << "\n";
-
- // Collect all of the values to check for aliasing behavior.
AliasAnalysis &aliasAnalysis = getAnalysis<AliasAnalysis>();
- SmallVector<Value, 32> valsToCheck;
- getOperation()->walk([&](Operation *op) {
- if (!op->getAttr("test.ptr"))
- return;
- valsToCheck.append(op->result_begin(), op->result_end());
- for (Region ®ion : op->getRegions())
- for (Block &block : region)
- valsToCheck.append(block.args_begin(), block.args_end());
- });
-
- // Check for aliasing behavior between each of the values.
- for (auto &it : valsToCheck) {
- getOperation()->walk([&](Operation *op) {
- if (!op->getAttr("test.ptr"))
- return;
- printModRefResult(aliasAnalysis.getModRef(op, it), op, it);
- });
- }
- }
-
- /// Print the result of an alias query.
- void printModRefResult(ModRefResult result, Operation *op, Value location) {
- printAliasOperand(op);
- llvm::errs() << " -> ";
- printAliasOperand(location);
- llvm::errs() << ": " << result << "\n";
+ runAliasAnalysisOnOperation(getOperation(), aliasAnalysis);
}
};
} // namespace
--- /dev/null
+//===- TestAliasAnalysis.h - MLIR Test Utility ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a common facility that can be reused for the
+// testing of various aliasing analyses
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TEST_LIB_ANALYSIS_ALIASANALYSIS_H
+#define MLIR_TEST_LIB_ANALYSIS_ALIASANALYSIS_H
+
+#include "mlir/Analysis/AliasAnalysis.h"
+
+namespace mlir {
+namespace test {
+
+/// Print the result of an alias query.
+void printAliasResult(AliasResult result, Value lhs, Value rhs);
+void printModRefResult(ModRefResult result, Operation *op, Value location);
+
+struct TestAliasAnalysisBase {
+ void runAliasAnalysisOnOperation(Operation *op, AliasAnalysis &aliasAnalysis);
+};
+
+struct TestAliasAnalysisModRefBase {
+ void runAliasAnalysisOnOperation(Operation *op, AliasAnalysis &aliasAnalysis);
+};
+
+} // namespace test
+} // namespace mlir
+
+#endif // MLIR_TEST_LIB_ANALYSIS_ALIASANALYSIS_H