Index: llvm/include/llvm/Analysis/FunctionAnnotation.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/FunctionAnnotation.h @@ -0,0 +1,32 @@ +//= FunctionAnnotation.h - Function Annotation with Function Attributes- 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 defines the FunctionAnnotation class used to annotate functions +// with function attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_FUNCTIONANNOTATION_H_ +#define LLVM_ANALYSIS_FUNCTIONANNOTATION_H_ + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class FunctionAnnotation : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + +public: + using Result = StringRef; + Result run(Function &F, FunctionAnalysisManager &FAM); +}; + +} // namespace llvm + +#endif // LLVM_ANALYSIS_FUNCTIONANNOTATION_H_ Index: llvm/lib/Analysis/CMakeLists.txt =================================================================== --- llvm/lib/Analysis/CMakeLists.txt +++ llvm/lib/Analysis/CMakeLists.txt @@ -69,6 +69,7 @@ DomTreeUpdater.cpp DominanceFrontier.cpp EHPersonalities.cpp + FunctionAnnotation.cpp FunctionPropertiesAnalysis.cpp GlobalsModRef.cpp GuardUtils.cpp Index: llvm/lib/Analysis/FunctionAnnotation.cpp =================================================================== --- /dev/null +++ llvm/lib/Analysis/FunctionAnnotation.cpp @@ -0,0 +1,71 @@ +//=== FunctionAnnotation.cpp - Function Annotation with Function Attributes ==// +// +// 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 implements the FunctionAnnotation class used to annotate functions +// with function attributes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/FunctionAnnotation.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include + +namespace llvm { + +static cl::opt FunctionAnnotationAttributeName( + "func-annotate-attribute-name", cl::init(""), cl::Hidden, + cl::desc("Specify the name of the attribute to annotate functions with.")); + +static cl::opt FunctionAnnotationCSVPath( + "func-annotate-csv-path", cl::init("-"), cl::Hidden, + cl::desc("Specify the path to the CSV file containing the functions and " + "their attribute values.\nCSV file header should have the format: " + "[Index, Function Name, Attribute Value]")); + +AnalysisKey FunctionAnnotation::Key; + +FunctionAnnotation::Result +FunctionAnnotation::run(Function &F, FunctionAnalysisManager &AM) { + const StringRef FunctionName = F.getName(); + + if (FunctionAnnotationAttributeName.empty()) { + report_fatal_error( + "Name of the function annotation attribute not specified."); + } + const Attribute &A = F.getFnAttribute(FunctionAnnotationAttributeName); + const StringRef FnOptLevel = A.getValueAsString(); + + if (FnOptLevel.empty()) { + std::ifstream InputFile; + InputFile.open(FunctionAnnotationCSVPath); + if (!InputFile.is_open()) { + report_fatal_error("Function annotation CSV file not found."); + } + + std::string Line; + while (std::getline(InputFile, Line)) { + std::istringstream ISS(Line); + std::string ID, Name, OLevel; + + if (std::getline(ISS, ID, ',') && std::getline(ISS, Name, ',') && + std::getline(ISS, OLevel)) { + char *endp = nullptr; + if (Name.c_str() != endp && Name == FunctionName) { + F.addFnAttr(FunctionAnnotationAttributeName, OLevel); + break; + } + } + } + InputFile.close(); + } + return FnOptLevel; +} + +} // namespace llvm Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -34,6 +34,7 @@ #include "llvm/Analysis/DependenceAnalysis.h" #include "llvm/Analysis/DivergenceAnalysis.h" #include "llvm/Analysis/DominanceFrontier.h" +#include "llvm/Analysis/FunctionAnnotation.h" #include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/IRSimilarityIdentifier.h" Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -155,6 +155,7 @@ FUNCTION_ANALYSIS("postdomtree", PostDominatorTreeAnalysis()) FUNCTION_ANALYSIS("demanded-bits", DemandedBitsAnalysis()) FUNCTION_ANALYSIS("domfrontier", DominanceFrontierAnalysis()) +FUNCTION_ANALYSIS("func-annotate", FunctionAnnotation()) FUNCTION_ANALYSIS("func-properties", FunctionPropertiesAnalysis()) FUNCTION_ANALYSIS("loops", LoopAnalysis()) FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis()) Index: llvm/test/Analysis/FunctionAnnotation/Inputs/matmul-look-up-table.csv =================================================================== --- /dev/null +++ llvm/test/Analysis/FunctionAnnotation/Inputs/matmul-look-up-table.csv @@ -0,0 +1,3 @@ +Index,Function,OptimizationLevel +0,multiply,O2 +1,main,O1 Index: llvm/test/Analysis/FunctionAnnotation/matmul.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/FunctionAnnotation/matmul.ll @@ -0,0 +1,125 @@ +; RUN: opt < %s -passes="require" -func-annotate-attribute-name=opt-level -func-annotate-csv-path=%S/Inputs/matmul-look-up-table.csv -S | FileCheck %s + +define i32 @main() { +; CHECK: define i32 @main() #0 +entry: + %retval = alloca i32, align 4 + %mat1 = alloca [2 x [2 x i32]], align 16 + %mat2 = alloca [2 x [2 x i32]], align 16 + %res = alloca [2 x [2 x i32]], align 16 + %i = alloca i32, align 4 + %j = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + %arraydecay = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %mat1, i64 0, i64 0 + %arraydecay1 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %mat2, i64 0, i64 0 + %arraydecay2 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %res, i64 0, i64 0 + call void @multiply([2 x i32]* %arraydecay, [2 x i32]* %arraydecay1, [2 x i32]* %arraydecay2) + ret i32 0 +} + +define void @multiply([2 x i32]* %mat1, [2 x i32]* %mat2, [2 x i32]* %res) { +; CHECK: define void @multiply([2 x i32]* %mat1, [2 x i32]* %mat2, [2 x i32]* %res) #1 +entry: + %mat1.addr = alloca [2 x i32]*, align 8 + %mat2.addr = alloca [2 x i32]*, align 8 + %res.addr = alloca [2 x i32]*, align 8 + %i = alloca i32, align 4 + %j = alloca i32, align 4 + %k = alloca i32, align 4 + store [2 x i32]* %mat1, [2 x i32]** %mat1.addr, align 8 + store [2 x i32]* %mat2, [2 x i32]** %mat2.addr, align 8 + store [2 x i32]* %res, [2 x i32]** %res.addr, align 8 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc24, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp slt i32 %0, 2 + br i1 %cmp, label %for.body, label %for.end26 + +for.body: ; preds = %for.cond + store i32 0, i32* %j, align 4 + br label %for.cond1 + +for.cond1: ; preds = %for.inc21, %for.body + %1 = load i32, i32* %j, align 4 + %cmp2 = icmp slt i32 %1, 2 + br i1 %cmp2, label %for.body3, label %for.end23 + +for.body3: ; preds = %for.cond1 + %2 = load [2 x i32]*, [2 x i32]** %res.addr, align 8 + %3 = load i32, i32* %i, align 4 + %idxprom = sext i32 %3 to i64 + %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 %idxprom + %4 = load i32, i32* %j, align 4 + %idxprom4 = sext i32 %4 to i64 + %arrayidx5 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx, i64 0, i64 %idxprom4 + store i32 0, i32* %arrayidx5, align 4 + store i32 0, i32* %k, align 4 + br label %for.cond6 + +for.cond6: ; preds = %for.inc, %for.body3 + %5 = load i32, i32* %k, align 4 + %cmp7 = icmp slt i32 %5, 2 + br i1 %cmp7, label %for.body8, label %for.end + +for.body8: ; preds = %for.cond6 + %6 = load [2 x i32]*, [2 x i32]** %mat1.addr, align 8 + %7 = load i32, i32* %i, align 4 + %idxprom9 = sext i32 %7 to i64 + %arrayidx10 = getelementptr inbounds [2 x i32], [2 x i32]* %6, i64 %idxprom9 + %8 = load i32, i32* %k, align 4 + %idxprom11 = sext i32 %8 to i64 + %arrayidx12 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx10, i64 0, i64 %idxprom11 + %9 = load i32, i32* %arrayidx12, align 4 + %10 = load [2 x i32]*, [2 x i32]** %mat2.addr, align 8 + %11 = load i32, i32* %k, align 4 + %idxprom13 = sext i32 %11 to i64 + %arrayidx14 = getelementptr inbounds [2 x i32], [2 x i32]* %10, i64 %idxprom13 + %12 = load i32, i32* %j, align 4 + %idxprom15 = sext i32 %12 to i64 + %arrayidx16 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx14, i64 0, i64 %idxprom15 + %13 = load i32, i32* %arrayidx16, align 4 + %mul = mul nsw i32 %9, %13 + %14 = load [2 x i32]*, [2 x i32]** %res.addr, align 8 + %15 = load i32, i32* %i, align 4 + %idxprom17 = sext i32 %15 to i64 + %arrayidx18 = getelementptr inbounds [2 x i32], [2 x i32]* %14, i64 %idxprom17 + %16 = load i32, i32* %j, align 4 + %idxprom19 = sext i32 %16 to i64 + %arrayidx20 = getelementptr inbounds [2 x i32], [2 x i32]* %arrayidx18, i64 0, i64 %idxprom19 + %17 = load i32, i32* %arrayidx20, align 4 + %add = add nsw i32 %17, %mul + store i32 %add, i32* %arrayidx20, align 4 + br label %for.inc + +for.inc: ; preds = %for.body8 + %18 = load i32, i32* %k, align 4 + %inc = add nsw i32 %18, 1 + store i32 %inc, i32* %k, align 4 + br label %for.cond6 + +for.end: ; preds = %for.cond6 + br label %for.inc21 + +for.inc21: ; preds = %for.end + %19 = load i32, i32* %j, align 4 + %inc22 = add nsw i32 %19, 1 + store i32 %inc22, i32* %j, align 4 + br label %for.cond1 + +for.end23: ; preds = %for.cond1 + br label %for.inc24 + +for.inc24: ; preds = %for.end23 + %20 = load i32, i32* %i, align 4 + %inc25 = add nsw i32 %20, 1 + store i32 %inc25, i32* %i, align 4 + br label %for.cond + +for.end26: ; preds = %for.cond + ret void +} + +; CHECK: attributes #0 = { "opt-level"="O1" } +; CHECK: attributes #1 = { "opt-level"="O2" }