@@ -1029,8 +1029,48 @@ static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
10291029 return cgm.getAddrOfFunction (gd);
10301030}
10311031
1032- static CIRGenCallee emitDirectCallee (CIRGenModule &cgm, GlobalDecl gd) {
1033- assert (!cir::MissingFeatures::opCallBuiltinFunc ());
1032+ // Detect the unusual situation where an inline version is shadowed by a
1033+ // non-inline version. In that case we should pick the external one
1034+ // everywhere. That's GCC behavior too.
1035+ static bool onlyHasInlineBuiltinDeclaration (const FunctionDecl *fd) {
1036+ for (const FunctionDecl *pd = fd; pd; pd = pd->getPreviousDecl ())
1037+ if (!pd->isInlineBuiltinDeclaration ())
1038+ return false ;
1039+ return true ;
1040+ }
1041+
1042+ CIRGenCallee CIRGenFunction::emitDirectCallee (const GlobalDecl &gd) {
1043+ const auto *fd = cast<FunctionDecl>(gd.getDecl ());
1044+
1045+ if (unsigned builtinID = fd->getBuiltinID ()) {
1046+ if (fd->getAttr <AsmLabelAttr>()) {
1047+ cgm.errorNYI (" AsmLabelAttr" );
1048+ }
1049+
1050+ StringRef ident = fd->getName ();
1051+ std::string fdInlineName = (ident + " .inline" ).str ();
1052+
1053+ bool isPredefinedLibFunction =
1054+ cgm.getASTContext ().BuiltinInfo .isPredefinedLibFunction (builtinID);
1055+ bool hasAttributeNoBuiltin = false ;
1056+ assert (!cir::MissingFeatures::attributeNoBuiltin ());
1057+
1058+ // When directing calling an inline builtin, call it through it's mangled
1059+ // name to make it clear it's not the actual builtin.
1060+ auto fn = cast<cir::FuncOp>(curFn);
1061+ if (fn.getName () != fdInlineName && onlyHasInlineBuiltinDeclaration (fd)) {
1062+ cgm.errorNYI (" Inline only builtin function calls" );
1063+ }
1064+
1065+ // Replaceable builtins provide their own implementation of a builtin. If we
1066+ // are in an inline builtin implementation, avoid trivial infinite
1067+ // recursion. Honor __attribute__((no_builtin("foo"))) or
1068+ // __attribute__((no_builtin)) on the current function unless foo is
1069+ // not a predefined library function which means we must generate the
1070+ // builtin no matter what.
1071+ else if (!isPredefinedLibFunction || !hasAttributeNoBuiltin)
1072+ return CIRGenCallee::forBuiltin (builtinID, fd);
1073+ }
10341074
10351075 cir::FuncOp callee = emitFunctionDeclPointer (cgm, gd);
10361076
@@ -1106,7 +1146,7 @@ CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *e) {
11061146 } else if (const auto *declRef = dyn_cast<DeclRefExpr>(e)) {
11071147 // Resolve direct calls.
11081148 const auto *funcDecl = cast<FunctionDecl>(declRef->getDecl ());
1109- return emitDirectCallee (cgm, funcDecl);
1149+ return emitDirectCallee (funcDecl);
11101150 } else if (isa<MemberExpr>(e)) {
11111151 cgm.errorNYI (e->getSourceRange (),
11121152 " emitCallee: call to member function is NYI" );
@@ -1162,10 +1202,9 @@ RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *e,
11621202
11631203 CIRGenCallee callee = emitCallee (e->getCallee ());
11641204
1165- if (e->getBuiltinCallee ()) {
1166- cgm.errorNYI (e->getSourceRange (), " call to builtin functions" );
1167- }
1168- assert (!cir::MissingFeatures::opCallBuiltinFunc ());
1205+ if (callee.isBuiltin ())
1206+ return emitBuiltinExpr (callee.getBuiltinDecl (), callee.getBuiltinID (), e,
1207+ returnValue);
11691208
11701209 if (isa<CXXPseudoDestructorExpr>(e->getCallee ())) {
11711210 cgm.errorNYI (e->getSourceRange (), " call to pseudo destructor" );
0 commit comments