diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt index d657e3f166903..fe9864a26295d 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 d0735bbeb2d3d..b366b6d40e4e2 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 8f03dc5cf7952..87196dbf9b97d 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 a57add9f73197..13838f9992988 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:$memref); + let arguments = (ins Arg:$memref, + OptionalAttr:$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:$memref); + Arg:$memref, + OptionalAttr:$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 0000000000000..f2d5b39acf3a7 --- /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 0000000000000..9ce720f3b1a57 --- /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(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(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(this->getOperation()); + return {op.getMemref()}; + }] + > + ]; +} diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index d1b7f3de93b46..f2ce123124895 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3085,7 +3085,10 @@ struct LoadOpConversion : public FIROpConversion { auto boxValue = rewriter.create( loc, boxPtrTy.cast().getElementType(), inputBoxStorage); - attachTBAATag(boxValue, boxTy, boxTy, nullptr); + if (std::optional optionalTag = load.getTbaa()) + boxValue.setTBAATags(*optionalTag); + else + attachTBAATag(boxValue, boxTy, boxTy, nullptr); auto newBoxStorage = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); auto storeOp = @@ -3096,7 +3099,10 @@ struct LoadOpConversion : public FIROpConversion { mlir::Type loadTy = convertType(load.getType()); auto loadOp = rewriter.create( load.getLoc(), loadTy, adaptor.getOperands(), load->getAttrs()); - attachTBAATag(loadOp, load.getType(), load.getType(), nullptr); + if (std::optional optionalTag = load.getTbaa()) + loadOp.setTBAATags(*optionalTag); + else + attachTBAATag(loadOp, load.getType(), load.getType(), nullptr); rewriter.replaceOp(load, loadOp.getResult()); } return mlir::success(); @@ -3340,7 +3346,10 @@ struct StoreOpConversion : public FIROpConversion { newStoreOp = rewriter.create( loc, adaptor.getOperands()[0], adaptor.getOperands()[1]); } - attachTBAATag(newStoreOp, storeTy, storeTy, nullptr); + if (std::optional 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 fe5edb54a78e9..745439b7e1e5e 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 c2377f112be84..997a6c90ada31 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()) { + getContext()->loadDialect(); registerTypes(); registerAttributes(); addOperations< diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 962b87acd5a80..2f08cd1b81115 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -2016,8 +2016,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) { @@ -3288,6 +3298,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 0000000000000..648f490f63bf3 --- /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(op); + + mlir::ArrayAttr tags = iface.getTBAATagsOrNull(); + if (!tags) + return mlir::success(); + + for (mlir::Attribute iter : tags) + if (!mlir::isa(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 0000000000000..386fe42eaaba9 --- /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 +#tbaa_type_desc = #llvm.tbaa_type_desc}> +#tbaa_type_desc1 = #llvm.tbaa_type_desc}> +#tbaa_type_desc2 = #llvm.tbaa_type_desc}> +#tbaa_type_desc3 = #llvm.tbaa_type_desc}> +#tbaa_tag = #llvm.tbaa_tag +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.target_triple = "aarch64-unknown-linux-gnu"} { + func.func @_QPsimple(%arg0: !fir.box> {fir.bindc_name = "a"}) { + %c1 = arith.constant 1 : index + %c2 = arith.constant 2 : index + %0 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFfuncEa"} : (!fir.box>) -> !fir.box> + %1 = fir.rebox %0 : (!fir.box>) -> !fir.box> + %2 = fir.array_coor %1 %c2 : (!fir.box>, index) -> !fir.ref + %3 = fir.load %2 {tbaa = [#tbaa_tag]} : !fir.ref + %4 = fir.array_coor %1 %c1 : (!fir.box>, index) -> !fir.ref + fir.store %3 to %4 {tbaa = [#tbaa_tag]} : !fir.ref + 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