diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 19aa040adc19..c0707d687fca 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -371,6 +371,13 @@ struct MissingFeatures { static bool setVisibilityFromDLLStorageClass() { return false; } static bool mustTailCallUndefinedGlobals() { return false; } + //-- Missing parts of the setCIRFunctionAttributesForDefinition skeleton. + static bool stackProtector() { return false; } + static bool optimizeForSize() { return false; } + static bool minSize() { return false; } + static bool setFunctionAlignment() { return false; } + static bool memberFunctionPointerTypeMetadata() { return false; } + //-- Other missing features // We need to track the parent record types that represent a field diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index fb5a44e12abb..b7197afeb896 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2506,26 +2506,101 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl, attrs.set(attr.getMnemonic(), attr); } + if (codeGenOpts.StackClashProtector) + llvm_unreachable("NYI"); + + if (codeGenOpts.StackProbeSize && codeGenOpts.StackProbeSize != 4096) + llvm_unreachable("NYI"); + if (!hasUnwindExceptions(getLangOpts())) { auto attr = cir::NoThrowAttr::get(&getMLIRContext()); attrs.set(attr.getMnemonic(), attr); } + assert(!MissingFeatures::stackProtector()); + + auto existingInlineAttr = dyn_cast_if_present( + attrs.get(cir::InlineAttr::getMnemonic())); + bool isNoInline = existingInlineAttr && existingInlineAttr.isNoInline(); + bool isAlwaysInline = + existingInlineAttr && existingInlineAttr.isAlwaysInline(); + if (!decl) { - // If we don't have a declaration to control inlining, the function isn't - // explicitly marked as alwaysinline for semantic reasons, and inlining is - // disabled, mark the function as noinline. - if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) { + // Non-entry HLSL functions must always be inlined. + if (getLangOpts().HLSL && !isNoInline) { auto attr = cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline); attrs.set(attr.getMnemonic(), attr); + } else if (!isAlwaysInline && codeGenOpts.getInlining() == + CodeGenOptions::OnlyAlwaysInlining) { + // If we don't have a declaration to control inlining, the function isn't + // explicitly marked as alwaysinline for semantic reasons, and inlining is + // disabled, mark the function as noinline. + auto attr = + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); + attrs.set(attr.getMnemonic(), attr); } - } else if (decl->hasAttr()) { + + f.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get( + &getMLIRContext(), attrs.getDictionary(&getMLIRContext()))); + return; + } + + // Handle SME attributes that apply to function definitions, + // rather than to function prototypes. + if (decl->hasAttr()) + llvm_unreachable("NYI"); + + if (auto *attr = decl->getAttr()) { + if (attr->isNewZA()) + llvm_unreachable("NYI"); + if (attr->isNewZT0()) + llvm_unreachable("NYI"); + } + + // Track whether we need to add the optnone attribute, + // starting with the default for this optimization level. + bool shouldAddOptNone = + !codeGenOpts.DisableO0ImplyOptNone && codeGenOpts.OptimizationLevel == 0; + // We can't add optnone in the following cases, it won't pass the verifier. + shouldAddOptNone &= !decl->hasAttr(); + shouldAddOptNone &= !decl->hasAttr(); + + // Non-entry HLSL functions must always be inlined. + if (getLangOpts().HLSL && !isNoInline && !decl->hasAttr()) { + auto attr = + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline); + attrs.set(attr.getMnemonic(), attr); + } else if ((shouldAddOptNone || decl->hasAttr()) && + !isAlwaysInline) { + // Add optnone, but do so only if the function isn't always_inline. + auto optNoneAttr = cir::OptNoneAttr::get(&getMLIRContext()); + attrs.set(optNoneAttr.getMnemonic(), optNoneAttr); + + // OptimizeNone implies noinline; we should not be inlining such functions. + auto noInlineAttr = + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); + attrs.set(noInlineAttr.getMnemonic(), noInlineAttr); + + // We still need to handle naked functions even though optnone subsumes + // much of their semantics. + if (decl->hasAttr()) + llvm_unreachable("NYI"); + + // OptimizeNone wins over OptimizeForSize and MinSize. + assert(!MissingFeatures::optimizeForSize()); + assert(!MissingFeatures::minSize()); + } else if (decl->hasAttr()) { + // Naked implies noinline: we should not be inlining such functions. + llvm_unreachable("NYI"); + } else if (decl->hasAttr()) { + llvm_unreachable("NYI"); + } else if (decl->hasAttr() && !isAlwaysInline) { // Add noinline if the function isn't always_inline. auto attr = cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); attrs.set(attr.getMnemonic(), attr); - } else if (decl->hasAttr()) { + } else if (decl->hasAttr() && !isNoInline) { // (noinline wins over always_inline, and we can't specify both in IR) auto attr = cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline); @@ -2533,57 +2608,66 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(const Decl *decl, } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) { // If we're not inlining, then force everything that isn't always_inline // to carry an explicit noinline attribute. - auto attr = - cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); - attrs.set(attr.getMnemonic(), attr); + if (!isAlwaysInline) { + auto attr = + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); + attrs.set(attr.getMnemonic(), attr); + } } else { // Otherwise, propagate the inline hint attribute and potentially use its // absence to mark things as noinline. // Search function and template pattern redeclarations for inline. - auto CheckForInline = [](const FunctionDecl *decl) { - auto CheckRedeclForInline = [](const FunctionDecl *Redecl) { - return Redecl->isInlineSpecified(); + if (auto *fd = dyn_cast(decl)) { + auto checkForInline = [](const FunctionDecl *decl) { + auto checkRedeclForInline = [](const FunctionDecl *redecl) { + return redecl->isInlineSpecified(); + }; + if (any_of(decl->redecls(), checkRedeclForInline)) + return true; + const FunctionDecl *pattern = decl->getTemplateInstantiationPattern(); + if (!pattern) + return false; + return any_of(pattern->redecls(), checkRedeclForInline); }; - if (any_of(decl->redecls(), CheckRedeclForInline)) - return true; - const FunctionDecl *Pattern = decl->getTemplateInstantiationPattern(); - if (!Pattern) - return false; - return any_of(Pattern->redecls(), CheckRedeclForInline); - }; - if (CheckForInline(cast(decl))) { - auto attr = - cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::InlineHint); - attrs.set(attr.getMnemonic(), attr); - } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyHintInlining) { - auto attr = - cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); - attrs.set(attr.getMnemonic(), attr); + if (checkForInline(fd)) { + auto attr = cir::InlineAttr::get(&getMLIRContext(), + cir::InlineKind::InlineHint); + attrs.set(attr.getMnemonic(), attr); + } else if (codeGenOpts.getInlining() == + CodeGenOptions::OnlyHintInlining && + !fd->isInlined() && !isAlwaysInline) { + auto attr = + cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); + attrs.set(attr.getMnemonic(), attr); + } } } - // Track whether we need to add the optnone attribute, - // starting with the default for this optimization level. - bool ShouldAddOptNone = - !codeGenOpts.DisableO0ImplyOptNone && codeGenOpts.OptimizationLevel == 0; - if (decl) { - ShouldAddOptNone &= !decl->hasAttr(); - ShouldAddOptNone &= !decl->hasAttr(); - ShouldAddOptNone |= decl->hasAttr(); + // Add other optimization related attributes if we are optimizing this + // function. + if (!decl->hasAttr()) { + if (decl->hasAttr()) { + llvm_unreachable("NYI"); + } + if (decl->hasAttr()) + llvm_unreachable("NYI"); + if (decl->hasAttr()) + assert(!MissingFeatures::minSize()); } - if (ShouldAddOptNone) { - auto optNoneAttr = cir::OptNoneAttr::get(&getMLIRContext()); - attrs.set(optNoneAttr.getMnemonic(), optNoneAttr); + f.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get( + &getMLIRContext(), attrs.getDictionary(&getMLIRContext()))); - // OptimizeNone implies noinline; we should not be inlining such functions. - auto noInlineAttr = - cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline); - attrs.set(noInlineAttr.getMnemonic(), noInlineAttr); + assert(!MissingFeatures::setFunctionAlignment()); + + // In the cross-dso CFI mode with canonical jump tables, we want !type + // attributes on definitions only. + if (codeGenOpts.SanitizeCfiCrossDso && + codeGenOpts.SanitizeCfiCanonicalJumpTables) { + llvm_unreachable("NYI"); } - f.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get( - &getMLIRContext(), attrs.getDictionary(&getMLIRContext()))); + assert(!MissingFeatures::memberFunctionPointerTypeMetadata()); } void CIRGenModule::setCIRFunctionAttributes(GlobalDecl GD,