[PATCH] D149903: [VPlan] Replace IR based truncateToMinimalBitwidths with VPlan version.

Ayal Zaks via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 4 16:03:24 PDT 2023


Ayal added a comment.

Various nits.



================
Comment at: llvm/lib/Transforms/Vectorize/VPlan.h:280
-  }
-
   bool hasScalarValue(VPValue *Def, VPIteration Instance) {
----------------
How/Is this removal related?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:805-806
+  auto GetSizeInBits = [](VPValue *VPV) {
+    auto *UV = VPV->getUnderlyingValue();
+    if (UV)
+      return UV->getType()->getScalarSizeInBits();
----------------
nit


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:808-810
+    if (auto *VPC = dyn_cast<VPWidenCastRecipe>(VPV)) {
+      return VPC->getResultType()->getScalarSizeInBits();
+    }
----------------
nit


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:814
+
+  unsigned ProcessedRecipes = 0;
+  for (VPValue *VPV : Plan.getLiveIns()) {
----------------
Define `ProcessedRecipes` only for debug?

/// First truncate live-ins that represent relevant Instructions.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:815
+  unsigned ProcessedRecipes = 0;
+  for (VPValue *VPV : Plan.getLiveIns()) {
+    auto *UI = dyn_cast<Instruction>(VPV->getLiveInIRValue());
----------------
(Future) Thought: wonder if instead of iterating over all live-ins looking to truncate any, it may be better to iterate over MinBWs and check if any are live-ins. Or lookup MinBWs upon construction of a live-in.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:816
+  for (VPValue *VPV : Plan.getLiveIns()) {
+    auto *UI = dyn_cast<Instruction>(VPV->getLiveInIRValue());
+    auto I = MinBWs.find(UI);
----------------
nit: use `LiveInInst` or something similar rather than `UI`?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:817
+    auto *UI = dyn_cast<Instruction>(VPV->getLiveInIRValue());
+    auto I = MinBWs.find(UI);
+    if (!UI || I == MinBWs.end())
----------------
Would ``MinBWs.lookup(UI)` look better? Returning zero clearly indicates unfound.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:822
+    unsigned NewResSizeInBits = I->second;
+    Type *ResTy = VPV->getLiveInIRValue()->getType();
+    if (!ResTy->isIntegerTy())
----------------



================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:823
+    Type *ResTy = VPV->getLiveInIRValue()->getType();
+    if (!ResTy->isIntegerTy())
+      continue;
----------------
Can this happen - continuing will lose a member of MinBWs - better assert instead?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:829
+    auto *Shrunk = new VPWidenCastRecipe(Instruction::Trunc, VPV, NewResTy);
+    VPBasicBlock *PH = dyn_cast<VPBasicBlock>(
+        Plan.getVectorLoopRegion()->getSinglePredecessor());
----------------
Set once before the loop for all live-ins to be truncated.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:838
+  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+           vp_depth_first_deep(Plan.getEntry()))) {
+    for (VPRecipeBase &R : make_early_inc_range(*VPBB)) {
----------------
Any order other than depth first would also do, right?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:849
+      VPValue *ResultVPV = R.getVPSingleValue();
+      auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
+      auto I = MinBWs.find(UI);
----------------
(Future) Thought: this is an awkward way of retrieving "the" recipe that corresponds to each member of MinBWs - look through all recipes for those having the desired "underlying" insn. Perhaps better lookup MinBWs upon construction of a recipe for an Instruction.
Or migrate the analysis that builds MinBWs to run on VPlan.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:850
+      auto *UI = cast_or_null<Instruction>(ResultVPV->getUnderlyingValue());
+      auto I = MinBWs.find(UI);
+      if (!UI || I == MinBWs.end())
----------------
nit: lookup.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:855
+      ProcessedRecipes++;
+
+      if (isa<VPReplicateRecipe>(&R))
----------------
Would be good to comment how memory and replicate cases are (not) processed.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:861
+      Type *ResTy = UI->getType();
+      if (!ResTy->isIntegerTy() || ResSizeInBits == NewResSizeInBits)
+        continue;
----------------
Better assert than continue? Here ProcessedRecipes was already bumped, but should all MinBWs members correspond to Integer types, of distinct (smaller) size, whether live-in or not?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:871
+        default:
+          break;
+        case Instruction::SExt:
----------------
This deals only with ZExt/SExt, easier to check directly if Opcode is one or the other?

OTOH, better handle Trunc here as well? Is it handled well below?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:875
+          auto *Op = R.getOperand(0);
+          if (GetSizeInBits(Op) == NewResSizeInBits) {
+            VPC->replaceAllUsesWith(Op);
----------------
`// SExt/Zext is redundant - stick with its operand.`
?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:882
+            Opcode = Instruction::Trunc;
+          assert(ResSizeInBits > NewResSizeInBits && "Nothing to shrink?");
+          auto *C = new VPWidenCastRecipe(Opcode, Op, NewResTy);
----------------
Place assert earlier?


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:884-885
+          auto *C = new VPWidenCastRecipe(Opcode, Op, NewResTy);
+          C->insertBefore(&R);
+          ResultVPV->replaceAllUsesWith(C);
+          continue;
----------------



================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:896
+        unsigned OpSizeInBits = GetSizeInBits(Op);
+        if (OpSizeInBits == NewResSizeInBits)
+          continue;
----------------
This means the size of all operands is equal to NewResSizeInBits, can this be? 


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:900-901
+        auto *Shrunk = new VPWidenCastRecipe(Instruction::Trunc, Op, NewResTy);
+        R.setOperand(Idx, Shrunk);
+        Shrunk->insertBefore(&R);
+      }
----------------
nit: keep consistent with above.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp:909-911
+      ResultVPV->replaceAllUsesWith(Ext);
+      Ext->setOperand(0, ResultVPV);
+      Ext->insertAfter(&R);
----------------
nit: keep consistent with above.


================
Comment at: llvm/lib/Transforms/Vectorize/VPlanTransforms.h:72
+  /// Insert truncates and extends for any truncated instructions as hints to
+  /// InstCombine.
+  static void
----------------
nit: a VPlan transform should fold redundant ZExt-Trunc pairs rather than leaving them ("as hints") to `InstCombine`.

Being a public method, which does not need SE, should the caller of optimize() precede its call with a direct call to trunctateToMinimalBitwidth(), rather than pass MinBWs to optimize()?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D149903/new/

https://reviews.llvm.org/D149903



More information about the llvm-commits mailing list