From patchwork Tue Aug 4 18:43:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Sayle X-Patchwork-Id: 140613 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 18CE84BB3B89 for ; Tue, 4 Aug 2026 18:44:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 18CE84BB3B89 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (2048-bit key, unprotected) header.d=nextmovesoftware.com header.i=@nextmovesoftware.com header.a=rsa-sha256 header.s=default header.b=JvTjzz7l X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from server.nextmovesoftware.com (server.nextmovesoftware.com [69.48.154.134]) by sourceware.org (Postfix) with ESMTPS id 994BF4BAE7CC for ; Tue, 4 Aug 2026 18:43:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 994BF4BAE7CC Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=nextmovesoftware.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nextmovesoftware.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 994BF4BAE7CC Authentication-Results: sourceware.org; arc=none smtp.remote-ip=69.48.154.134 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785869022; cv=none; b=ipghJwmWC/mAl7Fo9ZlFPnsmOnXJWfZbtPcBhWoQG784l1eXwbb5ZDDZu98grp3oc/xeEfz43zdDWoNN3t0W1nxBvqIjhEPrA29A4ZG9TzK/6yfvUNEv12Fm0nMfTFPzGwy4Q9f6Uaqj1pmxF0smvzSSS1wPMDNviZOy+ji3R8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785869022; c=relaxed/simple; bh=nmLHIZtPBcuWepcwUTeDb/mTrni/7gU/eh4Oluscplc=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=nORiR8uoXB8vQE29nBk3sGEQ0YsgsZN/B4le63ub5T87k7Cypqb9L7RcTIabSwOgAQisWKsO5UBgHbnx/BaB+eokRpaoMnJqZQS3wzrGkMEpXCqC28r5+eJuBpuB0xCwfiPKA/lhUhwBHZNJ02Tb1vNR4TOPLKmZCxJ6uz63Bdg= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=nextmovesoftware.com header.i=@nextmovesoftware.com header.a=rsa-sha256 header.s=default header.b=JvTjzz7l DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 994BF4BAE7CC DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=nextmovesoftware.com; s=default; h=Content-Type:MIME-Version:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=DdNyF+5oQiYfsl+fTMYIb3p6UfxgfmcODTyLA4ILeHs=; b=JvTjzz7lBZq3eI8gtokOxJ9GQl X7H9H1r00znUFbUF06FJM8ymMLO9lmUfnZh0elOaHx9oyAaqU9jqys7O5kKz7Jo+tL+uE3N956Eom yvPrJCy8FOgi/xX+FjW0hUcNhhaGUtXKNYZuUg+yrQArbOQMBtvPYLMAyFORftsOu8TBy59loMGF/ SkIdwwm7ImggXOJ8DAicgcjSmbgeJo3uWg8+3onYKlBScROa8SNoslUUQxMTUJPqg5GWmz9XBH5uq P+OR0J3vftIfXEbpmuaWKG9pRZsVCWdbgx3zMDYOn3ns52dKyWfRBQEDhwOR7416p36TYwaUkadK9 LJiAVgjw==; Received: from [168.86.198.175] (port=49194 helo=Dell) by server.nextmovesoftware.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.99.5) (envelope-from ) id 1wrK73-00000007bYI-0w7g; Tue, 04 Aug 2026 14:43:41 -0400 From: "Roger Sayle" To: "'Patches GCC'" Cc: "'Hans-Peter Nilsson'" , "'Jeffrey Law'" Subject: [CRIS PATCH] Support bitreverse32, rotatesi3_16 and other swap variants. Date: Tue, 4 Aug 2026 19:43:39 +0100 Message-ID: <01b801dd2441$2b9f3070$82dd9150$@nextmovesoftware.com> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 16.0 Thread-Index: Ad0kP3u+NWhUUYI0QHCjdyjXQ3HWgw== Content-Language: en-gb X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - server.nextmovesoftware.com X-AntiAbuse: Original Domain - gcc.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - nextmovesoftware.com X-Get-Message-Sender-Via: server.nextmovesoftware.com: authenticated_id: roger@nextmovesoftware.com X-Authenticated-Sender: server.nextmovesoftware.com: roger@nextmovesoftware.com X-Source: X-Source-Args: X-Source-Dir: X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Hi H-P and Jeff, I appreciate that folks are on vacation at the moment, but I thought I'd post this for the record, there's no rush/urgency on a review. Version 8 of the Axis Communications' CRIS architecture contains a very cool SWAP instruction. This patch adds support for several more variants not currently supported by the cris.md backend. One example use of the swap function is to implement 32-bit rotate by 16 bits. unsigned int foo(unsigned int x) { return (x >> 16) | (x << 16); } Previously with -O2 -march=v8, gcc would generate: foo: move.d $r10,$r9 lsrq 16,$r9 lslq 16,$r10 ret add.d $r9,$r10 with this patch we now generate: foo: ret swapw $r10 Likewise, this instruction can be used to implement bitreverse [cris.md currently uses this internally, but renaming it to a standard optab name exposes it to the compiler]. unsigned int bar(unsigned int x) { return __bitreverse32(x); } Previously with -O2 -march=v8 generated: bar: move.d $r10,$r9 swapwb $r9 move.d $r9,$r10 lsrq 4,$r10 and.d 252645135,$r10 and.d 252645135,$r9 lslq 4,$r9 or.d $r9,$r10 move.d $r10,$r9 lsrq 2,$r9 and.d 858993459,$r9 and.d 858993459,$r10 lslq 2,$r10 or.d $r10,$r9 move.d $r9,$r10 lsrq 1,$r10 and.d 1431655765,$r10 and.d 1431655765,$r9 lslq 1,$r9 ret or.d $r9,$r10 with this patch, it now generates: bar: ret swapwbr $r10 This patch has been tested on a cross-compiler to cris-elf with "make" and "make check RUNTESTFLAGS="--target_board=cris-sim" with no new failures. Ok for mainline? 2026-08-04 Roger Sayle gcc/ChangeLog * gcc/config/cris/cris.md (<...>bswapsi2_not<...>): New define_insn. (cris_swap_bits): Rename to... (<...>bitreversesi2<...>): Renamed from cris_swap_bits. (<...>bitreversesi2_not<...>): New define_insn. (<...>rotsi2_16<...>): Likewise. (<...>rotsi2_16_not<...>): Likewise. testsuite/ChangeLog * gcc.target/cris/swapnw_v3.c: New test case. * gcc.target/cris/swapnw_v8.c: Likewise. * gcc.target/cris/swapnwb_v3.c: Likewise. * gcc.target/cris/swapnwb_v8.c: Likewise. * gcc.target/cris/swapnwbr_v3.c: Likewise. * gcc.target/cris/swapnwbr_v8.c: Likewise. * gcc.target/cris/swapw_v3.c: Likewise. * gcc.target/cris/swapw_v8.c: Likewise. * gcc.target/cris/swapwbr_v3.c: Likewise. * gcc.target/cris/swapwbr_v8.c: Likewise. diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md index 83b60fbeca4e..4f944d447b76 100644 --- a/gcc/config/cris/cris.md +++ b/gcc/config/cris/cris.md @@ -2195,11 +2195,20 @@ "swapwb %0" [(set_attr "slottable" "yes")]) +(define_insn "bswapsi2_not" + [(set (match_operand:SI 0 "register_operand" "=r") + (bswap:SI + (not:SI (match_operand:SI 1 "register_operand" "0")))) + (clobber (reg:CC CRIS_CC0_REGNUM))] + "TARGET_HAS_SWAP" + "swapnwb %0" + [(set_attr "slottable" "yes")]) + ;; This instruction swaps all bits in a register. ;; That means that the most significant bit is put in the place ;; of the least significant bit, and so on. -(define_insn "cris_swap_bits" +(define_insn "bitreversesi2" [(set (match_operand:SI 0 "register_operand" "=r") (bitreverse:SI (match_operand:SI 1 "register_operand" "0"))) (clobber (reg:CC CRIS_CC0_REGNUM))] @@ -2207,6 +2216,35 @@ "swapwbr %0" [(set_attr "slottable" "yes")]) +;; Takes 2-cycles but is shorter than a BITREVERSE and a NOT. +(define_insn "bitreversesi2_not" + [(set (match_operand:SI 0 "register_operand" "=r") + (bitreverse:SI + (not:SI (match_operand:SI 1 "register_operand" "0")))) + (clobber (reg:CC CRIS_CC0_REGNUM))] + "TARGET_HAS_SWAP" + "swapnwbr %0" + [(set_attr "slottable" "yes")]) + +(define_insn "rotsi2_16" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (const_int 16))) + (clobber (reg:CC CRIS_CC0_REGNUM))] + "TARGET_HAS_SWAP" + "swapw %0" + [(set_attr "slottable" "yes")]) + +(define_insn "rotsi2_16_not" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (const_int 16)))) + (clobber (reg:CC CRIS_CC0_REGNUM))] + "TARGET_HAS_SWAP" + "swapnw %0" + [(set_attr "slottable" "yes")]) + ;; Implement ctz using two instructions, one for bit swap and one for clz. ;; Defines a scratch register to avoid clobbering input. diff --git a/gcc/testsuite/gcc.target/cris/swapnw_v3.c b/gcc/testsuite/gcc.target/cris/swapnw_v3.c new file mode 100644 index 000000000000..057b7ef5eb1c --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnw_v3.c @@ -0,0 +1,20 @@ +/* Check that we don't use the swap insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v3" } */ +/* { dg-final { scan-assembler-not "\[ \t\]swapnw\[ \t\]" } } */ + +unsigned int foo(unsigned int x) +{ + unsigned int t = ~x; + t = (t >> 16) | (t << 16); + return t; +} + +unsigned int bar(unsigned int x) +{ + unsigned int t = x; + t = (t >> 16) | (t << 16); + return ~t; +} diff --git a/gcc/testsuite/gcc.target/cris/swapnw_v8.c b/gcc/testsuite/gcc.target/cris/swapnw_v8.c new file mode 100644 index 000000000000..8a4810aa776e --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnw_v8.c @@ -0,0 +1,20 @@ +/* Check that we use the swapnw insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v8" } */ +/* { dg-final { scan-assembler-times "\[ \t\]swapnw\[ \t\]" 2 } } */ + +unsigned int foo(unsigned int x) +{ + unsigned int t = ~x; + t = (t >> 16) | (t << 16); + return t; +} + +unsigned int bar(unsigned int x) +{ + unsigned int t = x; + t = (t >> 16) | (t << 16); + return ~t; +} diff --git a/gcc/testsuite/gcc.target/cris/swapnwb_v3.c b/gcc/testsuite/gcc.target/cris/swapnwb_v3.c new file mode 100644 index 000000000000..b5ec7a471bc9 --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnwb_v3.c @@ -0,0 +1,16 @@ +/* Check that we don't use the swap insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v3" } */ +/* { dg-final { scan-assembler-not "\[ \t\]swapnwb\[ \t\]" } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bswap32(~x); +} + +unsigned int bar(unsigned int x) +{ + return ~__builtin_bswap32(x); +} diff --git a/gcc/testsuite/gcc.target/cris/swapnwb_v8.c b/gcc/testsuite/gcc.target/cris/swapnwb_v8.c new file mode 100644 index 000000000000..80bbb3d22f4d --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnwb_v8.c @@ -0,0 +1,16 @@ +/* Check that we use the swapnwb insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v8" } */ +/* { dg-final { scan-assembler-times "\[ \t\]swapnwb\[ \t\]" 2 } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bswap32(~x); +} + +unsigned int bar(unsigned int x) +{ + return ~__builtin_bswap32(x); +} diff --git a/gcc/testsuite/gcc.target/cris/swapnwbr_v3.c b/gcc/testsuite/gcc.target/cris/swapnwbr_v3.c new file mode 100644 index 000000000000..35bd7d4db77f --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnwbr_v3.c @@ -0,0 +1,16 @@ +/* Check that we don't use the swap insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v3" } */ +/* { dg-final { scan-assembler-not "\[ \t\]swapnwbr\[ \t\]" } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bitreverse32(~x); +} + +unsigned int bar(unsigned int x) +{ + return ~__builtin_bitreverse32(x); +} diff --git a/gcc/testsuite/gcc.target/cris/swapnwbr_v8.c b/gcc/testsuite/gcc.target/cris/swapnwbr_v8.c new file mode 100644 index 000000000000..9cddf6b4c0b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapnwbr_v8.c @@ -0,0 +1,16 @@ +/* Check that we use the swapnwbr insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v8" } */ +/* { dg-final { scan-assembler-times "\[ \t\]swapnwbr\[ \t\]" 2 } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bitreverse32(~x); +} + +unsigned int bar(unsigned int x) +{ + return ~__builtin_bitreverse32(x); +} diff --git a/gcc/testsuite/gcc.target/cris/swapw_v3.c b/gcc/testsuite/gcc.target/cris/swapw_v3.c new file mode 100644 index 000000000000..d816b58ce625 --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapw_v3.c @@ -0,0 +1,10 @@ +/* Check that we don't use the swap insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v3" } */ +/* { dg-final { scan-assembler-not "\[ \t\]swapw\[ \t\]" } } */ + +unsigned int rot16_ior(unsigned int x) { return (x >> 16) | (x << 16); } +unsigned int rot16_xor(unsigned int x) { return (x >> 16) ^ (x << 16); } +unsigned int rot16_add(unsigned int x) { return (x >> 16) + (x << 16); } diff --git a/gcc/testsuite/gcc.target/cris/swapw_v8.c b/gcc/testsuite/gcc.target/cris/swapw_v8.c new file mode 100644 index 000000000000..be867fe04e12 --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapw_v8.c @@ -0,0 +1,10 @@ +/* Check that we use the swapw insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v8" } */ +/* { dg-final { scan-assembler-times "\[ \t\]swapw\[ \t\]" 3 } } */ + +unsigned int rot16_ior(unsigned int x) { return (x >> 16) | (x << 16); } +unsigned int rot16_xor(unsigned int x) { return (x >> 16) ^ (x << 16); } +unsigned int rot16_add(unsigned int x) { return (x >> 16) + (x << 16); } diff --git a/gcc/testsuite/gcc.target/cris/swapwbr_v3.c b/gcc/testsuite/gcc.target/cris/swapwbr_v3.c new file mode 100644 index 000000000000..e2cb862b6e0c --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapwbr_v3.c @@ -0,0 +1,12 @@ +/* Check that we don't use the swap insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v3" } */ +/* { dg-final { scan-assembler-not "\[ \t\]swapwbr\[ \t\]" } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bitreverse32(x); +} + diff --git a/gcc/testsuite/gcc.target/cris/swapwbr_v8.c b/gcc/testsuite/gcc.target/cris/swapwbr_v8.c new file mode 100644 index 000000000000..a022fc12c4eb --- /dev/null +++ b/gcc/testsuite/gcc.target/cris/swapwbr_v8.c @@ -0,0 +1,12 @@ +/* Check that we use the swapwbr insn by checking assembler output. + The swap instruction was added in v8. */ +/* { dg-do compile } */ +/* { dg-skip-if "" { "cris*-*-elf" } { "-march*" } { "" } } */ +/* { dg-options "-O2 -march=v8" } */ +/* { dg-final { scan-assembler "\[ \t\]swapwbr\[ \t\]" } } */ + +unsigned int foo(unsigned int x) +{ + return __builtin_bitreverse32(x); +} +