diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenFunction.cpp')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 25a46df..d3c0d9f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -551,6 +551,49 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, const auto funcDecl = cast<FunctionDecl>(gd.getDecl()); curGD = gd; + if (funcDecl->isInlineBuiltinDeclaration()) { + // When generating code for a builtin with an inline declaration, use a + // mangled name to hold the actual body, while keeping an external + // declaration in case the function pointer is referenced somewhere. + std::string fdInlineName = (cgm.getMangledName(funcDecl) + ".inline").str(); + cir::FuncOp clone = + mlir::cast_or_null<cir::FuncOp>(cgm.getGlobalValue(fdInlineName)); + if (!clone) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPoint(fn); + clone = builder.create<cir::FuncOp>(fn.getLoc(), fdInlineName, + fn.getFunctionType()); + clone.setLinkage(cir::GlobalLinkageKind::InternalLinkage); + clone.setSymVisibility("private"); + clone.setInlineKind(cir::InlineKind::AlwaysInline); + } + fn.setLinkage(cir::GlobalLinkageKind::ExternalLinkage); + fn.setSymVisibility("private"); + fn = clone; + } else { + // Detect the unusual situation where an inline version is shadowed by a + // non-inline version. In that case we should pick the external one + // everywhere. That's GCC behavior too. + for (const FunctionDecl *pd = funcDecl->getPreviousDecl(); pd; + pd = pd->getPreviousDecl()) { + if (LLVM_UNLIKELY(pd->isInlineBuiltinDeclaration())) { + std::string inlineName = funcDecl->getName().str() + ".inline"; + if (auto inlineFn = mlir::cast_or_null<cir::FuncOp>( + cgm.getGlobalValue(inlineName))) { + // Replace all uses of the .inline function with the regular function + // FIXME: This performs a linear walk over the module. Introduce some + // caching here. + if (inlineFn + .replaceAllSymbolUses(fn.getSymNameAttr(), cgm.getModule()) + .failed()) + llvm_unreachable("Failed to replace inline builtin symbol uses"); + inlineFn.erase(); + } + break; + } + } + } + SourceLocation loc = funcDecl->getLocation(); Stmt *body = funcDecl->getBody(); SourceRange bodyRange = |