Skip to content

[SPIR-V] Add partial order tests, assert reducible #117887

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 28, 2024

Conversation

Keenuts
Copy link
Contributor

@Keenuts Keenuts commented Nov 27, 2024

Add testing for the visitor and added a note explaining irreducible CFG are not supported.
Related to #116692

@llvmbot
Copy link
Member

llvmbot commented Nov 27, 2024

@llvm/pr-subscribers-backend-spir-v

Author: Nathan Gauër (Keenuts)

Changes

Add testing for the visitor and added a note explaining irreducible CFG are not supported.
Related to #116692


Patch is 27.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/117887.diff

6 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVUtils.cpp (+9-1)
  • (modified) llvm/lib/Target/SPIRV/SPIRVUtils.h (+4-1)
  • (modified) llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll (+18-18)
  • (modified) llvm/test/CodeGen/SPIRV/structurizer/cf.switch.ifstmt.simple2.ll (+157-190)
  • (modified) llvm/unittests/Target/SPIRV/CMakeLists.txt (+2-2)
  • (added) llvm/unittests/Target/SPIRV/SPIRVSortBlocksTests.cpp (+342)
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index ad8dfa0e8811b7..ddba5e76e33fa5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -519,8 +519,11 @@ bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
 }
 
 size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
-  size_t result = 0;
+  auto It = BlockToOrder.find(BB);
+  if (It != BlockToOrder.end())
+    return It->second.Rank;
 
+  size_t result = 0;
   for (BasicBlock *P : predecessors(BB)) {
     // Ignore back-edges.
     if (DT.dominates(BB, P))
@@ -552,15 +555,20 @@ size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
   ToVisit.push(BB);
   Queued.insert(BB);
 
+  size_t QueueIndex = 0;
   while (ToVisit.size() != 0) {
     BasicBlock *BB = ToVisit.front();
     ToVisit.pop();
 
     if (!CanBeVisited(BB)) {
       ToVisit.push(BB);
+      assert(QueueIndex < ToVisit.size() &&
+             "No valid candidate in the queue. Is the graph reducible?");
+      QueueIndex++;
       continue;
     }
 
+    QueueIndex = 0;
     size_t Rank = GetNodeRank(BB);
     OrderInfo Info = {Rank, BlockToOrder.size()};
     BlockToOrder.emplace(BB, Info);
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index da0e8769cac1b6..d218dbd850dc7a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -41,6 +41,8 @@ class SPIRVSubtarget;
 // ignores back-edges. The cycle is visited from the entry in the same
 // topological-like ordering.
 //
+// Note: this visitor REQUIRES a reducible graph.
+//
 // This means once we visit a node, we know all the possible ancestors have been
 // visited.
 //
@@ -84,10 +86,11 @@ class PartialOrderingVisitor {
   // Visits |BB| with the current rank being |Rank|.
   size_t visit(BasicBlock *BB, size_t Rank);
 
-  size_t GetNodeRank(BasicBlock *BB) const;
   bool CanBeVisited(BasicBlock *BB) const;
 
 public:
+  size_t GetNodeRank(BasicBlock *BB) const;
+
   // Build the visitor to operate on the function F.
   PartialOrderingVisitor(Function &F);
 
diff --git a/llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll b/llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll
index a69475a59db6f4..95910edd6b4ce6 100644
--- a/llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll
+++ b/llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll
@@ -34,28 +34,28 @@
 ; CHECK:    %[[#bb30:]] = OpLabel
 ; CHECK:                  OpSelectionMerge %[[#bb31:]] None
 ; CHECK:                  OpBranchConditional %[[#]] %[[#bb32:]] %[[#bb33:]]
-; CHECK:    %[[#bb32:]] = OpLabel
+; CHECK:     %[[#bb32]] = OpLabel
 ; CHECK:                  OpSelectionMerge %[[#bb34:]] None
-; CHECK:                  OpBranchConditional %[[#]] %[[#bb35:]] %[[#bb34:]]
-; CHECK:    %[[#bb33:]] = OpLabel
+; CHECK:                  OpBranchConditional %[[#]] %[[#bb35:]] %[[#bb34]]
+; CHECK:     %[[#bb33]] = OpLabel
 ; CHECK:                  OpSelectionMerge %[[#bb36:]] None
 ; CHECK:                  OpBranchConditional %[[#]] %[[#bb37:]] %[[#bb38:]]
-; CHECK:    %[[#bb35:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb34:]]
-; CHECK:    %[[#bb37:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb36:]]
-; CHECK:    %[[#bb38:]] = OpLabel
+; CHECK:     %[[#bb35]] = OpLabel
+; CHECK:                  OpBranch %[[#bb34]]
+; CHECK:     %[[#bb37]] = OpLabel
+; CHECK:                  OpBranch %[[#bb36]]
+; CHECK:     %[[#bb38]] = OpLabel
 ; CHECK:                  OpSelectionMerge %[[#bb39:]] None
-; CHECK:                  OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb39:]]
-; CHECK:    %[[#bb34:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb31:]]
-; CHECK:    %[[#bb40:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb39:]]
-; CHECK:    %[[#bb39:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb36:]]
-; CHECK:    %[[#bb36:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb31:]]
-; CHECK:    %[[#bb31:]] = OpLabel
+; CHECK:                  OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb39]]
+; CHECK:     %[[#bb34]] = OpLabel
+; CHECK:                  OpBranch %[[#bb31]]
+; CHECK:     %[[#bb40]] = OpLabel
+; CHECK:                  OpBranch %[[#bb39]]
+; CHECK:     %[[#bb39]] = OpLabel
+; CHECK:                  OpBranch %[[#bb36]]
+; CHECK:     %[[#bb36]] = OpLabel
+; CHECK:                  OpBranch %[[#bb31]]
+; CHECK:     %[[#bb31]] = OpLabel
 ; CHECK:                  OpReturnValue %[[#]]
 ; CHECK:                  OpFunctionEnd
 ; CHECK: %[[#func_26:]] = OpFunction %[[#void:]] DontInline %[[#]]
diff --git a/llvm/test/CodeGen/SPIRV/structurizer/cf.switch.ifstmt.simple2.ll b/llvm/test/CodeGen/SPIRV/structurizer/cf.switch.ifstmt.simple2.ll
index cf50b982b23dc8..f2f86ed9e64fa0 100644
--- a/llvm/test/CodeGen/SPIRV/structurizer/cf.switch.ifstmt.simple2.ll
+++ b/llvm/test/CodeGen/SPIRV/structurizer/cf.switch.ifstmt.simple2.ll
@@ -1,10 +1,9 @@
 ; RUN: llc -mtriple=spirv-unknown-vulkan-compute -O0 %s -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
 
+; static int foo() { return 200; }
 ;
-; int foo() { return 200; }
-;
-; int process() {
+; static int process() {
 ;   int a = 0;
 ;   int b = 0;
 ;   int c = 0;
@@ -20,10 +19,10 @@
 ;       b += 2;
 ;       break;
 ;     case 3:
-;     {
-;       b += 3;
-;       break;
-;     }
+;       {
+;         b += 3;
+;         break;
+;       }
 ;     case t:
 ;       b += t;
 ;     case 4:
@@ -31,10 +30,10 @@
 ;       b += 5;
 ;       break;
 ;     case 6: {
-;     case 7:
-;       break;}
+;               case 7:
+;                 break;}
 ;     default:
-;       break;
+;             break;
 ;   }
 ;
 ;   return a + b + c;
@@ -45,198 +44,166 @@
 ;   process();
 ; }
 
-; CHECK: %[[#func_18:]] = OpFunction %[[#uint:]] DontInline %[[#]]
-; CHECK:    %[[#bb52:]] = OpLabel
-; CHECK:                  OpReturnValue %[[#]]
-; CHECK:                  OpFunctionEnd
-; CHECK: %[[#func_19:]] = OpFunction %[[#uint:]] DontInline %[[#]]
-; CHECK:    %[[#bb53:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb54:]] None
-; CHECK:                  OpBranchConditional %[[#]] %[[#bb55:]] %[[#bb56:]]
-; CHECK:    %[[#bb55:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb57:]] None
-; CHECK:                  OpBranchConditional %[[#]] %[[#bb58:]] %[[#bb59:]]
-; CHECK:    %[[#bb56:]] = OpLabel
-; CHECK:    %[[#bb58:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb60:]] None
-; CHECK:                  OpBranchConditional %[[#]] %[[#bb61:]] %[[#bb62:]]
-; CHECK:    %[[#bb59:]] = OpLabel
-; CHECK:    %[[#bb61:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb63:]] None
-; CHECK:                  OpSwitch %[[#]] %[[#bb64:]] 1 %[[#bb65:]] 2 %[[#bb63:]] 3 %[[#bb66:]] 140 %[[#bb67:]] 4 %[[#bb68:]] 5 %[[#bb69:]] 6 %[[#bb70:]] 7 %[[#bb71:]]
-; CHECK:    %[[#bb62:]] = OpLabel
-; CHECK:    %[[#bb64:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb65:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb66:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb67:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb68:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb69:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb70:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb71:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb63:]]
-; CHECK:    %[[#bb63:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb72:]] None
-; CHECK:                  OpSwitch %[[#]] %[[#bb73:]] 1 %[[#bb72:]] 2 %[[#bb74:]] 3 %[[#bb75:]]
-; CHECK:    %[[#bb73:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb72:]]
-; CHECK:    %[[#bb74:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb72:]]
-; CHECK:    %[[#bb75:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb72:]]
-; CHECK:    %[[#bb72:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb60:]]
-; CHECK:    %[[#bb60:]] = OpLabel
-; CHECK:                  OpSelectionMerge %[[#bb76:]] None
-; CHECK:                  OpSwitch %[[#]] %[[#bb77:]] 1 %[[#bb76:]] 2 %[[#bb78:]]
-; CHECK:    %[[#bb77:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb76:]]
-; CHECK:    %[[#bb78:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb76:]]
-; CHECK:    %[[#bb76:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb57:]]
-; CHECK:    %[[#bb57:]] = OpLabel
-; CHECK:                  OpBranch %[[#bb54:]]
-; CHECK:    %[[#bb54:]] = OpLabel
-; CHECK:                  OpReturnValue %[[#]]
-; CHECK:                  OpFunctionEnd
-; CHECK: %[[#func_48:]] = OpFunction %[[#void:]] DontInline %[[#]]
-; CHECK:    %[[#bb79:]] = OpLabel
-; CHECK:                  OpReturn
-; CHECK:                  OpFunctionEnd
-; CHECK: %[[#func_50:]] = OpFunction %[[#void:]] None %[[#]]
-; CHECK:    %[[#bb80:]] = OpLabel
-; CHECK:                  OpReturn
-; CHECK:                  OpFunctionEnd
+; CHECK: %[[#func:]] = OpFunction %[[#]] DontInline %[[#]]
+; CHECK: %[[#bb30:]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb31:]] None
+; CHECK:               OpBranchConditional %[[#]] %[[#bb32:]] %[[#bb33:]]
+
+; CHECK:  %[[#bb32]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb34:]] None
+; CHECK:               OpBranchConditional %[[#]] %[[#bb35:]] %[[#bb36:]]
+
+; CHECK:  %[[#bb33]] = OpLabel
+; CHECK:               OpUnreachable
+
+; CHECK:  %[[#bb35]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb37:]] None
+; CHECK:               OpBranchConditional %[[#]] %[[#bb38:]] %[[#bb39:]]
+
+; CHECK:  %[[#bb36]] = OpLabel
+; CHECK:               OpUnreachable
+
+; CHECK:  %[[#bb38]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb40:]] None
+; CHECK:               OpSwitch %[[#]] %[[#bb41:]] 1 %[[#bb42:]] 2 %[[#bb43:]] 3 %[[#bb44:]] 140 %[[#bb45:]] 4 %[[#bb46:]] 5 %[[#bb47:]] 6 %[[#bb48:]] 7 %[[#bb49:]]
+; CHECK:  %[[#bb39]] = OpLabel
+; CHECK:               OpUnreachable
+
+; CHECK:  %[[#bb41]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb42]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb43]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb44]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb45]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb46]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb47]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb48]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+; CHECK:  %[[#bb49]] = OpLabel
+; CHECK:               OpBranch %[[#bb40]]
+
+; CHECK:  %[[#bb40]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb50:]] None
+; CHECK:               OpSwitch %[[#]] %[[#bb50]] 1 %[[#bb51:]] 2 %[[#bb52:]] 3 %[[#bb53:]]
+; CHECK:  %[[#bb51]] = OpLabel
+; CHECK:               OpBranch %[[#bb50]]
+; CHECK:  %[[#bb52]] = OpLabel
+; CHECK:               OpBranch %[[#bb50]]
+; CHECK:  %[[#bb53]] = OpLabel
+; CHECK:               OpBranch %[[#bb50]]
+; CHECK:  %[[#bb50]] = OpLabel
+; CHECK:               OpBranch %[[#bb37]]
+
+; CHECK:  %[[#bb37]] = OpLabel
+; CHECK:               OpSelectionMerge %[[#bb54:]] None
+; CHECK:               OpSwitch %[[#]] %[[#bb54]] 1 %[[#bb55:]] 2 %[[#bb56:]]
+; CHECK:  %[[#bb55]] = OpLabel
+; CHECK:               OpBranch %[[#bb54]]
+; CHECK:  %[[#bb56]] = OpLabel
+; CHECK:               OpBranch %[[#bb54]]
+; CHECK:  %[[#bb54]] = OpLabel
+; CHECK:               OpBranch %[[#bb34]]
+
+; CHECK:  %[[#bb34]] = OpLabel
+; CHECK:               OpBranch %[[#bb31]]
+
+; CHECK:  %[[#bb31]] = OpLabel
+; CHECK:               OpReturn
+; CHECK:               OpFunctionEnd
 
 
 
 target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"
 target triple = "spirv-unknown-vulkan1.3-compute"
 
-; Function Attrs: convergent noinline norecurse nounwind optnone
-define spir_func noundef i32 @_Z3foov() #0 {
+; Function Attrs: convergent noinline norecurse
+define void @main() #0 {
 entry:
+  %a.i = alloca i32, align 4
+  %b.i = alloca i32, align 4
+  %c.i = alloca i32, align 4
+  %r.i = alloca i32, align 4
+  %s.i = alloca i32, align 4
+  %t.i = alloca i32, align 4
+  %d.i = alloca i32, align 4
   %0 = call token @llvm.experimental.convergence.entry()
-  ret i32 200
-}
-
-; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
-declare token @llvm.experimental.convergence.entry() #1
-
-; Function Attrs: convergent noinline norecurse nounwind optnone
-define spir_func noundef i32 @_Z7processv() #0 {
-entry:
-  %0 = call token @llvm.experimental.convergence.entry()
-  %a = alloca i32, align 4
-  %b = alloca i32, align 4
-  %c = alloca i32, align 4
-  %r = alloca i32, align 4
-  %s = alloca i32, align 4
-  %t = alloca i32, align 4
-  %d = alloca i32, align 4
-  store i32 0, ptr %a, align 4
-  store i32 0, ptr %b, align 4
-  store i32 0, ptr %c, align 4
-  store i32 20, ptr %r, align 4
-  store i32 40, ptr %s, align 4
-  store i32 140, ptr %t, align 4
-  store i32 5, ptr %d, align 4
-  %1 = load i32, ptr %d, align 4
-  switch i32 %1, label %sw.default [
-    i32 1, label %sw.bb
-    i32 2, label %sw.bb3
-    i32 3, label %sw.bb5
-    i32 140, label %sw.bb7
-    i32 4, label %sw.bb9
-    i32 5, label %sw.bb9
-    i32 6, label %sw.bb11
-    i32 7, label %sw.bb12
+  store i32 0, ptr %a.i, align 4
+  store i32 0, ptr %b.i, align 4
+  store i32 0, ptr %c.i, align 4
+  store i32 20, ptr %r.i, align 4
+  store i32 40, ptr %s.i, align 4
+  store i32 140, ptr %t.i, align 4
+  store i32 5, ptr %d.i, align 4
+  %1 = load i32, ptr %d.i, align 4
+  switch i32 %1, label %sw.default.i [
+    i32 1, label %sw.bb.i
+    i32 2, label %sw.bb3.i
+    i32 3, label %sw.bb5.i
+    i32 140, label %sw.bb7.i
+    i32 4, label %sw.bb9.i
+    i32 5, label %sw.bb9.i
+    i32 6, label %sw.bb11.i
+    i32 7, label %sw.bb12.i
   ]
 
-sw.bb:                                            ; preds = %entry
-  %2 = load i32, ptr %b, align 4
-  %add = add nsw i32 %2, 1
-  store i32 %add, ptr %b, align 4
-  %call1 = call spir_func noundef i32 @_Z3foov() #3 [ "convergencectrl"(token %0) ]
-  %3 = load i32, ptr %c, align 4
-  %add2 = add nsw i32 %3, %call1
-  store i32 %add2, ptr %c, align 4
-  br label %sw.bb3
-
-sw.bb3:                                           ; preds = %entry, %sw.bb
-  %4 = load i32, ptr %b, align 4
-  %add4 = add nsw i32 %4, 2
-  store i32 %add4, ptr %b, align 4
-  br label %sw.epilog
-
-sw.bb5:                                           ; preds = %entry
-  %5 = load i32, ptr %b, align 4
-  %add6 = add nsw i32 %5, 3
-  store i32 %add6, ptr %b, align 4
-  br label %sw.epilog
-
-sw.bb7:                                           ; preds = %entry
-  %6 = load i32, ptr %b, align 4
-  %add8 = add nsw i32 %6, 140
-  store i32 %add8, ptr %b, align 4
-  br label %sw.bb9
-
-sw.bb9:                                           ; preds = %entry, %entry, %sw.bb7
-  %7 = load i32, ptr %b, align 4
-  %add10 = add nsw i32 %7, 5
-  store i32 %add10, ptr %b, align 4
-  br label %sw.epilog
-
-sw.bb11:                                          ; preds = %entry
-  br label %sw.bb12
-
-sw.bb12:                                          ; preds = %entry, %sw.bb11
-  br label %sw.epilog
-
-sw.default:                                       ; preds = %entry
-  br label %sw.epilog
-
-sw.epilog:                                        ; preds = %sw.default, %sw.bb12, %sw.bb9, %sw.bb5, %sw.bb3
-  %8 = load i32, ptr %a, align 4
-  %9 = load i32, ptr %b, align 4
-  %add13 = add nsw i32 %8, %9
-  %10 = load i32, ptr %c, align 4
-  %add14 = add nsw i32 %add13, %10
-  ret i32 %add14
-}
-
-; Function Attrs: convergent noinline norecurse nounwind optnone
-define internal spir_func void @main() #0 {
-entry:
-  %0 = call token @llvm.experimental.convergence.entry()
-  %call1 = call spir_func noundef i32 @_Z7processv() #3 [ "convergencectrl"(token %0) ]
+sw.bb.i:
+  %2 = load i32, ptr %b.i, align 4
+  %add.i = add nsw i32 %2, 1
+  store i32 %add.i, ptr %b.i, align 4
+  %3 = load i32, ptr %c.i, align 4
+  %add2.i = add nsw i32 %3, 200
+  store i32 %add2.i, ptr %c.i, align 4
+  br label %sw.bb3.i
+
+sw.bb3.i:
+  %4 = load i32, ptr %b.i, align 4
+  %add4.i = add nsw i32 %4, 2
+  store i32 %add4.i, ptr %b.i, align 4
+  br label %_ZL7processv.exit
+
+sw.bb5.i:
+  %5 = load i32, ptr %b.i, align 4
+  %add6.i = add nsw i32 %5, 3
+  store i32 %add6.i, ptr %b.i, align 4
+  br label %_ZL7processv.exit
+
+sw.bb7.i:
+  %6 = load i32, ptr %b.i, align 4
+  %add8.i = add nsw i32 %6, 140
+  store i32 %add8.i, ptr %b.i, align 4
+  br label %sw.bb9.i
+
+sw.bb9.i:
+  %7 = load i32, ptr %b.i, align 4
+  %add10.i = add nsw i32 %7, 5
+  store i32 %add10.i, ptr %b.i, align 4
+  br label %_ZL7processv.exit
+
+sw.bb11.i:
+  br label %sw.bb12.i
+
+sw.bb12.i:
+  br label %_ZL7processv.exit
+
+sw.default.i:
+  br label %_ZL7processv.exit
+
+_ZL7processv.exit:
+  %8 = load i32, ptr %a.i, align 4
+  %9 = load i32, ptr %b.i, align 4
+  %add13.i = add nsw i32 %8, %9
+  %10 = load i32, ptr %c.i, align 4
+  %add14.i = add nsw i32 %add13.i, %10
   ret void
 }
 
-; Function Attrs: convergent norecurse
-define void @main.1() #2 {
-entry:
-  call void @main()
-  ret void
-}
+declare token @llvm.experimental.convergence.entry() #1
 
-attributes #0 = { convergent noinline norecurse nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #0 = { convergent noinline norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
 attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
-attributes #2 = { convergent norecurse "frame-pointer"="all" "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
-attributes #3 = { convergent }
-
-!llvm.module.flags = !{!0, !1, !2}
-
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 4, !"dx.disable_optimizations", i32 1}
-!2 = !{i32 7, !"frame-pointer", i32 2}
-
-
diff --git a/llvm/unittests/Target/SPIRV/CMakeLists.txt b/llvm/unittests/Target/SPIRV/CMakeLists.txt
index e9fe4883e5b024..2af36225c5f200 100644
--- a/llvm/unittests/Target/SPIRV/CMakeLists.txt
+++ b/llvm/unittests/Target/SPIRV/CMakeLists.txt
@@ -15,6 +15,6 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_target_unittest(SPIRVTests
   SPIRVConvergenceRegionAnalysisTests.cpp
+  SPIRVSortBlocksTests.cpp
   SPIRVAPITest.cpp
-  )
-
+)
diff --git a/llvm/unittests/Target/SPIRV/SPIRVSortBlocksTests.cpp b/llvm/unittests/Target/SPIRV/SPIRVSortBlocksTests.cpp
new file mode 100644
index 00000000000000..7f64333eabe950
--- /dev/null
+++ b/llvm/unittests/Target/SPIRV/SPIRVSortBlocksTests.cpp
@@ -0,0 +1,342 @@
+//===- SPIRVSortBlocksTests.cpp ----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "SPIRVUtils.h"
+#include "llvm/Analysis/DominanceFrontier.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassInstrumentation.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/TypedPointerType.h"
+#include "llvm/Support/SourceMgr.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <queue>
+
+using namespace llvm;
+using namespace llvm::SPIRV;
+
+class SPIRVSortBlocksTest : public testing::Test {
+protected:
+  void TearDown() override { M.reset(); }
+
+  void run(StringRef Assembly) {
+    assert(M == nullptr &&
+           "Calling runAnalysis multiple times is unsafe. See getAnalysis().");
+
+    SMDiagnostic Error;
+    M = parseAssemblyString(Assembly, Error, Context);
+    assert(M && "Bad assembly. Bad test?");
+
+    llvm::Function *F = M->getFunction("main");
+    Visitor = std::make_unique<...
[truncated]

Add testing for the visitor and added a note explaining
irreducible CFG are not supported.
Related to llvm#116692

Signed-off-by: Nathan Gauër <[email protected]>
@Keenuts
Copy link
Contributor Author

Keenuts commented Nov 28, 2024

rebased on main, will merge once green.

@Keenuts
Copy link
Contributor Author

Keenuts commented Nov 28, 2024

Broken test in the CI is non-related (OpConstant vs OpConstantNull). Merging this.
Thanks for the review!

@Keenuts Keenuts merged commit 45b567b into llvm:main Nov 28, 2024
8 of 9 checks passed
@Keenuts Keenuts deleted the refuse-irreducible branch November 28, 2024 15:33
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 28, 2024

LLVM Buildbot has detected a new failure on builder libc-x86_64-debian-fullbuild-dbg-asan running on libc-x86_64-debian-fullbuild while building llvm at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/171/builds/11275

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py ...' (failure)
...
[==========] Running 4 tests from 1 test suite.
[ RUN      ] LlvmLibcHashTest.SanityCheck
[       OK ] LlvmLibcHashTest.SanityCheck (16 ms)
[ RUN      ] LlvmLibcHashTest.Avalanche
[       OK ] LlvmLibcHashTest.Avalanche (2064 ms)
[ RUN      ] LlvmLibcHashTest.UniformLSB
[       OK ] LlvmLibcHashTest.UniformLSB (202 ms)
[ RUN      ] LlvmLibcHashTest.UniformMSB
[       OK ] LlvmLibcHashTest.UniformMSB (154 us)
Ran 4 tests.  PASS: 4  FAIL: 0
command timed out: 1200 seconds without output running [b'python', b'../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py', b'--debug', b'--asan'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1256.708299
Step 8 (libc-unit-tests) failure: libc-unit-tests (failure)
...
[ RUN      ] LlvmLibcStrtoint64Test.InvalidBase
[       OK ] LlvmLibcStrtoint64Test.InvalidBase (7 us)
[ RUN      ] LlvmLibcStrtoint64Test.CleanBaseTenDecode
[       OK ] LlvmLibcStrtoint64Test.CleanBaseTenDecode (14 us)
[ RUN      ] LlvmLibcStrtoint64Test.MessyBaseTenDecode
[       OK ] LlvmLibcStrtoint64Test.MessyBaseTenDecode (10 us)
[ RUN      ] LlvmLibcStrtoint64Test.DecodeInOtherBases
[       OK ] LlvmLibcStrtoint64Test.DecodeInOtherBases (410 ms)
[ RUN      ] LlvmLibcStrtoint64Test.CleanBaseSixteenDecode
[       OK ] LlvmLibcStrtoint64Test.CleanBaseSixteenDecode (8 us)
[ RUN      ] LlvmLibcStrtoint64Test.MessyBaseSixteenDecode
[       OK ] LlvmLibcStrtoint64Test.MessyBaseSixteenDecode (4 us)
[ RUN      ] LlvmLibcStrtoint64Test.AutomaticBaseSelection
[       OK ] LlvmLibcStrtoint64Test.AutomaticBaseSelection (4 us)
[ RUN      ] LlvmLibcStrtouint64Test.InvalidBase
[       OK ] LlvmLibcStrtouint64Test.InvalidBase (11 us)
[ RUN      ] LlvmLibcStrtouint64Test.CleanBaseTenDecode
[       OK ] LlvmLibcStrtouint64Test.CleanBaseTenDecode (7 us)
[ RUN      ] LlvmLibcStrtouint64Test.MessyBaseTenDecode
[       OK ] LlvmLibcStrtouint64Test.MessyBaseTenDecode (6 us)
[ RUN      ] LlvmLibcStrtouint64Test.DecodeInOtherBases
[       OK ] LlvmLibcStrtouint64Test.DecodeInOtherBases (234 ms)
[ RUN      ] LlvmLibcStrtouint64Test.CleanBaseSixteenDecode
[       OK ] LlvmLibcStrtouint64Test.CleanBaseSixteenDecode (8 us)
[ RUN      ] LlvmLibcStrtouint64Test.MessyBaseSixteenDecode
[       OK ] LlvmLibcStrtouint64Test.MessyBaseSixteenDecode (3 us)
[ RUN      ] LlvmLibcStrtouint64Test.AutomaticBaseSelection
[       OK ] LlvmLibcStrtouint64Test.AutomaticBaseSelection (5 us)
Ran 14 tests.  PASS: 14  FAIL: 0
[1096/1098] Running unit test libc.test.src.time.nanosleep_test.__unit__
[==========] Running 1 test from 1 test suite.
[ RUN      ] LlvmLibcNanosleep.SmokeTest
[       OK ] LlvmLibcNanosleep.SmokeTest (50 us)
Ran 1 tests.  PASS: 1  FAIL: 0
[1097/1098] Running unit test libc.test.src.__support.hash_test.__unit__
[==========] Running 4 tests from 1 test suite.
[ RUN      ] LlvmLibcHashTest.SanityCheck
[       OK ] LlvmLibcHashTest.SanityCheck (16 ms)
[ RUN      ] LlvmLibcHashTest.Avalanche
[       OK ] LlvmLibcHashTest.Avalanche (2064 ms)
[ RUN      ] LlvmLibcHashTest.UniformLSB
[       OK ] LlvmLibcHashTest.UniformLSB (202 ms)
[ RUN      ] LlvmLibcHashTest.UniformMSB
[       OK ] LlvmLibcHashTest.UniformMSB (154 us)
Ran 4 tests.  PASS: 4  FAIL: 0

command timed out: 1200 seconds without output running [b'python', b'../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py', b'--debug', b'--asan'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1256.708299

@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 28, 2024

LLVM Buildbot has detected a new failure on builder libc-x86_64-debian-gcc-fullbuild-dbg running on libc-x86_64-debian-fullbuild while building llvm at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/131/builds/11368

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py ...' (failure)
...
[ RUN      ] LlvmLibcRoundToIntegerTest.RoundNumbers
[       OK ] LlvmLibcRoundToIntegerTest.RoundNumbers (10 us)
[ RUN      ] LlvmLibcRoundToIntegerTest.SubnormalRange
[       OK ] LlvmLibcRoundToIntegerTest.SubnormalRange (1357 ms)
Ran 3 tests.  PASS: 3  FAIL: 0
[1101/1102] Running unit test libc.test.src.time.nanosleep_test.__unit__
[==========] Running 1 test from 1 test suite.
[ RUN      ] LlvmLibcNanosleep.SmokeTest
[       OK ] LlvmLibcNanosleep.SmokeTest (35 us)
Ran 1 tests.  PASS: 1  FAIL: 0
command timed out: 1200 seconds without output running [b'python', b'../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py', b'--debug'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1263.025300
Step 8 (libc-unit-tests) failure: libc-unit-tests (failure)
...
[       OK ] LlvmLibcStrtoint64Test.DecodeInOtherBases (407 ms)
[ RUN      ] LlvmLibcStrtoint64Test.CleanBaseSixteenDecode
[       OK ] LlvmLibcStrtoint64Test.CleanBaseSixteenDecode (10 us)
[ RUN      ] LlvmLibcStrtoint64Test.MessyBaseSixteenDecode
[       OK ] LlvmLibcStrtoint64Test.MessyBaseSixteenDecode (4 us)
[ RUN      ] LlvmLibcStrtoint64Test.AutomaticBaseSelection
[       OK ] LlvmLibcStrtoint64Test.AutomaticBaseSelection (5 us)
[ RUN      ] LlvmLibcStrtouint64Test.InvalidBase
[       OK ] LlvmLibcStrtouint64Test.InvalidBase (2 us)
[ RUN      ] LlvmLibcStrtouint64Test.CleanBaseTenDecode
[       OK ] LlvmLibcStrtouint64Test.CleanBaseTenDecode (8 us)
[ RUN      ] LlvmLibcStrtouint64Test.MessyBaseTenDecode
[       OK ] LlvmLibcStrtouint64Test.MessyBaseTenDecode (7 us)
[ RUN      ] LlvmLibcStrtouint64Test.DecodeInOtherBases
[       OK ] LlvmLibcStrtouint64Test.DecodeInOtherBases (285 ms)
[ RUN      ] LlvmLibcStrtouint64Test.CleanBaseSixteenDecode
[       OK ] LlvmLibcStrtouint64Test.CleanBaseSixteenDecode (10 us)
[ RUN      ] LlvmLibcStrtouint64Test.MessyBaseSixteenDecode
[       OK ] LlvmLibcStrtouint64Test.MessyBaseSixteenDecode (3 us)
[ RUN      ] LlvmLibcStrtouint64Test.AutomaticBaseSelection
[       OK ] LlvmLibcStrtouint64Test.AutomaticBaseSelection (4 us)
Ran 14 tests.  PASS: 14  FAIL: 0
[1099/1102] Running unit test libc.test.src.math.smoke.lrintl_test.__unit__
[==========] Running 3 tests from 1 test suite.
[ RUN      ] LlvmLibcRoundToIntegerTest.InfinityAndNaN
[       OK ] LlvmLibcRoundToIntegerTest.InfinityAndNaN (9 us)
[ RUN      ] LlvmLibcRoundToIntegerTest.RoundNumbers
[       OK ] LlvmLibcRoundToIntegerTest.RoundNumbers (10 us)
[ RUN      ] LlvmLibcRoundToIntegerTest.SubnormalRange
[       OK ] LlvmLibcRoundToIntegerTest.SubnormalRange (1332 ms)
Ran 3 tests.  PASS: 3  FAIL: 0
[1100/1102] Running unit test libc.test.src.math.smoke.llrintl_test.__unit__
[==========] Running 3 tests from 1 test suite.
[ RUN      ] LlvmLibcRoundToIntegerTest.InfinityAndNaN
[       OK ] LlvmLibcRoundToIntegerTest.InfinityAndNaN (9 us)
[ RUN      ] LlvmLibcRoundToIntegerTest.RoundNumbers
[       OK ] LlvmLibcRoundToIntegerTest.RoundNumbers (10 us)
[ RUN      ] LlvmLibcRoundToIntegerTest.SubnormalRange
[       OK ] LlvmLibcRoundToIntegerTest.SubnormalRange (1357 ms)
Ran 3 tests.  PASS: 3  FAIL: 0
[1101/1102] Running unit test libc.test.src.time.nanosleep_test.__unit__
[==========] Running 1 test from 1 test suite.
[ RUN      ] LlvmLibcNanosleep.SmokeTest
[       OK ] LlvmLibcNanosleep.SmokeTest (35 us)
Ran 1 tests.  PASS: 1  FAIL: 0

command timed out: 1200 seconds without output running [b'python', b'../llvm-zorg/zorg/buildbot/builders/annotated/libc-linux.py', b'--debug'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1263.025300

@damyanp
Copy link
Contributor

damyanp commented Dec 3, 2024

@Keenuts - I think that the build failures above, that are timeouts, are related to this change. I also see a SPIRVTests.exe process get stuck when I run the tests locally.

@Keenuts
Copy link
Contributor Author

Keenuts commented Dec 4, 2024

@Keenuts - I think that the build failures above, that are timeouts, are related to this change. I also see a SPIRVTests.exe process get stuck when I run the tests locally.

Thanks!
There is a test that is expected to hit an assert (otherwise it hangs). Do you build with asserts enabled?
(I might need to replace this assert with another way to die)

@VyacheslavLevytskyy
Copy link
Contributor

yes, let's please do smth like report_fatal_error instead of the assert if it hangs

@Keenuts
Copy link
Contributor Author

Keenuts commented Dec 4, 2024

Sent out #118617

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants