Skip to content
Open
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
42 changes: 4 additions & 38 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1085,44 +1085,10 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
//===----------------------------------------------------------------------===//

def CIR_InlineKind : CIR_I32EnumAttr<"InlineKind", "inlineKind", [
I32EnumAttrCase<"NoInline", 1, "never">,
I32EnumAttrCase<"AlwaysInline", 2, "always">,
I32EnumAttrCase<"InlineHint", 3, "hint">
]> {
let genSpecializedAttr = 0;
}

def CIR_InlineAttr : CIR_EnumAttr<CIR_InlineKind, "inline"> {
let summary = "Inline attribute";
let description = [{
Inline attribute represents user directives for inlining behavior.
This attribute is only used by `cir.func` operations.

Values:
- `never`: Prevents the function from being inlined (__attribute__((noinline)))
- `always`: Forces the function to be inlined (__attribute__((always_inline)))
- `hint`: Suggests the function should be inlined (inline keyword)

Example:
```
cir.func @noinline_func(%arg0: !s32i) -> !s32i inline(never) {
cir.return %arg0 : !s32i
}
cir.func @always_inline_func() -> !s32i inline(always) {
%0 = cir.const #cir.int<42> : !s32i
cir.return %0 : !s32i
}
```
}];

let cppClassName = "InlineAttr";

let extraClassDeclaration = [{
bool isNoInline() const { return getValue() == InlineKind::NoInline; };
bool isAlwaysInline() const { return getValue() == InlineKind::AlwaysInline; };
bool isInlineHint() const { return getValue() == InlineKind::InlineHint; };
}];
}
I32EnumAttrCase<"NoInline", 1, "no_inline">,
I32EnumAttrCase<"AlwaysInline", 2, "always_inline">,
I32EnumAttrCase<"InlineHint", 3, "inline_hint">
]>;

//===----------------------------------------------------------------------===//
// CatchAllAttr & UnwindAttr
Expand Down
50 changes: 27 additions & 23 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2564,9 +2564,9 @@ def CIR_FuncOp : CIR_Op<"func", [
Similarly, for global destructors both `global_dtor` and
`global_dtor(<priority>)` are available.

The `inline(never)` keyword marks a function that should not be inlined.
The `inline(always)` keyword marks a function that should always be inlined.
The `inline(hint)` keyword suggests that the function should be inlined.
The `no_inline` attribute marks a function that should not be inlined.
The `always_inline` attribute marks a function that should always be inlined.
The `inline_hint` attribute suggests that the function should be inlined.

Example:

Expand All @@ -2580,7 +2580,10 @@ def CIR_FuncOp : CIR_Op<"func", [

// Linkage information
cir.func linkonce_odr @some_method(...)
```

// Inline information
cir.func no_inline @some_method(...)

// Builtin function
cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool
// Coroutine
Expand All @@ -2592,25 +2595,26 @@ def CIR_FuncOp : CIR_Op<"func", [
```
}];

let arguments = (ins SymbolNameAttr:$sym_name,
CIR_VisibilityAttr:$global_visibility,
TypeAttrOf<CIR_FuncType>:$function_type,
UnitAttr:$builtin,
UnitAttr:$coroutine,
UnitAttr:$lambda,
UnitAttr:$no_proto,
UnitAttr:$dso_local,
DefaultValuedAttr<CIR_GlobalLinkageKind,
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
OptionalAttr<CIR_InlineAttr>:$inline_kind,
OptionalAttr<StrAttr>:$sym_visibility,
UnitAttr:$comdat,
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<FlatSymbolRefAttr>:$aliasee,
CIR_OptionalPriorityAttr:$global_ctor_priority,
CIR_OptionalPriorityAttr:$global_dtor_priority,
OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
let arguments = (ins
SymbolNameAttr:$sym_name,
CIR_VisibilityAttr:$global_visibility,
TypeAttrOf<CIR_FuncType>:$function_type,
UnitAttr:$builtin,
UnitAttr:$coroutine,
OptionalAttr<CIR_InlineKind>:$inline_kind,
UnitAttr:$lambda,
UnitAttr:$no_proto,
UnitAttr:$dso_local,
DefaultValuedAttr<CIR_GlobalLinkageKind,
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
OptionalAttr<StrAttr>:$sym_visibility,
UnitAttr:$comdat,
OptionalAttr<DictArrayAttr>:$arg_attrs,
OptionalAttr<DictArrayAttr>:$res_attrs,
OptionalAttr<FlatSymbolRefAttr>:$aliasee,
CIR_OptionalPriorityAttr:$global_ctor_priority,
CIR_OptionalPriorityAttr:$global_dtor_priority,
OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
);

let regions = (region AnyRegion:$body);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1870,8 +1870,7 @@ CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
clone.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
&cgm.getMLIRContext(), cir::GlobalLinkageKind::InternalLinkage));
clone.setSymVisibility("private");
clone.setInlineKindAttr(cir::InlineAttr::get(
&cgm.getMLIRContext(), cir::InlineKind::AlwaysInline));
clone.setInlineKind(cir::InlineKind::AlwaysInline);
}
return CIRGenCallee::forDirect(clone, gd);
}
Expand Down
19 changes: 6 additions & 13 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1975,7 +1975,6 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline;
bool isAlwaysInline = existingInlineKind &&
*existingInlineKind == cir::InlineKind::AlwaysInline;

if (!decl) {
assert(!cir::MissingFeatures::hlsl());

Expand All @@ -1984,8 +1983,7 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
// If inlining is disabled and we don't have a declaration to control
// inlining, mark the function as 'noinline' unless it is explicitly
// marked as 'alwaysinline'.
f.setInlineKindAttr(
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
f.setInlineKind(cir::InlineKind::NoInline);
}

return;
Expand All @@ -2002,19 +2000,16 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
// Handle inline attributes
if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) {
// Add noinline if the function isn't always_inline.
f.setInlineKindAttr(
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
f.setInlineKind(cir::InlineKind::NoInline);
} else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) {
// Don't override AlwaysInline with NoInline, or vice versa, since we can't
// specify both in IR.
f.setInlineKindAttr(
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline));
f.setInlineKind(cir::InlineKind::AlwaysInline);
} else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
// If inlining is disabled, force everything that isn't always_inline
// to carry an explicit noinline attribute.
if (!isAlwaysInline) {
f.setInlineKindAttr(
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
f.setInlineKind(cir::InlineKind::NoInline);
}
} else {
// Otherwise, propagate the inline hint attribute and potentially use its
Expand All @@ -2036,13 +2031,11 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
return any_of(pattern->redecls(), checkRedeclForInline);
};
if (checkForInline(fd)) {
f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(),
cir::InlineKind::InlineHint));
f.setInlineKind(cir::InlineKind::InlineHint);
} else if (codeGenOpts.getInlining() ==
CodeGenOptions::OnlyHintInlining &&
!fd->isInlined() && !isAlwaysInline) {
f.setInlineKindAttr(
cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
f.setInlineKind(cir::InlineKind::NoInline);
}
}
}
Expand Down
80 changes: 46 additions & 34 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,41 @@ void parseVisibilityAttr(OpAsmParser &parser, cir::VisibilityAttr &visibility) {
visibility = cir::VisibilityAttr::get(parser.getContext(), visibilityKind);
}

//===----------------------------------------------------------------------===//
// InlineKindAttr (FIXME: remove once FuncOp uses assembly format)
//===----------------------------------------------------------------------===//

ParseResult parseInlineKindAttr(OpAsmParser &parser,
cir::InlineKindAttr &inlineKindAttr) {
// Static list of possible inline kind keywords
static constexpr llvm::StringRef keywords[] = {"no_inline", "always_inline",
"inline_hint"};

// Parse the inline kind keyword (optional)
llvm::StringRef keyword;
if (parser.parseOptionalKeyword(&keyword, keywords).failed()) {
// Not an inline kind keyword, leave inlineKindAttr empty
return success();
}

// Parse the enum value from the keyword
auto inlineKindResult = ::cir::symbolizeEnum<::cir::InlineKind>(keyword);
if (!inlineKindResult) {
return parser.emitError(parser.getCurrentLocation(), "expected one of [")
<< llvm::join(llvm::ArrayRef(keywords), ", ")
<< "] for inlineKind, got: " << keyword;
}

inlineKindAttr =
::cir::InlineKindAttr::get(parser.getContext(), *inlineKindResult);
return success();
}

void printInlineKindAttr(OpAsmPrinter &p, cir::InlineKindAttr inlineKindAttr) {
if (inlineKindAttr) {
p << " " << stringifyInlineKind(inlineKindAttr.getValue());
}
}
//===----------------------------------------------------------------------===//
// CIR Custom Parsers/Printers
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1753,6 +1788,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {

mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);
mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);
mlir::StringAttr inlineKindNameAttr = getInlineKindAttrName(state.name);
mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);
mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);
mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
Expand All @@ -1765,6 +1801,14 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
if (::mlir::succeeded(
parser.parseOptionalKeyword(coroutineNameAttr.strref())))
state.addAttribute(coroutineNameAttr, parser.getBuilder().getUnitAttr());

// Parse optional inline kind attribute
cir::InlineKindAttr inlineKindAttr;
if (failed(parseInlineKindAttr(parser, inlineKindAttr)))
return failure();
if (inlineKindAttr)
state.addAttribute(inlineKindNameAttr, inlineKindAttr);

if (::mlir::succeeded(parser.parseOptionalKeyword(lambdaNameAttr.strref())))
state.addAttribute(lambdaNameAttr, parser.getBuilder().getUnitAttr());
if (parser.parseOptionalKeyword(noProtoNameAttr).succeeded())
Expand Down Expand Up @@ -1890,36 +1934,6 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
}).failed())
return failure();

// Parse optional inline kind: inline(never|always|hint)
if (parser.parseOptionalKeyword("inline").succeeded()) {
if (parser.parseLParen().failed())
return failure();

llvm::StringRef inlineKindStr;
const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()>
allowedInlineKindStrs{
cir::stringifyInlineKind(cir::InlineKind::NoInline),
cir::stringifyInlineKind(cir::InlineKind::AlwaysInline),
cir::stringifyInlineKind(cir::InlineKind::InlineHint),
};
if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs)
.failed())
return parser.emitError(parser.getCurrentLocation(),
"expected 'never', 'always', or 'hint'");

std::optional<InlineKind> inlineKind =
cir::symbolizeInlineKind(inlineKindStr);
if (!inlineKind)
return parser.emitError(parser.getCurrentLocation(),
"invalid inline kind");

state.addAttribute(getInlineKindAttrName(state.name),
cir::InlineAttr::get(builder.getContext(), *inlineKind));

if (parser.parseRParen().failed())
return failure();
}

// Parse the optional function body.
auto *body = state.addRegion();
OptionalParseResult parseResult = parser.parseOptionalRegion(
Expand Down Expand Up @@ -2014,6 +2028,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
if (getCoroutine())
p << " coroutine";

printInlineKindAttr(p, getInlineKindAttr());

if (getLambda())
p << " lambda";

Expand Down Expand Up @@ -2069,10 +2085,6 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
p << "(" << globalDtorPriority.value() << ")";
}

if (cir::InlineAttr inlineAttr = getInlineKindAttr()) {
p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")";
}

// Print the body if this is not an external function.
Region &body = getOperation()->getRegion(0);
if (!body.empty()) {
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1978,10 +1978,10 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(

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

if (auto inlineKind = op.getInlineKind()) {
fn.setNoInline(inlineKind == cir::InlineKind::NoInline);
fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint);
fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline);
if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint);
fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline);
}

fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
Expand Down
14 changes: 7 additions & 7 deletions clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ int check_load(st1 *s1) {
return s1->b;
}

// CIR: cir.func dso_local @check_load
// CIR: cir.func {{.*}} @check_load
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st1>>, !cir.ptr<!rec_st1>
// CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "b"} : !cir.ptr<!rec_st1> -> !cir.ptr<!u16i>
// CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b, [[MEMBER]] {is_volatile} : !cir.ptr<!u16i>) -> !u32i
Expand Down Expand Up @@ -114,7 +114,7 @@ int check_load_exception(st3 *s3) {
return s3->b;
}

// CIR: cir.func dso_local @check_load_exception
// CIR: cir.func {{.*}} @check_load_exception
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
// CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][2] {name = "b"} : !cir.ptr<!rec_st3> -> !cir.ptr<!u8i>
// CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b1, [[MEMBER]] {is_volatile} : !cir.ptr<!u8i>) -> !u32i
Expand Down Expand Up @@ -151,7 +151,7 @@ int clip_load_exception2(clip *c) {
return c->a;
}

// CIR: cir.func dso_local @clip_load_exception2
// CIR: cir.func {{.*}} @clip_load_exception2
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
// CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
// CIR: [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_a1, [[MEMBER]] {is_volatile} : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i
Expand All @@ -178,7 +178,7 @@ void check_store(st2 *s2) {
s2->a = 1;
}

// CIR: cir.func dso_local @check_store
// CIR: cir.func {{.*}} @check_store
// CIR: [[CONST:%.*]] = cir.const #cir.int<1> : !s32i
// CIR: [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !s16i
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st2>>, !cir.ptr<!rec_st2>
Expand Down Expand Up @@ -209,7 +209,7 @@ void check_store_exception(st3 *s3) {
s3->b = 2;
}

// CIR: cir.func dso_local @check_store_exception
// CIR: cir.func {{.*}} @check_store_exception
// CIR: [[CONST:%.*]] = cir.const #cir.int<2> : !s32i
// CIR: [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !u32i
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
Expand Down Expand Up @@ -239,7 +239,7 @@ void clip_store_exception2(clip *c) {
c->a = 3;
}

// CIR: cir.func dso_local @clip_store_exception2
// CIR: cir.func {{.*}} @clip_store_exception2
// CIR: [[CONST:%.*]] = cir.const #cir.int<3> : !s32i
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
// CIR: [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
Expand All @@ -261,7 +261,7 @@ void check_store_second_member (st4 *s4) {
s4->b = 1;
}

// CIR: cir.func dso_local @check_store_second_member
// CIR: cir.func {{.*}} @check_store_second_member
// CIR: [[ONE:%.*]] = cir.const #cir.int<1> : !s32i
// CIR: [[CAST:%.*]] = cir.cast integral [[ONE]] : !s32i -> !u64i
// CIR: [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st4>>, !cir.ptr<!rec_st4>
Expand Down
Loading