[flang-commits] [flang] 8301e48 - [flang][FIR] add FirAliasAnalysisOpInterface (#68317)
via flang-commits
flang-commits at lists.llvm.org
Wed Oct 11 07:06:57 PDT 2023
Author: Tom Eccles
Date: 2023-10-11T15:06:50+01:00
New Revision: 8301e485001b936a15809be6ae55f7927c610551
URL: https://github.com/llvm/llvm-project/commit/8301e485001b936a15809be6ae55f7927c610551
DIFF: https://github.com/llvm/llvm-project/commit/8301e485001b936a15809be6ae55f7927c610551.diff
LOG: [flang][FIR] add FirAliasAnalysisOpInterface (#68317)
This interface allows (HL)FIR passes to add TBAA information to fir.load
and fir.store. If present, these TBAA tags take precedence over those
added during CodeGen.
We can't reuse mlir::LLVMIR::AliasAnalysisOpInterface because that uses
the mlir::LLVMIR namespace so it tries to define methods for fir
operations in the wrong namespace. But I did re-use the tbaa tag type to
minimise boilerplate code.
The new builders are to preserve the old interface without the tbaa tag.
Added:
flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.h
flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.td
flang/lib/Optimizer/Dialect/FirAliasTagOpInterface.cpp
flang/test/Fir/tbaa-codegen.fir
Modified:
flang/include/flang/Optimizer/Dialect/CMakeLists.txt
flang/include/flang/Optimizer/Dialect/FIRDialect.td
flang/include/flang/Optimizer/Dialect/FIROps.h
flang/include/flang/Optimizer/Dialect/FIROps.td
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/lib/Optimizer/Dialect/CMakeLists.txt
flang/lib/Optimizer/Dialect/FIRDialect.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
index d657e3f16690377..fe9864a26295d22 100644
--- a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
@@ -18,6 +18,10 @@ set(LLVM_TARGET_DEFINITIONS FortranVariableInterface.td)
mlir_tablegen(FortranVariableInterface.h.inc -gen-op-interface-decls)
mlir_tablegen(FortranVariableInterface.cpp.inc -gen-op-interface-defs)
+set(LLVM_TARGET_DEFINITIONS FirAliasTagOpInterface.td)
+mlir_tablegen(FirAliasTagOpInterface.h.inc -gen-op-interface-decls)
+mlir_tablegen(FirAliasTagOpInterface.cpp.inc -gen-op-interface-defs)
+
set(LLVM_TARGET_DEFINITIONS CanonicalizationPatterns.td)
mlir_tablegen(CanonicalizationPatterns.inc -gen-rewriters)
add_public_tablegen_target(CanonicalizationPatternsIncGen)
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.td b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
index d0735bbeb2d3d88..b366b6d40e4e213 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.td
@@ -30,7 +30,9 @@ def fir_Dialect : Dialect {
let dependentDialects = [
// Arith dialect provides FastMathFlagsAttr
// supported by some FIR operations.
- "arith::ArithDialect"
+ "arith::ArithDialect",
+ // TBAA Tag types
+ "LLVM::LLVMDialect"
];
}
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index 8f03dc5cf795225..87196dbf9b97d2e 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -11,6 +11,7 @@
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index cb39619f526e85e..2b877379f138462 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -16,10 +16,12 @@
include "mlir/Dialect/Arith/IR/ArithBase.td"
include "mlir/Dialect/Arith/IR/ArithOpsInterfaces.td"
+include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
include "flang/Optimizer/Dialect/FIRDialect.td"
include "flang/Optimizer/Dialect/FIRTypes.td"
include "flang/Optimizer/Dialect/FIRAttr.td"
include "flang/Optimizer/Dialect/FortranVariableInterface.td"
+include "flang/Optimizer/Dialect/FirAliasTagOpInterface.td"
include "mlir/IR/BuiltinAttributes.td"
// Base class for FIR operations.
@@ -258,7 +260,7 @@ def fir_FreeMemOp : fir_Op<"freemem", [MemoryEffects<[MemFree]>]> {
let assemblyFormat = "$heapref attr-dict `:` qualified(type($heapref))";
}
-def fir_LoadOp : fir_OneResultOp<"load", []> {
+def fir_LoadOp : fir_OneResultOp<"load", [FirAliasTagOpInterface]> {
let summary = "load a value from a memory reference";
let description = [{
Load a value from a memory reference into an ssa-value (virtual register).
@@ -274,9 +276,11 @@ def fir_LoadOp : fir_OneResultOp<"load", []> {
or null.
}];
- let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref);
+ let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref,
+ OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
- let builders = [OpBuilder<(ins "mlir::Value":$refVal)>];
+ let builders = [OpBuilder<(ins "mlir::Value":$refVal)>,
+ OpBuilder<(ins "mlir::Type":$resTy, "mlir::Value":$refVal)>];
let hasCustomAssemblyFormat = 1;
@@ -285,7 +289,7 @@ def fir_LoadOp : fir_OneResultOp<"load", []> {
}];
}
-def fir_StoreOp : fir_Op<"store", []> {
+def fir_StoreOp : fir_Op<"store", [FirAliasTagOpInterface]> {
let summary = "store an SSA-value to a memory location";
let description = [{
@@ -305,7 +309,10 @@ def fir_StoreOp : fir_Op<"store", []> {
}];
let arguments = (ins AnyType:$value,
- Arg<AnyReferenceLike, "", [MemWrite]>:$memref);
+ Arg<AnyReferenceLike, "", [MemWrite]>:$memref,
+ OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa);
+
+ let builders = [OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$memref)>];
let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;
diff --git a/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.h b/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.h
new file mode 100644
index 000000000000000..f2d5b39acf3a723
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.h
@@ -0,0 +1,27 @@
+//===- FirAliasTagOpInterface.h ---------------------------------*- 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 contains an interface for adding alias analysis information to
+// loads and stores
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_FIR_ALIAS_TAG_OP_INTERFACE_H
+#define FORTRAN_OPTIMIZER_DIALECT_FIR_ALIAS_TAG_OP_INTERFACE_H
+
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/Support/LogicalResult.h"
+
+namespace fir::detail {
+mlir::LogicalResult verifyFirAliasTagOpInterface(mlir::Operation *op);
+} // namespace fir::detail
+
+#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_FIR_ALIAS_TAG_OP_INTERFACE_H
diff --git a/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.td b/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.td
new file mode 100644
index 000000000000000..9ce720f3b1a5722
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/FirAliasTagOpInterface.td
@@ -0,0 +1,59 @@
+//===-- FirAliasTagOpInterface.td --------------------------*- tablegen -*-===//
+//
+// 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/IR/Interfaces.td"
+
+def FirAliasTagOpInterface : OpInterface<"FirAliasTagOpInterface"> {
+ let description = [{
+ An interface for memory operations that can carry alias analysis metadata.
+ It provides setters and getters for the operation's alias analysis
+ attributes. The default implementations of the interface methods expect
+ the operation to have an attribute of type ArrayAttr named tbaa.
+ Unlike the mlir::LLVM::AliasAnalysisOpInterface, this only supports tbaa.
+ }];
+
+ let cppNamespace = "::fir";
+ let verify = [{ return detail::verifyFirAliasTagOpInterface($_op); }];
+
+ let methods = [
+ InterfaceMethod<
+ /*desc=*/ "Returns the tbaa attribute or nullptr",
+ /*returnType=*/ "mlir::ArrayAttr",
+ /*methodName=*/ "getTBAATagsOrNull",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ auto op = mlir::cast<ConcreteOp>(this->getOperation());
+ return op.getTbaaAttr();
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Sets the tbaa attribute",
+ /*returnType=*/ "void",
+ /*methodName=*/ "setTBAATags",
+ /*args=*/ (ins "const mlir::ArrayAttr":$attr),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ auto op = mlir::cast<ConcreteOp>(this->getOperation());
+ op.setTbaaAttr(attr);
+ }]
+ >,
+ InterfaceMethod<
+ /*desc=*/ "Returns a list of all pointer operands accessed by the "
+ "operation",
+ /*returnType=*/ "::llvm::SmallVector<::mlir::Value>",
+ /*methodName=*/ "getAccessedOperands",
+ /*args=*/ (ins),
+ /*methodBody=*/ [{}],
+ /*defaultImpl=*/ [{
+ auto op = mlir::cast<ConcreteOp>(this->getOperation());
+ return {op.getMemref()};
+ }]
+ >
+ ];
+}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 5bf6b87615c685d..3559d9c95fe7671 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3086,7 +3086,10 @@ struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
auto boxValue = rewriter.create<mlir::LLVM::LoadOp>(
loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
inputBoxStorage);
- attachTBAATag(boxValue, boxTy, boxTy, nullptr);
+ if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
+ boxValue.setTBAATags(*optionalTag);
+ else
+ attachTBAATag(boxValue, boxTy, boxTy, nullptr);
auto newBoxStorage =
genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
auto storeOp =
@@ -3097,7 +3100,10 @@ struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
mlir::Type loadTy = convertType(load.getType());
auto loadOp = rewriter.create<mlir::LLVM::LoadOp>(
load.getLoc(), loadTy, adaptor.getOperands(), load->getAttrs());
- attachTBAATag(loadOp, load.getType(), load.getType(), nullptr);
+ if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
+ loadOp.setTBAATags(*optionalTag);
+ else
+ attachTBAATag(loadOp, load.getType(), load.getType(), nullptr);
rewriter.replaceOp(load, loadOp.getResult());
}
return mlir::success();
@@ -3341,7 +3347,10 @@ struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
newStoreOp = rewriter.create<mlir::LLVM::StoreOp>(
loc, adaptor.getOperands()[0], adaptor.getOperands()[1]);
}
- attachTBAATag(newStoreOp, storeTy, storeTy, nullptr);
+ if (std::optional<mlir::ArrayAttr> optionalTag = store.getTbaa())
+ newStoreOp.setTBAATags(*optionalTag);
+ else
+ attachTBAATag(newStoreOp, storeTy, storeTy, nullptr);
rewriter.eraseOp(store);
return mlir::success();
}
diff --git a/flang/lib/Optimizer/Dialect/CMakeLists.txt b/flang/lib/Optimizer/Dialect/CMakeLists.txt
index fe5edb54a78e9e5..745439b7e1e5e87 100644
--- a/flang/lib/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/lib/Optimizer/Dialect/CMakeLists.txt
@@ -6,6 +6,7 @@ add_flang_library(FIRDialect
FIROps.cpp
FIRType.cpp
FortranVariableInterface.cpp
+ FirAliasTagOpInterface.cpp
Inliner.cpp
DEPENDS
diff --git a/flang/lib/Optimizer/Dialect/FIRDialect.cpp b/flang/lib/Optimizer/Dialect/FIRDialect.cpp
index c2377f112be8473..997a6c90ada314a 100644
--- a/flang/lib/Optimizer/Dialect/FIRDialect.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRDialect.cpp
@@ -14,6 +14,7 @@
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Transforms/InliningUtils.h"
using namespace fir;
@@ -58,6 +59,7 @@ struct FIRInlinerInterface : public mlir::DialectInlinerInterface {
fir::FIROpsDialect::FIROpsDialect(mlir::MLIRContext *ctx)
: mlir::Dialect("fir", ctx, mlir::TypeID::get<FIROpsDialect>()) {
+ getContext()->loadDialect<mlir::LLVM::LLVMDialect>();
registerTypes();
registerAttributes();
addOperations<
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index d60e5e9657ea0f4..c35147f6d07b8d7 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1977,8 +1977,18 @@ void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
mlir::emitError(result.location, "not a memory reference type");
return;
}
+ build(builder, result, eleTy, refVal);
+}
+
+void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
+ mlir::Type resTy, mlir::Value refVal) {
+
+ if (!refVal) {
+ mlir::emitError(result.location, "LoadOp has null argument");
+ return;
+ }
result.addOperands(refVal);
- result.addTypes(eleTy);
+ result.addTypes(resTy);
}
mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) {
@@ -3249,6 +3259,11 @@ mlir::LogicalResult fir::StoreOp::verify() {
return mlir::success();
}
+void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
+ mlir::Value value, mlir::Value memref) {
+ build(builder, result, value, memref, {});
+}
+
//===----------------------------------------------------------------------===//
// StringLitOp
//===----------------------------------------------------------------------===//
diff --git a/flang/lib/Optimizer/Dialect/FirAliasTagOpInterface.cpp b/flang/lib/Optimizer/Dialect/FirAliasTagOpInterface.cpp
new file mode 100644
index 000000000000000..648f490f63bf364
--- /dev/null
+++ b/flang/lib/Optimizer/Dialect/FirAliasTagOpInterface.cpp
@@ -0,0 +1,31 @@
+//===-- FirAliasTagOpInterface.cpp ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+
+#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.cpp.inc"
+
+mlir::LogicalResult
+fir::detail::verifyFirAliasTagOpInterface(mlir::Operation *op) {
+ auto iface = mlir::cast<FirAliasTagOpInterface>(op);
+
+ mlir::ArrayAttr tags = iface.getTBAATagsOrNull();
+ if (!tags)
+ return mlir::success();
+
+ for (mlir::Attribute iter : tags)
+ if (!mlir::isa<mlir::LLVM::TBAATagAttr>(iter))
+ return op->emitOpError("expected op to return array of ")
+ << mlir::LLVM::TBAATagAttr::getMnemonic() << " attributes";
+ return mlir::success();
+}
diff --git a/flang/test/Fir/tbaa-codegen.fir b/flang/test/Fir/tbaa-codegen.fir
new file mode 100644
index 000000000000000..386fe42eaaba9a2
--- /dev/null
+++ b/flang/test/Fir/tbaa-codegen.fir
@@ -0,0 +1,47 @@
+// test that tbaa attributes can be added to fir.load and fir.store
+// and that these attributes are propagated to LLVMIR
+
+// RUN: tco %s | FileCheck %s
+
+// subroutine simple(a)
+// integer, intent(inout) :: a(:)
+// a(1) = a(2)
+// end subroutine
+#tbaa_root = #llvm.tbaa_root<id = "Flang function root _QPsimple">
+#tbaa_type_desc = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+#tbaa_type_desc1 = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+#tbaa_type_desc2 = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
+#tbaa_type_desc3 = #llvm.tbaa_type_desc<id = "dummy arg data/a", members = {<#tbaa_type_desc2, 0>}>
+#tbaa_tag = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
+module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
+ func.func @_QPsimple(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
+ %c1 = arith.constant 1 : index
+ %c2 = arith.constant 2 : index
+ %0 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QFfuncEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %1 = fir.rebox %0 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %2 = fir.array_coor %1 %c2 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+ %3 = fir.load %2 {tbaa = [#tbaa_tag]} : !fir.ref<i32>
+ %4 = fir.array_coor %1 %c1 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+ fir.store %3 to %4 {tbaa = [#tbaa_tag]} : !fir.ref<i32>
+ return
+ }
+}
+
+// CHECK-LABEL: define void @_QPsimple(
+// CHECK-SAME: ptr %[[ARG0:.*]]) {
+// [...]
+// load a(2):
+// CHECK: %[[VAL20:.*]] = getelementptr i8, ptr %{{.*}}, i64 %{{.*}}
+// CHECK: %[[A2:.*]] = load i32, ptr %[[VAL20]], align 4, !tbaa ![[A_ACCESS_TAG:.*]]
+// [...]
+// store a(2) to a(1):
+// CHECK: %[[A1:.*]] = getelementptr i8, ptr %{{.*}}, i64 %{{.*}}
+// CHECK: store i32 %[[A2]], ptr %[[A1]], align 4, !tbaa ![[A_ACCESS_TAG]]
+// CHECK: ret void
+// CHECK: }
+// CHECK: ![[A_ACCESS_TAG]] = !{![[A_ACCESS_TYPE:.*]], ![[A_ACCESS_TYPE]], i64 0}
+// CHECK: ![[A_ACCESS_TYPE]] = !{!"dummy arg data/a", ![[DUMMY_ARG_TYPE:.*]], i64 0}
+// CHECK: ![[DUMMY_ARG_TYPE]] = !{!"dummy arg data", ![[DATA_ACCESS_TYPE:.*]], i64 0}
+// CHECK: ![[DATA_ACCESS_TYPE]] = !{!"any data access", ![[ANY_ACCESS_TYPE:.*]], i64 0}
+// CHECK: ![[ANY_ACCESS_TYPE]] = !{!"any access", ![[ROOT:.*]], i64 0}
+// CHECK: ![[ROOT]] = !{!"Flang function root _QPsimple"}
\ No newline at end of file
More information about the flang-commits
mailing list