From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Antonio Maiorano Date: Thu, 20 Jun 2024 14:02:42 -0400 Subject: indvars: don't replace a phi when that breaks LCSSA (#6695) Induction variable simplification (indvars) tries to rewrite exit values; these appear as phi nodes in loop exit blocks. If the replacement for the phi is still in the loop, then that would break the LCSSA property. Don't do that. Add a test for this. Bug: chromium:345993680 Change-Id: Ib2330afa3c6f47373cb4336cfd00e851044fea3a Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5645925 Reviewed-by: dan sinclair Reviewed-by: James Price diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index f5b1455d5932b63dfef699991c5eeab38e447a7d..e6ff7b3ab4d81bbb782f0bd0a7b5185a30fd1285 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -24,7 +24,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Scalar.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -41,11 +40,13 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SimplifyIndVar.h" @@ -698,6 +699,16 @@ void IndVarSimplify::RewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) { continue; } + // HLSL Change Begin + // Avoid breaking LCSSA: Don't replace the PHI if its replacement + // is defined inside the loop. + if (auto *ExitValInst = dyn_cast(ExitVal)) { + if (L->contains(ExitValInst)) { + continue; + } + } + // HLSL Change End + // Collect all the candidate PHINodes to be rewritten. RewritePhiSet.push_back( RewritePhi(PN, i, ExitVal, HighCost, LCSSASafePhiForRAUW)); diff --git a/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll new file mode 100644 index 0000000000000000000000000000000000000000..b550ce993837814229f8223a47b2af328cc7c87c --- /dev/null +++ b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll @@ -0,0 +1,49 @@ +; RUN: opt < %s -indvars -S | FileCheck %s + +; The inner loop (%header1) has a fixed trip count. +; The indvars pass is tempted to delete the phi instruction %hexit, +; and replace its uses with %add3. +; But %hexit is used in %latch0, which is outside the inner loop and +; its exit block. Deleting the phi %hexit would break LCSSA form. + +; CHECK: @main +; CHECK: exit1: +; CHECK-NEXT: %hexit = phi i32 [ %hnext, %header1 ] +; CHECK-NEXT: br label %latch0 + +; CHECK: latch0: + +target triple = "dxil-ms-dx" + +define void @main(i32 %arg) { +entry: + br label %header0 + +header0: + %isgt0 = icmp sgt i32 %arg, 0 + %smax = select i1 %isgt0, i32 %arg, i32 0 + %h0 = add i32 %smax, 1 + %j0 = add i32 %smax, 2 + %doinner = icmp slt i32 %j0, 1 + br i1 %doinner, label %header1.pre, label %latch0 + +header1.pre: + br label %header1 + +header1: + %hi = phi i32 [ %hnext, %header1 ], [ %h0, %header1.pre ] + %ji = phi i32 [ %jnext, %header1 ], [ %j0, %header1.pre ] + %add3 = add i32 %smax, 3 + %hnext = add i32 %hi, 1 + %jnext = add nsw i32 %ji, 1 ; the nsw here is essential + %do1again = icmp slt i32 %ji, %add3 + br i1 %do1again, label %header1, label %exit1 + +exit1: + %hexit = phi i32 [ %hnext, %header1 ] + br label %latch0 + +latch0: + %useh = phi i32 [ %h0, %header0 ], [ %hexit, %exit1 ] + br label %header0 +}