llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-temporal-safety

Author: Utkarsh Saxena (usx95)

<details>
<summary>Changes</summary>

Optimize lifetime safety analysis performance

- Added early return optimization in `join` function for ImmutableSet when sets 
are identical
- Improved ImmutableMap join logic to avoid unnecessary operations when values 
are equal

I was under the impression that ImmutableSets/Maps would not modify the 
underlying if already existing elements are added to the container (and was 
hoping for structural equality in this aspect). It looks like the current 
implementation of `ImmutableSet` would perform addition nevertheless thereby 
creating (presumably `O(log(N))` tree nodes.

This change considerably brings down compile times for some edge cases which 
happened to be present in the LLVM codebase. Now it is actually possible to 
compile LLVM in under 20 min with the lifetime analysis.
The compile time hit is still significant but not as bad as before this change 
where it was not possible to compile LLVM without severely limiting analysis' 
scope (giving up on CFG with &gt; 3000 blocks).

Fixes https://github.com/llvm/llvm-project/issues/157420

---
Full diff: https://github.com/llvm/llvm-project/pull/159582.diff


2 Files Affected:

- (modified) clang/lib/Analysis/LifetimeSafety.cpp (+6-3) 
- (modified) clang/test/Analysis/LifetimeSafety/benchmark.py (+6-5) 


``````````diff
diff --git a/clang/lib/Analysis/LifetimeSafety.cpp 
b/clang/lib/Analysis/LifetimeSafety.cpp
index 0dd5716d93fb6..ddcdd0e72a723 100644
--- a/clang/lib/Analysis/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety.cpp
@@ -910,6 +910,8 @@ template <typename T>
 static llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A,
                                   llvm::ImmutableSet<T> B,
                                   typename llvm::ImmutableSet<T>::Factory &F) {
+  if (A == B)
+    return A;
   if (A.getHeight() < B.getHeight())
     std::swap(A, B);
   for (const T &E : B)
@@ -947,10 +949,11 @@ join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> 
B,
   for (const auto &Entry : B) {
     const K &Key = Entry.first;
     const V &ValB = Entry.second;
-    if (const V *ValA = A.lookup(Key))
-      A = F.add(A, Key, JoinValues(*ValA, ValB));
-    else
+    const V *ValA = A.lookup(Key);
+    if (!ValA)
       A = F.add(A, Key, ValB);
+    else if (*ValA != ValB)
+      A = F.add(A, Key, JoinValues(*ValA, ValB));
   }
   return A;
 }
diff --git a/clang/test/Analysis/LifetimeSafety/benchmark.py 
b/clang/test/Analysis/LifetimeSafety/benchmark.py
index 4421fe9a81e21..2373f9984eecd 100644
--- a/clang/test/Analysis/LifetimeSafety/benchmark.py
+++ b/clang/test/Analysis/LifetimeSafety/benchmark.py
@@ -252,7 +252,7 @@ def generate_markdown_report(results: dict) -> str:
             report.append(" ".join(row))
 
         report.append("\n**Complexity Analysis:**\n")
-        report.append("| Analysis Phase    | Complexity O(n<sup>k</sup>) |")
+        report.append("| Analysis Phase    | Complexity O(n<sup>k</sup>) | ")
         report.append("|:------------------|:--------------------------|")
 
         analysis_phases = {
@@ -302,7 +302,7 @@ def run_single_test(
         source_file,
     ]
 
-    result = subprocess.run(clang_command, capture_output=True, text=True)
+    result = subprocess.run(clang_command, capture_output=True, text=True, 
timeout=60)
 
     if result.returncode != 0:
         print(f"Compilation failed for N={n}!", file=sys.stderr)
@@ -334,24 +334,25 @@ def run_single_test(
     os.makedirs(args.output_dir, exist_ok=True)
     print(f"Benchmark files will be saved in: 
{os.path.abspath(args.output_dir)}\n")
 
+    # Maximize 'n' values while keeping execution time under 10s.
     test_configurations = [
         {
             "name": "cycle",
             "title": "Pointer Cycle in Loop",
             "generator_func": generate_cpp_cycle_test,
-            "n_values": [10, 25, 50, 75, 100, 150],
+            "n_values": [25, 50, 75, 100],
         },
         {
             "name": "merge",
             "title": "CFG Merges",
             "generator_func": generate_cpp_merge_test,
-            "n_values": [10, 50, 100, 200, 400, 800],
+            "n_values": [400, 1000, 2000, 5000],
         },
         {
             "name": "nested_loops",
             "title": "Deeply Nested Loops",
             "generator_func": generate_cpp_nested_loop_test,
-            "n_values": [10, 50, 100, 200, 400, 800],
+            "n_values": [50, 100, 150, 200],
         },
     ]
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/159582
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to