Skip to content

Commit c1811d9

Browse files
smeenailanza
authored andcommitted
[CIR][CIRGen] Implement CIRGenModule::shouldEmitFunction (#984)
This is the usual copy-paste-modify from CodeGen, though I changed all the variable names to conform to our new style. All these functions should be pulled out as common helpers when we're upstream.
1 parent d83778a commit c1811d9

File tree

3 files changed

+114
-8
lines changed

3 files changed

+114
-8
lines changed

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,9 +3031,110 @@ void CIRGenModule::Release() {
30313031
// TODO: FINISH THE REST OF THIS
30323032
}
30333033

3034-
bool CIRGenModule::shouldEmitFunction(GlobalDecl GD) {
3035-
// TODO: implement this -- requires defining linkage for CIR
3036-
return true;
3034+
namespace {
3035+
// TODO(cir): This should be a common helper shared with CodeGen.
3036+
struct FunctionIsDirectlyRecursive
3037+
: public ConstStmtVisitor<FunctionIsDirectlyRecursive, bool> {
3038+
const StringRef name;
3039+
const Builtin::Context &builtinCtx;
3040+
FunctionIsDirectlyRecursive(StringRef name,
3041+
const Builtin::Context &builtinCtx)
3042+
: name(name), builtinCtx(builtinCtx) {}
3043+
3044+
bool VisitCallExpr(const CallExpr *expr) {
3045+
const FunctionDecl *func = expr->getDirectCallee();
3046+
if (!func)
3047+
return false;
3048+
AsmLabelAttr *attr = func->getAttr<AsmLabelAttr>();
3049+
if (attr && name == attr->getLabel())
3050+
return true;
3051+
unsigned builtinId = func->getBuiltinID();
3052+
if (!builtinId || !builtinCtx.isLibFunction(builtinId))
3053+
return false;
3054+
StringRef builtinName = builtinCtx.getName(builtinId);
3055+
if (builtinName.starts_with("__builtin_") &&
3056+
name == builtinName.slice(strlen("__builtin_"), StringRef::npos)) {
3057+
return true;
3058+
}
3059+
return false;
3060+
}
3061+
3062+
bool VisitStmt(const Stmt *stmt) {
3063+
for (const Stmt *child : stmt->children())
3064+
if (child && this->Visit(child))
3065+
return true;
3066+
return false;
3067+
}
3068+
};
3069+
} // namespace
3070+
3071+
// isTriviallyRecursive - Check if this function calls another
3072+
// decl that, because of the asm attribute or the other decl being a builtin,
3073+
// ends up pointing to itself.
3074+
// TODO(cir): This should be a common helper shared with CodeGen.
3075+
bool CIRGenModule::isTriviallyRecursive(const FunctionDecl *func) {
3076+
StringRef name;
3077+
if (getCXXABI().getMangleContext().shouldMangleDeclName(func)) {
3078+
// asm labels are a special kind of mangling we have to support.
3079+
AsmLabelAttr *attr = func->getAttr<AsmLabelAttr>();
3080+
if (!attr)
3081+
return false;
3082+
name = attr->getLabel();
3083+
} else {
3084+
name = func->getName();
3085+
}
3086+
3087+
FunctionIsDirectlyRecursive walker(name, astCtx.BuiltinInfo);
3088+
const Stmt *body = func->getBody();
3089+
return body ? walker.Visit(body) : false;
3090+
}
3091+
3092+
// TODO(cir): This should be a common helper shared with CodeGen.
3093+
bool CIRGenModule::shouldEmitFunction(GlobalDecl globalDecl) {
3094+
if (getFunctionLinkage(globalDecl) !=
3095+
GlobalLinkageKind::AvailableExternallyLinkage)
3096+
return true;
3097+
3098+
const auto *func = cast<FunctionDecl>(globalDecl.getDecl());
3099+
// Inline builtins declaration must be emitted. They often are fortified
3100+
// functions.
3101+
if (func->isInlineBuiltinDeclaration())
3102+
return true;
3103+
3104+
if (codeGenOpts.OptimizationLevel == 0 && !func->hasAttr<AlwaysInlineAttr>())
3105+
return false;
3106+
3107+
// We don't import function bodies from other named module units since that
3108+
// behavior may break ABI compatibility of the current unit.
3109+
if (const Module *mod = func->getOwningModule();
3110+
mod && mod->getTopLevelModule()->isNamedModule() &&
3111+
astCtx.getCurrentNamedModule() != mod->getTopLevelModule()) {
3112+
// There are practices to mark template member function as always-inline
3113+
// and mark the template as extern explicit instantiation but not give
3114+
// the definition for member function. So we have to emit the function
3115+
// from explicitly instantiation with always-inline.
3116+
//
3117+
// See https://github.com/llvm/llvm-project/issues/86893 for details.
3118+
//
3119+
// TODO: Maybe it is better to give it a warning if we call a non-inline
3120+
// function from other module units which is marked as always-inline.
3121+
if (!func->isTemplateInstantiation() || !func->hasAttr<AlwaysInlineAttr>())
3122+
return false;
3123+
}
3124+
3125+
if (func->hasAttr<NoInlineAttr>())
3126+
return false;
3127+
3128+
if (func->hasAttr<DLLImportAttr>() && !func->hasAttr<AlwaysInlineAttr>())
3129+
assert(!MissingFeatures::setDLLImportDLLExport() &&
3130+
"shouldEmitFunction for dllimport is NYI");
3131+
3132+
// PR9614. Avoid cases where the source code is lying to us. An available
3133+
// externally function should have an equivalent function somewhere else,
3134+
// but a function that calls itself through asm label/`__builtin_` trickery is
3135+
// clearly not equivalent to the real implementation.
3136+
// This happens in glibc's btowc and in some configure checks.
3137+
return !isTriviallyRecursive(func);
30373138
}
30383139

30393140
bool CIRGenModule::supportsCOMDAT() const {

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,9 @@ class CIRGenModule : public CIRGenTypeCache {
665665
// Finalize CIR code generation.
666666
void Release();
667667

668-
bool shouldEmitFunction(clang::GlobalDecl GD);
668+
bool isTriviallyRecursive(const clang::FunctionDecl *func);
669+
670+
bool shouldEmitFunction(clang::GlobalDecl globalDecl);
669671

670672
/// Returns a pointer to a global variable representing a temporary with
671673
/// static or thread storage duration.

clang/test/CIR/CodeGen/linkage.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2-
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t-O0.cir
2+
// RUN: FileCheck --input-file=%t-O0.cir %s -check-prefixes=CIR,CIR-O0
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -O1 -o %t-O1.cir
4+
// RUN: FileCheck --input-file=%t-O1.cir %s -check-prefixes=CIR,CIR-O1
35
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
46
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
57

@@ -24,7 +26,8 @@ int get_var(void) {
2426
return var;
2527
}
2628

27-
// Should generate available_externally linkage.
29+
// Should generate available_externally linkage when optimizing.
2830
inline int availableExternallyMethod(void) { return 0; }
2931
void callAvailableExternallyMethod(void) { availableExternallyMethod(); }
30-
// CIR: cir.func available_externally @availableExternallyMethod
32+
// CIR-O0-NOT: cir.func available_externally @availableExternallyMethod
33+
// CIR-O1: cir.func available_externally @availableExternallyMethod

0 commit comments

Comments
 (0)