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
