mstorsjo created this revision. mstorsjo added reviewers: aaron.ballman, rnk. Herald added a project: All. mstorsjo requested review of this revision. Herald added a project: clang.
If a function is renamed with `__asm__`, the name provided is the exact symbol name, without any extra implicit symbol prefixes. If the target does use symbol prefixes, the IR level symbol gets an `\01` prefix to indicate that it's a literal symbol name to be taken as is. When a builtin function is specialized by providing an inline version of it, that inline function is named `<funcname>.inline`. When the base function has been renamed due to `__asm__`, the inline function ends up named `<asmname>.inline`. Up to this point, things did work as expected before. However, for targets with symbol prefixes, one codepath that produced the combined name `<asmname>.inline` used the mangled `asmname` with `\01` prefix, while others didn't. This patch fixes this. This fixes the combination of asm renamed builtin function, with inline override of the function, on any target with symbol prefixes (such as i386 windows and any Darwin target). Alternatively, instead of reimplementing this piece of logic here, should it try to call MangleContext::mangleName somehow? Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D137073 Files: clang/lib/CodeGen/CGExpr.cpp clang/test/CodeGen/inline-builtin-asm-name.c Index: clang/test/CodeGen/inline-builtin-asm-name.c =================================================================== --- /dev/null +++ clang/test/CodeGen/inline-builtin-asm-name.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -o - %s -disable-llvm-optzns | FileCheck %s + +// CHECK: call i32 @"\01_asm_func_name.inline" + +// CHECK: declare dso_local i32 @"\01_asm_func_name"(ptr noundef, i32 noundef, ptr noundef, ptr noundef) + +// CHECK: define internal i32 @"\01_asm_func_name.inline" + +// CHECK: call i32 @__mingw_vsnprintf + +// CHECK: declare dso_local i32 @__mingw_vsnprintf + +typedef unsigned int size_t; + +int __mingw_vsnprintf(char *_DstBuf, size_t _MaxCount, const char *_Format, __builtin_va_list _ArgList); + +// For the real use case, "_asm_func_name" is actually "___mingw_vsnprintf", but it's renamed in the testcase for disambiguation. +int vsnprintf(char *__stream, size_t __n, const char *__format, __builtin_va_list __local_argv) __asm__("_asm_func_name"); + +extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) +int vsnprintf(char *__stream, size_t __n, const char *__format, __builtin_va_list __local_argv) +{ + return __mingw_vsnprintf(__stream, __n, __format, __local_argv); +} + +void call(const char* fmt, ...) { + char buf[200]; + __builtin_va_list ap; + __builtin_va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + __builtin_va_end(ap); +} Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -5014,8 +5014,18 @@ std::string NoBuiltinFD = ("no-builtin-" + FD->getName()).str(); std::string NoBuiltins = "no-builtins"; - auto *A = FD->getAttr<AsmLabelAttr>(); - StringRef Ident = A ? A->getLabel() : FD->getName(); + StringRef Ident = FD->getName(); + + std::string AsmName; + if (auto *A = FD->getAttr<AsmLabelAttr>()) { + StringRef UserLabelPrefix = + CGF.getContext().getTargetInfo().getUserLabelPrefix(); + if (!UserLabelPrefix.empty()) + AsmName += '\01'; // LLVM IR Marker for __asm("foo") + AsmName += A->getLabel(); + Ident = AsmName; + } + std::string FDInlineName = (Ident + ".inline").str(); bool IsPredefinedLibFunction =
Index: clang/test/CodeGen/inline-builtin-asm-name.c =================================================================== --- /dev/null +++ clang/test/CodeGen/inline-builtin-asm-name.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -o - %s -disable-llvm-optzns | FileCheck %s + +// CHECK: call i32 @"\01_asm_func_name.inline" + +// CHECK: declare dso_local i32 @"\01_asm_func_name"(ptr noundef, i32 noundef, ptr noundef, ptr noundef) + +// CHECK: define internal i32 @"\01_asm_func_name.inline" + +// CHECK: call i32 @__mingw_vsnprintf + +// CHECK: declare dso_local i32 @__mingw_vsnprintf + +typedef unsigned int size_t; + +int __mingw_vsnprintf(char *_DstBuf, size_t _MaxCount, const char *_Format, __builtin_va_list _ArgList); + +// For the real use case, "_asm_func_name" is actually "___mingw_vsnprintf", but it's renamed in the testcase for disambiguation. +int vsnprintf(char *__stream, size_t __n, const char *__format, __builtin_va_list __local_argv) __asm__("_asm_func_name"); + +extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) +int vsnprintf(char *__stream, size_t __n, const char *__format, __builtin_va_list __local_argv) +{ + return __mingw_vsnprintf(__stream, __n, __format, __local_argv); +} + +void call(const char* fmt, ...) { + char buf[200]; + __builtin_va_list ap; + __builtin_va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + __builtin_va_end(ap); +} Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -5014,8 +5014,18 @@ std::string NoBuiltinFD = ("no-builtin-" + FD->getName()).str(); std::string NoBuiltins = "no-builtins"; - auto *A = FD->getAttr<AsmLabelAttr>(); - StringRef Ident = A ? A->getLabel() : FD->getName(); + StringRef Ident = FD->getName(); + + std::string AsmName; + if (auto *A = FD->getAttr<AsmLabelAttr>()) { + StringRef UserLabelPrefix = + CGF.getContext().getTargetInfo().getUserLabelPrefix(); + if (!UserLabelPrefix.empty()) + AsmName += '\01'; // LLVM IR Marker for __asm("foo") + AsmName += A->getLabel(); + Ident = AsmName; + } + std::string FDInlineName = (Ident + ".inline").str(); bool IsPredefinedLibFunction =
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits