[llvm] [AArch64] Add costs for ROTR and ROTL. (PR #169335)

David Green via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 25 05:29:09 PST 2025


https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/169335

>From e6f4258a398b979188534c3d6ff71b1b81911a5b Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 25 Nov 2025 13:28:56 +0000
Subject: [PATCH] [AArch64] Add costs for ROTR and ROTL.

A funnel shift with the first two operands is a rotate. AArch64 has scalar
instructions for ror so can handle a ROTR but a constant or variant amount
cheaply. A ROTL is a ROTR by the opposite amount, which for constants is cheap
and for variable shifts requires a neg.
---
 .../Target/AArch64/AArch64TargetTransformInfo.cpp  | 14 +++++++++++++-
 llvm/test/Analysis/CostModel/AArch64/fshl.ll       |  4 ++--
 llvm/test/Analysis/CostModel/AArch64/fshr.ll       |  4 ++--
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 0bae00bafee3c..08780c69ff9aa 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -921,8 +921,20 @@ AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
     if (ICA.getArgs().empty())
       break;
 
-    // TODO: Add handling for fshl where third argument is not a constant.
     const TTI::OperandValueInfo OpInfoZ = TTI::getOperandInfo(ICA.getArgs()[2]);
+
+    // ROTR / ROTL is a funnel shift with equal first and second operand. For
+    // ROTR on integer registers (i32/i64) this can be done in a single ror
+    // instruction. A fshl with a non-constant shift uses a neg + ror.
+    if (RetTy->isIntegerTy() && ICA.getArgs()[0] == ICA.getArgs()[1] &&
+        (RetTy->getPrimitiveSizeInBits() == 32 ||
+         RetTy->getPrimitiveSizeInBits() == 64)) {
+      InstructionCost NegCost =
+          (ICA.getID() == Intrinsic::fshl && !OpInfoZ.isConstant()) ? 1 : 0;
+      return 1 + NegCost;
+    }
+
+    // TODO: Add handling for fshl where third argument is not a constant.
     if (!OpInfoZ.isConstant())
       break;
 
diff --git a/llvm/test/Analysis/CostModel/AArch64/fshl.ll b/llvm/test/Analysis/CostModel/AArch64/fshl.ll
index cd6068d382169..61296a8e3c5d3 100644
--- a/llvm/test/Analysis/CostModel/AArch64/fshl.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/fshl.ll
@@ -349,7 +349,7 @@ entry:
 
 define i32 @rotl_i32_3rd_arg_var(i32 %a, i32 %c) {
 ; CHECK-LABEL: 'rotl_i32_3rd_arg_var'
-; CHECK-NEXT:  Cost Model: Found costs of 5 for: %r = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %c)
+; CHECK-NEXT:  Cost Model: Found costs of 2 for: %r = tail call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 %c)
 ; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret i32 %r
 ;
 entry:
@@ -369,7 +369,7 @@ entry:
 
 define i64 @rotl_i64_3rd_arg_var(i64 %a, i64 %c) {
 ; CHECK-LABEL: 'rotl_i64_3rd_arg_var'
-; CHECK-NEXT:  Cost Model: Found costs of 5 for: %r = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %c)
+; CHECK-NEXT:  Cost Model: Found costs of 2 for: %r = tail call i64 @llvm.fshl.i64(i64 %a, i64 %a, i64 %c)
 ; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret i64 %r
 ;
 entry:
diff --git a/llvm/test/Analysis/CostModel/AArch64/fshr.ll b/llvm/test/Analysis/CostModel/AArch64/fshr.ll
index 795371e9f3f68..213013092e827 100644
--- a/llvm/test/Analysis/CostModel/AArch64/fshr.ll
+++ b/llvm/test/Analysis/CostModel/AArch64/fshr.ll
@@ -349,7 +349,7 @@ entry:
 
 define i32 @rotl_i32_3rd_arg_var(i32 %a, i32 %c) {
 ; CHECK-LABEL: 'rotl_i32_3rd_arg_var'
-; CHECK-NEXT:  Cost Model: Found costs of 5 for: %r = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %c)
+; CHECK-NEXT:  Cost Model: Found costs of 1 for: %r = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 %c)
 ; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret i32 %r
 ;
 entry:
@@ -369,7 +369,7 @@ entry:
 
 define i64 @rotl_i64_3rd_arg_var(i64 %a, i64 %c) {
 ; CHECK-LABEL: 'rotl_i64_3rd_arg_var'
-; CHECK-NEXT:  Cost Model: Found costs of 5 for: %r = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %c)
+; CHECK-NEXT:  Cost Model: Found costs of 1 for: %r = tail call i64 @llvm.fshr.i64(i64 %a, i64 %a, i64 %c)
 ; CHECK-NEXT:  Cost Model: Found costs of RThru:0 CodeSize:1 Lat:1 SizeLat:1 for: ret i64 %r
 ;
 entry:



More information about the llvm-commits mailing list