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

David Green via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 24 06:57:26 PST 2025


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

A funnel shift with the first two operands is a rotate. AArch64 has scalar instructions for ror so can handle a ROTR by 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 an extra neg.

>From af72dfe39ab43f1a107bf3ee0ac3920776e59bf3 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Mon, 24 Nov 2025 14:43:13 +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   | 13 ++++++++++++-
 llvm/test/Analysis/CostModel/AArch64/fshl.ll        |  4 ++--
 llvm/test/Analysis/CostModel/AArch64/fshr.ll        |  4 ++--
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 0bae00bafee3c..7572aec43e919 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -921,8 +921,19 @@ 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 on integer registers can be done in a single 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