[SCEV] Improve modelling for (null) pointer constants

This is a continuation of D89456.

As it was suggested there, now that SCEV models `PtrToInt`,
we can try to improve SCEV's pointer handling.
In particular, i believe, i will need this in the future
to further fix `SCEVAddExpr`operation type handling.

This removes special handling of `ConstantPointerNull`
from `ScalarEvolution::createSCEV()`, and add constant folding
into `ScalarEvolution::getPtrToIntExpr()`.
This way, `null` constants stay as such in SCEV's,
but gracefully become zero integers when asked.

Reviewed By: Meinersbur

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

GitOrigin-RevId: 61f006ac655431bd44b9e089f74c73bec0c1a48c
diff --git a/lib/Analysis/ScopBuilder.cpp b/lib/Analysis/ScopBuilder.cpp
index 4def171..e12261c 100644
--- a/lib/Analysis/ScopBuilder.cpp
+++ b/lib/Analysis/ScopBuilder.cpp
@@ -1761,6 +1761,11 @@
   if (DestAccFunc->isZero())
     return true;
 
+  if (auto *U = dyn_cast<SCEVUnknown>(DestAccFunc)) {
+    if (isa<ConstantPointerNull>(U->getValue()))
+      return true;
+  }
+
   auto *DestPtrSCEV = dyn_cast<SCEVUnknown>(SE.getPointerBase(DestAccFunc));
   assert(DestPtrSCEV);
   DestAccFunc = SE.getMinusSCEV(DestAccFunc, DestPtrSCEV);
@@ -1837,6 +1842,11 @@
       if (ArgSCEV->isZero())
         continue;
 
+      if (auto *U = dyn_cast<SCEVUnknown>(ArgSCEV)) {
+        if (isa<ConstantPointerNull>(U->getValue()))
+          return true;
+      }
+
       auto *ArgBasePtr = cast<SCEVUnknown>(SE.getPointerBase(ArgSCEV));
       addArrayAccess(Stmt, Inst, AccType, ArgBasePtr->getValue(),
                      ArgBasePtr->getType(), false, {AF}, {nullptr}, CI);
diff --git a/lib/Support/SCEVAffinator.cpp b/lib/Support/SCEVAffinator.cpp
index 9d2e7d9..1691b2a 100644
--- a/lib/Support/SCEVAffinator.cpp
+++ b/lib/Support/SCEVAffinator.cpp
@@ -551,8 +551,15 @@
     }
   }
 
-  llvm_unreachable(
-      "Unknowns SCEV was neither parameter nor a valid instruction.");
+  if (isa<ConstantPointerNull>(Expr->getValue())) {
+    isl::val v{Ctx, 0};
+    isl::space Space{Ctx, 0, NumIterators};
+    isl::local_space ls{Space};
+    return getPWACtxFromPWA(isl::aff(ls, v));
+  }
+
+  llvm_unreachable("Unknowns SCEV was neither a parameter, a constant nor a "
+                   "valid instruction.");
 }
 
 PWACtx SCEVAffinator::complexityBailout() {
diff --git a/lib/Support/SCEVValidator.cpp b/lib/Support/SCEVValidator.cpp
index 94b5516..0e0ec73 100644
--- a/lib/Support/SCEVValidator.cpp
+++ b/lib/Support/SCEVValidator.cpp
@@ -461,6 +461,11 @@
       }
     }
 
+    if (Expr->getType()->isPointerTy()) {
+      if (isa<ConstantPointerNull>(V))
+        return ValidatorResult(SCEVType::INT); // "int"
+    }
+
     return ValidatorResult(SCEVType::PARAM, Expr);
   }
 };
diff --git a/test/Isl/CodeGen/partial_write_impossible_restriction.ll b/test/Isl/CodeGen/partial_write_impossible_restriction.ll
index e4c2ce2..3b17518 100644
--- a/test/Isl/CodeGen/partial_write_impossible_restriction.ll
+++ b/test/Isl/CodeGen/partial_write_impossible_restriction.ll
@@ -7,7 +7,7 @@
 ;
 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
 
-define void @partial_write_impossible_restriction() {
+define void @partial_write_impossible_restriction(i32* %.pn) {
 entry:
   br i1 undef, label %invoke.cont258, label %cond.true.i.i.i.i1007
 
@@ -15,7 +15,6 @@
   br label %invoke.cont258
 
 invoke.cont258:
-  %.pn = phi i32* [ null, %cond.true.i.i.i.i1007 ], [ null, %entry ]
   br label %invoke.cont274
 
 invoke.cont274:                                   ; preds = %invoke.cont258
@@ -49,11 +48,11 @@
 
 
 ; CHECK-LABEL: polly.stmt.cond.false:
-; CHECK:         %polly.access..pn2 = getelementptr i32, i32* %.pn, i64 %polly.indvar
-; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_, i32* %polly.access..pn2, align 4, !alias.scope !0, !noalias !2
+; CHECK:         %polly.access..pn{{[0-9]*}} = getelementptr i32, i32* %.pn, i64 %polly.indvar
+; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_, i32* %polly.access..pn{{[0-9]*}}, align 4, !alias.scope !0, !noalias !2
 ; CHECK:         br label %polly.merge
 
-; CHECK-LABEL: polly.stmt.cond.false11:
-; CHECK:         %polly.access..pn14 = getelementptr i32, i32* %.pn, i64 0
-; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_13, i32* %polly.access..pn14, align 4, !alias.scope !0, !noalias !2
-; CHECK:         br label %polly.stmt.cond.end15
+; CHECK-LABEL: polly.stmt.cond.false{{[0-9]*}}:
+; CHECK:         %polly.access..pn{{[0-9]*}} = getelementptr i32, i32* %.pn, i64 0
+; CHECK:         store i32 %cond.in.sroa.speculate.load.cond.false_p_scalar_{{[0-9]*}}, i32* %polly.access..pn{{[0-9]*}}, align 4, !alias.scope !0, !noalias !2
+; CHECK:         br label %polly.stmt.cond.end{{[0-9]*}}
diff --git a/test/Isl/CodeGen/scev_looking_through_bitcasts.ll b/test/Isl/CodeGen/scev_looking_through_bitcasts.ll
index 1012e23..3521f00 100644
--- a/test/Isl/CodeGen/scev_looking_through_bitcasts.ll
+++ b/test/Isl/CodeGen/scev_looking_through_bitcasts.ll
@@ -31,7 +31,9 @@
 }
 
 
-; CHECK:       polly.stmt.cond.end73.i:
-; CHECK-NEXT:   %0 = bitcast %structty** %b.s2a to i8**
-; CHECK-NEXT:   store i8* undef, i8** %0
+
+; CHECK:      polly.stmt.cond.end73.i:
+; CHECK-NEXT:   %scevgep = getelementptr i8, i8* null, i64 %a
+; CHECK-NEXT:   %scevgep1 = bitcast i8* %scevgep to %structty*
+; CHECK-NEXT:   store %structty* %scevgep1, %structty** %b.s2a, align 8
 ; CHECK-NEXT:   br label %polly.exiting