[SCEV] Recognize vscale intrinsics
authorNikita Popov <npopov@redhat.com>
Thu, 16 Mar 2023 10:27:25 +0000 (11:27 +0100)
committerNikita Popov <npopov@redhat.com>
Fri, 17 Mar 2023 09:07:39 +0000 (10:07 +0100)
Now that SCEV has a dedicated vscale node type, we should also map
vscale intrinsics to it. To make sure this does not regress ranges
(which were KnownBits based previously), add support for vscale to
getRangeRef() as well.

Differential Revision: https://reviews.llvm.org/D146226

llvm/include/llvm/Analysis/ValueTracking.h
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Analysis/ScalarEvolution/scalable-vector.ll

index 26fb105..0a8af8c 100644 (file)
@@ -654,6 +654,10 @@ OverflowResult computeOverflowForSignedSub(const Value *LHS, const Value *RHS,
 bool isOverflowIntrinsicNoWrap(const WithOverflowInst *WO,
                                const DominatorTree &DT);
 
+/// Determine the possible constant range of vscale with the given bit width,
+/// based on the vscale_range function attribute.
+ConstantRange getVScaleRange(const Function *F, unsigned BitWidth);
+
 /// Determine the possible constant range of an integer or vector of integer
 /// value. This is intended as a cheap, non-recursive check.
 ConstantRange computeConstantRange(const Value *V, bool ForSigned,
index 09c6432..e3c4fc5 100644 (file)
@@ -6600,7 +6600,7 @@ const ConstantRange &ScalarEvolution::getRangeRef(
   case scConstant:
     llvm_unreachable("Already handled above.");
   case scVScale:
-    return setRange(S, SignHint, std::move(ConservativeResult));
+    return setRange(S, SignHint, getVScaleRange(&F, BitWidth));
   case scTruncate: {
     const SCEVTruncateExpr *Trunc = cast<SCEVTruncateExpr>(S);
     ConstantRange X = getRangeRef(Trunc->getOperand(), SignHint, Depth + 1);
@@ -8007,6 +8007,8 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
         // A start_loop_iterations or llvm.annotation or llvm.prt.annotation is
         // just eqivalent to the first operand for SCEV purposes.
         return getSCEV(II->getArgOperand(0));
+      case Intrinsic::vscale:
+        return getVScale(II->getType());
       default:
         break;
       }
index 6cc2fb2..1ce06e5 100644 (file)
@@ -1152,7 +1152,7 @@ KnownBits llvm::analyzeKnownBitsFromAndXorOr(
       Query(DL, AC, safeCxtI(I, CxtI), DT, UseInstrInfo, ORE));
 }
 
-static ConstantRange getVScaleRange(const Function *F, unsigned BitWidth) {
+ConstantRange llvm::getVScaleRange(const Function *F, unsigned BitWidth) {
   Attribute Attr = F->getFnAttribute(Attribute::VScaleRange);
   // Without vscale_range, we only know that vscale is non-zero.
   if (!Attr.isValid())
index 3bc709e..13648eb 100644 (file)
@@ -19,9 +19,9 @@ define void @vscale_gep_range(ptr %p) vscale_range(2, 16) {
 ; CHECK-LABEL: 'vscale_gep_range'
 ; CHECK-NEXT:  Classifying expressions for: @vscale_gep_range
 ; CHECK-NEXT:    %1 = getelementptr <vscale x 4 x i32>, ptr null, i32 3
-; CHECK-NEXT:    --> ((48 * vscale) + null) U: [0,-15) S: [-9223372036854775808,9223372036854775793)
+; CHECK-NEXT:    --> ((48 * vscale)<nuw><nsw> + null) U: [96,769) S: [96,769)
 ; CHECK-NEXT:    %2 = getelementptr <vscale x 1 x i64>, ptr %p, i32 1
-; CHECK-NEXT:    --> ((8 * vscale) + %p) U: full-set S: full-set
+; CHECK-NEXT:    --> ((8 * vscale)<nuw><nsw> + %p) U: full-set S: full-set
 ; CHECK-NEXT:  Determining loop execution counts for: @vscale_gep_range
 ;
   getelementptr <vscale x 4 x i32>, ptr null, i32 3
@@ -33,7 +33,7 @@ define i64 @vscale_no_range() {
 ; CHECK-LABEL: 'vscale_no_range'
 ; CHECK-NEXT:  Classifying expressions for: @vscale_no_range
 ; CHECK-NEXT:    %vscale = call i64 @llvm.vscale.i64()
-; CHECK-NEXT:    --> %vscale U: [1,0) S: [1,0)
+; CHECK-NEXT:    --> vscale U: [1,0) S: [1,0)
 ; CHECK-NEXT:  Determining loop execution counts for: @vscale_no_range
 ;
   %vscale = call i64 @llvm.vscale.i64()
@@ -44,7 +44,7 @@ define i64 @vscale_min_max_range() vscale_range(2, 16) {
 ; CHECK-LABEL: 'vscale_min_max_range'
 ; CHECK-NEXT:  Classifying expressions for: @vscale_min_max_range
 ; CHECK-NEXT:    %vscale = call i64 @llvm.vscale.i64()
-; CHECK-NEXT:    --> %vscale U: [1,32) S: [1,32)
+; CHECK-NEXT:    --> vscale U: [2,17) S: [2,17)
 ; CHECK-NEXT:  Determining loop execution counts for: @vscale_min_max_range
 ;
   %vscale = call i64 @llvm.vscale.i64()
@@ -55,7 +55,7 @@ define i64 @vscale_min_range() vscale_range(2, 0) {
 ; CHECK-LABEL: 'vscale_min_range'
 ; CHECK-NEXT:  Classifying expressions for: @vscale_min_range
 ; CHECK-NEXT:    %vscale = call i64 @llvm.vscale.i64()
-; CHECK-NEXT:    --> %vscale U: [1,0) S: [1,0)
+; CHECK-NEXT:    --> vscale U: [2,0) S: [2,0)
 ; CHECK-NEXT:  Determining loop execution counts for: @vscale_min_range
 ;
   %vscale = call i64 @llvm.vscale.i64()
@@ -66,7 +66,7 @@ define i64 @vscale_exact_range() vscale_range(2) {
 ; CHECK-LABEL: 'vscale_exact_range'
 ; CHECK-NEXT:  Classifying expressions for: @vscale_exact_range
 ; CHECK-NEXT:    %vscale = call i64 @llvm.vscale.i64()
-; CHECK-NEXT:    --> %vscale U: [2,3) S: [2,3)
+; CHECK-NEXT:    --> vscale U: [2,3) S: [2,3)
 ; CHECK-NEXT:  Determining loop execution counts for: @vscale_exact_range
 ;
   %vscale = call i64 @llvm.vscale.i64()