Skip to content

Commit bff94d7

Browse files
authored
[CIR] Emit allocas into the proper lexical scope (#132468)
Alloca operations were being emitted into the entry block of the current function unconditionally, even if the variable they represented was declared in a different scope. This change upstreams the code for handling insertion of the alloca into the proper lexcial scope. It also adds a CIR-to-CIR transformation to hoist allocas to the function entry block, which is necessary to produce the expected LLVM IR during lowering.
1 parent e04d739 commit bff94d7

File tree

13 files changed

+406
-16
lines changed

13 files changed

+406
-16
lines changed

clang/include/clang/CIR/Dialect/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace mlir {
2222

2323
std::unique_ptr<Pass> createCIRCanonicalizePass();
2424
std::unique_ptr<Pass> createCIRFlattenCFGPass();
25+
std::unique_ptr<Pass> createHoistAllocasPass();
2526

2627
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
2728

clang/include/clang/CIR/Dialect/Passes.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ def CIRCanonicalize : Pass<"cir-canonicalize"> {
2929
let dependentDialects = ["cir::CIRDialect"];
3030
}
3131

32+
def HoistAllocas : Pass<"cir-hoist-allocas"> {
33+
let summary = "Hoist allocas to the entry of the function";
34+
let description = [{
35+
This pass hoist all non-dynamic allocas to the entry of the function.
36+
This is helpful for later code generation.
37+
}];
38+
let constructor = "mlir::createHoistAllocasPass()";
39+
let dependentDialects = ["cir::CIRDialect"];
40+
}
41+
3242
def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
3343
let summary = "Produces flatten CFG";
3444
let description = [{

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,16 @@ struct MissingFeatures {
130130
static bool continueOp() { return false; }
131131
static bool ifOp() { return false; }
132132
static bool labelOp() { return false; }
133+
static bool ptrDiffOp() { return false; }
134+
static bool ptrStrideOp() { return false; }
133135
static bool selectOp() { return false; }
134136
static bool switchOp() { return false; }
135137
static bool ternaryOp() { return false; }
136138
static bool tryOp() { return false; }
137139
static bool zextOp() { return false; }
138-
static bool ptrStrideOp() { return false; }
139-
static bool ptrDiffOp() { return false; }
140+
141+
// Future CIR attributes
142+
static bool optInfoAttr() { return false; }
140143
};
141144

142145
} // namespace cir

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
4949
// A normal fixed sized variable becomes an alloca in the entry block,
5050
mlir::Type allocaTy = convertTypeForMem(ty);
5151
// Create the temp alloca and declare variable using it.
52-
address = createTempAlloca(allocaTy, alignment, loc, d.getName());
52+
address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
53+
/*insertIntoFnEntryBlock=*/false);
5354
declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
5455

5556
emission.Addr = address;

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,27 @@ void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
317317
}
318318

319319
mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
320-
mlir::Location loc,
321-
CharUnits alignment) {
322-
mlir::Block *entryBlock = getCurFunctionEntryBlock();
320+
mlir::Location loc, CharUnits alignment,
321+
bool insertIntoFnEntryBlock,
322+
mlir::Value arraySize) {
323+
mlir::Block *entryBlock = insertIntoFnEntryBlock
324+
? getCurFunctionEntryBlock()
325+
: curLexScope->getEntryBlock();
326+
327+
// If this is an alloca in the entry basic block of a cir.try and there's
328+
// a surrounding cir.scope, make sure the alloca ends up in the surrounding
329+
// scope instead. This is necessary in order to guarantee all SSA values are
330+
// reachable during cleanups.
331+
assert(!cir::MissingFeatures::tryOp());
332+
333+
return emitAlloca(name, ty, loc, alignment,
334+
builder.getBestAllocaInsertPoint(entryBlock), arraySize);
335+
}
323336

337+
mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
338+
mlir::Location loc, CharUnits alignment,
339+
mlir::OpBuilder::InsertPoint ip,
340+
mlir::Value arraySize) {
324341
// CIR uses its own alloca address space rather than follow the target data
325342
// layout like original CodeGen. The data layout awareness should be done in
326343
// the lowering pass instead.
@@ -331,7 +348,7 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
331348
mlir::Value addr;
332349
{
333350
mlir::OpBuilder::InsertionGuard guard(builder);
334-
builder.restoreInsertionPoint(builder.getBestAllocaInsertPoint(entryBlock));
351+
builder.restoreInsertionPoint(ip);
335352
addr = builder.createAlloca(loc, /*addr type*/ localVarPtrTy,
336353
/*var type*/ ty, name, alignIntAttr);
337354
assert(!cir::MissingFeatures::astVarDeclInterface());
@@ -346,11 +363,13 @@ mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
346363
return builder.createDummyValue(loc, t, alignment);
347364
}
348365

349-
/// This creates an alloca and inserts it at the current insertion point of the
350-
/// builder.
366+
/// This creates an alloca and inserts it into the entry block if
367+
/// \p insertIntoFnEntryBlock is true, otherwise it inserts it at the current
368+
/// insertion point of the builder.
351369
Address CIRGenFunction::createTempAlloca(mlir::Type ty, CharUnits align,
352-
mlir::Location loc,
353-
const Twine &name) {
354-
mlir::Value alloca = emitAlloca(name.str(), ty, loc, align);
370+
mlir::Location loc, const Twine &name,
371+
bool insertIntoFnEntryBlock) {
372+
mlir::Value alloca =
373+
emitAlloca(name.str(), ty, loc, align, insertIntoFnEntryBlock);
355374
return Address(alloca, ty, align);
356375
}

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ mlir::Location CIRGenFunction::getLoc(mlir::Location lhs, mlir::Location rhs) {
138138
void CIRGenFunction::emitAndUpdateRetAlloca(QualType type, mlir::Location loc,
139139
CharUnits alignment) {
140140
if (!type->isVoidType()) {
141-
fnRetAlloca = emitAlloca("__retval", convertType(type), loc, alignment);
141+
fnRetAlloca = emitAlloca("__retval", convertType(type), loc, alignment,
142+
/*insertIntoFnEntryBlock=*/false);
142143
}
143144
}
144145

@@ -293,7 +294,8 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
293294

294295
mlir::Value addrVal =
295296
emitAlloca(cast<NamedDecl>(paramVar)->getName(),
296-
convertType(paramVar->getType()), paramLoc, alignment);
297+
convertType(paramVar->getType()), paramLoc, alignment,
298+
/*insertIntoFnEntryBlock=*/true);
297299

298300
declare(addrVal, paramVar, paramVar->getType(), paramLoc, alignment,
299301
/*isParam=*/true);

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,13 @@ class CIRGenFunction : public CIRGenTypeCache {
109109

110110
public:
111111
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,
112-
mlir::Location loc, clang::CharUnits alignment);
112+
mlir::Location loc, clang::CharUnits alignment,
113+
bool insertIntoFnEntryBlock,
114+
mlir::Value arraySize = nullptr);
115+
mlir::Value emitAlloca(llvm::StringRef name, mlir::Type ty,
116+
mlir::Location loc, clang::CharUnits alignment,
117+
mlir::OpBuilder::InsertPoint ip,
118+
mlir::Value arraySize = nullptr);
113119

114120
mlir::Value createDummyValue(mlir::Location loc, clang::QualType qt);
115121

@@ -483,7 +489,7 @@ class CIRGenFunction : public CIRGenTypeCache {
483489
LexicalScope *curLexScope = nullptr;
484490

485491
Address createTempAlloca(mlir::Type ty, CharUnits align, mlir::Location loc,
486-
const Twine &name = "tmp");
492+
const Twine &name, bool insertIntoFnEntryBlock);
487493
};
488494

489495
} // namespace clang::CIRGen

clang/lib/CIR/Dialect/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_clang_library(MLIRCIRTransforms
22
CIRCanonicalize.cpp
33
FlattenCFG.cpp
4+
HoistAllocas.cpp
45

56
DEPENDS
67
MLIRCIRPassIncGen
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "PassDetail.h"
10+
#include "mlir/Dialect/Func/IR/FuncOps.h"
11+
#include "mlir/IR/PatternMatch.h"
12+
#include "mlir/Support/LogicalResult.h"
13+
#include "mlir/Transforms/DialectConversion.h"
14+
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
15+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
16+
#include "clang/CIR/Dialect/Passes.h"
17+
#include "clang/CIR/MissingFeatures.h"
18+
#include "llvm/Support/TimeProfiler.h"
19+
20+
using namespace mlir;
21+
using namespace cir;
22+
23+
namespace {
24+
25+
struct HoistAllocasPass : public HoistAllocasBase<HoistAllocasPass> {
26+
27+
HoistAllocasPass() = default;
28+
void runOnOperation() override;
29+
};
30+
31+
static void process(mlir::ModuleOp mod, cir::FuncOp func) {
32+
if (func.getRegion().empty())
33+
return;
34+
35+
// Hoist all static allocas to the entry block.
36+
mlir::Block &entryBlock = func.getRegion().front();
37+
mlir::Operation *insertPoint = &*entryBlock.begin();
38+
39+
// Post-order is the default, but the code below requires it, so
40+
// let's not depend on the default staying that way.
41+
func.getBody().walk<mlir::WalkOrder::PostOrder>([&](cir::AllocaOp alloca) {
42+
if (alloca->getBlock() == &entryBlock)
43+
return;
44+
// Don't hoist allocas with dynamic alloca size.
45+
assert(!cir::MissingFeatures::opAllocaDynAllocSize());
46+
47+
// Hoist allocas into the entry block.
48+
49+
// Preserving the `const` attribute on hoisted allocas can cause LLVM to
50+
// incorrectly introduce invariant group metadata in some circumstances.
51+
// The incubator performs some analysis to determine whether the attribute
52+
// can be preserved, but it only runs this analysis when optimizations are
53+
// enabled. Until we start tracking the optimization level, we can just
54+
// always remove the `const` attribute.
55+
assert(!cir::MissingFeatures::optInfoAttr());
56+
if (alloca.getConstant())
57+
alloca.setConstant(false);
58+
59+
alloca->moveBefore(insertPoint);
60+
});
61+
}
62+
63+
void HoistAllocasPass::runOnOperation() {
64+
llvm::TimeTraceScope scope("Hoist Allocas");
65+
llvm::SmallVector<Operation *, 16> ops;
66+
67+
Operation *op = getOperation();
68+
auto mod = mlir::dyn_cast<mlir::ModuleOp>(op);
69+
if (!mod)
70+
mod = op->getParentOfType<mlir::ModuleOp>();
71+
72+
// If we ever introduce nested cir.function ops, we'll need to make this
73+
// walk in post-order and recurse into nested functions.
74+
getOperation()->walk<mlir::WalkOrder::PreOrder>([&](cir::FuncOp op) {
75+
process(mod, op);
76+
return mlir::WalkResult::skip();
77+
});
78+
}
79+
80+
} // namespace
81+
82+
std::unique_ptr<Pass> mlir::createHoistAllocasPass() {
83+
return std::make_unique<HoistAllocasPass>();
84+
}

clang/lib/CIR/Lowering/CIRPasses.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule,
3737
namespace mlir {
3838

3939
void populateCIRPreLoweringPasses(OpPassManager &pm) {
40+
pm.addPass(createHoistAllocasPass());
4041
pm.addPass(createCIRFlattenCFGPass());
4142
}
4243

0 commit comments

Comments
 (0)