https://github.com/pvimal816a created 
https://github.com/llvm/llvm-project/pull/217596

The existing implementation of __rev16ll results in a suboptimal code with 
multiple instructions than necessary and does not make use of 64-bit variant of 
`rev16` instruction which was introduced after the C function was originally 
introduced.

Fixing this in the instruction selection phase is also not clean because it's 
not as simple as adding a TableGen pattern because of existing C++ based 
overrides which takes precedence and prevent any pattern match in this case. 
Another solution would have been to canonicalize relevant IR before instruction 
selection but that would not be specific to aarch64 backend.

Overall, updating implementation of __rev16ll in arm_acle.h itself is cleaner. 
With this __rev16ll lowers to only one instruction at assembly level.

>From 5d39a0e72821ef4e73d961c81fc717d43643ac93 Mon Sep 17 00:00:00 2001
From: Vimal Patel <[email protected]>
Date: Thu, 20 Aug 2026 10:09:12 +0000
Subject: [PATCH] [ARM_ACLE] Update implementation of __rev16ll for better
 codegen quality

The existing implementation results in a suboptimal code with multiple
instructions than necessary and does not make use of 64-bit variant of
`rev` instruction which was introduced after the C function was
originally introduced.

Fixing this in the instruction selection phase is also not clean because
it's not as simple as adding a TableGen pattern because of existing C++
based overrides which takes precedence and prevent any pattern match in
this case. Another solution would have been to canonicalize relevant IR
before instruction selection but that would not be specific to aarch64
backend.

Overall, updating implementation of __rev16ll in arm_acle.h itself is
cleaner. With this __rev16ll lowers to only one instruction at assembly
level.
---
 clang/lib/Headers/arm_acle.h  |  3 +-
 clang/test/CodeGen/arm_acle.c | 80 +++++------------------------------
 2 files changed, 12 insertions(+), 71 deletions(-)

diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h
index 9a6b6a837fa5a..73b1e841b6719 100644
--- a/clang/lib/Headers/arm_acle.h
+++ b/clang/lib/Headers/arm_acle.h
@@ -222,7 +222,8 @@ __rev16(uint32_t __t) {
 
 static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
 __rev16ll(uint64_t __t) {
-  return (((uint64_t)__rev16(__t >> 32)) << 32) | 
(uint64_t)__rev16((uint32_t)__t);
+  return (((__t >> 8) & 0x00ff00ff00ff00ff) |
+          ((__t << 8) & 0xff00ff00ff00ff00));
 }
 
 static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
diff --git a/clang/test/CodeGen/arm_acle.c b/clang/test/CodeGen/arm_acle.c
index cd18fa63bfdbd..e1bbc3d745bcd 100644
--- a/clang/test/CodeGen/arm_acle.c
+++ b/clang/test/CodeGen/arm_acle.c
@@ -494,41 +494,11 @@ uint32_t test_rev16(uint32_t t) {
 //
 // AArch64-LABEL: @test_rev16l(
 // AArch64-NEXT:  entry:
-// AArch64-NEXT:    [[SHR_I:%.*]] = lshr i64 [[T:%.*]], 32
-// AArch64-NEXT:    [[CONV_I:%.*]] = trunc i64 [[SHR_I]] to i32
-// AArch64-NEXT:    [[TMP0:%.*]] = call i32 @llvm.bswap.i32(i32 [[CONV_I]])
-// AArch64-NEXT:    [[REM_I_I10_I:%.*]] = urem i32 16, 32
-// AArch64-NEXT:    [[CMP_I_I11_I:%.*]] = icmp eq i32 [[REM_I_I10_I]], 0
-// AArch64-NEXT:    br i1 [[CMP_I_I11_I]], label [[IF_THEN_I_I17_I:%.*]], 
label [[IF_END_I_I12_I:%.*]]
-// AArch64:       if.then.i.i17.i:
-// AArch64-NEXT:    br label [[__REV16_EXIT18_I:%.*]]
-// AArch64:       if.end.i.i12.i:
-// AArch64-NEXT:    [[SHR_I_I13_I:%.*]] = lshr i32 [[TMP0]], [[REM_I_I10_I]]
-// AArch64-NEXT:    [[SUB_I_I14_I:%.*]] = sub i32 32, [[REM_I_I10_I]]
-// AArch64-NEXT:    [[SHL_I_I15_I:%.*]] = shl i32 [[TMP0]], [[SUB_I_I14_I]]
-// AArch64-NEXT:    [[OR_I_I16_I:%.*]] = or i32 [[SHR_I_I13_I]], 
[[SHL_I_I15_I]]
-// AArch64-NEXT:    br label [[__REV16_EXIT18_I]]
-// AArch64:       __rev16.exit18.i:
-// AArch64-NEXT:    [[RETVAL_I_I6_I_0:%.*]] = phi i32 [ [[TMP0]], 
[[IF_THEN_I_I17_I]] ], [ [[OR_I_I16_I]], [[IF_END_I_I12_I]] ]
-// AArch64-NEXT:    [[CONV1_I:%.*]] = zext i32 [[RETVAL_I_I6_I_0]] to i64
-// AArch64-NEXT:    [[SHL_I:%.*]] = shl i64 [[CONV1_I]], 32
-// AArch64-NEXT:    [[CONV2_I:%.*]] = trunc i64 [[T]] to i32
-// AArch64-NEXT:    [[TMP1:%.*]] = call i32 @llvm.bswap.i32(i32 [[CONV2_I]])
-// AArch64-NEXT:    [[REM_I_I_I:%.*]] = urem i32 16, 32
-// AArch64-NEXT:    [[CMP_I_I_I:%.*]] = icmp eq i32 [[REM_I_I_I]], 0
-// AArch64-NEXT:    br i1 [[CMP_I_I_I]], label [[IF_THEN_I_I_I:%.*]], label 
[[IF_END_I_I_I:%.*]]
-// AArch64:       if.then.i.i.i:
-// AArch64-NEXT:    br label [[__REV16LL_EXIT:%.*]]
-// AArch64:       if.end.i.i.i:
-// AArch64-NEXT:    [[SHR_I_I_I:%.*]] = lshr i32 [[TMP1]], [[REM_I_I_I]]
-// AArch64-NEXT:    [[SUB_I_I_I:%.*]] = sub i32 32, [[REM_I_I_I]]
-// AArch64-NEXT:    [[SHL_I_I_I:%.*]] = shl i32 [[TMP1]], [[SUB_I_I_I]]
-// AArch64-NEXT:    [[OR_I_I_I:%.*]] = or i32 [[SHR_I_I_I]], [[SHL_I_I_I]]
-// AArch64-NEXT:    br label [[__REV16LL_EXIT]]
-// AArch64:       __rev16ll.exit:
-// AArch64-NEXT:    [[RETVAL_I_I_I_0:%.*]] = phi i32 [ [[TMP1]], 
[[IF_THEN_I_I_I]] ], [ [[OR_I_I_I]], [[IF_END_I_I_I]] ]
-// AArch64-NEXT:    [[CONV4_I:%.*]] = zext i32 [[RETVAL_I_I_I_0]] to i64
-// AArch64-NEXT:    [[OR_I:%.*]] = or i64 [[SHL_I]], [[CONV4_I]]
+// AArch64-NEXT:    [[SHR_I:%.*]] = lshr i64 [[T:%.*]], 8
+// AArch64-NEXT:    [[AND_I:%.*]] = and i64 [[SHR_I]], 71777214294589695
+// AArch64-NEXT:    [[SHL_I:%.*]] = shl i64 [[T]], 8
+// AArch64-NEXT:    [[AND1_I:%.*]] = and i64 [[SHL_I]], -71777214294589696
+// AArch64-NEXT:    [[OR_I:%.*]] = or i64 [[AND_I]], [[AND1_I]]
 // AArch64-NEXT:    ret i64 [[OR_I]]
 //
 long test_rev16l(long t) {
@@ -537,41 +507,11 @@ long test_rev16l(long t) {
 
 // ARM-LABEL: @test_rev16ll(
 // ARM-NEXT:  entry:
-// ARM-NEXT:    [[SHR_I:%.*]] = lshr i64 [[T:%.*]], 32
-// ARM-NEXT:    [[CONV_I:%.*]] = trunc i64 [[SHR_I]] to i32
-// ARM-NEXT:    [[TMP0:%.*]] = call i32 @llvm.bswap.i32(i32 [[CONV_I]])
-// ARM-NEXT:    [[REM_I_I10_I:%.*]] = urem i32 16, 32
-// ARM-NEXT:    [[CMP_I_I11_I:%.*]] = icmp eq i32 [[REM_I_I10_I]], 0
-// ARM-NEXT:    br i1 [[CMP_I_I11_I]], label [[IF_THEN_I_I17_I:%.*]], label 
[[IF_END_I_I12_I:%.*]]
-// ARM:       if.then.i.i17.i:
-// ARM-NEXT:    br label [[__REV16_EXIT18_I:%.*]]
-// ARM:       if.end.i.i12.i:
-// ARM-NEXT:    [[SHR_I_I13_I:%.*]] = lshr i32 [[TMP0]], [[REM_I_I10_I]]
-// ARM-NEXT:    [[SUB_I_I14_I:%.*]] = sub i32 32, [[REM_I_I10_I]]
-// ARM-NEXT:    [[SHL_I_I15_I:%.*]] = shl i32 [[TMP0]], [[SUB_I_I14_I]]
-// ARM-NEXT:    [[OR_I_I16_I:%.*]] = or i32 [[SHR_I_I13_I]], [[SHL_I_I15_I]]
-// ARM-NEXT:    br label [[__REV16_EXIT18_I]]
-// ARM:       __rev16.exit18.i:
-// ARM-NEXT:    [[RETVAL_I_I6_I_0:%.*]] = phi i32 [ [[TMP0]], 
[[IF_THEN_I_I17_I]] ], [ [[OR_I_I16_I]], [[IF_END_I_I12_I]] ]
-// ARM-NEXT:    [[CONV1_I:%.*]] = zext i32 [[RETVAL_I_I6_I_0]] to i64
-// ARM-NEXT:    [[SHL_I:%.*]] = shl i64 [[CONV1_I]], 32
-// ARM-NEXT:    [[CONV2_I:%.*]] = trunc i64 [[T]] to i32
-// ARM-NEXT:    [[TMP1:%.*]] = call i32 @llvm.bswap.i32(i32 [[CONV2_I]])
-// ARM-NEXT:    [[REM_I_I_I:%.*]] = urem i32 16, 32
-// ARM-NEXT:    [[CMP_I_I_I:%.*]] = icmp eq i32 [[REM_I_I_I]], 0
-// ARM-NEXT:    br i1 [[CMP_I_I_I]], label [[IF_THEN_I_I_I:%.*]], label 
[[IF_END_I_I_I:%.*]]
-// ARM:       if.then.i.i.i:
-// ARM-NEXT:    br label [[__REV16LL_EXIT:%.*]]
-// ARM:       if.end.i.i.i:
-// ARM-NEXT:    [[SHR_I_I_I:%.*]] = lshr i32 [[TMP1]], [[REM_I_I_I]]
-// ARM-NEXT:    [[SUB_I_I_I:%.*]] = sub i32 32, [[REM_I_I_I]]
-// ARM-NEXT:    [[SHL_I_I_I:%.*]] = shl i32 [[TMP1]], [[SUB_I_I_I]]
-// ARM-NEXT:    [[OR_I_I_I:%.*]] = or i32 [[SHR_I_I_I]], [[SHL_I_I_I]]
-// ARM-NEXT:    br label [[__REV16LL_EXIT]]
-// ARM:       __rev16ll.exit:
-// ARM-NEXT:    [[RETVAL_I_I_I_0:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN_I_I_I]] 
], [ [[OR_I_I_I]], [[IF_END_I_I_I]] ]
-// ARM-NEXT:    [[CONV4_I:%.*]] = zext i32 [[RETVAL_I_I_I_0]] to i64
-// ARM-NEXT:    [[OR_I:%.*]] = or i64 [[SHL_I]], [[CONV4_I]]
+// ARM-NEXT:    [[SHR_I:%.*]] = lshr i64 [[T:%.*]], 8
+// ARM-NEXT:    [[AND_I:%.*]] = and i64 [[SHR_I]], 71777214294589695
+// ARM-NEXT:    [[SHL_I:%.*]] = shl i64 [[T]], 8
+// ARM-NEXT:    [[AND1_I:%.*]] = and i64 [[SHL_I]], -71777214294589696
+// ARM-NEXT:    [[OR_I:%.*]] = or i64 [[AND_I]], [[AND1_I]]
 // ARM-NEXT:    ret i64 [[OR_I]]
 //
 uint64_t test_rev16ll(uint64_t t) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to