{"id":2232490,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2232490/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260504152323.4034277-1-disservin.social@gmail.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/1.1/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20260504152323.4034277-1-disservin.social@gmail.com>","date":"2026-05-04T15:23:24","name":"[v2] Add __builtin_bitreverse{8,16,32,64} [PR50481]","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"1765c69facaa99d4673ce3dcf418dd60cc4517ec","submitter":{"id":93304,"url":"http://patchwork.ozlabs.org/api/1.1/people/93304/?format=json","name":"Disservin","email":"disservin.social@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260504152323.4034277-1-disservin.social@gmail.com/mbox/","series":[{"id":502683,"url":"http://patchwork.ozlabs.org/api/1.1/series/502683/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=502683","date":"2026-05-04T15:23:24","name":"[v2] Add __builtin_bitreverse{8,16,32,64} [PR50481]","version":2,"mbox":"http://patchwork.ozlabs.org/series/502683/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2232490/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2232490/checks/","tags":{},"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=GbU5MmhD;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=GbU5MmhD","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","sourceware.org; spf=pass smtp.mailfrom=gmail.com","server2.sourceware.org;\n arc=none smtp.remote-ip=2a00:1450:4864:20::32d"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g8QSZ6xyrz1yKC\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 05 May 2026 01:25:17 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id A67494BA23F3\n\tfor <incoming@patchwork.ozlabs.org>; Mon,  4 May 2026 15:25:15 +0000 (GMT)","from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com\n [IPv6:2a00:1450:4864:20::32d])\n by sourceware.org (Postfix) with ESMTPS id 7F73C4BA23F3\n for <gcc-patches@gcc.gnu.org>; Mon,  4 May 2026 15:24:46 +0000 (GMT)","by mail-wm1-x32d.google.com with SMTP id\n 5b1f17b1804b1-488ab2db91aso51300465e9.3\n for <gcc-patches@gcc.gnu.org>; Mon, 04 May 2026 08:24:46 -0700 (PDT)","from ABC.fritz.box ([95.88.170.219])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a8ebb2f32sm283635285e9.13.2026.05.04.08.24.43\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 04 May 2026 08:24:44 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org A67494BA23F3","OpenDKIM Filter v2.11.0 sourceware.org 7F73C4BA23F3"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 7F73C4BA23F3","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 7F73C4BA23F3","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777908286; cv=none;\n b=OpERPqOtcJar6WtZHjp6tSDeX4zrqpi8yXjpD6rFJU7lOSt5tv7y4X5DXGF9YwRuhLNzVFCg3A7HZtL9R1Kd3fPRbr0nkNZpWonypbhM7GF0CHJiH9NNt4sjSnZ0A4MINzRgpGiIW5ofRgHXZrpub1XMIT9U/SFRTBp7bkcNJR4=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777908286; c=relaxed/simple;\n bh=dTMSdCjCr5EojSuDTeziqNNaoDNod6eYZ7NWA8BPzN4=;\n h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version;\n b=PFozCf/e7i4fjV6e7IR5A8DtOpuZQgunk9ibo/pUfK/CyEJ+EOO7Ld0Mr4n7l5NC9giL3+B8mebqZPvNU6IaoT2sbs7hf9QK6i8qslw8kuQ+gyQrKcyg2BS+sZ2kzF/66uUoHSOsvCWQ4X+uWcDOap++/UkH0W6GUVyrjh1GOCE=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1777908285; x=1778513085; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=e5SrUHjOSHTBq0/mFBnBMs/u2s9oJydgiRS1iqSgBsU=;\n b=GbU5MmhDtNlg8aZ6wftBQSFMyYsTflRG9DvHPyi6tkDhrPS53yKZhD1d3+Yv1NQkwm\n 3ILi4UKMT1NeDpKRmrUf4GmO9dMcKfRWYaO4RKTtNo1EcbaDdNm5esm/XTMMgFqFH332\n DCplExzG71Saf3y/mZspW55Vk6xfK48Ki6D4OwOIwybO4in8cU8WLCbOIXGJnzDmZ2Du\n +V2jdgoxYmM6cb5JvTZyU3VUU9Gp8RNdkAdmos49gVCJqO8wEw42Nsn8NHgoA1OkOhJS\n AUK2UYCKO8M0Lf/OW3bCODZFT45R8UdD/cW/3tBfhD5IsirI7vgFvQdaW79JvoZmS83Y\n ICfQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777908285; x=1778513085;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=e5SrUHjOSHTBq0/mFBnBMs/u2s9oJydgiRS1iqSgBsU=;\n b=hOFEPgaFAih1HtInRyaw0YTv9SA/oMZH7D3zo75MLpY/9F7fe7jvyeG5KwjbCJHM3z\n Lz9ibkCxRj7G8ZI6if8RIUzN+Q6tZLmmBJOaJSxNSX1SGofCTczpqnGES81CtL5ctl7R\n LrDcvjDS4FBcdjUuo5Ixv+QdqcoKvVgHL15Ie0MVv2IisaWZusW924Sdpe0IM1mmgNXv\n 8amvyujXtgUUSLGKqmw/60M0LtbHZYE1Z6PdWrpQnJSpycw0HJWpKIvICWVWUDLrAlGi\n yybeNSx8IULFrYtwtzm8bb4nR+cb26aGhPMy/OyiSUW8Ej/gggpmweKSn9Zx8ijwQ/xa\n albg==","X-Gm-Message-State":"AOJu0YzS39eDnpORhxjNo5hHQ6r8eIEMWE/mLzHzmxFFFnmN8AbaF8Vw\n 4/JF4Xt0t6kTjOVMt0aVM8pZTC9LR8O43yxtsgJrb9hvMrT5oeRMHR8QCsBlTw==","X-Gm-Gg":"AeBDietSL6lC7s96GXyHdrnIIqYW2mNEGUzdONTtIhrpbkQ9dCn9NFPGnGGMktMKj7w\n RAR33Q/70Lf6RZT6osaupTfRrDpj+ZRSz7GLAUag5CDaYCk1TqEN13GTbAFSJCpQDqvJUbJLSS/\n AgIxSfQv6tqAh+jn2j405/eJUYIi4zyNzn6ia64pJGwt4AAVdmdGE8rRtmYa1wbNvolzU3oUGKR\n o2I60MjLLcL4tiTM2lwlYNzzNYNma8ZBnuxtxOe33Za28/YYBQ3oVgdt+uRaQwrNESfZD2Te8WA\n KjbCmoIrCEQyCnxPp8xhVuu9mR3BSLAKHTOiGBYAiFw403VI81d4dQP0DvGSfqsz9NPUaJxBqP/\n FJui97qZsQerdyvtKnytrMtiGPDmupYsCQpmf46GlU5gtNRhYG4Ab5vf7BfjVMn0NFFaK/mUDDp\n X+RfdnkFdk4vpE70uWxyaCcMl+kpm3NdqL+KBaiD+K+1E=","X-Received":"by 2002:a05:600c:4f8a:b0:48d:46a:6e43 with SMTP id\n 5b1f17b1804b1-48d046a7074mr108783225e9.5.1777908284600;\n Mon, 04 May 2026 08:24:44 -0700 (PDT)","From":"Disservin <disservin.social@gmail.com>","To":"gcc-patches@gcc.gnu.org","Cc":"Disservin <disservin.social@gmail.com>","Subject":"[PATCH v2] Add __builtin_bitreverse{8,16,32,64} [PR50481]","Date":"Mon,  4 May 2026 17:23:24 +0200","Message-Id":"<20260504152323.4034277-1-disservin.social@gmail.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20260502101755.308183-1-disservin.social@gmail.com>","References":"<20260502101755.308183-1-disservin.social@gmail.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"This patch adds a first version of __builtin_bitreverse{8,16,32,64}\nbuiltins.\nPR target/50481\nhttps://gcc.gnu.org/bugzilla/show_bug.cgi?id=50481\n\nFuture work could optimize this on specific targets:\n- ARM: lower to RBIT\n- x86 with GFNI: lower to vgf2p8affineqb [1]\n\nThis is my first GCC patch; any feedback on process or style is welcome.\n\n[1] https://wunkolo.github.io/post/2020/11/gf2p8affineqb-bit-reversal/\n\ngcc/ChangeLog:\n\t* builtin-types.def (BT_FN_UINT8_UINT8): New.\n\t* builtins.def (BUILT_IN_BITREVERSE8, BUILT_IN_BITREVERSE16,\n\tBUILT_IN_BITREVERSE32, BUILT_IN_BITREVERSE64): New builtins.\n\t* builtins.cc (expand_builtin, is_inexpensive_builtin): Handle\n\tbitreverse builtins.\n\t* fold-const-call.cc (fold_const_call_ss): Fold bitreverse builtins.\n\t* fold-const.cc (tree_call_nonnegative_warnv_p): Handle\n\tbitreverse builtins.\n\t* optabs.def (bitreverse_optab): New.\n\t* optabs.cc (expand_bitreverse): New function.\n\t(expand_unop): Use it for bitreverse_optab.\n\t* tree-ssa-ccp.cc (evaluate_stmt): Handle bitreverse builtins.\n\t* tree-ssa-phiopt.cc (empty_bb_or_one_feeding_into_p,\n\tcond_removal_in_builtin_zero_pattern): Likewise.\n\t* doc/extend.texi: Document __builtin_bitreverse{8,16,32,64}.\n\ngcc/testsuite/ChangeLog:\n\t* gcc.dg/builtin-bitreverse-fold.c: New test.\n\t* gcc.dg/builtin-bitreverse64.c: New test.\n\n---\n\nv2 fix formatting nits\n\ngcc/ChangeLog:\n\t* fold-const-call.cc (fold_const_call_ss): Update formatting nits.\n\t* optabs.cc (expand_bitreverse): Update formatting nits.\n\ngcc/testsuite/ChangeLog:\n\t* gcc.dg/builtin-bitreverse-fold.c: Update compile target to int32.\n\nSigned-off-by: Disservin <disservin.social@gmail.com>\n---\n gcc/builtin-types.def                         |   1 +\n gcc/builtins.cc                               |  14 ++\n gcc/builtins.def                              |   4 +\n gcc/doc/extend.texi                           |  19 +++\n gcc/fold-const-call.cc                        |   8 ++\n gcc/fold-const.cc                             |   4 +\n gcc/optabs.cc                                 | 127 ++++++++++++++++++\n gcc/optabs.def                                |   1 +\n .../gcc.dg/builtin-bitreverse-fold.c          |   9 ++\n gcc/testsuite/gcc.dg/builtin-bitreverse64.c   |  24 ++++\n gcc/tree-ssa-ccp.cc                           |   4 +\n gcc/tree-ssa-phiopt.cc                        |   8 ++\n 12 files changed, 223 insertions(+)\n create mode 100644 gcc/testsuite/gcc.dg/builtin-bitreverse-fold.c\n create mode 100644 gcc/testsuite/gcc.dg/builtin-bitreverse64.c","diff":"diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def\nindex ab0cbc65cfc..365badca2aa 100644\n--- a/gcc/builtin-types.def\n+++ b/gcc/builtin-types.def\n@@ -412,6 +412,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_INT16_FLOAT, BT_INT16, BT_FLOAT)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_FLOAT, BT_UINT32, BT_FLOAT)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_FLOAT, BT_UINT16, BT_FLOAT)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT8_FLOAT, BT_UINT8, BT_FLOAT)\n+DEF_FUNCTION_TYPE_1 (BT_FN_UINT8_UINT8, BT_UINT8, BT_UINT8)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)\n DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)\ndiff --git a/gcc/builtins.cc b/gcc/builtins.cc\nindex 692e20088c2..0475bb88a61 100644\n--- a/gcc/builtins.cc\n+++ b/gcc/builtins.cc\n@@ -8184,6 +8184,16 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,\n \treturn target;\n       break;\n \n+    case BUILT_IN_BITREVERSE8:\n+    case BUILT_IN_BITREVERSE16:\n+    case BUILT_IN_BITREVERSE32:\n+    case BUILT_IN_BITREVERSE64:\n+      target = expand_builtin_unop (target_mode, exp, target, subtarget,\n+\t\t\t\t    bitreverse_optab);\n+      if (target)\n+\treturn target;\n+      break;\n+\n     CASE_INT_FN (BUILT_IN_FFS):\n       target = expand_builtin_unop (target_mode, exp, target,\n \t\t\t\t    subtarget, ffs_optab);\n@@ -12343,6 +12353,10 @@ is_inexpensive_builtin (tree decl)\n       case BUILT_IN_BSWAP32:\n       case BUILT_IN_BSWAP64:\n       case BUILT_IN_BSWAP128:\n+      case BUILT_IN_BITREVERSE8:\n+      case BUILT_IN_BITREVERSE16:\n+      case BUILT_IN_BITREVERSE32:\n+      case BUILT_IN_BITREVERSE64:\n       case BUILT_IN_CLZ:\n       case BUILT_IN_CLZIMAX:\n       case BUILT_IN_CLZL:\ndiff --git a/gcc/builtins.def b/gcc/builtins.def\nindex 8ab0599b17f..68838de55f1 100644\n--- a/gcc/builtins.def\n+++ b/gcc/builtins.def\n@@ -1024,6 +1024,10 @@ DEF_GCC_BUILTIN        (BUILT_IN_BSWAP16, \"bswap16\", BT_FN_UINT16_UINT16, ATTR_C\n DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32, \"bswap32\", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)\n DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64, \"bswap64\", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)\n DEF_GCC_BUILTIN        (BUILT_IN_BSWAP128, \"bswap128\", BT_FN_UINT128_UINT128, ATTR_CONST_NOTHROW_LEAF_LIST)\n+DEF_GCC_BUILTIN        (BUILT_IN_BITREVERSE8, \"bitreverse8\", BT_FN_UINT8_UINT8, ATTR_CONST_NOTHROW_LEAF_LIST)\n+DEF_GCC_BUILTIN        (BUILT_IN_BITREVERSE16, \"bitreverse16\", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)\n+DEF_GCC_BUILTIN        (BUILT_IN_BITREVERSE32, \"bitreverse32\", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)\n+DEF_GCC_BUILTIN        (BUILT_IN_BITREVERSE64, \"bitreverse64\", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)\n \n DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_CACHE, \"__clear_cache\", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)\n /* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed.  */\ndiff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi\nindex 0faa5323ce1..aa1f526f7fd 100644\n--- a/gcc/doc/extend.texi\n+++ b/gcc/doc/extend.texi\n@@ -16064,6 +16064,25 @@ Similar to @code{__builtin_bswap64}, except the argument and return types\n are 128-bit.  Only supported on targets when 128-bit types are supported.\n @enddefbuiltin\n \n+@defbuiltin{uint8_t __builtin_bitreverse8 (uint8_t @var{x})}\n+Returns @var{x} with all bits reversed.\n+@enddefbuiltin\n+\n+@defbuiltin{uint16_t __builtin_bitreverse16 (uint16_t @var{x})}\n+Similar to @code{__builtin_bitreverse8}, except the argument and return types\n+are 16-bit.\n+@enddefbuiltin\n+\n+@defbuiltin{uint32_t __builtin_bitreverse32 (uint32_t @var{x})}\n+Similar to @code{__builtin_bitreverse8}, except the argument and return types\n+are 32-bit.\n+@enddefbuiltin\n+\n+@defbuiltin{uint64_t __builtin_bitreverse64 (uint64_t @var{x})}\n+Similar to @code{__builtin_bitreverse8}, except the argument and return types\n+are 64-bit.\n+@enddefbuiltin\n+\n @node CRC Builtins\n @subsection CRC Builtins\n @cindex CRC builtins\ndiff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc\nindex 7dd1b21c34f..d5408f252f7 100644\n--- a/gcc/fold-const-call.cc\n+++ b/gcc/fold-const-call.cc\n@@ -1102,6 +1102,14 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,\n \t\t\t\t\t   TYPE_SIGN (arg_type)));\n       return true;\n \n+    case CFN_BUILT_IN_BITREVERSE8:\n+    case CFN_BUILT_IN_BITREVERSE16:\n+    case CFN_BUILT_IN_BITREVERSE32:\n+    case CFN_BUILT_IN_BITREVERSE64:\n+      *result = wi::bitreverse (wide_int::from (arg, precision,\n+\t\t\t\t\t\tTYPE_SIGN (arg_type)));\n+      return true;\n+\n     default:\n       return false;\n     }\ndiff --git a/gcc/fold-const.cc b/gcc/fold-const.cc\nindex 56503e570bc..3bc82a108db 100644\n--- a/gcc/fold-const.cc\n+++ b/gcc/fold-const.cc\n@@ -14984,6 +14984,10 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1,\n     case CFN_BUILT_IN_BSWAP32:\n     case CFN_BUILT_IN_BSWAP64:\n     case CFN_BUILT_IN_BSWAP128:\n+    case CFN_BUILT_IN_BITREVERSE8:\n+    case CFN_BUILT_IN_BITREVERSE16:\n+    case CFN_BUILT_IN_BITREVERSE32:\n+    case CFN_BUILT_IN_BITREVERSE64:\n       /* Always true.  */\n       return true;\n \ndiff --git a/gcc/optabs.cc b/gcc/optabs.cc\nindex 111b9be9913..46f3a7c9ca1 100644\n--- a/gcc/optabs.cc\n+++ b/gcc/optabs.cc\n@@ -2941,6 +2941,129 @@ expand_doubleword_bswap (machine_mode mode, rtx op, rtx target)\n   return target;\n }\n \n+/* Try calculating (bitreverse x) using masks and shifts.  */\n+\n+static rtx\n+expand_bitreverse (scalar_int_mode mode, rtx op0, rtx target)\n+{\n+  unsigned int precision = GET_MODE_BITSIZE (mode);\n+  rtx_insn *last;\n+\n+  /* Operation requires at least 4 bits (one nibble swap makes no sense below that) */\n+  if (precision < 4)\n+    return NULL_RTX;\n+\n+  if (target == NULL_RTX\n+      || target == op0\n+      || reg_overlap_mentioned_p (target, op0))\n+    target = gen_reg_rtx (mode);\n+\n+  last = get_last_insn ();\n+\n+  rtx x, lo, hi;\n+\n+  /* Step 1: byte-swap (only meaningful for >= 16 bits) */\n+  if (precision >= 16)\n+    {\n+      x = expand_unop (mode, bswap_optab, op0, NULL_RTX, true);\n+      if (x == NULL_RTX)\n+        goto fail;\n+    }\n+  else\n+    x = op0;\n+\n+  /* Step 2: swap nibbles within each byte (shift=4, only for >= 8 bits) */\n+  if (precision >= 8)\n+    {\n+      wide_int mask = wi::zero (precision);\n+      for (unsigned int start = 0; start < precision; start += 8)\n+        mask = wi::bit_or (mask, wi::shifted_mask (start, 4, false, precision));\n+\n+      rtx mask_rtx = immed_wide_int_const (mask, mode);\n+\n+      hi = expand_simple_binop (mode, LSHIFTRT, x, GEN_INT (4),\n+                                NULL_RTX, true, OPTAB_LIB_WIDEN);\n+      if (hi == NULL_RTX) goto fail;\n+      hi = expand_binop (mode, and_optab, hi, mask_rtx,\n+                         NULL_RTX, true, OPTAB_LIB_WIDEN);\n+      if (hi == NULL_RTX) goto fail;\n+\n+      lo = expand_binop (mode, and_optab, x, mask_rtx,\n+                         NULL_RTX, true, OPTAB_LIB_WIDEN);\n+      if (lo == NULL_RTX) goto fail;\n+      lo = expand_simple_binop (mode, ASHIFT, lo, GEN_INT (4),\n+                                NULL_RTX, true, OPTAB_LIB_WIDEN);\n+      if (lo == NULL_RTX) goto fail;\n+\n+      x = expand_binop (mode, ior_optab, hi, lo,\n+                        NULL_RTX, true, OPTAB_LIB_WIDEN);\n+      if (x == NULL_RTX) goto fail;\n+    }\n+\n+  /* Step 3: swap pairs of bits within each nibble (shift=2) */\n+  {\n+    wide_int mask = wi::zero (precision);\n+    for (unsigned int start = 0; start < precision; start += 4)\n+      mask = wi::bit_or (mask, wi::shifted_mask (start, 2, false, precision));\n+\n+    rtx mask_rtx = immed_wide_int_const (mask, mode);\n+\n+    hi = expand_simple_binop (mode, LSHIFTRT, x, GEN_INT (2),\n+                              NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (hi == NULL_RTX) goto fail;\n+    hi = expand_binop (mode, and_optab, hi, mask_rtx,\n+                       NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (hi == NULL_RTX) goto fail;\n+\n+    lo = expand_binop (mode, and_optab, x, mask_rtx,\n+                       NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (lo == NULL_RTX) goto fail;\n+    lo = expand_simple_binop (mode, ASHIFT, lo, GEN_INT (2),\n+                              NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (lo == NULL_RTX) goto fail;\n+\n+    x = expand_binop (mode, ior_optab, hi, lo,\n+                      NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (x == NULL_RTX) goto fail;\n+  }\n+\n+  /* Step 4: swap adjacent bits (shift=1) */\n+  {\n+    wide_int mask = wi::zero (precision);\n+    for (unsigned int start = 0; start < precision; start += 2)\n+      mask = wi::bit_or (mask, wi::shifted_mask (start, 1, false, precision));\n+\n+    rtx mask_rtx = immed_wide_int_const (mask, mode);\n+\n+    hi = expand_simple_binop (mode, LSHIFTRT, x, GEN_INT (1),\n+                              NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (hi == NULL_RTX) goto fail;\n+    hi = expand_binop (mode, and_optab, hi, mask_rtx,\n+                       NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (hi == NULL_RTX) goto fail;\n+\n+    lo = expand_binop (mode, and_optab, x, mask_rtx,\n+                       NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (lo == NULL_RTX) goto fail;\n+    lo = expand_simple_binop (mode, ASHIFT, lo, GEN_INT (1),\n+                              NULL_RTX, true, OPTAB_LIB_WIDEN);\n+    if (lo == NULL_RTX) goto fail;\n+\n+    x = expand_binop (mode, ior_optab, hi, lo,\n+                      target, true, OPTAB_LIB_WIDEN);\n+    if (x == NULL_RTX) goto fail;\n+  }\n+\n+  if (x != target)\n+    emit_move_insn (target, x);\n+\n+  return target;\n+\n+ fail:\n+  delete_insns_since (last);\n+  return NULL_RTX;\n+}\n+\n /* Try calculating (parity x) as (and (popcount x) 1), where\n    popcount can also be done in a wider mode.  */\n static rtx\n@@ -3391,6 +3514,10 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target,\n       goto try_libcall;\n     }\n \n+  if (unoptab == bitreverse_optab && is_a <scalar_int_mode> (mode, &int_mode))\n+      if (temp = expand_bitreverse (int_mode, op0, target))\n+\treturn temp;\n+\n   /* Neg should be tried via expand_absneg_bit before widening.  */\n   if (optab_to_code (unoptab) == NEG)\n     {\ndiff --git a/gcc/optabs.def b/gcc/optabs.def\nindex 193f42a728a..7ccea18543f 100644\n--- a/gcc/optabs.def\n+++ b/gcc/optabs.def\n@@ -184,6 +184,7 @@ OPTAB_VC(absv_optab, \"absv$I$a2\", ABS)\n OPTAB_VX(absv_optab, \"abs$F$a2\")\n OPTAB_NL(one_cmpl_optab, \"one_cmpl$a2\", NOT, \"one_cmpl\", '2', gen_int_libfunc)\n OPTAB_NC(bswap_optab, \"bswap$a2\", BSWAP)\n+OPTAB_NC(bitreverse_optab, \"bitreverse$a2\", BITREVERSE)\n OPTAB_NL(ffs_optab, \"ffs$a2\", FFS, \"ffs\", '2', gen_int_libfunc)\n OPTAB_NL(clz_optab, \"clz$a2\", CLZ, \"clz\", '2', gen_int_libfunc)\n OPTAB_NL(ctz_optab, \"ctz$a2\", CTZ, \"ctz\", '2', gen_int_libfunc)\ndiff --git a/gcc/testsuite/gcc.dg/builtin-bitreverse-fold.c b/gcc/testsuite/gcc.dg/builtin-bitreverse-fold.c\nnew file mode 100644\nindex 00000000000..311fd45263a\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/builtin-bitreverse-fold.c\n@@ -0,0 +1,9 @@\n+/* { dg-do compile { target int32 } } */\n+/* { dg-options \"-std=gnu11\" } */\n+\n+_Static_assert (__builtin_bitreverse8 (0x01u) == 0x80u, \"bitreverse8\");\n+_Static_assert (__builtin_bitreverse16 (0x0001u) == 0x8000u, \"bitreverse16\");\n+_Static_assert (__builtin_bitreverse32 (0x12345678u) == 0x1e6a2c48u,\n+\t\t\"bitreverse32\");\n+_Static_assert (__builtin_bitreverse64 (0x0123456789abcdefull)\n+\t\t == 0xf7b3d591e6a2c480ull, \"bitreverse64\");\ndiff --git a/gcc/testsuite/gcc.dg/builtin-bitreverse64.c b/gcc/testsuite/gcc.dg/builtin-bitreverse64.c\nnew file mode 100644\nindex 00000000000..8419452ff60\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/builtin-bitreverse64.c\n@@ -0,0 +1,24 @@\n+/* { dg-do run } */\n+/* { dg-options \"-O2\" } */\n+\n+extern void abort (void);\n+\n+static unsigned long long\n+br64 (unsigned long long x)\n+{\n+  return __builtin_bitreverse64 (x);\n+}\n+\n+int\n+main (void)\n+{\n+  if (br64 (0x0000000000000000ull) != 0x0000000000000000ull)\n+    abort ();\n+  if (br64 (0x0000000000000001ull) != 0x8000000000000000ull)\n+    abort ();\n+  if (br64 (0x0123456789abcdefull) != 0xf7b3d591e6a2c480ull)\n+    abort ();\n+  if (br64 (0xffffffffffffffffull) != 0xffffffffffffffffull)\n+    abort ();\n+  return 0;\n+}\ndiff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc\nindex 952ebf17e7a..974bef17832 100644\n--- a/gcc/tree-ssa-ccp.cc\n+++ b/gcc/tree-ssa-ccp.cc\n@@ -2435,6 +2435,10 @@ evaluate_stmt (gimple *stmt)\n \t    case BUILT_IN_BSWAP32:\n \t    case BUILT_IN_BSWAP64:\n \t    case BUILT_IN_BSWAP128:\n+\t    case BUILT_IN_BITREVERSE8:\n+\t    case BUILT_IN_BITREVERSE16:\n+\t    case BUILT_IN_BITREVERSE32:\n+\t    case BUILT_IN_BITREVERSE64:\n \t      val = get_value_for_expr (gimple_call_arg (stmt, 0), true);\n \t      if (val.lattice_val == UNDEFINED)\n \t\tbreak;\ndiff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc\nindex 0bf7e58b8f0..50ddeaa67c1 100644\n--- a/gcc/tree-ssa-phiopt.cc\n+++ b/gcc/tree-ssa-phiopt.cc\n@@ -819,6 +819,10 @@ empty_bb_or_one_feeding_into_p (basic_block bb,\n \tcase CFN_BUILT_IN_BSWAP32:\n \tcase CFN_BUILT_IN_BSWAP64:\n \tcase CFN_BUILT_IN_BSWAP128:\n+\tcase CFN_BUILT_IN_BITREVERSE8:\n+\tcase CFN_BUILT_IN_BITREVERSE16:\n+\tcase CFN_BUILT_IN_BITREVERSE32:\n+\tcase CFN_BUILT_IN_BITREVERSE64:\n \tCASE_CFN_FFS:\n \tCASE_CFN_PARITY:\n \tCASE_CFN_POPCOUNT:\n@@ -2578,6 +2582,10 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb,\n     case CFN_BUILT_IN_BSWAP32:\n     case CFN_BUILT_IN_BSWAP64:\n     case CFN_BUILT_IN_BSWAP128:\n+    case CFN_BUILT_IN_BITREVERSE8:\n+    case CFN_BUILT_IN_BITREVERSE16:\n+    case CFN_BUILT_IN_BITREVERSE32:\n+    case CFN_BUILT_IN_BITREVERSE64:\n     CASE_CFN_FFS:\n     CASE_CFN_PARITY:\n     CASE_CFN_POPCOUNT:\n","prefixes":["v2"]}