| 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 | |