[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-09 Thread Steffen Larsen via cfe-commits

https://github.com/steffenlarsen closed 
https://github.com/llvm/llvm-project/pull/220496
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-09 Thread Steffen Larsen via cfe-commits

https://github.com/steffenlarsen updated 
https://github.com/llvm/llvm-project/pull/220496

>From 04fd30b1587c974bdd376b01f1c9e808eb5969a4 Mon Sep 17 00:00:00 2001
From: Steffen Holst Larsen 
Date: Tue, 1 Sep 2026 08:55:22 -0500
Subject: [PATCH] [CIR] Reposition entry-block allocas ahead of control flow

HoistAllocas returned early when an alloca was already in the entry
block, but being in the block is not the same as being ahead of the
control flow in it. The pass runs before FlattenCFG, which splits the
body at each structured control-flow op, so an alloca sitting after one
is left in a block that is no longer the entry block.

That matters because SROA only collects allocas from the entry block. An
alloca stranded behind a scope is invisible to it and never promoted, so
anything whose address it holds stays in memory.
---
 .../CIR/Dialect/Transforms/HoistAllocas.cpp   | 16 +--
 clang/test/CIR/Transforms/hoist-allocas.cir   | 27 +++
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 5c41541ec76bf..1eb3e2524e124 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -64,11 +64,23 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
   // let's not depend on the default staying that way.
   func.getBody().walk([&](cir::AllocaOp alloca) {
 mlir::Block *destBlock = getHoistDestBlock(alloca);
-if (alloca->getBlock() == destBlock)
-  return;
 // Don't hoist allocas with dynamic alloca size.
 if (alloca.getDynAllocSize())
   return;
+if (alloca->getBlock() == destBlock) {
+  // Already in the right block, but not necessarily ahead of the control
+  // flow in it. This pass runs before FlattenCFG, which splits the body at
+  // each structured control-flow op, so an alloca that sits after one ends
+  // up in a non-entry block and SROA only ever collects allocas from the
+  // entry block, so it would never be promoted at all.
+  // Only a region-carrying op ahead of the alloca can strand it that way;
+  // straight-line code cannot.
+  if (std::all_of(destBlock->begin(), alloca->getIterator(),
+  [](mlir::Operation &blockOp) {
+return blockOp.getNumRegions() == 0;
+  }))
+return;
+}
 
 // Hoist allocas into the entry block.
 
diff --git a/clang/test/CIR/Transforms/hoist-allocas.cir 
b/clang/test/CIR/Transforms/hoist-allocas.cir
index db04030412252..222be921b3a17 100644
--- a/clang/test/CIR/Transforms/hoist-allocas.cir
+++ b/clang/test/CIR/Transforms/hoist-allocas.cir
@@ -196,3 +196,30 @@ module {
   // CHECK-NEXT:   cir.return
   // CHECK-NEXT: }
 }
+
+cir.func @alloca_after_scope() {
+  cir.scope {
+%0 = cir.alloca "inner" align(4) init : !cir.ptr
+  }
+  %1 = cir.alloca "after" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_scope()
+// CHECK-NEXT: cir.alloca{{.*}}"inner"
+// CHECK-NEXT: cir.alloca{{.*}}"after"
+// CHECK-NEXT: cir.scope
+
+cir.func @alloca_after_straightline() {
+  %0 = cir.alloca "first" align(4) init : !cir.ptr
+  %1 = cir.const #cir.int<0> : !s32i
+  cir.store %1, %0 : !s32i, !cir.ptr
+  %2 = cir.alloca "second" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_straightline()
+// CHECK-NEXT: cir.alloca{{.*}}"first"
+// CHECK-NEXT: cir.const
+// CHECK-NEXT: cir.store
+// CHECK-NEXT: cir.alloca{{.*}}"second"

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-08 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor approved this pull request.

lgtm

https://github.com/llvm/llvm-project/pull/220496
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-06 Thread Steffen Larsen via cfe-commits

https://github.com/steffenlarsen updated 
https://github.com/llvm/llvm-project/pull/220496

>From 04fd30b1587c974bdd376b01f1c9e808eb5969a4 Mon Sep 17 00:00:00 2001
From: Steffen Holst Larsen 
Date: Tue, 1 Sep 2026 08:55:22 -0500
Subject: [PATCH] [CIR] Reposition entry-block allocas ahead of control flow

HoistAllocas returned early when an alloca was already in the entry
block, but being in the block is not the same as being ahead of the
control flow in it. The pass runs before FlattenCFG, which splits the
body at each structured control-flow op, so an alloca sitting after one
is left in a block that is no longer the entry block.

That matters because SROA only collects allocas from the entry block. An
alloca stranded behind a scope is invisible to it and never promoted, so
anything whose address it holds stays in memory.
---
 .../CIR/Dialect/Transforms/HoistAllocas.cpp   | 16 +--
 clang/test/CIR/Transforms/hoist-allocas.cir   | 27 +++
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 5c41541ec76bf..1eb3e2524e124 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -64,11 +64,23 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
   // let's not depend on the default staying that way.
   func.getBody().walk([&](cir::AllocaOp alloca) {
 mlir::Block *destBlock = getHoistDestBlock(alloca);
-if (alloca->getBlock() == destBlock)
-  return;
 // Don't hoist allocas with dynamic alloca size.
 if (alloca.getDynAllocSize())
   return;
+if (alloca->getBlock() == destBlock) {
+  // Already in the right block, but not necessarily ahead of the control
+  // flow in it. This pass runs before FlattenCFG, which splits the body at
+  // each structured control-flow op, so an alloca that sits after one ends
+  // up in a non-entry block and SROA only ever collects allocas from the
+  // entry block, so it would never be promoted at all.
+  // Only a region-carrying op ahead of the alloca can strand it that way;
+  // straight-line code cannot.
+  if (std::all_of(destBlock->begin(), alloca->getIterator(),
+  [](mlir::Operation &blockOp) {
+return blockOp.getNumRegions() == 0;
+  }))
+return;
+}
 
 // Hoist allocas into the entry block.
 
diff --git a/clang/test/CIR/Transforms/hoist-allocas.cir 
b/clang/test/CIR/Transforms/hoist-allocas.cir
index db04030412252..222be921b3a17 100644
--- a/clang/test/CIR/Transforms/hoist-allocas.cir
+++ b/clang/test/CIR/Transforms/hoist-allocas.cir
@@ -196,3 +196,30 @@ module {
   // CHECK-NEXT:   cir.return
   // CHECK-NEXT: }
 }
+
+cir.func @alloca_after_scope() {
+  cir.scope {
+%0 = cir.alloca "inner" align(4) init : !cir.ptr
+  }
+  %1 = cir.alloca "after" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_scope()
+// CHECK-NEXT: cir.alloca{{.*}}"inner"
+// CHECK-NEXT: cir.alloca{{.*}}"after"
+// CHECK-NEXT: cir.scope
+
+cir.func @alloca_after_straightline() {
+  %0 = cir.alloca "first" align(4) init : !cir.ptr
+  %1 = cir.const #cir.int<0> : !s32i
+  cir.store %1, %0 : !s32i, !cir.ptr
+  %2 = cir.alloca "second" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_straightline()
+// CHECK-NEXT: cir.alloca{{.*}}"first"
+// CHECK-NEXT: cir.const
+// CHECK-NEXT: cir.store
+// CHECK-NEXT: cir.alloca{{.*}}"second"

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-02 Thread Mariya Podchishchaeva via cfe-commits

https://github.com/Fznamznon commented:

That makes sense to me, though I don't think I'm yet qualified enough in CIR to 
give a real approval.


https://github.com/llvm/llvm-project/pull/220496
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-01 Thread via cfe-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-clangir

Author: Steffen Larsen (steffenlarsen)


Changes

HoistAllocas returns early when an alloca was already in the entry block, but 
being in the block is not the same as being ahead of the control flow in it. 
The pass runs before FlattenCFG, which splits the body at each structured 
control-flow op, so an alloca sitting after one is left in a block that is no 
longer the entry block.

That matters because SROA only collects allocas from the entry block. An alloca 
stranded behind a scope is invisible to it and never promoted, so anything 
whose address it holds stays in memory.

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


2 Files Affected:

- (modified) clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp (+14-2) 
- (modified) clang/test/CIR/Transforms/hoist-allocas.cir (+27) 


``diff
diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 5c41541ec76bf..1eb3e2524e124 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -64,11 +64,23 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
   // let's not depend on the default staying that way.
   func.getBody().walk([&](cir::AllocaOp alloca) {
 mlir::Block *destBlock = getHoistDestBlock(alloca);
-if (alloca->getBlock() == destBlock)
-  return;
 // Don't hoist allocas with dynamic alloca size.
 if (alloca.getDynAllocSize())
   return;
+if (alloca->getBlock() == destBlock) {
+  // Already in the right block, but not necessarily ahead of the control
+  // flow in it. This pass runs before FlattenCFG, which splits the body at
+  // each structured control-flow op, so an alloca that sits after one ends
+  // up in a non-entry block and SROA only ever collects allocas from the
+  // entry block, so it would never be promoted at all.
+  // Only a region-carrying op ahead of the alloca can strand it that way;
+  // straight-line code cannot.
+  if (std::all_of(destBlock->begin(), alloca->getIterator(),
+  [](mlir::Operation &blockOp) {
+return blockOp.getNumRegions() == 0;
+  }))
+return;
+}
 
 // Hoist allocas into the entry block.
 
diff --git a/clang/test/CIR/Transforms/hoist-allocas.cir 
b/clang/test/CIR/Transforms/hoist-allocas.cir
index db04030412252..222be921b3a17 100644
--- a/clang/test/CIR/Transforms/hoist-allocas.cir
+++ b/clang/test/CIR/Transforms/hoist-allocas.cir
@@ -196,3 +196,30 @@ module {
   // CHECK-NEXT:   cir.return
   // CHECK-NEXT: }
 }
+
+cir.func @alloca_after_scope() {
+  cir.scope {
+%0 = cir.alloca "inner" align(4) init : !cir.ptr
+  }
+  %1 = cir.alloca "after" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_scope()
+// CHECK-NEXT: cir.alloca{{.*}}"inner"
+// CHECK-NEXT: cir.alloca{{.*}}"after"
+// CHECK-NEXT: cir.scope
+
+cir.func @alloca_after_straightline() {
+  %0 = cir.alloca "first" align(4) init : !cir.ptr
+  %1 = cir.const #cir.int<0> : !s32i
+  cir.store %1, %0 : !s32i, !cir.ptr
+  %2 = cir.alloca "second" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_straightline()
+// CHECK-NEXT: cir.alloca{{.*}}"first"
+// CHECK-NEXT: cir.const
+// CHECK-NEXT: cir.store
+// CHECK-NEXT: cir.alloca{{.*}}"second"

``




https://github.com/llvm/llvm-project/pull/220496
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-01 Thread via cfe-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-clang

Author: Steffen Larsen (steffenlarsen)


Changes

HoistAllocas returns early when an alloca was already in the entry block, but 
being in the block is not the same as being ahead of the control flow in it. 
The pass runs before FlattenCFG, which splits the body at each structured 
control-flow op, so an alloca sitting after one is left in a block that is no 
longer the entry block.

That matters because SROA only collects allocas from the entry block. An alloca 
stranded behind a scope is invisible to it and never promoted, so anything 
whose address it holds stays in memory.

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


2 Files Affected:

- (modified) clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp (+14-2) 
- (modified) clang/test/CIR/Transforms/hoist-allocas.cir (+27) 


``diff
diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 5c41541ec76bf..1eb3e2524e124 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -64,11 +64,23 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
   // let's not depend on the default staying that way.
   func.getBody().walk([&](cir::AllocaOp alloca) {
 mlir::Block *destBlock = getHoistDestBlock(alloca);
-if (alloca->getBlock() == destBlock)
-  return;
 // Don't hoist allocas with dynamic alloca size.
 if (alloca.getDynAllocSize())
   return;
+if (alloca->getBlock() == destBlock) {
+  // Already in the right block, but not necessarily ahead of the control
+  // flow in it. This pass runs before FlattenCFG, which splits the body at
+  // each structured control-flow op, so an alloca that sits after one ends
+  // up in a non-entry block and SROA only ever collects allocas from the
+  // entry block, so it would never be promoted at all.
+  // Only a region-carrying op ahead of the alloca can strand it that way;
+  // straight-line code cannot.
+  if (std::all_of(destBlock->begin(), alloca->getIterator(),
+  [](mlir::Operation &blockOp) {
+return blockOp.getNumRegions() == 0;
+  }))
+return;
+}
 
 // Hoist allocas into the entry block.
 
diff --git a/clang/test/CIR/Transforms/hoist-allocas.cir 
b/clang/test/CIR/Transforms/hoist-allocas.cir
index db04030412252..222be921b3a17 100644
--- a/clang/test/CIR/Transforms/hoist-allocas.cir
+++ b/clang/test/CIR/Transforms/hoist-allocas.cir
@@ -196,3 +196,30 @@ module {
   // CHECK-NEXT:   cir.return
   // CHECK-NEXT: }
 }
+
+cir.func @alloca_after_scope() {
+  cir.scope {
+%0 = cir.alloca "inner" align(4) init : !cir.ptr
+  }
+  %1 = cir.alloca "after" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_scope()
+// CHECK-NEXT: cir.alloca{{.*}}"inner"
+// CHECK-NEXT: cir.alloca{{.*}}"after"
+// CHECK-NEXT: cir.scope
+
+cir.func @alloca_after_straightline() {
+  %0 = cir.alloca "first" align(4) init : !cir.ptr
+  %1 = cir.const #cir.int<0> : !s32i
+  cir.store %1, %0 : !s32i, !cir.ptr
+  %2 = cir.alloca "second" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_straightline()
+// CHECK-NEXT: cir.alloca{{.*}}"first"
+// CHECK-NEXT: cir.const
+// CHECK-NEXT: cir.store
+// CHECK-NEXT: cir.alloca{{.*}}"second"

``




https://github.com/llvm/llvm-project/pull/220496
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Reposition entry-block allocas ahead of control flow (PR #220496)

2026-09-01 Thread Steffen Larsen via cfe-commits

https://github.com/steffenlarsen created 
https://github.com/llvm/llvm-project/pull/220496

HoistAllocas returns early when an alloca was already in the entry block, but 
being in the block is not the same as being ahead of the control flow in it. 
The pass runs before FlattenCFG, which splits the body at each structured 
control-flow op, so an alloca sitting after one is left in a block that is no 
longer the entry block.

That matters because SROA only collects allocas from the entry block. An alloca 
stranded behind a scope is invisible to it and never promoted, so anything 
whose address it holds stays in memory.

>From 04fd30b1587c974bdd376b01f1c9e808eb5969a4 Mon Sep 17 00:00:00 2001
From: Steffen Holst Larsen 
Date: Tue, 1 Sep 2026 08:55:22 -0500
Subject: [PATCH] [CIR] Reposition entry-block allocas ahead of control flow

HoistAllocas returned early when an alloca was already in the entry
block, but being in the block is not the same as being ahead of the
control flow in it. The pass runs before FlattenCFG, which splits the
body at each structured control-flow op, so an alloca sitting after one
is left in a block that is no longer the entry block.

That matters because SROA only collects allocas from the entry block. An
alloca stranded behind a scope is invisible to it and never promoted, so
anything whose address it holds stays in memory.
---
 .../CIR/Dialect/Transforms/HoistAllocas.cpp   | 16 +--
 clang/test/CIR/Transforms/hoist-allocas.cir   | 27 +++
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp 
b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
index 5c41541ec76bf..1eb3e2524e124 100644
--- a/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/HoistAllocas.cpp
@@ -64,11 +64,23 @@ static void process(mlir::ModuleOp mod, cir::FuncOp func) {
   // let's not depend on the default staying that way.
   func.getBody().walk([&](cir::AllocaOp alloca) {
 mlir::Block *destBlock = getHoistDestBlock(alloca);
-if (alloca->getBlock() == destBlock)
-  return;
 // Don't hoist allocas with dynamic alloca size.
 if (alloca.getDynAllocSize())
   return;
+if (alloca->getBlock() == destBlock) {
+  // Already in the right block, but not necessarily ahead of the control
+  // flow in it. This pass runs before FlattenCFG, which splits the body at
+  // each structured control-flow op, so an alloca that sits after one ends
+  // up in a non-entry block and SROA only ever collects allocas from the
+  // entry block, so it would never be promoted at all.
+  // Only a region-carrying op ahead of the alloca can strand it that way;
+  // straight-line code cannot.
+  if (std::all_of(destBlock->begin(), alloca->getIterator(),
+  [](mlir::Operation &blockOp) {
+return blockOp.getNumRegions() == 0;
+  }))
+return;
+}
 
 // Hoist allocas into the entry block.
 
diff --git a/clang/test/CIR/Transforms/hoist-allocas.cir 
b/clang/test/CIR/Transforms/hoist-allocas.cir
index db04030412252..222be921b3a17 100644
--- a/clang/test/CIR/Transforms/hoist-allocas.cir
+++ b/clang/test/CIR/Transforms/hoist-allocas.cir
@@ -196,3 +196,30 @@ module {
   // CHECK-NEXT:   cir.return
   // CHECK-NEXT: }
 }
+
+cir.func @alloca_after_scope() {
+  cir.scope {
+%0 = cir.alloca "inner" align(4) init : !cir.ptr
+  }
+  %1 = cir.alloca "after" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_scope()
+// CHECK-NEXT: cir.alloca{{.*}}"inner"
+// CHECK-NEXT: cir.alloca{{.*}}"after"
+// CHECK-NEXT: cir.scope
+
+cir.func @alloca_after_straightline() {
+  %0 = cir.alloca "first" align(4) init : !cir.ptr
+  %1 = cir.const #cir.int<0> : !s32i
+  cir.store %1, %0 : !s32i, !cir.ptr
+  %2 = cir.alloca "second" align(4) init : !cir.ptr
+  cir.return
+}
+
+// CHECK: cir.func{{.*}} @alloca_after_straightline()
+// CHECK-NEXT: cir.alloca{{.*}}"first"
+// CHECK-NEXT: cir.const
+// CHECK-NEXT: cir.store
+// CHECK-NEXT: cir.alloca{{.*}}"second"

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits