Skip to content

Commit 1d614a9

Browse files
authored
[CIR] Add GlobalOp ctor and dtor regions (#160779)
This adds support for ctor and dtor regions in cir::GlobalOp. These regions are used to capture the code that initializes and cleans up the variable, keeping this initialization and cleanup code with the variable definition. This change only adds the CIR dialect support for these regions. Support for generating the code in these regions from source and lowering these to LLVM IR will be added in a later change, as will LoweringPrepare support to move the code into the __cxx_global_var_init() function.
1 parent d23f781 commit 1d614a9

File tree

3 files changed

+182
-33
lines changed

3 files changed

+182
-33
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -683,8 +683,8 @@ def CIR_ConditionOp : CIR_Op<"condition", [
683683
//===----------------------------------------------------------------------===//
684684

685685
defvar CIR_YieldableScopes = [
686-
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp",
687-
"SwitchOp", "TernaryOp", "WhileOp"
686+
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp",
687+
"ScopeOp", "SwitchOp", "TernaryOp", "WhileOp"
688688
];
689689

690690
def CIR_YieldOp : CIR_Op<"yield", [
@@ -1776,7 +1776,9 @@ def CIR_GlobalLinkageKind : CIR_I32EnumAttr<
17761776
// is upstreamed.
17771777

17781778
def CIR_GlobalOp : CIR_Op<"global", [
1779-
DeclareOpInterfaceMethods<CIRGlobalValueInterface>
1779+
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
1780+
DeclareOpInterfaceMethods<CIRGlobalValueInterface>,
1781+
NoRegionArguments
17801782
]> {
17811783
let summary = "Declare or define a global variable";
17821784
let description = [{
@@ -1807,6 +1809,9 @@ def CIR_GlobalOp : CIR_Op<"global", [
18071809
UnitAttr:$dso_local,
18081810
OptionalAttr<I64Attr>:$alignment);
18091811

1812+
let regions = (region MaxSizedRegion<1>:$ctorRegion,
1813+
MaxSizedRegion<1>:$dtorRegion);
1814+
18101815
let assemblyFormat = [{
18111816
($sym_visibility^)?
18121817
(`` $global_visibility^)?
@@ -1815,24 +1820,34 @@ def CIR_GlobalOp : CIR_Op<"global", [
18151820
(`comdat` $comdat^)?
18161821
(`dso_local` $dso_local^)?
18171822
$sym_name
1818-
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
1823+
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value,
1824+
$ctorRegion, $dtorRegion)
18191825
attr-dict
18201826
}];
18211827

18221828
let extraClassDeclaration = [{
1823-
bool isDeclaration() { return !getInitialValue(); }
1829+
bool isDeclaration() {
1830+
return !getInitialValue() && getCtorRegion().empty() && getDtorRegion().empty();
1831+
}
18241832
bool hasInitializer() { return !isDeclaration(); }
18251833
}];
18261834

18271835
let skipDefaultBuilders = 1;
18281836

1829-
let builders = [OpBuilder<(ins
1830-
"llvm::StringRef":$sym_name,
1831-
"mlir::Type":$sym_type,
1832-
CArg<"bool", "false">:$isConstant,
1833-
// CIR defaults to external linkage.
1834-
CArg<"cir::GlobalLinkageKind",
1835-
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
1837+
let builders = [
1838+
OpBuilder<(ins
1839+
"llvm::StringRef":$sym_name,
1840+
"mlir::Type":$sym_type,
1841+
CArg<"bool", "false">:$isConstant,
1842+
// CIR defaults to external linkage.
1843+
CArg<"cir::GlobalLinkageKind",
1844+
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
1845+
CArg<"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>",
1846+
"nullptr">:$ctorBuilder,
1847+
CArg<"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>",
1848+
"nullptr">:$dtorBuilder)
1849+
>
1850+
];
18361851

18371852
let hasVerifier = 1;
18381853

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,9 +1355,11 @@ mlir::LogicalResult cir::GlobalOp::verify() {
13551355
return success();
13561356
}
13571357

1358-
void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
1359-
llvm::StringRef sym_name, mlir::Type sym_type,
1360-
bool isConstant, cir::GlobalLinkageKind linkage) {
1358+
void cir::GlobalOp::build(
1359+
OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name,
1360+
mlir::Type sym_type, bool isConstant, cir::GlobalLinkageKind linkage,
1361+
function_ref<void(OpBuilder &, Location)> ctorBuilder,
1362+
function_ref<void(OpBuilder &, Location)> dtorBuilder) {
13611363
odsState.addAttribute(getSymNameAttrName(odsState.name),
13621364
odsBuilder.getStringAttr(sym_name));
13631365
odsState.addAttribute(getSymTypeAttrName(odsState.name),
@@ -1370,43 +1372,127 @@ void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
13701372
cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage);
13711373
odsState.addAttribute(getLinkageAttrName(odsState.name), linkageAttr);
13721374

1375+
Region *ctorRegion = odsState.addRegion();
1376+
if (ctorBuilder) {
1377+
odsBuilder.createBlock(ctorRegion);
1378+
ctorBuilder(odsBuilder, odsState.location);
1379+
}
1380+
1381+
Region *dtorRegion = odsState.addRegion();
1382+
if (dtorBuilder) {
1383+
odsBuilder.createBlock(dtorRegion);
1384+
dtorBuilder(odsBuilder, odsState.location);
1385+
}
1386+
13731387
odsState.addAttribute(getGlobalVisibilityAttrName(odsState.name),
13741388
cir::VisibilityAttr::get(odsBuilder.getContext()));
13751389
}
13761390

1391+
/// Given the region at `index`, or the parent operation if `index` is None,
1392+
/// return the successor regions. These are the regions that may be selected
1393+
/// during the flow of control. `operands` is a set of optional attributes that
1394+
/// correspond to a constant value for each operand, or null if that operand is
1395+
/// not a constant.
1396+
void cir::GlobalOp::getSuccessorRegions(
1397+
mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
1398+
// The `ctor` and `dtor` regions always branch back to the parent operation.
1399+
if (!point.isParent()) {
1400+
regions.push_back(RegionSuccessor());
1401+
return;
1402+
}
1403+
1404+
// Don't consider the ctor region if it is empty.
1405+
Region *ctorRegion = &this->getCtorRegion();
1406+
if (ctorRegion->empty())
1407+
ctorRegion = nullptr;
1408+
1409+
// Don't consider the dtor region if it is empty.
1410+
Region *dtorRegion = &this->getCtorRegion();
1411+
if (dtorRegion->empty())
1412+
dtorRegion = nullptr;
1413+
1414+
// If the condition isn't constant, both regions may be executed.
1415+
if (ctorRegion)
1416+
regions.push_back(RegionSuccessor(ctorRegion));
1417+
if (dtorRegion)
1418+
regions.push_back(RegionSuccessor(dtorRegion));
1419+
}
1420+
13771421
static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op,
1378-
TypeAttr type,
1379-
Attribute initAttr) {
1422+
TypeAttr type, Attribute initAttr,
1423+
mlir::Region &ctorRegion,
1424+
mlir::Region &dtorRegion) {
1425+
auto printType = [&]() { p << ": " << type; };
13801426
if (!op.isDeclaration()) {
13811427
p << "= ";
1382-
// This also prints the type...
1383-
if (initAttr)
1384-
printConstant(p, initAttr);
1428+
if (!ctorRegion.empty()) {
1429+
p << "ctor ";
1430+
printType();
1431+
p << " ";
1432+
p.printRegion(ctorRegion,
1433+
/*printEntryBlockArgs=*/false,
1434+
/*printBlockTerminators=*/false);
1435+
} else {
1436+
// This also prints the type...
1437+
if (initAttr)
1438+
printConstant(p, initAttr);
1439+
}
1440+
1441+
if (!dtorRegion.empty()) {
1442+
p << " dtor ";
1443+
p.printRegion(dtorRegion,
1444+
/*printEntryBlockArgs=*/false,
1445+
/*printBlockTerminators=*/false);
1446+
}
13851447
} else {
1386-
p << ": " << type;
1448+
printType();
13871449
}
13881450
}
13891451

1390-
static ParseResult
1391-
parseGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr,
1392-
Attribute &initialValueAttr) {
1452+
static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser,
1453+
TypeAttr &typeAttr,
1454+
Attribute &initialValueAttr,
1455+
mlir::Region &ctorRegion,
1456+
mlir::Region &dtorRegion) {
13931457
mlir::Type opTy;
13941458
if (parser.parseOptionalEqual().failed()) {
13951459
// Absence of equal means a declaration, so we need to parse the type.
13961460
// cir.global @a : !cir.int<s, 32>
13971461
if (parser.parseColonType(opTy))
13981462
return failure();
13991463
} else {
1400-
// Parse constant with initializer, examples:
1401-
// cir.global @y = #cir.fp<1.250000e+00> : !cir.double
1402-
// cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>
1403-
if (parseConstantValue(parser, initialValueAttr).failed())
1404-
return failure();
1464+
// Parse contructor, example:
1465+
// cir.global @rgb = ctor : type { ... }
1466+
if (!parser.parseOptionalKeyword("ctor")) {
1467+
if (parser.parseColonType(opTy))
1468+
return failure();
1469+
auto parseLoc = parser.getCurrentLocation();
1470+
if (parser.parseRegion(ctorRegion, /*arguments=*/{}, /*argTypes=*/{}))
1471+
return failure();
1472+
if (ensureRegionTerm(parser, ctorRegion, parseLoc).failed())
1473+
return failure();
1474+
} else {
1475+
// Parse constant with initializer, examples:
1476+
// cir.global @y = 3.400000e+00 : f32
1477+
// cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>
1478+
if (parseConstantValue(parser, initialValueAttr).failed())
1479+
return failure();
1480+
1481+
assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&
1482+
"Non-typed attrs shouldn't appear here.");
1483+
auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);
1484+
opTy = typedAttr.getType();
1485+
}
14051486

1406-
assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&
1407-
"Non-typed attrs shouldn't appear here.");
1408-
auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);
1409-
opTy = typedAttr.getType();
1487+
// Parse destructor, example:
1488+
// dtor { ... }
1489+
if (!parser.parseOptionalKeyword("dtor")) {
1490+
auto parseLoc = parser.getCurrentLocation();
1491+
if (parser.parseRegion(dtorRegion, /*arguments=*/{}, /*argTypes=*/{}))
1492+
return failure();
1493+
if (ensureRegionTerm(parser, dtorRegion, parseLoc).failed())
1494+
return failure();
1495+
}
14101496
}
14111497

14121498
typeAttr = TypeAttr::get(opTy);

clang/test/CIR/IR/global-init.cir

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: cir-opt --verify-roundtrip %s -o - | FileCheck %s
2+
3+
!u8i = !cir.int<u, 8>
4+
5+
!rec_NeedsCtor = !cir.record<struct "NeedsCtor" padded {!u8i}>
6+
!rec_NeedsDtor = !cir.record<struct "NeedsDtor" padded {!u8i}>
7+
!rec_NeedsCtorDtor = !cir.record<struct "NeedsCtorDtor" padded {!u8i}>
8+
9+
module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
10+
cir.func private @_ZN9NeedsCtorC1Ev(!cir.ptr<!rec_NeedsCtor>)
11+
cir.global external @needsCtor = ctor : !rec_NeedsCtor {
12+
%0 = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
13+
cir.call @_ZN9NeedsCtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtor>) -> ()
14+
}
15+
// CHECK: cir.global external @needsCtor = ctor : !rec_NeedsCtor {
16+
// CHECK: %0 = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
17+
// CHECK: cir.call @_ZN9NeedsCtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtor>) -> ()
18+
// CHECK: }
19+
20+
cir.func private @_ZN9NeedsDtorD1Ev(!cir.ptr<!rec_NeedsDtor>)
21+
cir.global external dso_local @needsDtor = #cir.zero : !rec_NeedsDtor dtor {
22+
%0 = cir.get_global @needsDtor : !cir.ptr<!rec_NeedsDtor>
23+
cir.call @_ZN9NeedsDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsDtor>) -> ()
24+
}
25+
// CHECK: cir.global external dso_local @needsDtor = #cir.zero : !rec_NeedsDtor dtor {
26+
// CHECK: %0 = cir.get_global @needsDtor : !cir.ptr<!rec_NeedsDtor>
27+
// CHECK: cir.call @_ZN9NeedsDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsDtor>) -> ()
28+
// CHECK: }
29+
30+
cir.func private @_ZN13NeedsCtorDtorC1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
31+
cir.func private @_ZN13NeedsCtorDtorD1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
32+
cir.global external dso_local @needsCtorDtor = ctor : !rec_NeedsCtorDtor {
33+
%0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
34+
cir.call @_ZN13NeedsCtorDtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
35+
} dtor {
36+
%0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
37+
cir.call @_ZN13NeedsCtorDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
38+
}
39+
// CHECK: cir.func private @_ZN13NeedsCtorDtorC1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
40+
// CHECK: cir.func private @_ZN13NeedsCtorDtorD1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
41+
// CHECK: cir.global external dso_local @needsCtorDtor = ctor : !rec_NeedsCtorDtor {
42+
// CHECK: %0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
43+
// CHECK: cir.call @_ZN13NeedsCtorDtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
44+
// CHECK: } dtor {
45+
// CHECK: %0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
46+
// CHECK: cir.call @_ZN13NeedsCtorDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
47+
// CHECK: }
48+
}

0 commit comments

Comments
 (0)