[llvm] ea9e47d - `ForceFunctionAttrs`: support overriding attributes via csv file

Mircea Trofin via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 7 15:39:45 PDT 2023


Author: Puneeth A R
Date: 2023-09-07T18:39:19-04:00
New Revision: ea9e47d534fb396b5792bef26d669dc0c2618af0

URL: https://github.com/llvm/llvm-project/commit/ea9e47d534fb396b5792bef26d669dc0c2618af0
DIFF: https://github.com/llvm/llvm-project/commit/ea9e47d534fb396b5792bef26d669dc0c2618af0.diff

LOG: `ForceFunctionAttrs`: support overriding attributes via csv file

Update `ForceFunctionAttrs` pass to optionally take its input from a csv file, for example, function-level optimization attributes. A subsequent patch will enable the pass pipeline to be aware of these attributes, and this pass will be used to test that is the case. Eventually, the annotations would be driven by an agent, e.g. a machine learning-based policy.

This patch is a part of GSoC 2023, more details can be found [[ https://summerofcode.withgoogle.com/programs/2023/projects/T8rB84Sr | here ]]

Reviewed By: mtrofin, aeubanks

Differential Revision: https://reviews.llvm.org/D155617

Added: 
    llvm/test/Transforms/ForcedFunctionAttrs/DoesNotExist.csv
    llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotation.csv
    llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotator.ll

Modified: 
    llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
index 46560aa4c3c5aca..9cf4e448c9b6f87 100644
--- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
@@ -11,6 +11,8 @@
 #include "llvm/IR/Module.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
@@ -36,6 +38,12 @@ static cl::list<std::string> ForceRemoveAttributes(
              "module. This "
              "option can be specified multiple times."));
 
+static cl::opt<std::string> CSVFilePath(
+    "forceattrs-csv-path", cl::Hidden,
+    cl::desc(
+        "Path to CSV file containing lines of function names and attributes to "
+        "add to them in the form of `f1,attr1` or `f2,attr2=str`."));
+
 /// If F has any forced attributes given on the command line, add them.
 /// If F has any forced remove attributes given on the command line, remove
 /// them. When both force and force-remove are given to a function, the latter
@@ -80,12 +88,52 @@ static bool hasForceAttributes() {
 
 PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
                                               ModuleAnalysisManager &) {
-  if (!hasForceAttributes())
-    return PreservedAnalyses::all();
-
-  for (Function &F : M.functions())
-    forceAttributes(F);
-
-  // Just conservatively invalidate analyses, this isn't likely to be important.
-  return PreservedAnalyses::none();
+  bool Changed = false;
+  if (!CSVFilePath.empty()) {
+    auto BufferOrError = MemoryBuffer::getFileOrSTDIN(CSVFilePath);
+    if (!BufferOrError)
+      report_fatal_error("Cannot open CSV file.");
+    StringRef Buffer = BufferOrError.get()->getBuffer();
+    auto MemoryBuffer = MemoryBuffer::getMemBuffer(Buffer);
+    line_iterator It(*MemoryBuffer);
+    for (; !It.is_at_end(); ++It) {
+      auto SplitPair = It->split(',');
+      if (SplitPair.second.empty())
+        continue;
+      Function *Func = M.getFunction(SplitPair.first);
+      if (Func) {
+        if (Func->isDeclaration())
+          continue;
+        auto SecondSplitPair = SplitPair.second.split('=');
+        if (!SecondSplitPair.second.empty()) {
+          Func->addFnAttr(SecondSplitPair.first, SecondSplitPair.second);
+          Changed = true;
+        } else {
+          auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
+          if (AttrKind != Attribute::None &&
+              Attribute::canUseAsFnAttr(AttrKind)) {
+            // TODO: There could be string attributes without a value, we should
+            // support those, too.
+            Func->addFnAttr(AttrKind);
+            Changed = true;
+          } else
+            errs() << "Cannot add " << SplitPair.second
+                   << " as an attribute name.\n";
+        }
+      } else {
+        errs() << "Function in CSV file at line " << It.line_number()
+               << " does not exist.\n";
+        // TODO: `report_fatal_error at end of pass for missing functions.
+        continue;
+      }
+    }
+  }
+  if (hasForceAttributes()) {
+    for (Function &F : M.functions())
+      forceAttributes(F);
+    Changed = true;
+  }
+  // Just conservatively invalidate analyses if we've made any changes, this
+  // isn't likely to be important.
+  return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
 }

diff  --git a/llvm/test/Transforms/ForcedFunctionAttrs/DoesNotExist.csv b/llvm/test/Transforms/ForcedFunctionAttrs/DoesNotExist.csv
new file mode 100644
index 000000000000000..fcef16514daa9de
--- /dev/null
+++ b/llvm/test/Transforms/ForcedFunctionAttrs/DoesNotExist.csv
@@ -0,0 +1 @@
+unknown_function,hot=cold

diff  --git a/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotation.csv b/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotation.csv
new file mode 100644
index 000000000000000..7606cdf9fa4df01
--- /dev/null
+++ b/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotation.csv
@@ -0,0 +1,5 @@
+first_function,opt-level=O1
+second_function,cold
+third_function,opt-level=O1
+fourth_function,opt-level=O2
+fifth_function,foo=bar

diff  --git a/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotator.ll b/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotator.ll
new file mode 100644
index 000000000000000..2789e830e587db9
--- /dev/null
+++ b/llvm/test/Transforms/ForcedFunctionAttrs/FunctionAnnotator.ll
@@ -0,0 +1,36 @@
+; RUN: opt -passes='forceattrs' -forceattrs-csv-path="%S/FunctionAnnotation.csv" -S < %s | FileCheck %s
+; RUN: opt -passes='forceattrs' -forceattrs-csv-path="%S/DoesNotExist.csv" -S < %s 2>&1 | FileCheck %s --check-prefix=NonexistentFunc
+define void @first_function() {
+; CHECK: @first_function() #0
+  ret void
+}
+
+define void @second_function() {
+; CHECK: @second_function() #1
+  ret void
+}
+
+define void @third_function() {
+; CHECK: @third_function() #0
+  ret void
+}
+
+define void @fourth_function() {
+; CHECK: @fourth_function() #2
+  ret void
+}
+
+define void @fifth_function() {
+; CHECK: @fifth_function() #3
+  ret void
+}
+
+; CHECK-LABEL: attributes #0 = { "opt-level"="O1" }
+
+; CHECK-LABEL: attributes #1 = { cold }
+
+; CHECK-LABEL: attributes #2 = { "opt-level"="O2" }
+
+; CHECK-LABEL: attributes #3 = { "foo"="bar" }
+
+; NonexistentFunc: Function in CSV file at line 1 does not exist.


        


More information about the llvm-commits mailing list