Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -683,8 +683,8 @@ def CIR_ConditionOp : CIR_Op<"condition", [
//===----------------------------------------------------------------------===//

defvar CIR_YieldableScopes = [
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp",
"SwitchOp", "TernaryOp", "WhileOp"
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp",
"ScopeOp", "SwitchOp", "TernaryOp", "WhileOp"
];

def CIR_YieldOp : CIR_Op<"yield", [
Expand Down Expand Up @@ -1776,7 +1776,9 @@ def CIR_GlobalLinkageKind : CIR_I32EnumAttr<
// is upstreamed.

def CIR_GlobalOp : CIR_Op<"global", [
DeclareOpInterfaceMethods<CIRGlobalValueInterface>
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
DeclareOpInterfaceMethods<CIRGlobalValueInterface>,
NoRegionArguments
]> {
let summary = "Declare or define a global variable";
let description = [{
Expand Down Expand Up @@ -1807,6 +1809,9 @@ def CIR_GlobalOp : CIR_Op<"global", [
UnitAttr:$dso_local,
OptionalAttr<I64Attr>:$alignment);

let regions = (region MaxSizedRegion<1>:$ctorRegion,
MaxSizedRegion<1>:$dtorRegion);

let assemblyFormat = [{
($sym_visibility^)?
(`` $global_visibility^)?
Expand All @@ -1815,24 +1820,34 @@ def CIR_GlobalOp : CIR_Op<"global", [
(`comdat` $comdat^)?
(`dso_local` $dso_local^)?
$sym_name
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value,
$ctorRegion, $dtorRegion)
attr-dict
}];

let extraClassDeclaration = [{
bool isDeclaration() { return !getInitialValue(); }
bool isDeclaration() {
return !getInitialValue() && getCtorRegion().empty() && getDtorRegion().empty();
}
bool hasInitializer() { return !isDeclaration(); }
}];

let skipDefaultBuilders = 1;

let builders = [OpBuilder<(ins
"llvm::StringRef":$sym_name,
"mlir::Type":$sym_type,
CArg<"bool", "false">:$isConstant,
// CIR defaults to external linkage.
CArg<"cir::GlobalLinkageKind",
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
let builders = [
OpBuilder<(ins
"llvm::StringRef":$sym_name,
"mlir::Type":$sym_type,
CArg<"bool", "false">:$isConstant,
// CIR defaults to external linkage.
CArg<"cir::GlobalLinkageKind",
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
CArg<"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>",
"nullptr">:$ctorBuilder,
CArg<"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>",
"nullptr">:$dtorBuilder)
>
];

let hasVerifier = 1;

Expand Down
128 changes: 107 additions & 21 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1355,9 +1355,11 @@ mlir::LogicalResult cir::GlobalOp::verify() {
return success();
}

void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
llvm::StringRef sym_name, mlir::Type sym_type,
bool isConstant, cir::GlobalLinkageKind linkage) {
void cir::GlobalOp::build(
OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name,
mlir::Type sym_type, bool isConstant, cir::GlobalLinkageKind linkage,
function_ref<void(OpBuilder &, Location)> ctorBuilder,
function_ref<void(OpBuilder &, Location)> dtorBuilder) {
odsState.addAttribute(getSymNameAttrName(odsState.name),
odsBuilder.getStringAttr(sym_name));
odsState.addAttribute(getSymTypeAttrName(odsState.name),
Expand All @@ -1370,43 +1372,127 @@ void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState,
cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage);
odsState.addAttribute(getLinkageAttrName(odsState.name), linkageAttr);

Region *ctorRegion = odsState.addRegion();
if (ctorBuilder) {
odsBuilder.createBlock(ctorRegion);
ctorBuilder(odsBuilder, odsState.location);
}

Region *dtorRegion = odsState.addRegion();
if (dtorBuilder) {
odsBuilder.createBlock(dtorRegion);
dtorBuilder(odsBuilder, odsState.location);
}

odsState.addAttribute(getGlobalVisibilityAttrName(odsState.name),
cir::VisibilityAttr::get(odsBuilder.getContext()));
}

/// Given the region at `index`, or the parent operation if `index` is None,
/// return the successor regions. These are the regions that may be selected
/// during the flow of control. `operands` is a set of optional attributes that
/// correspond to a constant value for each operand, or null if that operand is
/// not a constant.
void cir::GlobalOp::getSuccessorRegions(
mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
// The `ctor` and `dtor` regions always branch back to the parent operation.
if (!point.isParent()) {
regions.push_back(RegionSuccessor());
return;
}

// Don't consider the ctor region if it is empty.
Region *ctorRegion = &this->getCtorRegion();
if (ctorRegion->empty())
ctorRegion = nullptr;

// Don't consider the dtor region if it is empty.
Region *dtorRegion = &this->getCtorRegion();
if (dtorRegion->empty())
dtorRegion = nullptr;

// If the condition isn't constant, both regions may be executed.
if (ctorRegion)
regions.push_back(RegionSuccessor(ctorRegion));
if (dtorRegion)
regions.push_back(RegionSuccessor(dtorRegion));
}

static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op,
TypeAttr type,
Attribute initAttr) {
TypeAttr type, Attribute initAttr,
mlir::Region &ctorRegion,
mlir::Region &dtorRegion) {
auto printType = [&]() { p << ": " << type; };
if (!op.isDeclaration()) {
p << "= ";
// This also prints the type...
if (initAttr)
printConstant(p, initAttr);
if (!ctorRegion.empty()) {
p << "ctor ";
printType();
p << " ";
p.printRegion(ctorRegion,
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/false);
} else {
// This also prints the type...
if (initAttr)
printConstant(p, initAttr);
}

if (!dtorRegion.empty()) {
p << " dtor ";
p.printRegion(dtorRegion,
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/false);
}
} else {
p << ": " << type;
printType();
}
}

static ParseResult
parseGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr,
Attribute &initialValueAttr) {
static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser,
TypeAttr &typeAttr,
Attribute &initialValueAttr,
mlir::Region &ctorRegion,
mlir::Region &dtorRegion) {
mlir::Type opTy;
if (parser.parseOptionalEqual().failed()) {
// Absence of equal means a declaration, so we need to parse the type.
// cir.global @a : !cir.int<s, 32>
if (parser.parseColonType(opTy))
return failure();
} else {
// Parse constant with initializer, examples:
// cir.global @y = #cir.fp<1.250000e+00> : !cir.double
// cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>
if (parseConstantValue(parser, initialValueAttr).failed())
return failure();
// Parse contructor, example:
// cir.global @rgb = ctor : type { ... }
if (!parser.parseOptionalKeyword("ctor")) {
if (parser.parseColonType(opTy))
return failure();
auto parseLoc = parser.getCurrentLocation();
if (parser.parseRegion(ctorRegion, /*arguments=*/{}, /*argTypes=*/{}))
return failure();
if (ensureRegionTerm(parser, ctorRegion, parseLoc).failed())
return failure();
} else {
// Parse constant with initializer, examples:
// cir.global @y = 3.400000e+00 : f32
// cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>
if (parseConstantValue(parser, initialValueAttr).failed())
return failure();

assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&
"Non-typed attrs shouldn't appear here.");
auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);
opTy = typedAttr.getType();
}

assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&
"Non-typed attrs shouldn't appear here.");
auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);
opTy = typedAttr.getType();
// Parse destructor, example:
// dtor { ... }
if (!parser.parseOptionalKeyword("dtor")) {
auto parseLoc = parser.getCurrentLocation();
if (parser.parseRegion(dtorRegion, /*arguments=*/{}, /*argTypes=*/{}))
return failure();
if (ensureRegionTerm(parser, dtorRegion, parseLoc).failed())
return failure();
}
}

typeAttr = TypeAttr::get(opTy);
Expand Down
48 changes: 48 additions & 0 deletions clang/test/CIR/IR/global-init.cir
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// RUN: cir-opt --verify-roundtrip %s -o - | FileCheck %s

!u8i = !cir.int<u, 8>

!rec_NeedsCtor = !cir.record<struct "NeedsCtor" padded {!u8i}>
!rec_NeedsDtor = !cir.record<struct "NeedsDtor" padded {!u8i}>
!rec_NeedsCtorDtor = !cir.record<struct "NeedsCtorDtor" padded {!u8i}>

module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
cir.func private @_ZN9NeedsCtorC1Ev(!cir.ptr<!rec_NeedsCtor>)
cir.global external @needsCtor = ctor : !rec_NeedsCtor {
%0 = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
cir.call @_ZN9NeedsCtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtor>) -> ()
}
// CHECK: cir.global external @needsCtor = ctor : !rec_NeedsCtor {
// CHECK: %0 = cir.get_global @needsCtor : !cir.ptr<!rec_NeedsCtor>
// CHECK: cir.call @_ZN9NeedsCtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtor>) -> ()
// CHECK: }

cir.func private @_ZN9NeedsDtorD1Ev(!cir.ptr<!rec_NeedsDtor>)
cir.global external dso_local @needsDtor = #cir.zero : !rec_NeedsDtor dtor {
%0 = cir.get_global @needsDtor : !cir.ptr<!rec_NeedsDtor>
cir.call @_ZN9NeedsDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsDtor>) -> ()
}
// CHECK: cir.global external dso_local @needsDtor = #cir.zero : !rec_NeedsDtor dtor {
// CHECK: %0 = cir.get_global @needsDtor : !cir.ptr<!rec_NeedsDtor>
// CHECK: cir.call @_ZN9NeedsDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsDtor>) -> ()
// CHECK: }

cir.func private @_ZN13NeedsCtorDtorC1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
cir.func private @_ZN13NeedsCtorDtorD1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
cir.global external dso_local @needsCtorDtor = ctor : !rec_NeedsCtorDtor {
%0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
cir.call @_ZN13NeedsCtorDtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
} dtor {
%0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
cir.call @_ZN13NeedsCtorDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
}
// CHECK: cir.func private @_ZN13NeedsCtorDtorC1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
// CHECK: cir.func private @_ZN13NeedsCtorDtorD1Ev(!cir.ptr<!rec_NeedsCtorDtor>)
// CHECK: cir.global external dso_local @needsCtorDtor = ctor : !rec_NeedsCtorDtor {
// CHECK: %0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
// CHECK: cir.call @_ZN13NeedsCtorDtorC1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
// CHECK: } dtor {
// CHECK: %0 = cir.get_global @needsCtorDtor : !cir.ptr<!rec_NeedsCtorDtor>
// CHECK: cir.call @_ZN13NeedsCtorDtorD1Ev(%0) : (!cir.ptr<!rec_NeedsCtorDtor>) -> ()
// CHECK: }
}