Skip to content

Commit ab27364

Browse files
[CIR] Add lowering of BlockAddressOp (#1909)
This PR adds lowering of `BlockAddressOp`. It uses two maps, `blockInfoToTagOp` and `unresolvedBlockAddressOp`, to defer matching `mlir::LLVM::BlockAddressOp` to its corresponding `mlir::LLVM::BlockTagOp` in cases where the matching label has not yet been emitted. If the `BlockTagOp` is not emitted, a placeholder value `std::numeric_limits<uint32_t>::max()` is used, which will later be resolved in `resolveBlockAddressOp`. Support for indirect goto and label differences will be added in a future PR.
1 parent 260599e commit ab27364

File tree

3 files changed

+256
-6
lines changed

3 files changed

+256
-6
lines changed

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,8 @@ struct ConvertCIRToLLVMPass
14881488
llvm::StringMap<mlir::LLVM::GlobalOp> &argStringGlobalsMap,
14891489
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> &argsVarMap);
14901490

1491+
void resolveBlockAddressOp(LLVMBlockAddressInfo &blockInfoAddr);
1492+
14911493
void processCIRAttrs(mlir::ModuleOp moduleOp);
14921494

14931495
StringRef getDescription() const override {
@@ -4496,16 +4498,74 @@ mlir::LogicalResult CIRToLLVMLinkerOptionsOpLowering::matchAndRewrite(
44964498
return mlir::success();
44974499
}
44984500

4501+
mlir::LogicalResult CIRToLLVMLabelOpLowering::matchAndRewrite(
4502+
cir::LabelOp op, OpAdaptor adaptor,
4503+
mlir::ConversionPatternRewriter &rewriter) const {
4504+
mlir::MLIRContext *ctx = rewriter.getContext();
4505+
mlir::Block *block = op->getBlock();
4506+
// A BlockTagOp cannot reside in the entry block. The address of the entry
4507+
// block cannot be taken
4508+
if (block->isEntryBlock()) {
4509+
mlir::Block *newBlock =
4510+
rewriter.splitBlock(op->getBlock(), mlir::Block::iterator(op));
4511+
rewriter.setInsertionPointToEnd(block);
4512+
mlir::LLVM::BrOp::create(rewriter, op.getLoc(), newBlock);
4513+
}
4514+
auto tagAttr =
4515+
mlir::LLVM::BlockTagAttr::get(ctx, blockInfoAddr.getTagIndex());
4516+
rewriter.setInsertionPoint(op);
4517+
4518+
auto blockTagOp =
4519+
mlir::LLVM::BlockTagOp::create(rewriter, op->getLoc(), tagAttr);
4520+
auto func = op->getParentOfType<mlir::LLVM::LLVMFuncOp>();
4521+
blockInfoAddr.mapBlockTag(func.getSymName(), op.getLabel(), blockTagOp);
4522+
rewriter.eraseOp(op);
4523+
4524+
return mlir::success();
4525+
}
4526+
4527+
mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite(
4528+
cir::BlockAddressOp op, OpAdaptor adaptor,
4529+
mlir::ConversionPatternRewriter &rewriter) const {
4530+
mlir::MLIRContext *ctx = rewriter.getContext();
4531+
4532+
mlir::LLVM::BlockTagOp matchLabel =
4533+
blockInfoAddr.lookupBlockTag(op.getFunc(), op.getLabel());
4534+
mlir::LLVM::BlockTagAttr tagAttr;
4535+
if (!matchLabel)
4536+
// If the BlockTagOp has not been emitted yet, use a placeholder.
4537+
// This will later be replaced with the correct tag index during
4538+
// `resolveBlockAddressOp`.
4539+
tagAttr = {};
4540+
else
4541+
tagAttr = matchLabel.getTag();
4542+
4543+
auto blkAddr = mlir::LLVM::BlockAddressAttr::get(rewriter.getContext(),
4544+
op.getFuncAttr(), tagAttr);
4545+
rewriter.setInsertionPoint(op);
4546+
auto newOp = mlir::LLVM::BlockAddressOp::create(
4547+
rewriter, op.getLoc(), mlir::LLVM::LLVMPointerType::get(ctx), blkAddr);
4548+
if (!matchLabel)
4549+
blockInfoAddr.addUnresolvedBlockAddress(newOp, op.getFunc(), op.getLabel());
4550+
rewriter.replaceOp(op, newOp);
4551+
return mlir::success();
4552+
}
4553+
44994554
void populateCIRToLLVMConversionPatterns(
45004555
mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter,
45014556
mlir::DataLayout &dataLayout, cir::LowerModule *lowerModule,
45024557
llvm::StringMap<mlir::LLVM::GlobalOp> &stringGlobalsMap,
45034558
llvm::StringMap<mlir::LLVM::GlobalOp> &argStringGlobalsMap,
4504-
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> &argsVarMap) {
4559+
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> &argsVarMap,
4560+
LLVMBlockAddressInfo &blockAddrInfo) {
45054561
patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());
45064562
patterns.add<CIRToLLVMAllocaOpLowering>(converter, dataLayout,
45074563
stringGlobalsMap, argStringGlobalsMap,
45084564
argsVarMap, patterns.getContext());
4565+
patterns.add<CIRToLLVMBlockAddressOpLowering>(
4566+
converter, patterns.getContext(), blockAddrInfo);
4567+
patterns.add<CIRToLLVMLabelOpLowering>(converter, patterns.getContext(),
4568+
blockAddrInfo);
45094569
patterns.add<
45104570
// clang-format off
45114571
CIRToLLVMCastOpLowering,
@@ -4990,6 +5050,25 @@ void ConvertCIRToLLVMPass::buildGlobalAnnotationsVar(
49905050
}
49915051
}
49925052

5053+
void ConvertCIRToLLVMPass::resolveBlockAddressOp(
5054+
LLVMBlockAddressInfo &blockInfoAddr) {
5055+
5056+
mlir::ModuleOp module = getOperation();
5057+
mlir::OpBuilder opBuilder(module.getContext());
5058+
for (auto &[blockAddOp, blockInfo] :
5059+
blockInfoAddr.getUnresolvedBlockAddress()) {
5060+
mlir::LLVM::BlockTagOp resolvedLabel =
5061+
blockInfoAddr.lookupBlockTag(blockInfo.first, blockInfo.second);
5062+
assert(resolvedLabel && "expected BlockTagOp to already be emitted");
5063+
auto fnSym =
5064+
mlir::FlatSymbolRefAttr::get(module.getContext(), blockInfo.first);
5065+
auto blkAddTag = mlir::LLVM::BlockAddressAttr::get(
5066+
opBuilder.getContext(), fnSym, resolvedLabel.getTagAttr());
5067+
blockAddOp.setBlockAddrAttr(blkAddTag);
5068+
}
5069+
blockInfoAddr.clearUnresolvedMap();
5070+
}
5071+
49935072
void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
49945073
// Lower the module attributes to LLVM equivalents.
49955074
if (auto tripleAttr = module->getAttr(cir::CIRDialect::getTripleAttrName()))
@@ -5021,10 +5100,15 @@ void ConvertCIRToLLVMPass::runOnOperation() {
50215100
llvm::StringMap<mlir::LLVM::GlobalOp> argStringGlobalsMap;
50225101
// Track globals created for annotation args.
50235102
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> argsVarMap;
5103+
/// Tracks the state required to lower CIR `LabelOp` and `BlockAddressOp`.
5104+
/// Maps labels to their corresponding `BlockTagOp` and keeps bookkeeping
5105+
/// of unresolved `BlockAddressOp`s until they are matched with the
5106+
/// corresponding `BlockTagOp` in `resolveBlockAddressOp`.
5107+
LLVMBlockAddressInfo blockInfoAddr;
5108+
populateCIRToLLVMConversionPatterns(
5109+
patterns, converter, dataLayout, lowerModule.get(), stringGlobalsMap,
5110+
argStringGlobalsMap, argsVarMap, blockInfoAddr);
50245111

5025-
populateCIRToLLVMConversionPatterns(patterns, converter, dataLayout,
5026-
lowerModule.get(), stringGlobalsMap,
5027-
argStringGlobalsMap, argsVarMap);
50285112
mlir::populateFuncToLLVMConversionPatterns(converter, patterns);
50295113

50305114
mlir::ConversionTarget target(getContext());
@@ -5078,7 +5162,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
50785162
dtorAttr.getPriority());
50795163
});
50805164
buildGlobalAnnotationsVar(stringGlobalsMap, argStringGlobalsMap, argsVarMap);
5081-
5165+
resolveBlockAddressOp(blockInfoAddr);
50825166
processCIRAttrs(module);
50835167
}
50845168

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,60 @@ void buildCtorDtorList(
4545
llvm::function_ref<std::pair<mlir::StringRef, int>(mlir::Attribute)>
4646
createXtor);
4747

48+
struct LLVMBlockAddressInfo {
49+
// Get the next tag index
50+
uint32_t getTagIndex() { return blockTagOpIndex++; }
51+
52+
void mapBlockTag(llvm::StringRef func, llvm::StringRef label,
53+
mlir::LLVM::BlockTagOp tagOp) {
54+
auto result = blockInfoToTagOp.try_emplace({func, label}, tagOp);
55+
assert(result.second &&
56+
"attempting to map a BlockTag operation that is already mapped");
57+
}
58+
59+
// Lookup a BlockTagOp, may return nullptr if not yet registered.
60+
mlir::LLVM::BlockTagOp lookupBlockTag(llvm::StringRef func,
61+
llvm::StringRef label) const {
62+
return blockInfoToTagOp.lookup({func, label});
63+
}
64+
65+
// Record an unresolved BlockAddressOp that needs patching later.
66+
void addUnresolvedBlockAddress(mlir::LLVM::BlockAddressOp op,
67+
llvm::StringRef func, llvm::StringRef label) {
68+
unresolvedBlockAddressOp.try_emplace(op, std::make_pair(func, label));
69+
}
70+
71+
void clearUnresolvedMap() { unresolvedBlockAddressOp.clear(); }
72+
73+
llvm::DenseMap<mlir::LLVM::BlockAddressOp,
74+
std::pair<llvm::StringRef, llvm::StringRef>> &
75+
getUnresolvedBlockAddress() {
76+
return unresolvedBlockAddressOp;
77+
}
78+
79+
private:
80+
// Maps a (function name, label name) pair to the corresponding BlockTagOp.
81+
// Used to resolve CIR LabelOps into their LLVM BlockTagOp.
82+
llvm::DenseMap<std::pair<llvm::StringRef, llvm::StringRef>,
83+
mlir::LLVM::BlockTagOp>
84+
blockInfoToTagOp;
85+
// Tracks BlockAddressOps that could not yet be fully resolved because
86+
// their BlockTagOp was not available at the time of lowering. The map
87+
// stores the unresolved BlockAddressOp along with its (function name, label
88+
// name) pair so it can be patched later.
89+
llvm::DenseMap<mlir::LLVM::BlockAddressOp,
90+
std::pair<llvm::StringRef, llvm::StringRef>>
91+
unresolvedBlockAddressOp;
92+
int32_t blockTagOpIndex;
93+
};
94+
4895
void populateCIRToLLVMConversionPatterns(
4996
mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter,
5097
mlir::DataLayout &dataLayout,
5198
llvm::StringMap<mlir::LLVM::GlobalOp> &stringGlobalsMap,
5299
llvm::StringMap<mlir::LLVM::GlobalOp> &argStringGlobalsMap,
53-
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> &argsVarMap);
100+
llvm::MapVector<mlir::ArrayAttr, mlir::LLVM::GlobalOp> &argsVarMap,
101+
LLVMBlockAddressInfo &blockAddrInfo);
54102

55103
std::unique_ptr<cir::LowerModule> prepareLowerModule(mlir::ModuleOp module);
56104

@@ -1329,6 +1377,40 @@ class CIRToLLVMLinkerOptionsOpLowering
13291377
mlir::ConversionPatternRewriter &rewriter) const override;
13301378
};
13311379

1380+
class CIRToLLVMLabelOpLowering
1381+
: public mlir::OpConversionPattern<cir::LabelOp> {
1382+
LLVMBlockAddressInfo &blockInfoAddr;
1383+
1384+
public:
1385+
CIRToLLVMLabelOpLowering(const mlir::TypeConverter &typeConverter,
1386+
mlir::MLIRContext *context,
1387+
LLVMBlockAddressInfo &blockInfoAddr)
1388+
: OpConversionPattern<cir::LabelOp>(typeConverter, context),
1389+
blockInfoAddr(blockInfoAddr) {}
1390+
using mlir::OpConversionPattern<cir::LabelOp>::OpConversionPattern;
1391+
1392+
mlir::LogicalResult
1393+
matchAndRewrite(cir::LabelOp op, OpAdaptor,
1394+
mlir::ConversionPatternRewriter &) const override;
1395+
};
1396+
1397+
class CIRToLLVMBlockAddressOpLowering
1398+
: public mlir::OpConversionPattern<cir::BlockAddressOp> {
1399+
LLVMBlockAddressInfo &blockInfoAddr;
1400+
1401+
public:
1402+
CIRToLLVMBlockAddressOpLowering(const mlir::TypeConverter &typeConverter,
1403+
mlir::MLIRContext *context,
1404+
LLVMBlockAddressInfo &blockInfoAddr)
1405+
: OpConversionPattern<cir::BlockAddressOp>(typeConverter, context),
1406+
blockInfoAddr(blockInfoAddr) {}
1407+
using mlir::OpConversionPattern<cir::BlockAddressOp>::OpConversionPattern;
1408+
1409+
mlir::LogicalResult
1410+
matchAndRewrite(cir::BlockAddressOp op, OpAdaptor,
1411+
mlir::ConversionPatternRewriter &) const override;
1412+
};
1413+
13321414
mlir::ArrayAttr lowerCIRTBAAAttr(mlir::Attribute tbaa,
13331415
mlir::ConversionPatternRewriter &rewriter,
13341416
cir::LowerModule *lowerMod);

clang/test/CIR/CodeGen/label-values.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
22
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
37

48
void A(void) {
59
void *ptr = &&A;
@@ -14,6 +18,22 @@ void A(void) {
1418
// CIR: ^bb1: // pred: ^bb0
1519
// CIR: cir.label "A"
1620
// CIR: cir.return
21+
//
22+
// LLVM: define dso_local void @A()
23+
// LLVM: [[PTR:%.*]] = alloca ptr, i64 1, align 8
24+
// LLVM: store ptr blockaddress(@A, %[[A:.*]]), ptr [[PTR]], align 8
25+
// LLVM: br label %[[A]]
26+
// LLVM: [[A]]: ; preds = %0
27+
// LLVM: ret void
28+
29+
// OGCG: define dso_local void @A()
30+
// OGCG: [[PTR:%.*]] = alloca ptr, align 8
31+
// OGCG: store ptr blockaddress(@A, %A), ptr [[PTR]], align 8
32+
// OGCG: br label %A
33+
// OGCG: A: ; preds = %entry, %indirectgoto
34+
// OGCG: ret void
35+
// OGCG: indirectgoto: ; No predecessors!
36+
// OGCG: indirectbr ptr poison, [label %A]
1737

1838
void B(void) {
1939
B:
@@ -27,6 +47,22 @@ void B(void) {
2747
// CIR: cir.store align(8) [[BLOCK]], [[PTR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
2848
// CIR: cir.return
2949

50+
// LLVM: define dso_local void @B
51+
// LLVM: br label %[[B:.*]]
52+
// LLVM: [[B]]:
53+
// LLVM: %[[PTR:.*]] = alloca ptr, i64 1, align 8
54+
// LLVM: store ptr blockaddress(@B, %[[B]]), ptr %[[PTR]], align 8
55+
// LLVM: ret void
56+
57+
// OGCG: define dso_local void @B
58+
// OGCG: [[PTR:%.*]] = alloca ptr, align 8
59+
// OGCG: br label %B
60+
// OGCG: B: ; preds = %indirectgoto, %entry
61+
// OGCG: store ptr blockaddress(@B, %B), ptr [[PTR]], align 8
62+
// OGCG: ret void
63+
// OGCG: indirectgoto: ; No predecessors!
64+
// OGCG: indirectbr ptr poison, [label %B]
65+
3066
void C(int x) {
3167
void *ptr = (x == 0) ? &&A : &&B;
3268
A:
@@ -50,6 +86,30 @@ void C(int x) {
5086
// CIR: cir.label "B"
5187
// CIR: cir.br ^bb1
5288

89+
// LLVM: define dso_local void @C(i32 %0)
90+
// LLVM: [[COND:%.*]] = select i1 [[CMP:%.*]], ptr blockaddress(@C, %[[A:.*]]), ptr blockaddress(@C, %[[B:.*]])
91+
// LLVM: store ptr [[COND]], ptr [[PTR:%.*]], align 8
92+
// LLVM: br label %[[A]]
93+
// LLVM: [[RET:.*]]:
94+
// LLVM: ret void
95+
// LLVM: [[A]]:
96+
// LLVM: br label %[[RET]]
97+
// LLVM: [[B]]:
98+
// LLVM: br label %[[RET]]
99+
100+
// OGCG: define dso_local void @C
101+
// OGCG: [[COND:%.*]] = select i1 [[CMP:%.*]], ptr blockaddress(@C, %A), ptr blockaddress(@C, %B)
102+
// OGCG: store ptr [[COND]], ptr [[PTR:%.*]], align 8
103+
// OGCG: br label %A
104+
// OGCG: A: ; preds = %entry, %indirectgoto
105+
// OGCG: br label %return
106+
// OGCG: B: ; preds = %indirectgoto
107+
// OGCG: br label %return
108+
// OGCG: return: ; preds = %B, %A
109+
// OGCG: ret void
110+
// OGCG: indirectgoto: ; No predecessors!
111+
// OGCG: indirectbr ptr poison, [label %A, label %B]
112+
53113
void D(void) {
54114
void *ptr = &&A;
55115
void *ptr2 = &&A;
@@ -72,3 +132,27 @@ void D(void) {
72132
// CIR: %[[BLK3:.*]] = cir.blockaddress(@D, "A") -> !cir.ptr<!void>
73133
// CIR: cir.store align(8) %[[BLK3]], %[[PTR3]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
74134
// CIR: cir.return
135+
136+
// LLVM: define dso_local void @D
137+
// LLVM: %[[PTR:.*]] = alloca ptr, i64 1, align 8
138+
// LLVM: %[[PTR2:.*]] = alloca ptr, i64 1, align 8
139+
// LLVM: %[[PTR3:.*]] = alloca ptr, i64 1, align 8
140+
// LLVM: store ptr blockaddress(@D, %[[A:.*]]), ptr %[[PTR]], align 8
141+
// LLVM: store ptr blockaddress(@D, %[[A]]), ptr %[[PTR2]], align 8
142+
// LLVM: br label %[[A]]
143+
// LLVM: [[A]]:
144+
// LLVM: store ptr blockaddress(@D, %[[A]]), ptr %[[PTR3]], align 8
145+
// LLVM: ret void
146+
147+
// OGCG: define dso_local void @D
148+
// OGCG: %[[PTR:.*]] = alloca ptr, align 8
149+
// OGCG: %[[PTR2:.*]] = alloca ptr, align 8
150+
// OGCG: %[[PTR3:.*]] = alloca ptr, align 8
151+
// OGCG: store ptr blockaddress(@D, %A), ptr %[[PTR]], align 8
152+
// OGCG: store ptr blockaddress(@D, %A), ptr %[[PTR2]], align 8
153+
// OGCG: br label %A
154+
// OGCG: A:
155+
// OGCG: store ptr blockaddress(@D, %A), ptr %[[PTR3]], align 8
156+
// OGCG: ret void
157+
// OGCG: indirectgoto:
158+
// OGCG: indirectbr ptr poison, [label %A, label %A, label %A]

0 commit comments

Comments
 (0)