Skip to content

Commit 1e45ea1

Browse files
authored
[CIR] Add support for function linkage and visibility (#145600)
This change adds support for function linkage and visibility and related attributes. Most of the test changes are generalizations to allow 'dso_local' to be accepted where we aren't specifically testing for it. Some tests based on CIR inputs have been updated to add 'private' to function declarations where required by newly supported interfaces. The dso-local.c test has been updated to add specific tests for dso_local being set correctly, and a new test, func-linkage.cpp tests other linkage settings. This change sets `comdat` correctly in CIR, but it is not yet applied to functions when lowering to LLVM IR. That will be handled in a later change.
1 parent 1276a5b commit 1e45ea1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+845
-542
lines changed

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,25 +1737,51 @@ def GetMemberOp : CIR_Op<"get_member"> {
17371737

17381738
def FuncOp : CIR_Op<"func", [
17391739
AutomaticAllocationScope, CallableOpInterface, FunctionOpInterface,
1740+
DeclareOpInterfaceMethods<CIRGlobalValueInterface>,
17401741
IsolatedFromAbove
17411742
]> {
17421743
let summary = "Declare or define a function";
17431744
let description = [{
17441745
The `cir.func` operation defines a function, similar to the `mlir::FuncOp`
17451746
built-in.
1747+
1748+
The function linkage information is specified by `linkage`, as defined by
1749+
`GlobalLinkageKind` attribute.
1750+
1751+
Example:
1752+
1753+
```mlir
1754+
// External function definitions.
1755+
cir.func @abort()
1756+
1757+
// A function with internal linkage.
1758+
cir.func internal @count(%x: i64) -> (i64)
1759+
return %x : i64
1760+
1761+
// Linkage information
1762+
cir.func linkonce_odr @some_method(...)
1763+
```
17461764
}];
17471765

17481766
let arguments = (ins SymbolNameAttr:$sym_name,
1767+
CIR_VisibilityAttr:$global_visibility,
17491768
TypeAttrOf<CIR_FuncType>:$function_type,
1769+
UnitAttr:$dso_local,
1770+
DefaultValuedAttr<CIR_GlobalLinkageKind,
1771+
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
1772+
OptionalAttr<StrAttr>:$sym_visibility,
1773+
UnitAttr:$comdat,
17501774
OptionalAttr<DictArrayAttr>:$arg_attrs,
17511775
OptionalAttr<DictArrayAttr>:$res_attrs);
17521776

17531777
let regions = (region AnyRegion:$body);
17541778

17551779
let skipDefaultBuilders = 1;
17561780

1757-
let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name,
1758-
"FuncType":$type)>];
1781+
let builders = [OpBuilder<(ins
1782+
"llvm::StringRef":$sym_name, "FuncType":$type,
1783+
CArg<"cir::GlobalLinkageKind", "cir::GlobalLinkageKind::ExternalLinkage">:$linkage)
1784+
>];
17591785

17601786
let extraClassDeclaration = [{
17611787
/// Returns the region on the current operation that is callable. This may

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,18 @@ struct MissingFeatures {
7272

7373
// FuncOp handling
7474
static bool opFuncOpenCLKernelMetadata() { return false; }
75+
static bool opFuncAstDeclAttr() { return false; }
7576
static bool opFuncCallingConv() { return false; }
7677
static bool opFuncExtraAttrs() { return false; }
77-
static bool opFuncDsoLocal() { return false; }
78-
static bool opFuncLinkage() { return false; }
79-
static bool opFuncVisibility() { return false; }
8078
static bool opFuncNoProto() { return false; }
8179
static bool opFuncCPUAndFeaturesAttributes() { return false; }
8280
static bool opFuncSection() { return false; }
83-
static bool opFuncSetComdat() { return false; }
81+
static bool opFuncMultipleReturnVals() { return false; }
8482
static bool opFuncAttributesForDefinition() { return false; }
83+
static bool opFuncMaybeHandleStaticInExternC() { return false; }
84+
static bool opFuncGlobalAliases() { return false; }
85+
static bool setLLVMFunctionFEnvAttributes() { return false; }
86+
static bool setFunctionAttributes() { return false; }
8587

8688
// CallOp handling
8789
static bool opCallPseudoDtor() { return false; }

clang/lib/CIR/CodeGen/CIRGenCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {
2525
cir::FuncType funcType = getTypes().getFunctionType(fnInfo);
2626
cir::FuncOp fn = getAddrOfCXXStructor(gd, &fnInfo, /*FnType=*/nullptr,
2727
/*DontDefer=*/true, ForDefinition);
28-
assert(!cir::MissingFeatures::opFuncLinkage());
28+
setFunctionLinkage(gd, fn);
2929
CIRGenFunction cgf{*this, builder};
3030
curCGF = &cgf;
3131
{

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -406,14 +406,34 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
406406
/*DontDefer=*/true, ForDefinition);
407407
}
408408

409+
// Already emitted.
410+
if (!funcOp.isDeclaration())
411+
return;
412+
413+
setFunctionLinkage(gd, funcOp);
414+
setGVProperties(funcOp, funcDecl);
415+
assert(!cir::MissingFeatures::opFuncMaybeHandleStaticInExternC());
416+
maybeSetTrivialComdat(*funcDecl, funcOp);
417+
assert(!cir::MissingFeatures::setLLVMFunctionFEnvAttributes());
418+
409419
CIRGenFunction cgf(*this, builder);
410420
curCGF = &cgf;
411421
{
412422
mlir::OpBuilder::InsertionGuard guard(builder);
413423
cgf.generateCode(gd, funcOp, funcType);
414424
}
415425
curCGF = nullptr;
426+
427+
setNonAliasAttributes(gd, funcOp);
416428
assert(!cir::MissingFeatures::opFuncAttributesForDefinition());
429+
430+
if (const ConstructorAttr *ca = funcDecl->getAttr<ConstructorAttr>())
431+
errorNYI(funcDecl->getSourceRange(), "constructor attribute");
432+
if (const DestructorAttr *da = funcDecl->getAttr<DestructorAttr>())
433+
errorNYI(funcDecl->getSourceRange(), "destructor attribute");
434+
435+
if (funcDecl->getAttr<AnnotateAttr>())
436+
errorNYI(funcDecl->getSourceRange(), "deferredAnnotations");
417437
}
418438

419439
mlir::Operation *CIRGenModule::getGlobalValue(StringRef name) {
@@ -855,10 +875,12 @@ static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) {
855875
void CIRGenModule::maybeSetTrivialComdat(const Decl &d, mlir::Operation *op) {
856876
if (!shouldBeInCOMDAT(*this, d))
857877
return;
858-
if (auto globalOp = dyn_cast_or_null<cir::GlobalOp>(op))
878+
if (auto globalOp = dyn_cast_or_null<cir::GlobalOp>(op)) {
859879
globalOp.setComdat(true);
860-
861-
assert(!cir::MissingFeatures::opFuncSetComdat());
880+
} else {
881+
auto funcOp = cast<cir::FuncOp>(op);
882+
funcOp.setComdat(true);
883+
}
862884
}
863885

864886
void CIRGenModule::updateCompletedType(const TagDecl *td) {
@@ -1028,6 +1050,17 @@ CIRGenModule::getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant) {
10281050
return getCIRLinkageForDeclarator(vd, linkage, isConstant);
10291051
}
10301052

1053+
cir::GlobalLinkageKind CIRGenModule::getFunctionLinkage(GlobalDecl gd) {
1054+
const auto *fd = cast<FunctionDecl>(gd.getDecl());
1055+
1056+
GVALinkage linkage = astContext.GetGVALinkageForFunction(fd);
1057+
1058+
if (const auto *dtor = dyn_cast<CXXDestructorDecl>(fd))
1059+
errorNYI(fd->getSourceRange(), "getFunctionLinkage: CXXDestructorDecl");
1060+
1061+
return getCIRLinkageForDeclarator(fd, linkage, /*IsConstantVariable=*/false);
1062+
}
1063+
10311064
static cir::GlobalOp
10321065
generateStringLiteral(mlir::Location loc, mlir::TypedAttr c,
10331066
cir::GlobalLinkageKind lt, CIRGenModule &cgm,
@@ -1534,6 +1567,27 @@ void CIRGenModule::setGVPropertiesAux(mlir::Operation *op,
15341567
assert(!cir::MissingFeatures::opGlobalPartition());
15351568
}
15361569

1570+
void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,
1571+
cir::FuncOp func,
1572+
bool isIncompleteFunction,
1573+
bool isThunk) {
1574+
// NOTE(cir): Original CodeGen checks if this is an intrinsic. In CIR we
1575+
// represent them in dedicated ops. The correct attributes are ensured during
1576+
// translation to LLVM. Thus, we don't need to check for them here.
1577+
1578+
assert(!cir::MissingFeatures::setFunctionAttributes());
1579+
assert(!cir::MissingFeatures::setTargetAttributes());
1580+
1581+
// TODO(cir): This needs a lot of work to better match CodeGen. That
1582+
// ultimately ends up in setGlobalVisibility, which already has the linkage of
1583+
// the LLVM GV (corresponding to our FuncOp) computed, so it doesn't have to
1584+
// recompute it here. This is a minimal fix for now.
1585+
if (!isLocalLinkage(getFunctionLinkage(globalDecl))) {
1586+
const Decl *decl = globalDecl.getDecl();
1587+
func.setGlobalVisibilityAttr(getGlobalVisibilityAttrFromDecl(decl));
1588+
}
1589+
}
1590+
15371591
cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
15381592
StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,
15391593
bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,
@@ -1576,8 +1630,9 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
15761630
// If there are two attempts to define the same mangled name, issue an
15771631
// error.
15781632
auto fn = cast<cir::FuncOp>(entry);
1579-
assert((!isForDefinition || !fn || !fn.isDeclaration()) &&
1580-
"Duplicate function definition");
1633+
if (isForDefinition && fn && !fn.isDeclaration()) {
1634+
errorNYI(d->getSourceRange(), "Duplicate function definition");
1635+
}
15811636
if (fn && fn.getFunctionType() == funcType) {
15821637
return fn;
15831638
}
@@ -1598,6 +1653,9 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
15981653
invalidLoc ? theModule->getLoc() : getLoc(funcDecl->getSourceRange()),
15991654
mangledName, mlir::cast<cir::FuncType>(funcType), funcDecl);
16001655

1656+
if (d)
1657+
setFunctionAttributes(gd, funcOp, /*isIncompleteFunction=*/false, isThunk);
1658+
16011659
// 'dontDefer' actually means don't move this to the deferredDeclsToEmit list.
16021660
if (dontDefer) {
16031661
// TODO(cir): This assertion will need an additional condition when we
@@ -1668,6 +1726,20 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
16681726

16691727
func = builder.create<cir::FuncOp>(loc, name, funcType);
16701728

1729+
assert(!cir::MissingFeatures::opFuncAstDeclAttr());
1730+
assert(!cir::MissingFeatures::opFuncNoProto());
1731+
1732+
assert(func.isDeclaration() && "expected empty body");
1733+
1734+
// A declaration gets private visibility by default, but external linkage
1735+
// as the default linkage.
1736+
func.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
1737+
&getMLIRContext(), cir::GlobalLinkageKind::ExternalLinkage));
1738+
mlir::SymbolTable::setSymbolVisibility(
1739+
func, mlir::SymbolTable::Visibility::Private);
1740+
1741+
assert(!cir::MissingFeatures::opFuncExtraAttrs());
1742+
16711743
if (!cgf)
16721744
theModule.push_back(func);
16731745
}

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ class CIRGenModule : public CIRGenTypeCache {
268268
void setGVProperties(mlir::Operation *op, const NamedDecl *d) const;
269269
void setGVPropertiesAux(mlir::Operation *op, const NamedDecl *d) const;
270270

271+
/// Set function attributes for a function declaration.
272+
void setFunctionAttributes(GlobalDecl gd, cir::FuncOp f,
273+
bool isIncompleteFunction, bool isThunk);
274+
271275
void emitGlobalDefinition(clang::GlobalDecl gd,
272276
mlir::Operation *op = nullptr);
273277
void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
@@ -340,10 +344,16 @@ class CIRGenModule : public CIRGenTypeCache {
340344
clang::VisibilityAttr::VisibilityType visibility);
341345
cir::VisibilityAttr getGlobalVisibilityAttrFromDecl(const Decl *decl);
342346
static mlir::SymbolTable::Visibility getMLIRVisibility(cir::GlobalOp op);
343-
347+
cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl gd);
344348
cir::GlobalLinkageKind getCIRLinkageForDeclarator(const DeclaratorDecl *dd,
345349
GVALinkage linkage,
346350
bool isConstantVariable);
351+
void setFunctionLinkage(GlobalDecl gd, cir::FuncOp f) {
352+
cir::GlobalLinkageKind l = getFunctionLinkage(gd);
353+
f.setLinkageAttr(cir::GlobalLinkageKindAttr::get(&getMLIRContext(), l));
354+
mlir::SymbolTable::setSymbolVisibility(f,
355+
getMLIRVisibilityFromCIRLinkage(l));
356+
}
347357

348358
cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *vd,
349359
bool isConstant);

0 commit comments

Comments
 (0)