1 | //===- FunctionAttr.cpp ---------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | //===----------------------------------------------------------------------===// |
10 | /// \file |
11 | /// This is a generic pass for adding attributes to functions. |
12 | //===----------------------------------------------------------------------===// |
13 | #include "flang/Optimizer/Dialect/FIROpsSupport.h" |
14 | #include "flang/Optimizer/Support/InternalNames.h" |
15 | #include "flang/Optimizer/Transforms/Passes.h" |
16 | #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" |
17 | #include "mlir/Dialect/LLVMIR/LLVMDialect.h" |
18 | |
19 | namespace fir { |
20 | #define GEN_PASS_DEF_FUNCTIONATTR |
21 | #include "flang/Optimizer/Transforms/Passes.h.inc" |
22 | } // namespace fir |
23 | |
24 | #define DEBUG_TYPE "func-attr" |
25 | |
26 | namespace { |
27 | |
28 | class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> { |
29 | public: |
30 | FunctionAttrPass(const fir::FunctionAttrOptions &options) : Base{options} {} |
31 | FunctionAttrPass() = default; |
32 | void runOnOperation() override; |
33 | }; |
34 | |
35 | } // namespace |
36 | |
37 | void FunctionAttrPass::runOnOperation() { |
38 | LLVM_DEBUG(llvm::dbgs() << "=== Begin " DEBUG_TYPE " ===\n" ); |
39 | mlir::func::FuncOp func = getOperation(); |
40 | |
41 | LLVM_DEBUG(llvm::dbgs() << "Func-name:" << func.getSymName() << "\n" ); |
42 | |
43 | llvm::StringRef name = func.getSymName(); |
44 | auto deconstructed = fir::NameUniquer::deconstruct(name); |
45 | bool isFromModule = !deconstructed.second.modules.empty(); |
46 | |
47 | if ((isFromModule || !func.isDeclaration()) && |
48 | !fir::hasBindcAttr(func.getOperation())) { |
49 | llvm::StringRef nocapture = mlir::LLVM::LLVMDialect::getNoCaptureAttrName(); |
50 | llvm::StringRef noalias = mlir::LLVM::LLVMDialect::getNoAliasAttrName(); |
51 | mlir::UnitAttr unitAttr = mlir::UnitAttr::get(func.getContext()); |
52 | |
53 | for (auto [index, argType] : llvm::enumerate(func.getArgumentTypes())) { |
54 | bool isNoCapture = false; |
55 | bool isNoAlias = false; |
56 | if (mlir::isa<fir::ReferenceType>(argType) && |
57 | !func.getArgAttr(index, fir::getTargetAttrName()) && |
58 | !func.getArgAttr(index, fir::getAsynchronousAttrName()) && |
59 | !func.getArgAttr(index, fir::getVolatileAttrName())) { |
60 | isNoCapture = true; |
61 | isNoAlias = !fir::isPointerType(argType); |
62 | } else if (mlir::isa<fir::BaseBoxType>(argType)) { |
63 | // !fir.box arguments will be passed as descriptor pointers |
64 | // at LLVM IR dialect level - they cannot be captured, |
65 | // and cannot alias with anything within the function. |
66 | isNoCapture = isNoAlias = true; |
67 | } |
68 | if (isNoCapture && setNoCapture) |
69 | func.setArgAttr(index, nocapture, unitAttr); |
70 | if (isNoAlias && setNoAlias) |
71 | func.setArgAttr(index, noalias, unitAttr); |
72 | } |
73 | } |
74 | |
75 | mlir::MLIRContext *context = &getContext(); |
76 | if (framePointerKind != mlir::LLVM::framePointerKind::FramePointerKind::None) |
77 | func->setAttr("frame_pointer" , mlir::LLVM::FramePointerKindAttr::get( |
78 | context, framePointerKind)); |
79 | |
80 | auto llvmFuncOpName = |
81 | mlir::OperationName(mlir::LLVM::LLVMFuncOp::getOperationName(), context); |
82 | if (!instrumentFunctionEntry.empty()) |
83 | func->setAttr(mlir::LLVM::LLVMFuncOp::getInstrumentFunctionEntryAttrName( |
84 | llvmFuncOpName), |
85 | mlir::StringAttr::get(context, instrumentFunctionEntry)); |
86 | if (!instrumentFunctionExit.empty()) |
87 | func->setAttr(mlir::LLVM::LLVMFuncOp::getInstrumentFunctionExitAttrName( |
88 | llvmFuncOpName), |
89 | mlir::StringAttr::get(context, instrumentFunctionExit)); |
90 | if (noInfsFPMath) |
91 | func->setAttr( |
92 | mlir::LLVM::LLVMFuncOp::getNoInfsFpMathAttrName(llvmFuncOpName), |
93 | mlir::BoolAttr::get(context, true)); |
94 | if (noNaNsFPMath) |
95 | func->setAttr( |
96 | mlir::LLVM::LLVMFuncOp::getNoNansFpMathAttrName(llvmFuncOpName), |
97 | mlir::BoolAttr::get(context, true)); |
98 | if (approxFuncFPMath) |
99 | func->setAttr( |
100 | mlir::LLVM::LLVMFuncOp::getApproxFuncFpMathAttrName(llvmFuncOpName), |
101 | mlir::BoolAttr::get(context, true)); |
102 | if (noSignedZerosFPMath) |
103 | func->setAttr( |
104 | mlir::LLVM::LLVMFuncOp::getNoSignedZerosFpMathAttrName(llvmFuncOpName), |
105 | mlir::BoolAttr::get(context, true)); |
106 | if (unsafeFPMath) |
107 | func->setAttr( |
108 | mlir::LLVM::LLVMFuncOp::getUnsafeFpMathAttrName(llvmFuncOpName), |
109 | mlir::BoolAttr::get(context, true)); |
110 | if (!reciprocals.empty()) |
111 | func->setAttr( |
112 | mlir::LLVM::LLVMFuncOp::getReciprocalEstimatesAttrName(llvmFuncOpName), |
113 | mlir::StringAttr::get(context, reciprocals)); |
114 | if (!preferVectorWidth.empty()) |
115 | func->setAttr( |
116 | mlir::LLVM::LLVMFuncOp::getPreferVectorWidthAttrName(llvmFuncOpName), |
117 | mlir::StringAttr::get(context, preferVectorWidth)); |
118 | |
119 | LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n" ); |
120 | } |
121 | |