[libcxx-commits] [libcxx] [libc++] Use .set for symbol assignment on Hexagon (PR #211578)

Brian Cain via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 23 08:13:24 PDT 2026


https://github.com/androm3da created https://github.com/llvm/llvm-project/pull/211578

std::__is_function_overridden() defines __impl_ref<_Func>::__impl_ as a local uses asm (`sym = expr`). On Hexagon `=` is the operand assignment operator of the instruction syntax, so the assembler parses that line as an instruction and rejects it:

  overridable_function.h:106:11: error: unrecognized instruction
    106 |   __asm__("%cc0 = %cc1" : : "X"(...), "X"(_Func));
        |           ^
  <inline asm>:1:2: note: instantiated into assembly here
      1 |         _ZNSt3__110__impl_refIXadL_ZnwjEEE7__impl_Ej = _Znwj

The assembler does accept the similar `.set sym, expr` directive, so let's use that here.

This was encountered in libfuzzer's libc++ - built w/-fno-exceptions.

>From 3e008014c7470fea07fdf89dcdbb3d0bd7e6f649 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Thu, 23 Jul 2026 09:36:49 -0500
Subject: [PATCH] [libc++] Use .set for symbol assignment on Hexagon

std::__is_function_overridden() defines __impl_ref<_Func>::__impl_ as a local
uses asm (`sym = expr`). On Hexagon `=` is the operand assignment
operator of the instruction syntax, so the assembler parses that line as an
instruction and rejects it:

  overridable_function.h:106:11: error: unrecognized instruction
    106 |   __asm__("%cc0 = %cc1" : : "X"(...), "X"(_Func));
        |           ^
  <inline asm>:1:2: note: instantiated into assembly here
      1 |         _ZNSt3__110__impl_refIXadL_ZnwjEEE7__impl_Ej = _Znwj

The assembler does accept the similar `.set sym, expr` directive, so
let's use that here.

This was encountered in libfuzzer's libc++ - built w/-fno-exceptions.
---
 libcxx/src/include/overridable_function.h | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/libcxx/src/include/overridable_function.h b/libcxx/src/include/overridable_function.h
index 307405812f9af..f75a26b4293b1 100644
--- a/libcxx/src/include/overridable_function.h
+++ b/libcxx/src/include/overridable_function.h
@@ -92,16 +92,22 @@ struct __impl_ref<_Func> {
   [[gnu::visibility("hidden")]] static _Ret __impl_(_Args...);
 };
 
+#    if defined(__hexagon__)
+#      define _LIBCPP_ASM_SYMBOL_ASSIGNMENT(__dst, __src) ".set " __dst ", " __src
+#    else
+#      define _LIBCPP_ASM_SYMBOL_ASSIGNMENT(__dst, __src) __dst " = " __src
+#    endif
+
 // This takes a function type template argument first so that the second non-type template
 // argument (pointer to the public function) gets the benefit of type-aware overload
 // resolution, rather than having to use a static_cast.
 template <typename T, T* _Func>
 _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
-#  if !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 2101
-  __asm__("%cc0 = %cc1" : : "X"(__impl_ref<_Func>::__impl_), "X"(_Func));
-#  else
-  __asm__("%c0 = %c1" : : "X"(__impl_ref<_Func>::__impl_), "X"(_Func));
-#  endif
+#    if !defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER >= 2101
+  __asm__(_LIBCPP_ASM_SYMBOL_ASSIGNMENT("%cc0", "%cc1") : : "X"(__impl_ref<_Func>::__impl_), "X"(_Func));
+#    else
+  __asm__(_LIBCPP_ASM_SYMBOL_ASSIGNMENT("%c0", "%c1") : : "X"(__impl_ref<_Func>::__impl_), "X"(_Func));
+#    endif
   // This just has the compiler compare the two symbols. For PIC mode, this will do a
   // direct PC-relative materialization for __impl_ref<...>::__impl_ and a GOT load for
   // the _Func symbol. The compiler thinks __impl_ref<...>::__impl_ is defined elsewhere
@@ -110,6 +116,8 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
   return __launder_function_pointer(_Func) != __impl_ref<_Func>::__impl_;
 }
 
+#    undef _LIBCPP_ASM_SYMBOL_ASSIGNMENT
+
 _LIBCPP_END_NAMESPACE_STD
 
 #  else // __has_feature(ptrauth_calls)



More information about the libcxx-commits mailing list