Skip to content

Commit 8412847

Browse files
committed
[CIR] Add inline function attributes
Unlike the incubator, this adds the inline attribute directly to FuncOp instead of adding the ExtraFnAttr dict. This adds three new optional keywords to CIR: inline_always, inline_never and inline_hint. Just like in OGCG -O0 implies inline_never on functions withoutt the C++ `inline` keyword and no other inlining-related attribute. This patch also adapts all tests that use functions so they account for LLVM attributes being attached now.
1 parent 514f829 commit 8412847

32 files changed

+398
-122
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,5 +959,31 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
959959
`<` custom<RecordMembers>($data) `>`
960960
}];
961961
}
962+
//===----------------------------------------------------------------------===//
963+
// InlineAttr
964+
//===----------------------------------------------------------------------===//
965+
966+
def CIR_InlineKind : CIR_I32EnumAttr<"InlineKind", "inlineKind", [
967+
I32EnumAttrCase<"NoInline", 1, "no">,
968+
I32EnumAttrCase<"AlwaysInline", 2, "always">,
969+
I32EnumAttrCase<"InlineHint", 3, "hint">
970+
]> {
971+
let genSpecializedAttr = 0;
972+
}
973+
974+
def CIR_InlineAttr : CIR_EnumAttr<CIR_InlineKind, "inline"> {
975+
let summary = "Inline attribute";
976+
let description = [{
977+
Inline attributes represents user directives.
978+
}];
979+
980+
let cppClassName = "InlineAttr";
981+
982+
let extraClassDeclaration = [{
983+
bool isNoInline() const { return getValue() == InlineKind::NoInline; };
984+
bool isAlwaysInline() const { return getValue() == InlineKind::AlwaysInline; };
985+
bool isInlineHint() const { return getValue() == InlineKind::InlineHint; };
986+
}];
987+
}
962988

963989
#endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,10 @@ def CIR_FuncOp : CIR_Op<"func", [
24492449
without a prototype and, consequently, may contain calls with invalid
24502450
arguments and undefined behavior.
24512451

2452+
The `inline_never` keyword marks a function that should not be inlined.
2453+
The `inline_always` keyword marks a function that should always be inlined.
2454+
The `inline_hint` keyword suggests that the function should be inlined.
2455+
24522456
Example:
24532457

24542458
```mlir
@@ -2483,6 +2487,7 @@ def CIR_FuncOp : CIR_Op<"func", [
24832487
UnitAttr:$dso_local,
24842488
DefaultValuedAttr<CIR_GlobalLinkageKind,
24852489
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
2490+
OptionalAttr<CIR_InlineAttr>:$inline_kind,
24862491
OptionalAttr<StrAttr>:$sym_visibility,
24872492
UnitAttr:$comdat,
24882493
OptionalAttr<DictArrayAttr>:$arg_attrs,

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,23 +70,30 @@ struct MissingFeatures {
7070
static bool opAllocaCaptureByInit() { return false; }
7171

7272
// FuncOp handling
73-
static bool opFuncOpenCLKernelMetadata() { return false; }
73+
static bool opFuncArmNewAttr() { return false; }
74+
static bool opFuncArmStreamingAttr() { return false; }
7475
static bool opFuncAstDeclAttr() { return false; }
75-
static bool opFuncAttributesForDefinition() { return false; }
7676
static bool opFuncCallingConv() { return false; }
77+
static bool opFuncColdHotAttr() { return false; }
7778
static bool opFuncCPUAndFeaturesAttributes() { return false; }
7879
static bool opFuncExceptions() { return false; }
7980
static bool opFuncExtraAttrs() { return false; }
8081
static bool opFuncMaybeHandleStaticInExternC() { return false; }
82+
static bool opFuncMinSizeAttr() { return false; }
8183
static bool opFuncMultipleReturnVals() { return false; }
84+
static bool opFuncNakedAttr() { return false; }
85+
static bool opFuncNoDuplicateAttr() { return false; }
8286
static bool opFuncNoUnwind() { return false; }
87+
static bool opFuncOpenCLKernelMetadata() { return false; }
8388
static bool opFuncOperandBundles() { return false; }
89+
static bool opFuncOptNoneAttr() { return false; }
8490
static bool opFuncParameterAttributes() { return false; }
8591
static bool opFuncReadOnly() { return false; }
8692
static bool opFuncSection() { return false; }
93+
static bool opFuncUnwindTablesAttr() { return false; }
8794
static bool opFuncWillReturn() { return false; }
88-
static bool setLLVMFunctionFEnvAttributes() { return false; }
8995
static bool setFunctionAttributes() { return false; }
96+
static bool setLLVMFunctionFEnvAttributes() { return false; }
9097

9198
// CallOp handling
9299
static bool opCallAggregateArgs() { return false; }
@@ -265,6 +272,7 @@ struct MissingFeatures {
265272
static bool objCBlocks() { return false; }
266273
static bool objCGC() { return false; }
267274
static bool objCLifetime() { return false; }
275+
static bool hlsl() { return false; }
268276
static bool openCL() { return false; }
269277
static bool openMP() { return false; }
270278
static bool opTBAA() { return false; }
@@ -282,6 +290,7 @@ struct MissingFeatures {
282290
static bool sourceLanguageCases() { return false; }
283291
static bool stackBase() { return false; }
284292
static bool stackSaveOp() { return false; }
293+
static bool stackProtector() { return false; }
285294
static bool targetCIRGenInfoArch() { return false; }
286295
static bool targetCIRGenInfoOS() { return false; }
287296
static bool targetCodeGenInfoGetNullPointer() { return false; }

clang/lib/CIR/CodeGen/CIRGenCXX.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {
171171
curCGF = nullptr;
172172

173173
setNonAliasAttributes(gd, fn);
174-
assert(!cir::MissingFeatures::opFuncAttributesForDefinition());
174+
setCIRFunctionAttributesForDefinition(mlir::cast<FunctionDecl>(gd.getDecl()),
175+
fn);
175176
return fn;
176177
}
177178

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
449449
curCGF = nullptr;
450450

451451
setNonAliasAttributes(gd, funcOp);
452-
assert(!cir::MissingFeatures::opFuncAttributesForDefinition());
452+
setCIRFunctionAttributesForDefinition(funcDecl, funcOp);
453453

454454
if (funcDecl->getAttr<ConstructorAttr>())
455455
errorNYI(funcDecl->getSourceRange(), "constructor attribute");
@@ -1885,6 +1885,87 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,
18851885
}
18861886
}
18871887

1888+
void CIRGenModule::setCIRFunctionAttributesForDefinition(
1889+
const clang::FunctionDecl *decl, cir::FuncOp f) {
1890+
assert(!cir::MissingFeatures::opFuncUnwindTablesAttr());
1891+
assert(!cir::MissingFeatures::stackProtector());
1892+
1893+
auto existingInlineKind = f.getInlineKind();
1894+
bool isNoInline =
1895+
existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline;
1896+
bool isAlwaysInline = existingInlineKind &&
1897+
*existingInlineKind == cir::InlineKind::AlwaysInline;
1898+
1899+
if (!decl) {
1900+
assert(!cir::MissingFeatures::hlsl());
1901+
1902+
if (!isAlwaysInline &&
1903+
codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
1904+
// If we don't have a declaration to control inlining, the function isn't
1905+
// explicitly marked as alwaysinline for semantic reasons, and inlining is
1906+
// disabled, mark the function as noinline.
1907+
f.setInlineKindAttr(
1908+
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
1909+
}
1910+
1911+
return;
1912+
}
1913+
1914+
assert(!cir::MissingFeatures::opFuncArmStreamingAttr());
1915+
assert(!cir::MissingFeatures::opFuncArmNewAttr());
1916+
assert(!cir::MissingFeatures::opFuncOptNoneAttr());
1917+
assert(!cir::MissingFeatures::opFuncMinSizeAttr());
1918+
assert(!cir::MissingFeatures::opFuncNakedAttr());
1919+
assert(!cir::MissingFeatures::opFuncNoDuplicateAttr());
1920+
assert(!cir::MissingFeatures::hlsl());
1921+
1922+
// Handle inline attributes
1923+
if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) {
1924+
// Add noinline if the function isn't always_inline.
1925+
f.setInlineKindAttr(
1926+
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
1927+
} else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) {
1928+
// (noinline wins over always_inline, and we can't specify both in IR)
1929+
f.setInlineKindAttr(
1930+
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline));
1931+
} else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
1932+
// If we're not inlining, then force everything that isn't always_inline
1933+
// to carry an explicit noinline attribute.
1934+
if (!isAlwaysInline) {
1935+
f.setInlineKindAttr(
1936+
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
1937+
}
1938+
} else {
1939+
// Otherwise, propagate the inline hint attribute and potentially use its
1940+
// absence to mark things as noinline.
1941+
// Search function and template pattern redeclarations for inline.
1942+
if (auto *fd = dyn_cast<FunctionDecl>(decl)) {
1943+
auto checkForInline = [](const FunctionDecl *decl) {
1944+
auto checkRedeclForInline = [](const FunctionDecl *redecl) {
1945+
return redecl->isInlineSpecified();
1946+
};
1947+
if (any_of(decl->redecls(), checkRedeclForInline))
1948+
return true;
1949+
const FunctionDecl *pattern = decl->getTemplateInstantiationPattern();
1950+
if (!pattern)
1951+
return false;
1952+
return any_of(pattern->redecls(), checkRedeclForInline);
1953+
};
1954+
if (checkForInline(fd)) {
1955+
f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(),
1956+
cir::InlineKind::InlineHint));
1957+
} else if (codeGenOpts.getInlining() ==
1958+
CodeGenOptions::OnlyHintInlining &&
1959+
!fd->isInlined() && !isAlwaysInline) {
1960+
f.setInlineKindAttr(
1961+
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
1962+
}
1963+
}
1964+
}
1965+
1966+
assert(!cir::MissingFeatures::opFuncColdHotAttr());
1967+
}
1968+
18881969
cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
18891970
StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,
18901971
bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ class CIRGenModule : public CIRGenTypeCache {
422422
void setFunctionAttributes(GlobalDecl gd, cir::FuncOp f,
423423
bool isIncompleteFunction, bool isThunk);
424424

425+
/// Set extra attributes (inline, etc.) for a function.
426+
void setCIRFunctionAttributesForDefinition(const clang::FunctionDecl *fd,
427+
cir::FuncOp f);
428+
425429
void emitGlobalDefinition(clang::GlobalDecl gd,
426430
mlir::Operation *op = nullptr);
427431
void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,22 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
17201720
hasAlias = true;
17211721
}
17221722

1723+
// Parse optional inline attribute: inline_never, inline_always, or
1724+
// inline_hint
1725+
if (parser.parseOptionalKeyword("inline_never").succeeded()) {
1726+
state.addAttribute(
1727+
getInlineKindAttrName(state.name),
1728+
cir::InlineAttr::get(builder.getContext(), cir::InlineKind::NoInline));
1729+
} else if (parser.parseOptionalKeyword("inline_always").succeeded()) {
1730+
state.addAttribute(getInlineKindAttrName(state.name),
1731+
cir::InlineAttr::get(builder.getContext(),
1732+
cir::InlineKind::AlwaysInline));
1733+
} else if (parser.parseOptionalKeyword("inline_hint").succeeded()) {
1734+
state.addAttribute(getInlineKindAttrName(state.name),
1735+
cir::InlineAttr::get(builder.getContext(),
1736+
cir::InlineKind::InlineHint));
1737+
}
1738+
17231739
// Parse the optional function body.
17241740
auto *body = state.addRegion();
17251741
OptionalParseResult parseResult = parser.parseOptionalRegion(
@@ -1801,6 +1817,16 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
18011817
p << ")";
18021818
}
18031819

1820+
if (auto inlineKind = getInlineKind()) {
1821+
if (*inlineKind == cir::InlineKind::NoInline) {
1822+
p << " inline_never";
1823+
} else if (*inlineKind == cir::InlineKind::AlwaysInline) {
1824+
p << " inline_always";
1825+
} else if (*inlineKind == cir::InlineKind::InlineHint) {
1826+
p << " inline_hint";
1827+
}
1828+
}
1829+
18041830
// Print the body if this is not an external function.
18051831
Region &body = getOperation()->getRegion(0);
18061832
if (!body.empty()) {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,7 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
15391539
attr.getName() == getLinkageAttrNameString() ||
15401540
attr.getName() == func.getGlobalVisibilityAttrName() ||
15411541
attr.getName() == func.getDsoLocalAttrName() ||
1542+
attr.getName() == func.getInlineKindAttrName() ||
15421543
(filterArgAndResAttrs &&
15431544
(attr.getName() == func.getArgAttrsAttrName() ||
15441545
attr.getName() == func.getResAttrsAttrName())))
@@ -1623,6 +1624,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
16231624

16241625
assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
16251626

1627+
// Add inline_kind attribute with "cir." prefix so amendOperation handles it
1628+
if (auto inlineKind = op.getInlineKind()) {
1629+
fn->setAttr("cir.inline_kind",
1630+
cir::InlineAttr::get(getContext(), *inlineKind));
1631+
}
1632+
16261633
fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
16271634
getContext(), lowerCIRVisibilityToLLVMVisibility(
16281635
op.getGlobalVisibilityAttr().getValue())));

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ class CIRDialectLLVMIRTranslationInterface
3434
public:
3535
using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
3636

37+
/// Any named attribute in the CIR dialect, i.e, with name started with
38+
/// "cir.", will be handled here.
39+
virtual mlir::LogicalResult amendOperation(
40+
mlir::Operation *op, llvm::ArrayRef<llvm::Instruction *> instructions,
41+
mlir::NamedAttribute attribute,
42+
mlir::LLVM::ModuleTranslation &moduleTranslation) const override {
43+
if (auto func = mlir::dyn_cast<mlir::LLVM::LLVMFuncOp>(op)) {
44+
amendFunction(func, instructions, attribute, moduleTranslation);
45+
}
46+
return mlir::success();
47+
}
48+
3749
/// Translates the given operation to LLVM IR using the provided IR builder
3850
/// and saving the state in `moduleTranslation`.
3951
mlir::LogicalResult convertOperation(
@@ -47,6 +59,32 @@ class CIRDialectLLVMIRTranslationInterface
4759

4860
return mlir::success();
4961
}
62+
63+
// Translate CIR's inline attribute to LLVM's function attributes.
64+
void amendFunction(mlir::LLVM::LLVMFuncOp func,
65+
llvm::ArrayRef<llvm::Instruction *> instructions,
66+
mlir::NamedAttribute attribute,
67+
mlir::LLVM::ModuleTranslation &moduleTranslation) const {
68+
llvm::Function *llvmFunc = moduleTranslation.lookupFunction(func.getName());
69+
if (auto inlineAttr = mlir::dyn_cast<cir::InlineAttr>(attribute.getValue())) {
70+
if (inlineAttr.isNoInline())
71+
llvmFunc->addFnAttr(llvm::Attribute::NoInline);
72+
else if (inlineAttr.isAlwaysInline())
73+
llvmFunc->addFnAttr(llvm::Attribute::AlwaysInline);
74+
else if (inlineAttr.isInlineHint())
75+
llvmFunc->addFnAttr(llvm::Attribute::InlineHint);
76+
else
77+
llvm_unreachable("Unknown inline kind");
78+
// Drop ammended CIR attribute from LLVM op.
79+
func->removeAttr(attribute.getName());
80+
}
81+
82+
assert(!cir::MissingFeatures::opFuncOptNoneAttr());
83+
assert(!cir::MissingFeatures::opFuncNoUnwind());
84+
assert(!cir::MissingFeatures::opFuncColdHotAttr());
85+
assert(!cir::MissingFeatures::opFuncUnwindTablesAttr());
86+
assert(!cir::MissingFeatures::openCL());
87+
}
5088
};
5189

5290
void registerCIRDialectTranslation(mlir::DialectRegistry &registry) {

0 commit comments

Comments
 (0)