[llvm] [Propeller] CFG drift detect (PR #80431)

via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 2 05:17:12 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: None (lifengxiang1025)

<details>
<summary>Changes</summary>

Now Propeller only detect code drift when using pgo together. This patch aims to add the ability to detect cfg drift.

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


3 Files Affected:

- (modified) llvm/include/llvm/CodeGen/MachineBasicBlock.h (+1-1) 
- (modified) llvm/lib/CodeGen/BasicBlockSections.cpp (+53) 
- (added) llvm/test/CodeGen/X86/basic-block-sections-cfg-drift-detect.ll (+67) 


``````````diff
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index dc2035fa598c4..c3d8f14313d0f 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -659,7 +659,7 @@ class MachineBasicBlock
 
   /// Sets the fixed BBID of this basic block.
   void setBBID(const UniqueBBID &V) {
-    assert(!BBID.has_value() && "Cannot change BBID.");
+    assert((!BBID.has_value() || BBID->BaseID == 0) && "Cannot change BBID.");
     BBID = V;
   }
 
diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index eb3f9e7078f1a..4ca278f405d54 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -79,6 +79,8 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Target/TargetMachine.h"
 #include <optional>
+#include <queue>
+#include <unordered_set>
 
 using namespace llvm;
 
@@ -97,6 +99,17 @@ static cl::opt<bool> BBSectionsDetectSourceDrift(
              "mismatch for this function"),
     cl::init(true), cl::Hidden);
 
+static cl::opt<bool> BBSectionsDetectCFGDrift(
+    "bbsections-detect-cfg-drift",
+    cl::desc("This checks if function's cfg hash mismatch "
+             "with cfg hash recorded in profile"),
+    cl::init(false), cl::Hidden);
+
+static cl::opt<bool>
+    FirstMBBContainCFGHash("first-mbb-contain-cfg-hash",
+                           cl::desc("Use cfg hash as first mbb base id"),
+                           cl::init(false), cl::Hidden);
+
 namespace {
 
 class BasicBlockSections : public MachineFunctionPass {
@@ -284,9 +297,44 @@ bool llvm::hasInstrProfHashMismatch(MachineFunction &MF) {
   return false;
 }
 
+static uint64_t getCFGMD5(MachineFunction &MF) {
+  std::unordered_set<MachineBasicBlock *> Visited;
+  MD5 Hash;
+  std::queue<MachineBasicBlock *> Q;
+  if (!MF.empty()) {
+    Q.push(&*MF.begin());
+    Visited.insert(&*MF.begin());
+  }
+  while (!Q.empty()) {
+    MachineBasicBlock *Now = Q.front();
+    Q.pop();
+    using namespace llvm::support;
+    uint64_t Value = endian::byte_swap<uint32_t, llvm::endianness::little>(
+        Now->getBBID()->BaseID);
+    Hash.update(llvm::ArrayRef((uint8_t *)&Value, sizeof(Value)));
+    for (auto Iter = Now->succ_begin(); Iter != Now->succ_end(); Iter++) {
+      if (Visited.count(&**Iter)) {
+        continue;
+      }
+      Q.push(&**Iter);
+      Visited.insert(&**Iter);
+    }
+  }
+  llvm::MD5::MD5Result Result;
+  Hash.final(Result);
+  return Result.low();
+}
+
 // Identify, arrange, and modify basic blocks which need separate sections
 // according to the specification provided by the -fbasic-block-sections flag.
 bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
+  unsigned CFGHash = 0;
+  if (BBSectionsDetectCFGDrift) {
+    CFGHash = static_cast<unsigned>(getCFGMD5(MF));
+    if (FirstMBBContainCFGHash)
+      MF.begin()->setBBID({CFGHash, 0});
+  }
+
   auto BBSectionsType = MF.getTarget().getBBSectionsType();
   if (BBSectionsType == BasicBlockSection::None)
     return false;
@@ -316,6 +364,11 @@ bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
             .getClusterInfoForFunction(MF.getName());
     if (!HasProfile)
       return false;
+    // Check for cfg drift.
+    if (BBSectionsDetectCFGDrift &&
+        ClusterInfo.begin()->BBID.BaseID != CFGHash) {
+      return false;
+    }
     for (auto &BBClusterInfo : ClusterInfo) {
       FuncClusterInfo.try_emplace(BBClusterInfo.BBID, BBClusterInfo);
     }
diff --git a/llvm/test/CodeGen/X86/basic-block-sections-cfg-drift-detect.ll b/llvm/test/CodeGen/X86/basic-block-sections-cfg-drift-detect.ll
new file mode 100644
index 0000000000000..4e44c0bc6128a
--- /dev/null
+++ b/llvm/test/CodeGen/X86/basic-block-sections-cfg-drift-detect.ll
@@ -0,0 +1,67 @@
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=labels -first-mbb-contain-cfg-hash=true -bbsections-detect-cfg-drift=true | FileCheck %s -check-prefix=HASH
+
+; RUN: echo '!_Z3fooi' > %t1
+; RUN: echo '!!2561660837 2' >> %t1
+; RUN: echo '!!1' >> %t1
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t1 -first-mbb-contain-cfg-hash=true -bbsections-detect-cfg-drift=true | FileCheck %s -check-prefix=MATCH
+
+; RUN: echo '!_Z3fooi' > %t1
+; RUN: echo '!!11111111 2' >> %t1
+; RUN: echo '!!1' >> %t1
+; RUN: llc < %s -O0 -mtriple=x86_64-pc-linux -function-sections -basic-block-sections=%t1 -first-mbb-contain-cfg-hash=true -bbsections-detect-cfg-drift=true | FileCheck %s -check-prefix=MISMATCH
+
+; HASH: .ascii	"\245\257\277\305\t"            # BB id
+; MATCH: callq	_Z3bazi at PLT
+; MATCH: callq	_Z3bari at PLT
+; MISMATCH: callq	_Z3bari at PLT
+; MISMATCH: callq	_Z3bazi at PLT
+
+; ModuleID = 'foo.cc'
+source_filename = "foo.cc"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: mustprogress noinline optnone uwtable
+define dso_local noundef i32 @_Z3fooi(i32 noundef %a) #0 {
+entry:
+  %retval = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  store i32 %a, ptr %a.addr, align 4
+  %0 = load i32, ptr %a.addr, align 4
+  %and = and i32 %0, 1
+  %tobool = icmp ne i32 %and, 0
+  br i1 %tobool, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, ptr %a.addr, align 4
+  %call = call noundef i32 @_Z3bari(i32 noundef %1)
+  store i32 %call, ptr %retval, align 4
+  br label %return
+
+if.end:                                           ; preds = %entry
+  %2 = load i32, ptr %a.addr, align 4
+  %call1 = call noundef i32 @_Z3bazi(i32 noundef %2)
+  store i32 %call1, ptr %retval, align 4
+  br label %return
+
+return:                                           ; preds = %if.end, %if.then
+  %3 = load i32, ptr %retval, align 4
+  ret i32 %3
+}
+
+declare noundef i32 @_Z3bari(i32 noundef) #1
+
+declare noundef i32 @_Z3bazi(i32 noundef) #1
+
+attributes #0 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+!llvm.ident = !{!5}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{i32 7, !"frame-pointer", i32 2}
+!5 = !{!"clang version 18.0.0"}

``````````

</details>


https://github.com/llvm/llvm-project/pull/80431


More information about the llvm-commits mailing list