Skip to content

Commit

Permalink
Alias Analysis infra in Flang
Browse files Browse the repository at this point in the history
Differential revision: https://reviews.llvm.org/D136889
  • Loading branch information
Renaud-K committed Nov 4, 2022
1 parent 3698994 commit ba65584
Show file tree
Hide file tree
Showing 17 changed files with 375 additions and 57 deletions.
3 changes: 3 additions & 0 deletions flang/CMakeLists.txt
Expand Up @@ -411,6 +411,9 @@ endif()
include(CMakeParseArguments)
include(AddFlang)

if (FLANG_INCLUDE_TESTS)
add_compile_definitions(FLANG_INCLUDE_TESTS=1)
endif()

add_subdirectory(include)
add_subdirectory(lib)
Expand Down
29 changes: 29 additions & 0 deletions flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -0,0 +1,29 @@
//===- 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_
2 changes: 1 addition & 1 deletion flang/lib/Lower/IntrinsicCall.cpp
Expand Up @@ -5004,7 +5004,7 @@ Fortran::lower::getIntrinsicArgumentLowering(llvm::StringRef specificName) {
/// 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};
Expand Down
67 changes: 67 additions & 0 deletions flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -0,0 +1,67 @@
//===- 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
16 changes: 16 additions & 0 deletions flang/lib/Optimizer/Analysis/CMakeLists.txt
@@ -0,0 +1,16 @@
add_flang_library(FIRAnalysis
AliasAnalysis.cpp

DEPENDS
FIRBuilder
FIRDialect
FIRSupport

LINK_LIBS
FIRBuilder
FIRDialect
MLIRFuncDialect
MLIRLLVMDialect
MLIRMathTransforms
FIRSupport
)
1 change: 1 addition & 0 deletions flang/lib/Optimizer/CMakeLists.txt
Expand Up @@ -4,3 +4,4 @@ add_subdirectory(Dialect)
add_subdirectory(HLFIR)
add_subdirectory(Support)
add_subdirectory(Transforms)
add_subdirectory(Analysis)
1 change: 1 addition & 0 deletions flang/test/CMakeLists.txt
@@ -1,5 +1,6 @@
# 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
Expand Down
29 changes: 29 additions & 0 deletions flang/test/lib/Analysis/AliasAnalysis/CMakeLists.txt
@@ -0,0 +1,29 @@
# 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}/..
)
72 changes: 72 additions & 0 deletions flang/test/lib/Analysis/AliasAnalysis/TestAliasAnalysis.cpp
@@ -0,0 +1,72 @@
//===- 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
21 changes: 21 additions & 0 deletions flang/test/lib/Analysis/AliasAnalysis/alias-analysis-1.fir
@@ -0,0 +1,21 @@
// 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
1 change: 1 addition & 0 deletions flang/test/lib/Analysis/CMakeLists.txt
@@ -0,0 +1 @@
add_subdirectory(AliasAnalysis)
1 change: 1 addition & 0 deletions flang/test/lib/CMakeLists.txt
@@ -0,0 +1 @@
add_subdirectory(Analysis)
7 changes: 7 additions & 0 deletions flang/test/lib/lit.local.cfg
@@ -0,0 +1,7 @@

# 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']

8 changes: 8 additions & 0 deletions flang/tools/fir-opt/CMakeLists.txt
Expand Up @@ -2,12 +2,20 @@ add_flang_tool(fir-opt fir-opt.cpp)
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
Expand Down
8 changes: 8 additions & 0 deletions flang/tools/fir-opt/fir-opt.cpp
Expand Up @@ -17,11 +17,19 @@
#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",
Expand Down

0 comments on commit ba65584

Please sign in to comment.