[clang] [clang-tools-extra] [llvm] [LLVM] Add IRNormalizer Pass (PR #68176)

Justin Fargnoli via cfe-commits cfe-commits at lists.llvm.org
Sun Nov 19 20:45:39 PST 2023


https://github.com/justinfargnoli updated https://github.com/llvm/llvm-project/pull/68176

>From f792a030ac1761a96176332fea906cd2d1826c7b Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 12 Aug 2023 10:58:45 -0700
Subject: [PATCH 01/40] Add IRCanonicalizer.cpp

---
 llvm/lib/Transforms/Utils/CMakeLists.txt      |   1 +
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 632 ++++++++++++++++++
 2 files changed, 633 insertions(+)
 create mode 100644 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp

diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index a870071f3f641dc..7866e7a8c09c3be 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -34,6 +34,7 @@ add_llvm_component_library(LLVMTransformUtils
   InjectTLIMappings.cpp
   InstructionNamer.cpp
   IntegerDivision.cpp
+  IRCanonicalizer.cpp
   LCSSA.cpp
   LibCallsShrinkWrap.cpp
   Local.cpp
diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
new file mode 100644
index 000000000000000..58e2dce0b96685b
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -0,0 +1,632 @@
+//===--------------- IRCanonicalizer.cpp - IR Canonicalizer ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements the IRCanonicalizer class which aims to transform LLVM
+/// Modules into a canonical form by reordering and renaming instructions while
+/// preserving the same semantics. The canonicalizer makes it easier to spot
+/// semantic differences while diffing two modules which have undergone
+/// different passes.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Transforms/Utils.h"
+#include <algorithm>
+#include <vector>
+
+#define DEBUG_TYPE "canon"
+
+using namespace llvm;
+
+namespace {
+/// IRCanonicalizer aims to transform LLVM IR into canonical form.
+class IRCanonicalizer : public FunctionPass {
+public:
+  static char ID;
+
+  /// \name Canonicalizer flags.
+  /// @{
+  /// Preserves original order of instructions.
+  static cl::opt<bool> PreserveOrder;
+  /// Renames all instructions (including user-named).
+  static cl::opt<bool> RenameAll;
+  /// Folds all regular instructions (including pre-outputs).
+  static cl::opt<bool> FoldPreoutputs;
+  /// Sorts and reorders operands in commutative instructions.
+  static cl::opt<bool> ReorderOperands;
+  /// @}
+
+  /// Constructor for the IRCanonicalizer.
+  IRCanonicalizer() : FunctionPass(ID) {}
+
+  bool runOnFunction(Function &F) override;
+
+private:
+  // Random constant for hashing, so the state isn't zero.
+  const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL;
+
+  /// \name Naming.
+  /// @{
+  void nameFunctionArguments(Function &F);
+  void nameBasicBlocks(Function &F);
+  void nameInstruction(Instruction *I);
+  void nameAsInitialInstruction(Instruction *I);
+  void nameAsRegularInstruction(Instruction *I);
+  void foldInstructionName(Instruction *I);
+  /// @}
+
+  /// \name Reordering.
+  /// @{
+  void reorderInstructions(SmallVector<Instruction *, 16> &Outputs);
+  void reorderInstruction(Instruction *Used, Instruction *User,
+                          SmallPtrSet<const Instruction *, 32> &Visited);
+  void reorderInstructionOperandsByNames(Instruction *I);
+  void reorderPHIIncomingValues(PHINode *PN);
+  /// @}
+
+  /// \name Utility methods.
+  /// @{
+  SmallVector<Instruction *, 16> collectOutputInstructions(Function &F);
+  bool isOutput(const Instruction *I);
+  bool isInitialInstruction(const Instruction *I);
+  bool hasOnlyImmediateOperands(const Instruction *I);
+  SetVector<int>
+  getOutputFootprint(Instruction *I,
+                     SmallPtrSet<const Instruction *, 32> &Visited);
+  /// @}
+};
+} // namespace
+
+char IRCanonicalizer::ID = 0;
+static RegisterPass<IRCanonicalizer> X("canon", "Canonicalize the IR",
+                                       false /* Only looks at CFG */,
+                                       false /* Analysis Pass */);
+
+cl::opt<bool> IRCanonicalizer::PreserveOrder(
+    "preserve-order", cl::Hidden,
+    cl::desc("Preserves original instruction order"));
+cl::opt<bool> IRCanonicalizer::RenameAll(
+    "rename-all", cl::Hidden,
+    cl::desc("Renames all instructions (including user-named)"));
+cl::opt<bool> IRCanonicalizer::FoldPreoutputs(
+    "fold-all", cl::Hidden,
+    cl::desc("Folds all regular instructions (including pre-outputs)"));
+cl::opt<bool> IRCanonicalizer::ReorderOperands(
+    "reorder-operands", cl::Hidden,
+    cl::desc("Sorts and reorders operands in commutative instructions"));
+
+/// Entry method to the IRCanonicalizer.
+///
+/// \param M Module to canonicalize.
+bool IRCanonicalizer::runOnFunction(Function &F) {
+  nameFunctionArguments(F);
+  nameBasicBlocks(F);
+
+  SmallVector<Instruction *, 16> Outputs = collectOutputInstructions(F);
+
+  if (!PreserveOrder)
+    reorderInstructions(Outputs);
+
+  for (auto &I : Outputs)
+    nameInstruction(I);
+
+  for (auto &I : instructions(F)) {
+    if (!PreserveOrder) {
+      if (ReorderOperands && I.isCommutative())
+        reorderInstructionOperandsByNames(&I);
+
+      if (auto *PN = dyn_cast<PHINode>(&I))
+        reorderPHIIncomingValues(PN);
+    }
+
+    foldInstructionName(&I);
+  }
+
+  return true;
+}
+
+/// Numbers arguments.
+///
+/// \param F Function whose arguments will be renamed.
+void IRCanonicalizer::nameFunctionArguments(Function &F) {
+  int ArgumentCounter = 0;
+  for (auto &A : F.args()) {
+    if (RenameAll || A.getName().empty()) {
+      A.setName("a" + Twine(ArgumentCounter));
+      ++ArgumentCounter;
+    }
+  }
+}
+
+/// Names basic blocks using a generated hash for each basic block in
+/// a function considering the opcode and the order of output instructions.
+///
+/// \param F Function containing basic blocks to rename.
+void IRCanonicalizer::nameBasicBlocks(Function &F) {
+  for (auto &B : F) {
+    // Initialize to a magic constant, so the state isn't zero.
+    uint64_t Hash = MagicHashConstant;
+
+    // Hash considering output instruction opcodes.
+    for (auto &I : B)
+      if (isOutput(&I))
+        Hash = hashing::detail::hash_16_bytes(Hash, I.getOpcode());
+
+    if (RenameAll || B.getName().empty()) {
+      // Name basic block. Substring hash to make diffs more readable.
+      B.setName("bb" + std::to_string(Hash).substr(0, 5));
+    }
+  }
+}
+
+/// Names instructions graphically (recursive) in accordance with the
+/// def-use tree, starting from the initial instructions (defs), finishing at
+/// the output (top-most user) instructions (depth-first).
+///
+/// \param I Instruction to be renamed.
+void IRCanonicalizer::nameInstruction(Instruction *I) {
+  // Determine the type of instruction to name.
+  if (isInitialInstruction(I)) {
+    // This is an initial instruction.
+    nameAsInitialInstruction(I);
+  } else {
+    // This must be a regular instruction.
+    nameAsRegularInstruction(I);
+  }
+}
+
+/// Names instruction following the scheme:
+/// vl00000Callee(Operands)
+///
+/// Where 00000 is a hash calculated considering instruction's opcode and output
+/// footprint. Callee's name is only included when instruction's type is
+/// CallInst. In cases where instruction is commutative, operands list is also
+/// sorted.
+///
+/// Renames instruction only when RenameAll flag is raised or instruction is
+/// unnamed.
+///
+/// \see getOutputFootprint()
+/// \param I Instruction to be renamed.
+void IRCanonicalizer::nameAsInitialInstruction(Instruction *I) {
+  if (I->getType()->isVoidTy() || (!I->getName().empty() && !RenameAll))
+    return;
+
+  // Instruction operands for further sorting.
+  SmallVector<SmallString<64>, 4> Operands;
+
+  // Collect operands.
+  for (auto &OP : I->operands()) {
+    if (!isa<Function>(OP)) {
+      std::string TextRepresentation;
+      raw_string_ostream Stream(TextRepresentation);
+      OP->printAsOperand(Stream, false);
+      Operands.push_back(StringRef(Stream.str()));
+    }
+  }
+
+  if (I->isCommutative())
+    llvm::sort(Operands);
+
+  // Initialize to a magic constant, so the state isn't zero.
+  uint64_t Hash = MagicHashConstant;
+
+  // Consider instruction's opcode in the hash.
+  Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode());
+
+  SmallPtrSet<const Instruction *, 32> Visited;
+  // Get output footprint for I.
+  SetVector<int> OutputFootprint = getOutputFootprint(I, Visited);
+
+  // Consider output footprint in the hash.
+  for (const int &Output : OutputFootprint)
+    Hash = hashing::detail::hash_16_bytes(Hash, Output);
+
+  // Base instruction name.
+  SmallString<256> Name;
+  Name.append("vl" + std::to_string(Hash).substr(0, 5));
+
+  // In case of CallInst, consider callee in the instruction name.
+  if (const auto *CI = dyn_cast<CallInst>(I)) {
+    Function *F = CI->getCalledFunction();
+
+    if (F != nullptr) {
+      Name.append(F->getName());
+    }
+  }
+
+  Name.append("(");
+  for (unsigned long i = 0; i < Operands.size(); ++i) {
+    Name.append(Operands[i]);
+
+    if (i < Operands.size() - 1)
+      Name.append(", ");
+  }
+  Name.append(")");
+
+  I->setName(Name);
+}
+
+/// Names instruction following the scheme:
+/// op00000Callee(Operands)
+///
+/// Where 00000 is a hash calculated considering instruction's opcode, its
+/// operands' opcodes and order. Callee's name is only included when
+/// instruction's type is CallInst. In cases where instruction is commutative,
+/// operand list is also sorted.
+///
+/// Names instructions recursively in accordance with the def-use tree,
+/// starting from the initial instructions (defs), finishing at
+/// the output (top-most user) instructions (depth-first).
+///
+/// Renames instruction only when RenameAll flag is raised or instruction is
+/// unnamed.
+///
+/// \see getOutputFootprint()
+/// \param I Instruction to be renamed.
+void IRCanonicalizer::nameAsRegularInstruction(Instruction *I) {
+  // Instruction operands for further sorting.
+  SmallVector<SmallString<128>, 4> Operands;
+
+  // The name of a regular instruction depends
+  // on the names of its operands. Hence, all
+  // operands must be named first in the use-def
+  // walk.
+
+  // Collect operands.
+  for (auto &OP : I->operands()) {
+    if (auto *IOP = dyn_cast<Instruction>(OP)) {
+      // Walk down the use-def chain.
+      nameInstruction(IOP);
+      Operands.push_back(IOP->getName());
+    } else if (isa<Value>(OP) && !isa<Function>(OP)) {
+      // This must be an immediate value.
+      std::string TextRepresentation;
+      raw_string_ostream Stream(TextRepresentation);
+      OP->printAsOperand(Stream, false);
+      Operands.push_back(StringRef(Stream.str()));
+    }
+  }
+
+  if (I->isCommutative())
+    llvm::sort(Operands.begin(), Operands.end());
+
+  // Initialize to a magic constant, so the state isn't zero.
+  uint64_t Hash = MagicHashConstant;
+
+  // Consider instruction opcode in the hash.
+  Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode());
+
+  // Operand opcodes for further sorting (commutative).
+  SmallVector<int, 4> OperandsOpcodes;
+
+  // Collect operand opcodes for hashing.
+  for (auto &OP : I->operands())
+    if (auto *IOP = dyn_cast<Instruction>(OP))
+      OperandsOpcodes.push_back(IOP->getOpcode());
+
+  if (I->isCommutative())
+    llvm::sort(OperandsOpcodes.begin(), OperandsOpcodes.end());
+
+  // Consider operand opcodes in the hash.
+  for (const int Code : OperandsOpcodes)
+    Hash = hashing::detail::hash_16_bytes(Hash, Code);
+
+  // Base instruction name.
+  SmallString<512> Name;
+  Name.append("op" + std::to_string(Hash).substr(0, 5));
+
+  // In case of CallInst, consider callee in the instruction name.
+  if (const auto *CI = dyn_cast<CallInst>(I))
+    if (const Function *F = CI->getCalledFunction())
+      Name.append(F->getName());
+
+  Name.append("(");
+  for (unsigned long i = 0; i < Operands.size(); ++i) {
+    Name.append(Operands[i]);
+
+    if (i < Operands.size() - 1)
+      Name.append(", ");
+  }
+  Name.append(")");
+
+  if ((I->getName().empty() || RenameAll) && !I->getType()->isVoidTy())
+    I->setName(Name);
+}
+
+/// Shortens instruction's name. This method removes called function name from
+/// the instruction name and substitutes the call chain with a corresponding
+/// list of operands.
+///
+/// Examples:
+/// op00000Callee(op00001Callee(...), vl00000Callee(1, 2), ...)  ->
+/// op00000(op00001, vl00000, ...) vl00000Callee(1, 2)  ->  vl00000(1, 2)
+///
+/// This method omits output instructions and pre-output (instructions directly
+/// used by an output instruction) instructions (by default). By default it also
+/// does not affect user named instructions.
+///
+/// \param I Instruction whose name will be folded.
+void IRCanonicalizer::foldInstructionName(Instruction *I) {
+  // If this flag is raised, fold all regular
+  // instructions (including pre-outputs).
+  if (!FoldPreoutputs) {
+    // Don't fold if one of the users is an output instruction.
+    for (auto *U : I->users())
+      if (auto *IU = dyn_cast<Instruction>(U))
+        if (isOutput(IU))
+          return;
+  }
+
+  // Don't fold if it is an output instruction or has no op prefix.
+  if (isOutput(I) || I->getName().substr(0, 2) != "op")
+    return;
+
+  // Instruction operands.
+  SmallVector<SmallString<64>, 4> Operands;
+
+  for (auto &OP : I->operands()) {
+    if (const Instruction *IOP = dyn_cast<Instruction>(OP)) {
+      bool HasCanonicalName = I->getName().substr(0, 2) == "op" ||
+                              I->getName().substr(0, 2) == "vl";
+
+      Operands.push_back(HasCanonicalName ? IOP->getName().substr(0, 7)
+                                          : IOP->getName());
+    }
+  }
+
+  if (I->isCommutative())
+    llvm::sort(Operands.begin(), Operands.end());
+
+  SmallString<256> Name;
+  Name.append(I->getName().substr(0, 7));
+
+  Name.append("(");
+  for (unsigned long i = 0; i < Operands.size(); ++i) {
+    Name.append(Operands[i]);
+
+    if (i < Operands.size() - 1)
+      Name.append(", ");
+  }
+  Name.append(")");
+
+  I->setName(Name);
+}
+
+/// Reorders instructions by walking up the tree from each operand of an output
+/// instruction and reducing the def-use distance.
+/// This method assumes that output instructions were collected top-down,
+/// otherwise the def-use chain may be broken.
+/// This method is a wrapper for recursive reorderInstruction().
+///
+/// \see reorderInstruction()
+/// \param Outputs Vector of pointers to output instructions collected top-down.
+void IRCanonicalizer::reorderInstructions(
+    SmallVector<Instruction *, 16> &Outputs) {
+  // This method assumes output instructions were collected top-down,
+  // otherwise the def-use chain may be broken.
+
+  SmallPtrSet<const Instruction *, 32> Visited;
+
+  // Walk up the tree.
+  for (auto &I : Outputs)
+    for (auto &OP : I->operands())
+      if (auto *IOP = dyn_cast<Instruction>(OP))
+        reorderInstruction(IOP, I, Visited);
+}
+
+/// Reduces def-use distance or places instruction at the end of the basic
+/// block. Continues to walk up the def-use tree recursively. Used by
+/// reorderInstructions().
+///
+/// \see reorderInstructions()
+/// \param Used Pointer to the instruction whose value is used by the \p User.
+/// \param User Pointer to the instruction which uses the \p Used.
+/// \param Visited Set of visited instructions.
+void IRCanonicalizer::reorderInstruction(
+    Instruction *Used, Instruction *User,
+    SmallPtrSet<const Instruction *, 32> &Visited) {
+
+  if (!Visited.count(Used)) {
+    Visited.insert(Used);
+
+    if (Used->getParent() == User->getParent()) {
+      // If Used and User share the same basic block move Used just before User.
+      Used->moveBefore(User);
+    } else {
+      // Otherwise move Used to the very end of its basic block.
+      Used->moveBefore(&Used->getParent()->back());
+    }
+
+    for (auto &OP : Used->operands()) {
+      if (auto *IOP = dyn_cast<Instruction>(OP)) {
+        // Walk up the def-use tree.
+        reorderInstruction(IOP, Used, Visited);
+      }
+    }
+  }
+}
+
+/// Reorders instruction's operands alphabetically. This method assumes
+/// that passed instruction is commutative. Changing the operand order
+/// in other instructions may change the semantics.
+///
+/// \param I Instruction whose operands will be reordered.
+void IRCanonicalizer::reorderInstructionOperandsByNames(Instruction *I) {
+  // This method assumes that passed I is commutative,
+  // changing the order of operands in other instructions
+  // may change the semantics.
+
+  // Instruction operands for further sorting.
+  SmallVector<std::pair<std::string, Value *>, 4> Operands;
+
+  // Collect operands.
+  for (auto &OP : I->operands()) {
+    if (auto *VOP = dyn_cast<Value>(OP)) {
+      if (isa<Instruction>(VOP)) {
+        // This is an an instruction.
+        Operands.push_back(
+            std::pair<std::string, Value *>(VOP->getName(), VOP));
+      } else {
+        std::string TextRepresentation;
+        raw_string_ostream Stream(TextRepresentation);
+        OP->printAsOperand(Stream, false);
+        Operands.push_back(std::pair<std::string, Value *>(Stream.str(), VOP));
+      }
+    }
+  }
+
+  // Sort operands.
+  llvm::sort(Operands.begin(), Operands.end(), llvm::less_first());
+
+  // Reorder operands.
+  unsigned Position = 0;
+  for (auto &OP : I->operands()) {
+    OP.set(Operands[Position].second);
+    Position++;
+  }
+}
+
+/// Reorders PHI node's values according to the names of corresponding basic
+/// blocks.
+///
+/// \param PN PHI node to canonicalize.
+void IRCanonicalizer::reorderPHIIncomingValues(PHINode *PN) {
+  // Values for further sorting.
+  SmallVector<std::pair<Value *, BasicBlock *>, 2> Values;
+
+  // Collect blocks and corresponding values.
+  for (auto &BB : PN->blocks()) {
+    Value *V = PN->getIncomingValueForBlock(BB);
+    Values.push_back(std::pair<Value *, BasicBlock *>(V, BB));
+  }
+
+  // Sort values according to the name of a basic block.
+  llvm::sort(Values, [](const std::pair<Value *, BasicBlock *> &LHS,
+                        const std::pair<Value *, BasicBlock *> &RHS) {
+    return LHS.second->getName() < RHS.second->getName();
+  });
+
+  // Swap.
+  for (unsigned i = 0; i < Values.size(); ++i) {
+    PN->setIncomingBlock(i, Values[i].second);
+    PN->setIncomingValue(i, Values[i].first);
+  }
+}
+
+/// Returns a vector of output instructions. An output is an instruction which
+/// has side-effects or is ReturnInst. Uses isOutput().
+///
+/// \see isOutput()
+/// \param F Function to collect outputs from.
+SmallVector<Instruction *, 16>
+IRCanonicalizer::collectOutputInstructions(Function &F) {
+  // Output instructions are collected top-down in each function,
+  // any change may break the def-use chain in reordering methods.
+  SmallVector<Instruction *, 16> Outputs;
+
+  for (auto &I : instructions(F))
+    if (isOutput(&I))
+      Outputs.push_back(&I);
+
+  return Outputs;
+}
+
+/// Helper method checking whether the instruction may have side effects or is
+/// ReturnInst.
+///
+/// \param I Considered instruction.
+bool IRCanonicalizer::isOutput(const Instruction *I) {
+  // Outputs are such instructions which may have side effects or is ReturnInst.
+  if (I->mayHaveSideEffects() || isa<ReturnInst>(I))
+    return true;
+
+  return false;
+}
+
+/// Helper method checking whether the instruction has users and only
+/// immediate operands.
+///
+/// \param I Considered instruction.
+bool IRCanonicalizer::isInitialInstruction(const Instruction *I) {
+  // Initial instructions are such instructions whose values are used by
+  // other instructions, yet they only depend on immediate values.
+  return !I->user_empty() && hasOnlyImmediateOperands(I);
+}
+
+/// Helper method checking whether the instruction has only immediate operands.
+///
+/// \param I Considered instruction.
+bool IRCanonicalizer::hasOnlyImmediateOperands(const Instruction *I) {
+  for (const auto &OP : I->operands())
+    if (isa<Instruction>(OP))
+      return false; // Found non-immediate operand (instruction).
+
+  return true;
+}
+
+/// Helper method returning indices (distance from the beginning of the basic
+/// block) of outputs using the \p I (eliminates repetitions). Walks down the
+/// def-use tree recursively.
+///
+/// \param I Considered instruction.
+/// \param Visited Set of visited instructions.
+SetVector<int> IRCanonicalizer::getOutputFootprint(
+    Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) {
+
+  // Vector containing indexes of outputs (no repetitions),
+  // which use I in the order of walking down the def-use tree.
+  SetVector<int> Outputs;
+
+  if (!Visited.count(I)) {
+    Visited.insert(I);
+
+    if (isOutput(I)) {
+      // Gets output instruction's parent function.
+      Function *Func = I->getParent()->getParent();
+
+      // Finds and inserts the index of the output to the vector.
+      unsigned Count = 0;
+      for (const auto &B : *Func) {
+        for (const auto &E : B) {
+          if (&E == I)
+            Outputs.insert(Count);
+          Count++;
+        }
+      }
+
+      // Returns to the used instruction.
+      return Outputs;
+    }
+
+    for (auto *U : I->users()) {
+      if (auto *UI = dyn_cast<Instruction>(U)) {
+        // Vector for outputs which use UI.
+        SetVector<int> OutputsUsingUI = getOutputFootprint(UI, Visited);
+
+        // Insert the indexes of outputs using UI.
+        Outputs.insert(OutputsUsingUI.begin(), OutputsUsingUI.end());
+      }
+    }
+  }
+
+  // Return to the used instruction.
+  return Outputs;
+}

>From d59bcfc2ccfd156e6ea152fc423feb213c169221 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 12 Aug 2023 15:55:40 -0700
Subject: [PATCH 02/40] Port IRCanonicalizer to new pass manager

---
 .../llvm/Transforms/Utils/IRCanonicalizer.h   | 15 +++++++++++++
 llvm/lib/Passes/PassBuilder.cpp               |  1 +
 llvm/lib/Passes/PassRegistry.def              |  1 +
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 22 +++++++++----------
 4 files changed, 27 insertions(+), 12 deletions(-)
 create mode 100644 llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h

diff --git a/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h b/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h
new file mode 100644
index 000000000000000..81bfd1bcfd2ad94
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h
@@ -0,0 +1,15 @@
+#ifndef LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
+#define LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+/// IRCanonicalizer aims to transform LLVM IR into canonical form.
+struct IRCanonicalizerPass : public PassInfoMixin<IRCanonicalizerPass> {
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index bb6b40b14f8b4c8..7b626f7df91cb39 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -237,6 +237,7 @@
 #include "llvm/Transforms/Utils/HelloWorld.h"
 #include "llvm/Transforms/Utils/InjectTLIMappings.h"
 #include "llvm/Transforms/Utils/InstructionNamer.h"
+#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include "llvm/Transforms/Utils/LCSSA.h"
 #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
 #include "llvm/Transforms/Utils/LoopSimplify.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index fe24e9da9125ff7..fd30e5a8b4b58b8 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -300,6 +300,7 @@ FUNCTION_PASS("bdce", BDCEPass())
 FUNCTION_PASS("bounds-checking", BoundsCheckingPass())
 FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass())
 FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass())
+FUNCTION_PASS("canon", IRCanonicalizerPass())
 FUNCTION_PASS("consthoist", ConstantHoistingPass())
 FUNCTION_PASS("count-visits", CountVisitsPass())
 FUNCTION_PASS("constraint-elimination", ConstraintEliminationPass())
diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 58e2dce0b96685b..afa3d94e7f55be6 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -28,6 +28,7 @@
 #include "llvm/PassRegistry.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils.h"
+#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include <algorithm>
 #include <vector>
 
@@ -37,10 +38,8 @@ using namespace llvm;
 
 namespace {
 /// IRCanonicalizer aims to transform LLVM IR into canonical form.
-class IRCanonicalizer : public FunctionPass {
+class IRCanonicalizer {
 public:
-  static char ID;
-
   /// \name Canonicalizer flags.
   /// @{
   /// Preserves original order of instructions.
@@ -53,10 +52,7 @@ class IRCanonicalizer : public FunctionPass {
   static cl::opt<bool> ReorderOperands;
   /// @}
 
-  /// Constructor for the IRCanonicalizer.
-  IRCanonicalizer() : FunctionPass(ID) {}
-
-  bool runOnFunction(Function &F) override;
+  bool runOnFunction(Function &F);
 
 private:
   // Random constant for hashing, so the state isn't zero.
@@ -94,11 +90,6 @@ class IRCanonicalizer : public FunctionPass {
 };
 } // namespace
 
-char IRCanonicalizer::ID = 0;
-static RegisterPass<IRCanonicalizer> X("canon", "Canonicalize the IR",
-                                       false /* Only looks at CFG */,
-                                       false /* Analysis Pass */);
-
 cl::opt<bool> IRCanonicalizer::PreserveOrder(
     "preserve-order", cl::Hidden,
     cl::desc("Preserves original instruction order"));
@@ -630,3 +621,10 @@ SetVector<int> IRCanonicalizer::getOutputFootprint(
   // Return to the used instruction.
   return Outputs;
 }
+
+PreservedAnalyses IRCanonicalizerPass::run(Function &F,
+                                           FunctionAnalysisManager &AM) {
+  errs() << F.getName() << "\n";
+  IRCanonicalizer{}.runOnFunction(F);
+  return PreservedAnalyses::all();
+}

>From 0c94ebab9a31092edfc409df6ffa922269fcf867 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 12 Aug 2023 16:06:29 -0700
Subject: [PATCH 03/40] Port doc updates

---
 llvm/docs/Passes.rst       | 8 ++++++++
 llvm/docs/ReleaseNotes.rst | 5 ++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
index 541e23677debf90..418ab17eb35e259 100644
--- a/llvm/docs/Passes.rst
+++ b/llvm/docs/Passes.rst
@@ -653,6 +653,14 @@ variables with initializers are marked as internal.
 An interprocedural variant of :ref:`Sparse Conditional Constant Propagation
 <passes-sccp>`.
 
+``-ir-canonicalizer``: Transforms IR into canonical form
+--------------------------------------------------------
+
+This pass aims to transform LLVM Modules into a canonical form by reordering and
+renaming instructions while preserving the same semantics. The canonicalizer makes
+it easier to spot semantic differences while diffing two modules which have undergone
+two different passes.
+
 ``-jump-threading``: Jump Threading
 -----------------------------------
 
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 8eb8affb5eba9e2..dec2eec7566929e 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -42,7 +42,10 @@ Non-comprehensive list of changes in this release
    functionality, or simply have a lot to talk about), see the `NOTE` below
    for adding a new subsection.
 
-* ...
+* Added a new IRCanonicalizer pass which aims to transform LLVM modules into
+  a canonical form by reordering and renaming instructions while preserving the
+  same semantics. The canonicalizer makes it easier to spot semantic differences
+  when diffing two modules which have undergone different passes.
 
 Update on required toolchains to build LLVM
 -------------------------------------------

>From 9dbcab1948bba93e61d80a10038ab471f99e1448 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 12 Aug 2023 16:29:46 -0700
Subject: [PATCH 04/40] Port tests

---
 .../IRCanonicalizer/naming-arguments.ll       |  7 ++++++
 .../IRCanonicalizer/naming-basic-blocks.ll    |  8 +++++++
 .../IRCanonicalizer/naming-instructions.ll    | 12 ++++++++++
 .../reordering-instructions.ll                | 14 +++++++++++
 .../reordering-phi-node-values.ll             | 24 +++++++++++++++++++
 5 files changed, 65 insertions(+)
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll

diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
new file mode 100644
index 000000000000000..b3f7630abd042f1
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
@@ -0,0 +1,7 @@
+; RUN: opt -S -passes=canon < %s | FileCheck %s
+
+; CHECK: @foo(i32 %a0, i32 %a1)
+define i32 @foo(i32, i32) {
+  %tmp = mul i32 %0, %1
+  ret i32 %tmp
+}
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll b/llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll
new file mode 100644
index 000000000000000..79e526f8efb7ac7
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll
@@ -0,0 +1,8 @@
+; RUN: opt -S -passes=canon --rename-all < %s | FileCheck %s
+
+define i32 @foo(i32 %a0) {
+; CHECK: bb{{([0-9]{5})}}
+entry:
+  %a = add i32 %a0, 2
+  ret i32 %a
+}
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll b/llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll
new file mode 100644
index 000000000000000..a22e816f5bf01e9
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll
@@ -0,0 +1,12 @@
+; RUN: opt -S -passes=canon --rename-all < %s | FileCheck %s
+
+define i32 @foo(i32 %a0) {
+entry:
+; CHECK: %"vl{{([0-9]{5})}}(%a0, 2)"
+  %a = add i32 %a0, 2
+; CHECK: %"op{{([0-9]{5})}}(vl{{([0-9]{5})}})"
+  %b = add i32 %a, 6
+; CHECK: %"op{{([0-9]{5})}}(8, op{{([0-9]{5})}}(6, vl{{([0-9]{5})}}(%a0, 2)))"
+  %c = add i32 %b, 8
+  ret i32 %c
+}
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
new file mode 100644
index 000000000000000..04660ac73c11bd2
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
@@ -0,0 +1,14 @@
+; RUN: opt -S -passes=canon < %s | FileCheck %s
+
+define double @foo(double %a0, double %a1) {
+entry:
+; CHECK: %a
+; CHECK: %c
+; CHECK: %b
+; CHECK: %d
+  %a = fmul double %a0, %a1
+  %b = fmul double %a0, 2.000000e+00
+  %c = fmul double %a, 6.000000e+00
+  %d = fmul double %b, 6.000000e+00
+  ret double %d
+}
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
new file mode 100644
index 000000000000000..5f344ec29be66f0
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
@@ -0,0 +1,24 @@
+; RUN: opt -S -passes=canon < %s | FileCheck %s
+
+declare double @foo()
+
+declare double @bar()
+
+define double @baz(double %x) {
+entry:
+  %ifcond = fcmp one double %x, 0.000000e+00
+  br i1 %ifcond, label %then, label %else
+
+then:       ; preds = %entry
+  %calltmp = call double @foo()
+  br label %ifcont
+
+else:       ; preds = %entry
+  %calltmp1 = call double @bar()
+  br label %ifcont
+
+ifcont:     ; preds = %else, %then
+; CHECK: %iftmp = phi double [ %calltmp1, %else ], [ %calltmp, %then ]
+  %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ]
+  ret double %iftmp
+}

>From f5b7445662310a2f329e0f4aaf45822058f307ba Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 19 Aug 2023 15:23:09 -0700
Subject: [PATCH 05/40] Turn rename-all and -reorder-operands on by default

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp               | 6 ++++--
 llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll    | 2 +-
 .../Transforms/IRCanonicalizer/reordering-instructions.ll   | 2 +-
 .../IRCanonicalizer/reordering-phi-node-values.ll           | 2 +-
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index afa3d94e7f55be6..b5a007c80b32b3f 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -95,13 +95,15 @@ cl::opt<bool> IRCanonicalizer::PreserveOrder(
     cl::desc("Preserves original instruction order"));
 cl::opt<bool> IRCanonicalizer::RenameAll(
     "rename-all", cl::Hidden,
-    cl::desc("Renames all instructions (including user-named)"));
+    cl::desc("Renames all instructions (including user-named)"), 
+    cl::init(true));
 cl::opt<bool> IRCanonicalizer::FoldPreoutputs(
     "fold-all", cl::Hidden,
     cl::desc("Folds all regular instructions (including pre-outputs)"));
 cl::opt<bool> IRCanonicalizer::ReorderOperands(
     "reorder-operands", cl::Hidden,
-    cl::desc("Sorts and reorders operands in commutative instructions"));
+    cl::desc("Sorts and reorders operands in commutative instructions"),
+    cl::init(true));
 
 /// Entry method to the IRCanonicalizer.
 ///
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
index b3f7630abd042f1..5a274f7cc5a3b70 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
 
 ; CHECK: @foo(i32 %a0, i32 %a1)
 define i32 @foo(i32, i32) {
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
index 04660ac73c11bd2..3ea19e8b6c78c97 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
 
 define double @foo(double %a0, double %a1) {
 entry:
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
index 5f344ec29be66f0..3ea0bab50b5b9ac 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
 
 declare double @foo()
 

>From 9f93dea7b9d1fb97f947481ac1211da11b897180 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 19 Aug 2023 15:25:12 -0700
Subject: [PATCH 06/40] Add infinite loop regression test

---
 .../IRCanonicalizer/infinite-loop.ll          | 100 ++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll

diff --git a/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll b/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
new file mode 100644
index 000000000000000..f67c1eb7fa5b223
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
@@ -0,0 +1,100 @@
+; RUN: opt -passes=canon < %s
+
+; XFAIL: *
+; FIXME: Infinite loop in name instructions
+
+define void @test(ptr) {
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb1, %bb
+  %tmp = phi i32 [ undef, %bb ], [ %tmp87, %bb1 ]
+  %tmp2 = phi i32 [ undef, %bb ], [ %tmp86, %bb1 ]
+  %tmp3 = mul i32 %tmp, undef
+  %tmp4 = xor i32 %tmp3, -1
+  %tmp5 = add i32 %tmp, %tmp4
+  %tmp6 = add i32 %tmp2, -1
+  %tmp7 = add i32 %tmp5, %tmp6
+  %tmp8 = mul i32 %tmp7, %tmp3
+  %tmp9 = xor i32 %tmp8, -1
+  %tmp10 = add i32 %tmp7, %tmp9
+  %tmp11 = add i32 %tmp10, undef
+  %tmp12 = mul i32 %tmp11, %tmp8
+  %tmp13 = xor i32 %tmp12, -1
+  %tmp14 = add i32 %tmp11, %tmp13
+  %tmp15 = add i32 %tmp14, undef
+  %tmp16 = mul i32 %tmp15, %tmp12
+  %tmp17 = add i32 %tmp15, undef
+  %tmp18 = add i32 %tmp17, undef
+  %tmp19 = mul i32 %tmp18, %tmp16
+  %tmp20 = xor i32 %tmp19, -1
+  %tmp21 = add i32 %tmp18, %tmp20
+  %tmp22 = add i32 %tmp21, undef
+  %tmp23 = mul i32 %tmp22, %tmp19
+  %tmp24 = xor i32 %tmp23, -1
+  %tmp25 = add i32 %tmp22, %tmp24
+  %tmp26 = add i32 %tmp25, undef
+  %tmp27 = mul i32 %tmp26, %tmp23
+  %tmp28 = xor i32 %tmp27, -1
+  %tmp29 = add i32 %tmp26, %tmp28
+  %tmp30 = add i32 %tmp29, undef
+  %tmp31 = mul i32 %tmp30, %tmp27
+  %tmp32 = xor i32 %tmp31, -1
+  %tmp33 = add i32 %tmp30, %tmp32
+  %tmp34 = add i32 %tmp33, undef
+  %tmp35 = mul i32 %tmp34, %tmp31
+  %tmp36 = xor i32 %tmp35, -1
+  %tmp37 = add i32 %tmp34, %tmp36
+  %tmp38 = add i32 %tmp2, -9
+  %tmp39 = add i32 %tmp37, %tmp38
+  %tmp40 = mul i32 %tmp39, %tmp35
+  %tmp41 = xor i32 %tmp40, -1
+  %tmp42 = add i32 %tmp39, %tmp41
+  %tmp43 = add i32 %tmp42, undef
+  %tmp44 = mul i32 %tmp43, %tmp40
+  %tmp45 = xor i32 %tmp44, -1
+  %tmp46 = add i32 %tmp43, %tmp45
+  %tmp47 = add i32 %tmp46, undef
+  %tmp48 = mul i32 %tmp47, %tmp44
+  %tmp49 = xor i32 %tmp48, -1
+  %tmp50 = add i32 %tmp47, %tmp49
+  %tmp51 = add i32 %tmp50, undef
+  %tmp52 = mul i32 %tmp51, %tmp48
+  %tmp53 = xor i32 %tmp52, -1
+  %tmp54 = add i32 %tmp51, %tmp53
+  %tmp55 = add i32 %tmp54, undef
+  %tmp56 = mul i32 %tmp55, %tmp52
+  %tmp57 = xor i32 %tmp56, -1
+  %tmp58 = add i32 %tmp55, %tmp57
+  %tmp59 = add i32 %tmp2, -14
+  %tmp60 = add i32 %tmp58, %tmp59
+  %tmp61 = mul i32 %tmp60, %tmp56
+  %tmp62 = xor i32 %tmp61, -1
+  %tmp63 = add i32 %tmp60, %tmp62
+  %tmp64 = add i32 %tmp63, undef
+  %tmp65 = mul i32 %tmp64, %tmp61
+  %tmp66 = xor i32 %tmp65, -1
+  %tmp67 = add i32 %tmp64, %tmp66
+  %tmp68 = add i32 %tmp67, undef
+  %tmp69 = mul i32 %tmp68, %tmp65
+  %tmp70 = xor i32 %tmp69, -1
+  %tmp71 = add i32 %tmp68, %tmp70
+  %tmp72 = add i32 %tmp71, undef
+  %tmp73 = mul i32 %tmp72, %tmp69
+  %tmp74 = xor i32 %tmp73, -1
+  %tmp75 = add i32 %tmp72, %tmp74
+  %tmp76 = add i32 %tmp75, undef
+  %tmp77 = mul i32 %tmp76, %tmp73
+  %tmp78 = xor i32 %tmp77, -1
+  %tmp79 = add i32 %tmp76, %tmp78
+  %tmp80 = add i32 %tmp79, undef
+  %tmp81 = mul i32 %tmp80, %tmp77
+  %tmp82 = xor i32 %tmp81, -1
+  %tmp83 = add i32 %tmp80, %tmp82
+  %tmp84 = add i32 %tmp83, undef
+  %tmp85 = add i32 %tmp84, undef
+  %tmp86 = add i32 %tmp2, -21
+  %tmp87 = add i32 %tmp85, %tmp86
+  store i32 %tmp87, ptr %0
+  br label %bb1
+}

>From 23a379fc765a86c35b7b9682a66199fdaa1b830f Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 27 Aug 2023 15:19:36 -0700
Subject: [PATCH 07/40] Add visited set to fix infinite loop bug

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index b5a007c80b32b3f..73433a9a05c0d4e 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -57,6 +57,7 @@ class IRCanonicalizer {
 private:
   // Random constant for hashing, so the state isn't zero.
   const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL;
+  DenseSet<const Instruction *> NamedInstructions;
 
   /// \name Naming.
   /// @{
@@ -175,6 +176,9 @@ void IRCanonicalizer::nameBasicBlocks(Function &F) {
 ///
 /// \param I Instruction to be renamed.
 void IRCanonicalizer::nameInstruction(Instruction *I) {
+  if (NamedInstructions.contains(I))
+    return;
+  NamedInstructions.insert(I); 
   // Determine the type of instruction to name.
   if (isInitialInstruction(I)) {
     // This is an initial instruction.

>From 560abe4f953f75a89e7a0407ff09ea866664a2fd Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 27 Aug 2023 15:20:12 -0700
Subject: [PATCH 08/40] Expand test to expose reordering bug

---
 .../Transforms/IRCanonicalizer/infinite-loop.ll     | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll b/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
index f67c1eb7fa5b223..3438a05b4aee489 100644
--- a/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
@@ -1,15 +1,14 @@
-; RUN: opt -passes=canon < %s
+; RUN: opt -passes=canon -preserve-order=true < %s
+; RUN: opt -passes=canon -preserve-order=false < %s
 
-; XFAIL: *
-; FIXME: Infinite loop in name instructions
-
-define void @test(ptr) {
+define void @test(ptr, i32) {
 bb:
+  %a = add i32 %1, 1
   br label %bb1
 
 bb1:                                              ; preds = %bb1, %bb
-  %tmp = phi i32 [ undef, %bb ], [ %tmp87, %bb1 ]
-  %tmp2 = phi i32 [ undef, %bb ], [ %tmp86, %bb1 ]
+  %tmp = phi i32 [ %a, %bb ], [ %tmp87, %bb1 ]
+  %tmp2 = phi i32 [ %a, %bb ], [ %tmp86, %bb1 ]
   %tmp3 = mul i32 %tmp, undef
   %tmp4 = xor i32 %tmp3, -1
   %tmp5 = add i32 %tmp, %tmp4

>From 3aaecbddf6a45ba23a32706ac99c8e6e963c924b Mon Sep 17 00:00:00 2001
From: Aidan <aidan.goldfarb at mail.mcgill.ca>
Date: Mon, 28 Aug 2023 12:28:20 -0400
Subject: [PATCH 09/40] added some documentation

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 73433a9a05c0d4e..600c2baf6e013a5 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -176,6 +176,9 @@ void IRCanonicalizer::nameBasicBlocks(Function &F) {
 ///
 /// \param I Instruction to be renamed.
 void IRCanonicalizer::nameInstruction(Instruction *I) {
+  //ensure instructions are not renamed. This is done
+  //to prevent situation where instructions are used
+  //before their definition (in phi nodes)
   if (NamedInstructions.contains(I))
     return;
   NamedInstructions.insert(I); 

>From 2111bf1e6a27c553990528abee3a9fa2c2390bdd Mon Sep 17 00:00:00 2001
From: Aidan <aidan.goldfarb at mail.mcgill.ca>
Date: Mon, 28 Aug 2023 13:56:05 -0400
Subject: [PATCH 10/40] pushed broken int test

---
 .../IRCanonicalizer/naming-args-instr-blocks.ll   | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll

diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll b/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
new file mode 100644
index 000000000000000..74e1944825011b0
--- /dev/null
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
@@ -0,0 +1,15 @@
+; RUN: opt -S -passes=canon --rename-all --preserve-order < %s | FileCheck %s
+
+
+; CHECK: @foo(i32 %a0)
+define i32 @foo(i32) {
+; CHECK: bb{{([0-9]{5})}}
+entry:
+    ; CHECK: %"vl{{([0-9]{5})}}(%a0, 2)"
+    %a = add i32 %0, 2
+    
+    ; CHECK: %"op{{([0-9]{5})}}(vl{{([0-9]{5})}})"
+    %b = add i32 %a, 6
+
+    ret i32 %a
+}

>From 1db7ecbc4a461295f7cdf04488b94984803a3e60 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Mon, 11 Sep 2023 12:27:35 -0700
Subject: [PATCH 11/40] Reformat `reorderInstruction`

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 600c2baf6e013a5..6f60d3d261d8286 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -443,23 +443,23 @@ void IRCanonicalizer::reorderInstructions(
 void IRCanonicalizer::reorderInstruction(
     Instruction *Used, Instruction *User,
     SmallPtrSet<const Instruction *, 32> &Visited) {
+  if (Visited.contains(Used)) {
+    return;
+  }
+  Visited.insert(Used);
 
-  if (!Visited.count(Used)) {
-    Visited.insert(Used);
-
-    if (Used->getParent() == User->getParent()) {
-      // If Used and User share the same basic block move Used just before User.
-      Used->moveBefore(User);
-    } else {
-      // Otherwise move Used to the very end of its basic block.
-      Used->moveBefore(&Used->getParent()->back());
-    }
+  if (Used->getParent() == User->getParent()) {
+    // If Used and User share the same basic block move Used just before User.
+    Used->moveBefore(User);
+  } else {
+    // Otherwise move Used to the very end of its basic block.
+    Used->moveBefore(&Used->getParent()->back());
+  }
 
-    for (auto &OP : Used->operands()) {
-      if (auto *IOP = dyn_cast<Instruction>(OP)) {
-        // Walk up the def-use tree.
-        reorderInstruction(IOP, Used, Visited);
-      }
+  for (auto &OP : Used->operands()) {
+    if (auto *IOP = dyn_cast<Instruction>(OP)) {
+      // Walk up the def-use tree.
+      reorderInstruction(IOP, Used, Visited);
     }
   }
 }

>From 2debd15624fe9b69840551288bec734e8ef2ea75 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Mon, 11 Sep 2023 13:05:30 -0700
Subject: [PATCH 12/40] Bug fix: don't reorder PHI nodes

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 6f60d3d261d8286..a40435f7b822932 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -443,9 +443,10 @@ void IRCanonicalizer::reorderInstructions(
 void IRCanonicalizer::reorderInstruction(
     Instruction *Used, Instruction *User,
     SmallPtrSet<const Instruction *, 32> &Visited) {
-  if (Visited.contains(Used)) {
+  if(isa<PHINode>(Used))
+    return;
+  if (Visited.contains(Used))
     return;
-  }
   Visited.insert(Used);
 
   if (Used->getParent() == User->getParent()) {

>From 8a05e501b94aa50a9802c4df5398dd5a0805572f Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Mon, 11 Sep 2023 13:29:27 -0700
Subject: [PATCH 13/40] Revert "Turn rename-all and -reorder-operands on by
 default"

This reverts commit f5b7445662310a2f329e0f4aaf45822058f307ba.
---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp               | 6 ++----
 llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll    | 2 +-
 .../Transforms/IRCanonicalizer/reordering-instructions.ll   | 2 +-
 .../IRCanonicalizer/reordering-phi-node-values.ll           | 2 +-
 4 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index a40435f7b822932..45dc954f97b9c7e 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -96,15 +96,13 @@ cl::opt<bool> IRCanonicalizer::PreserveOrder(
     cl::desc("Preserves original instruction order"));
 cl::opt<bool> IRCanonicalizer::RenameAll(
     "rename-all", cl::Hidden,
-    cl::desc("Renames all instructions (including user-named)"), 
-    cl::init(true));
+    cl::desc("Renames all instructions (including user-named)"));
 cl::opt<bool> IRCanonicalizer::FoldPreoutputs(
     "fold-all", cl::Hidden,
     cl::desc("Folds all regular instructions (including pre-outputs)"));
 cl::opt<bool> IRCanonicalizer::ReorderOperands(
     "reorder-operands", cl::Hidden,
-    cl::desc("Sorts and reorders operands in commutative instructions"),
-    cl::init(true));
+    cl::desc("Sorts and reorders operands in commutative instructions"));
 
 /// Entry method to the IRCanonicalizer.
 ///
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
index 5a274f7cc5a3b70..b3f7630abd042f1 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
+; RUN: opt -S -passes=canon < %s | FileCheck %s
 
 ; CHECK: @foo(i32 %a0, i32 %a1)
 define i32 @foo(i32, i32) {
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
index 3ea19e8b6c78c97..04660ac73c11bd2 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
+; RUN: opt -S -passes=canon < %s | FileCheck %s
 
 define double @foo(double %a0, double %a1) {
 entry:
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
index 3ea0bab50b5b9ac..5f344ec29be66f0 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all=false < %s | FileCheck %s
+; RUN: opt -S -passes=canon < %s | FileCheck %s
 
 declare double @foo()
 

>From fa6159c30002c530f40b41380ed2b64294543c01 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Mon, 25 Sep 2023 11:13:25 -0500
Subject: [PATCH 14/40] Fix naming-args-instr-blocks.ll

---
 .../Transforms/IRCanonicalizer/naming-args-instr-blocks.ll    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll b/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
index 74e1944825011b0..605c62863f2ad38 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
+++ b/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
@@ -8,8 +8,8 @@ entry:
     ; CHECK: %"vl{{([0-9]{5})}}(%a0, 2)"
     %a = add i32 %0, 2
     
-    ; CHECK: %"op{{([0-9]{5})}}(vl{{([0-9]{5})}})"
+    ; CHECK: %"op{{([0-9]{5})}}(6, vl{{([0-9]{5})}}(%a0, 2))"
     %b = add i32 %a, 6
 
-    ret i32 %a
+    ret i32 %b
 }

>From aaef294128bb37afff42527cefbac08e29f08e95 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Tue, 3 Oct 2023 21:55:04 -0700
Subject: [PATCH 15/40] clang format changes

---
 llvm/lib/Passes/PassBuilder.cpp               |  4 ++--
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 8a495e6d7dc14fc..7fc17ab31a11ec8 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -233,14 +233,14 @@
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
 #include "llvm/Transforms/Utils/CountVisits.h"
-#include "llvm/Transforms/Utils/Debugify.h"
 #include "llvm/Transforms/Utils/DXILUpgrade.h"
+#include "llvm/Transforms/Utils/Debugify.h"
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
 #include "llvm/Transforms/Utils/FixIrreducible.h"
 #include "llvm/Transforms/Utils/HelloWorld.h"
+#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include "llvm/Transforms/Utils/InjectTLIMappings.h"
 #include "llvm/Transforms/Utils/InstructionNamer.h"
-#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include "llvm/Transforms/Utils/LCSSA.h"
 #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
 #include "llvm/Transforms/Utils/LoopSimplify.h"
diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 45dc954f97b9c7e..7ea3959e5e90d00 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -174,12 +174,12 @@ void IRCanonicalizer::nameBasicBlocks(Function &F) {
 ///
 /// \param I Instruction to be renamed.
 void IRCanonicalizer::nameInstruction(Instruction *I) {
-  //ensure instructions are not renamed. This is done
-  //to prevent situation where instructions are used
-  //before their definition (in phi nodes)
+  // Ensure instructions are not renamed. This is done
+  // to prevent situation where instructions are used
+  // before their definition (in phi nodes)
   if (NamedInstructions.contains(I))
     return;
-  NamedInstructions.insert(I); 
+  NamedInstructions.insert(I);
   // Determine the type of instruction to name.
   if (isInitialInstruction(I)) {
     // This is an initial instruction.
@@ -381,7 +381,7 @@ void IRCanonicalizer::foldInstructionName(Instruction *I) {
   SmallVector<SmallString<64>, 4> Operands;
 
   for (auto &OP : I->operands()) {
-    if (const Instruction *IOP = dyn_cast<Instruction>(OP)) {
+    if (const auto *IOP = dyn_cast<Instruction>(OP)) {
       bool HasCanonicalName = I->getName().substr(0, 2) == "op" ||
                               I->getName().substr(0, 2) == "vl";
 
@@ -441,7 +441,7 @@ void IRCanonicalizer::reorderInstructions(
 void IRCanonicalizer::reorderInstruction(
     Instruction *Used, Instruction *User,
     SmallPtrSet<const Instruction *, 32> &Visited) {
-  if(isa<PHINode>(Used))
+  if (isa<PHINode>(Used))
     return;
   if (Visited.contains(Used))
     return;

>From d7b9fd5da45515624c6aa4b321d5d897612d2395 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Wed, 4 Oct 2023 08:12:40 -0700
Subject: [PATCH 16/40] clang-format changes

---
 llvm/lib/Transforms/Utils/IRCanonicalizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
index 7ea3959e5e90d00..c12595ba48a3f79 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
@@ -14,6 +14,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
@@ -28,7 +29,6 @@
 #include "llvm/PassRegistry.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils.h"
-#include "llvm/Transforms/Utils/IRCanonicalizer.h"
 #include <algorithm>
 #include <vector>
 

>From 9f07d54dd841c8da1ab77b2bd0bfa0ee538949cb Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 14 Oct 2023 18:04:58 -0400
Subject: [PATCH 17/40] Rename to IRNormalizer

---
 llvm/docs/Passes.rst                          |  2 +-
 llvm/docs/ReleaseNotes.rst                    |  2 +-
 .../llvm/Transforms/Utils/IRCanonicalizer.h   | 15 -----
 .../llvm/Transforms/Utils/IRNormalizer.h      | 15 +++++
 llvm/lib/Passes/PassBuilder.cpp               |  2 +-
 llvm/lib/Passes/PassRegistry.def              |  2 +-
 llvm/lib/Transforms/Utils/CMakeLists.txt      |  2 +-
 .../{IRCanonicalizer.cpp => IRNormalizer.cpp} | 60 +++++++++----------
 .../infinite-loop.ll                          |  4 +-
 .../naming-args-instr-blocks.ll               |  2 +-
 .../naming-arguments.ll                       |  2 +-
 .../naming-basic-blocks.ll                    |  2 +-
 .../naming-instructions.ll                    |  2 +-
 .../reordering-instructions.ll                |  2 +-
 .../reordering-phi-node-values.ll             |  2 +-
 15 files changed, 58 insertions(+), 58 deletions(-)
 delete mode 100644 llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h
 create mode 100644 llvm/include/llvm/Transforms/Utils/IRNormalizer.h
 rename llvm/lib/Transforms/Utils/{IRCanonicalizer.cpp => IRNormalizer.cpp} (92%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/infinite-loop.ll (96%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/naming-args-instr-blocks.ll (75%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/naming-arguments.ll (66%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/naming-basic-blocks.ll (60%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/naming-instructions.ll (80%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/reordering-instructions.ll (83%)
 rename llvm/test/Transforms/{IRCanonicalizer => IRNormalizer}/reordering-phi-node-values.ll (91%)

diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
index 7594a5b164ea3d5..e70e69161e7d5fd 100644
--- a/llvm/docs/Passes.rst
+++ b/llvm/docs/Passes.rst
@@ -543,7 +543,7 @@ variables with initializers are marked as internal.
 An interprocedural variant of :ref:`Sparse Conditional Constant Propagation
 <passes-sccp>`.
 
-``ir-canonicalizer``: Transforms IR into canonical form
+``ir-normalizer``: Transforms IR into a canonical form that's easier to diff
 --------------------------------------------------------
 
 This pass aims to transform LLVM Modules into a canonical form by reordering and
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 4528a818021d6b6..efe10a5a7de6329 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -42,7 +42,7 @@ Non-comprehensive list of changes in this release
    functionality, or simply have a lot to talk about), see the `NOTE` below
    for adding a new subsection.
 
-* Added a new IRCanonicalizer pass which aims to transform LLVM modules into
+* Added a new IRNormalizer pass which aims to transform LLVM modules into
   a canonical form by reordering and renaming instructions while preserving the
   same semantics. The canonicalizer makes it easier to spot semantic differences
   when diffing two modules which have undergone different passes.
diff --git a/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h b/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h
deleted file mode 100644
index 81bfd1bcfd2ad94..000000000000000
--- a/llvm/include/llvm/Transforms/Utils/IRCanonicalizer.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
-#define LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
-
-#include "llvm/IR/PassManager.h"
-
-namespace llvm {
-
-/// IRCanonicalizer aims to transform LLVM IR into canonical form.
-struct IRCanonicalizerPass : public PassInfoMixin<IRCanonicalizerPass> {
-  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
-};
-
-} // namespace llvm
-
-#endif // LLVM_TRANSFORMS_UTILS_IRCANONICALIZER_H
diff --git a/llvm/include/llvm/Transforms/Utils/IRNormalizer.h b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
new file mode 100644
index 000000000000000..2e3e23340bc5bc7
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
@@ -0,0 +1,15 @@
+#ifndef LLVM_TRANSFORMS_UTILS_IRNORMALIZER_H
+#define LLVM_TRANSFORMS_UTILS_IRNORMALIZER_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+/// IRNormalizer aims to transform LLVM IR into canonical form.
+struct IRNormalizerPass : public PassInfoMixin<IRNormalizerPass> {
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_IRNORMALIZER_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 7fc17ab31a11ec8..ebb907289223ad3 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -238,7 +238,7 @@
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
 #include "llvm/Transforms/Utils/FixIrreducible.h"
 #include "llvm/Transforms/Utils/HelloWorld.h"
-#include "llvm/Transforms/Utils/IRCanonicalizer.h"
+#include "llvm/Transforms/Utils/IRNormalizer.h"
 #include "llvm/Transforms/Utils/InjectTLIMappings.h"
 #include "llvm/Transforms/Utils/InstructionNamer.h"
 #include "llvm/Transforms/Utils/LCSSA.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index d27ed801c5dca64..ea0aba50588d481 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -310,7 +310,6 @@ FUNCTION_PASS("bdce", BDCEPass())
 FUNCTION_PASS("bounds-checking", BoundsCheckingPass())
 FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass())
 FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass())
-FUNCTION_PASS("canon", IRCanonicalizerPass())
 FUNCTION_PASS("consthoist", ConstantHoistingPass())
 FUNCTION_PASS("count-visits", CountVisitsPass())
 FUNCTION_PASS("constraint-elimination", ConstraintEliminationPass())
@@ -367,6 +366,7 @@ FUNCTION_PASS("mergereturn", UnifyFunctionExitNodesPass())
 FUNCTION_PASS("move-auto-init", MoveAutoInitPass())
 FUNCTION_PASS("nary-reassociate", NaryReassociatePass())
 FUNCTION_PASS("newgvn", NewGVNPass())
+FUNCTION_PASS("normalize", IRNormalizerPass())
 FUNCTION_PASS("jump-threading", JumpThreadingPass())
 FUNCTION_PASS("partially-inline-libcalls", PartiallyInlineLibCallsPass())
 FUNCTION_PASS("kcfi", KCFIPass())
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 9858873951ddacb..92883ea31380e92 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -35,7 +35,7 @@ add_llvm_component_library(LLVMTransformUtils
   InjectTLIMappings.cpp
   InstructionNamer.cpp
   IntegerDivision.cpp
-  IRCanonicalizer.cpp
+  IRNormalizer.cpp
   LCSSA.cpp
   LibCallsShrinkWrap.cpp
   Local.cpp
diff --git a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
similarity index 92%
rename from llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
rename to llvm/lib/Transforms/Utils/IRNormalizer.cpp
index c12595ba48a3f79..da2cbc41346d017 100644
--- a/llvm/lib/Transforms/Utils/IRCanonicalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -1,4 +1,4 @@
-//===--------------- IRCanonicalizer.cpp - IR Canonicalizer ---------------===//
+//===--------------- IRNormalizer.cpp - IR Canonicalizer ---------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,15 +6,15 @@
 //
 //===----------------------------------------------------------------------===//
 /// \file
-/// This file implements the IRCanonicalizer class which aims to transform LLVM
+/// This file implements the IRNormalizer class which aims to transform LLVM
 /// Modules into a canonical form by reordering and renaming instructions while
-/// preserving the same semantics. The canonicalizer makes it easier to spot
+/// preserving the same semantics. The normalizer makes it easier to spot
 /// semantic differences while diffing two modules which have undergone
 /// different passes.
 ///
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Transforms/Utils/IRCanonicalizer.h"
+#include "llvm/Transforms/Utils/IRNormalizer.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
@@ -32,13 +32,13 @@
 #include <algorithm>
 #include <vector>
 
-#define DEBUG_TYPE "canon"
+#define DEBUG_TYPE "normalize"
 
 using namespace llvm;
 
 namespace {
-/// IRCanonicalizer aims to transform LLVM IR into canonical form.
-class IRCanonicalizer {
+/// IRNormalizer aims to transform LLVM IR into canonical form.
+class IRNormalizer {
 public:
   /// \name Canonicalizer flags.
   /// @{
@@ -91,23 +91,23 @@ class IRCanonicalizer {
 };
 } // namespace
 
-cl::opt<bool> IRCanonicalizer::PreserveOrder(
+cl::opt<bool> IRNormalizer::PreserveOrder(
     "preserve-order", cl::Hidden,
     cl::desc("Preserves original instruction order"));
-cl::opt<bool> IRCanonicalizer::RenameAll(
+cl::opt<bool> IRNormalizer::RenameAll(
     "rename-all", cl::Hidden,
     cl::desc("Renames all instructions (including user-named)"));
-cl::opt<bool> IRCanonicalizer::FoldPreoutputs(
+cl::opt<bool> IRNormalizer::FoldPreoutputs(
     "fold-all", cl::Hidden,
     cl::desc("Folds all regular instructions (including pre-outputs)"));
-cl::opt<bool> IRCanonicalizer::ReorderOperands(
+cl::opt<bool> IRNormalizer::ReorderOperands(
     "reorder-operands", cl::Hidden,
     cl::desc("Sorts and reorders operands in commutative instructions"));
 
-/// Entry method to the IRCanonicalizer.
+/// Entry method to the IRNormalizer.
 ///
 /// \param M Module to canonicalize.
-bool IRCanonicalizer::runOnFunction(Function &F) {
+bool IRNormalizer::runOnFunction(Function &F) {
   nameFunctionArguments(F);
   nameBasicBlocks(F);
 
@@ -137,7 +137,7 @@ bool IRCanonicalizer::runOnFunction(Function &F) {
 /// Numbers arguments.
 ///
 /// \param F Function whose arguments will be renamed.
-void IRCanonicalizer::nameFunctionArguments(Function &F) {
+void IRNormalizer::nameFunctionArguments(Function &F) {
   int ArgumentCounter = 0;
   for (auto &A : F.args()) {
     if (RenameAll || A.getName().empty()) {
@@ -151,7 +151,7 @@ void IRCanonicalizer::nameFunctionArguments(Function &F) {
 /// a function considering the opcode and the order of output instructions.
 ///
 /// \param F Function containing basic blocks to rename.
-void IRCanonicalizer::nameBasicBlocks(Function &F) {
+void IRNormalizer::nameBasicBlocks(Function &F) {
   for (auto &B : F) {
     // Initialize to a magic constant, so the state isn't zero.
     uint64_t Hash = MagicHashConstant;
@@ -173,7 +173,7 @@ void IRCanonicalizer::nameBasicBlocks(Function &F) {
 /// the output (top-most user) instructions (depth-first).
 ///
 /// \param I Instruction to be renamed.
-void IRCanonicalizer::nameInstruction(Instruction *I) {
+void IRNormalizer::nameInstruction(Instruction *I) {
   // Ensure instructions are not renamed. This is done
   // to prevent situation where instructions are used
   // before their definition (in phi nodes)
@@ -203,7 +203,7 @@ void IRCanonicalizer::nameInstruction(Instruction *I) {
 ///
 /// \see getOutputFootprint()
 /// \param I Instruction to be renamed.
-void IRCanonicalizer::nameAsInitialInstruction(Instruction *I) {
+void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
   if (I->getType()->isVoidTy() || (!I->getName().empty() && !RenameAll))
     return;
 
@@ -279,7 +279,7 @@ void IRCanonicalizer::nameAsInitialInstruction(Instruction *I) {
 ///
 /// \see getOutputFootprint()
 /// \param I Instruction to be renamed.
-void IRCanonicalizer::nameAsRegularInstruction(Instruction *I) {
+void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
   // Instruction operands for further sorting.
   SmallVector<SmallString<128>, 4> Operands;
 
@@ -362,7 +362,7 @@ void IRCanonicalizer::nameAsRegularInstruction(Instruction *I) {
 /// does not affect user named instructions.
 ///
 /// \param I Instruction whose name will be folded.
-void IRCanonicalizer::foldInstructionName(Instruction *I) {
+void IRNormalizer::foldInstructionName(Instruction *I) {
   // If this flag is raised, fold all regular
   // instructions (including pre-outputs).
   if (!FoldPreoutputs) {
@@ -416,7 +416,7 @@ void IRCanonicalizer::foldInstructionName(Instruction *I) {
 ///
 /// \see reorderInstruction()
 /// \param Outputs Vector of pointers to output instructions collected top-down.
-void IRCanonicalizer::reorderInstructions(
+void IRNormalizer::reorderInstructions(
     SmallVector<Instruction *, 16> &Outputs) {
   // This method assumes output instructions were collected top-down,
   // otherwise the def-use chain may be broken.
@@ -438,7 +438,7 @@ void IRCanonicalizer::reorderInstructions(
 /// \param Used Pointer to the instruction whose value is used by the \p User.
 /// \param User Pointer to the instruction which uses the \p Used.
 /// \param Visited Set of visited instructions.
-void IRCanonicalizer::reorderInstruction(
+void IRNormalizer::reorderInstruction(
     Instruction *Used, Instruction *User,
     SmallPtrSet<const Instruction *, 32> &Visited) {
   if (isa<PHINode>(Used))
@@ -468,7 +468,7 @@ void IRCanonicalizer::reorderInstruction(
 /// in other instructions may change the semantics.
 ///
 /// \param I Instruction whose operands will be reordered.
-void IRCanonicalizer::reorderInstructionOperandsByNames(Instruction *I) {
+void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) {
   // This method assumes that passed I is commutative,
   // changing the order of operands in other instructions
   // may change the semantics.
@@ -507,7 +507,7 @@ void IRCanonicalizer::reorderInstructionOperandsByNames(Instruction *I) {
 /// blocks.
 ///
 /// \param PN PHI node to canonicalize.
-void IRCanonicalizer::reorderPHIIncomingValues(PHINode *PN) {
+void IRNormalizer::reorderPHIIncomingValues(PHINode *PN) {
   // Values for further sorting.
   SmallVector<std::pair<Value *, BasicBlock *>, 2> Values;
 
@@ -536,7 +536,7 @@ void IRCanonicalizer::reorderPHIIncomingValues(PHINode *PN) {
 /// \see isOutput()
 /// \param F Function to collect outputs from.
 SmallVector<Instruction *, 16>
-IRCanonicalizer::collectOutputInstructions(Function &F) {
+IRNormalizer::collectOutputInstructions(Function &F) {
   // Output instructions are collected top-down in each function,
   // any change may break the def-use chain in reordering methods.
   SmallVector<Instruction *, 16> Outputs;
@@ -552,7 +552,7 @@ IRCanonicalizer::collectOutputInstructions(Function &F) {
 /// ReturnInst.
 ///
 /// \param I Considered instruction.
-bool IRCanonicalizer::isOutput(const Instruction *I) {
+bool IRNormalizer::isOutput(const Instruction *I) {
   // Outputs are such instructions which may have side effects or is ReturnInst.
   if (I->mayHaveSideEffects() || isa<ReturnInst>(I))
     return true;
@@ -564,7 +564,7 @@ bool IRCanonicalizer::isOutput(const Instruction *I) {
 /// immediate operands.
 ///
 /// \param I Considered instruction.
-bool IRCanonicalizer::isInitialInstruction(const Instruction *I) {
+bool IRNormalizer::isInitialInstruction(const Instruction *I) {
   // Initial instructions are such instructions whose values are used by
   // other instructions, yet they only depend on immediate values.
   return !I->user_empty() && hasOnlyImmediateOperands(I);
@@ -573,7 +573,7 @@ bool IRCanonicalizer::isInitialInstruction(const Instruction *I) {
 /// Helper method checking whether the instruction has only immediate operands.
 ///
 /// \param I Considered instruction.
-bool IRCanonicalizer::hasOnlyImmediateOperands(const Instruction *I) {
+bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) {
   for (const auto &OP : I->operands())
     if (isa<Instruction>(OP))
       return false; // Found non-immediate operand (instruction).
@@ -587,7 +587,7 @@ bool IRCanonicalizer::hasOnlyImmediateOperands(const Instruction *I) {
 ///
 /// \param I Considered instruction.
 /// \param Visited Set of visited instructions.
-SetVector<int> IRCanonicalizer::getOutputFootprint(
+SetVector<int> IRNormalizer::getOutputFootprint(
     Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) {
 
   // Vector containing indexes of outputs (no repetitions),
@@ -630,9 +630,9 @@ SetVector<int> IRCanonicalizer::getOutputFootprint(
   return Outputs;
 }
 
-PreservedAnalyses IRCanonicalizerPass::run(Function &F,
+PreservedAnalyses IRNormalizerPass::run(Function &F,
                                            FunctionAnalysisManager &AM) {
   errs() << F.getName() << "\n";
-  IRCanonicalizer{}.runOnFunction(F);
+  IRNormalizer{}.runOnFunction(F);
   return PreservedAnalyses::all();
 }
diff --git a/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll b/llvm/test/Transforms/IRNormalizer/infinite-loop.ll
similarity index 96%
rename from llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
rename to llvm/test/Transforms/IRNormalizer/infinite-loop.ll
index 3438a05b4aee489..9b10e91e49b4de5 100644
--- a/llvm/test/Transforms/IRCanonicalizer/infinite-loop.ll
+++ b/llvm/test/Transforms/IRNormalizer/infinite-loop.ll
@@ -1,5 +1,5 @@
-; RUN: opt -passes=canon -preserve-order=true < %s
-; RUN: opt -passes=canon -preserve-order=false < %s
+; RUN: opt -passes=normalize -preserve-order=true < %s
+; RUN: opt -passes=normalize -preserve-order=false < %s
 
 define void @test(ptr, i32) {
 bb:
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll b/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
similarity index 75%
rename from llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
rename to llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
index 605c62863f2ad38..afb99585db2ccf6 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-args-instr-blocks.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all --preserve-order < %s | FileCheck %s
+; RUN: opt -S -passes=normalize --rename-all --preserve-order < %s | FileCheck %s
 
 
 ; CHECK: @foo(i32 %a0)
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll b/llvm/test/Transforms/IRNormalizer/naming-arguments.ll
similarity index 66%
rename from llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
rename to llvm/test/Transforms/IRNormalizer/naming-arguments.ll
index b3f7630abd042f1..3a1d435f76fdd07 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-arguments.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-arguments.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=normalize < %s | FileCheck %s
 
 ; CHECK: @foo(i32 %a0, i32 %a1)
 define i32 @foo(i32, i32) {
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll b/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
similarity index 60%
rename from llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll
rename to llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
index 79e526f8efb7ac7..f50c56bcca53f3a 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-basic-blocks.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all < %s | FileCheck %s
+; RUN: opt -S -passes=normalize --rename-all < %s | FileCheck %s
 
 define i32 @foo(i32 %a0) {
 ; CHECK: bb{{([0-9]{5})}}
diff --git a/llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll b/llvm/test/Transforms/IRNormalizer/naming-instructions.ll
similarity index 80%
rename from llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll
rename to llvm/test/Transforms/IRNormalizer/naming-instructions.ll
index a22e816f5bf01e9..f1fe503f53ca1d1 100644
--- a/llvm/test/Transforms/IRCanonicalizer/naming-instructions.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-instructions.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon --rename-all < %s | FileCheck %s
+; RUN: opt -S -passes=normalize --rename-all < %s | FileCheck %s
 
 define i32 @foo(i32 %a0) {
 entry:
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll b/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
similarity index 83%
rename from llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
rename to llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
index 04660ac73c11bd2..8978b01c3caa6d4 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-instructions.ll
+++ b/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=normalize < %s | FileCheck %s
 
 define double @foo(double %a0, double %a1) {
 entry:
diff --git a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll b/llvm/test/Transforms/IRNormalizer/reordering-phi-node-values.ll
similarity index 91%
rename from llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
rename to llvm/test/Transforms/IRNormalizer/reordering-phi-node-values.ll
index 5f344ec29be66f0..cba92e8eaf9ac53 100644
--- a/llvm/test/Transforms/IRCanonicalizer/reordering-phi-node-values.ll
+++ b/llvm/test/Transforms/IRNormalizer/reordering-phi-node-values.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=canon < %s | FileCheck %s
+; RUN: opt -S -passes=normalize < %s | FileCheck %s
 
 declare double @foo()
 

>From bd8417248b6b0d674cfd1722cece8b5b7fe4b55a Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 14 Oct 2023 18:07:59 -0400
Subject: [PATCH 18/40] Removing debugging line

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index da2cbc41346d017..a3bf5d1b940913a 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -632,7 +632,6 @@ SetVector<int> IRNormalizer::getOutputFootprint(
 
 PreservedAnalyses IRNormalizerPass::run(Function &F,
                                            FunctionAnalysisManager &AM) {
-  errs() << F.getName() << "\n";
   IRNormalizer{}.runOnFunction(F);
   return PreservedAnalyses::all();
 }

>From 4f194e2a3861372f3d24928926ff2db03befce51 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 15 Oct 2023 23:13:32 -0400
Subject: [PATCH 19/40] clang-format changes

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index a3bf5d1b940913a..dd6ad517ddd763d 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -631,7 +631,7 @@ SetVector<int> IRNormalizer::getOutputFootprint(
 }
 
 PreservedAnalyses IRNormalizerPass::run(Function &F,
-                                           FunctionAnalysisManager &AM) {
+                                        FunctionAnalysisManager &AM) {
   IRNormalizer{}.runOnFunction(F);
   return PreservedAnalyses::all();
 }

>From 3e6d7aa25f221ff068415d2b9ff17070c1d2ce7f Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 21 Oct 2023 14:04:05 -0700
Subject: [PATCH 20/40] Incorporate fixes

---
 llvm/docs/Passes.rst                       | 9 ++++-----
 llvm/docs/ReleaseNotes.rst                 | 2 +-
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 6 +++---
 3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
index e70e69161e7d5fd..abfa36992be7c8d 100644
--- a/llvm/docs/Passes.rst
+++ b/llvm/docs/Passes.rst
@@ -544,14 +544,13 @@ An interprocedural variant of :ref:`Sparse Conditional Constant Propagation
 <passes-sccp>`.
 
 ``ir-normalizer``: Transforms IR into a canonical form that's easier to diff
---------------------------------------------------------
+----------------------------------------------------------------------------
 
 This pass aims to transform LLVM Modules into a canonical form by reordering and
-renaming instructions while preserving the same semantics. The canonicalizer makes
-it easier to spot semantic differences while diffing two modules which have undergone
-two different passes.
+renaming instructions while preserving the same semantics. The normalizer makes
+it easier to spot semantic differences while diffing two modules which have
+undergone two different passes.
 
------------------------------------
 ``jump-threading``: Jump Threading
 ----------------------------------
 
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index efe10a5a7de6329..b1ec1dab9ead176 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -44,7 +44,7 @@ Non-comprehensive list of changes in this release
 
 * Added a new IRNormalizer pass which aims to transform LLVM modules into
   a canonical form by reordering and renaming instructions while preserving the
-  same semantics. The canonicalizer makes it easier to spot semantic differences
+  same semantics. The normalizer makes it easier to spot semantic differences
   when diffing two modules which have undergone different passes.
 
 Update on required toolchains to build LLVM
diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index dd6ad517ddd763d..539a53887997176 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -1,4 +1,4 @@
-//===--------------- IRNormalizer.cpp - IR Canonicalizer ---------------===//
+//===--------------- IRNormalizer.cpp - IR Normalizer ---------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -40,7 +40,7 @@ namespace {
 /// IRNormalizer aims to transform LLVM IR into canonical form.
 class IRNormalizer {
 public:
-  /// \name Canonicalizer flags.
+  /// \name Normalizer flags.
   /// @{
   /// Preserves original order of instructions.
   static cl::opt<bool> PreserveOrder;
@@ -106,7 +106,7 @@ cl::opt<bool> IRNormalizer::ReorderOperands(
 
 /// Entry method to the IRNormalizer.
 ///
-/// \param M Module to canonicalize.
+/// \param M Module to normalize.
 bool IRNormalizer::runOnFunction(Function &F) {
   nameFunctionArguments(F);
   nameBasicBlocks(F);

>From d7b08eca34fa91bce86f9c615b99f609da8c36c8 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 12:16:44 -0800
Subject: [PATCH 21/40] Add LLVM_DEBUG() for reordering code

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 539a53887997176..378db63e0bb77e0 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -424,10 +424,12 @@ void IRNormalizer::reorderInstructions(
   SmallPtrSet<const Instruction *, 32> Visited;
 
   // Walk up the tree.
-  for (auto &I : Outputs)
+  for (auto &I : Outputs) {
+    LLVM_DEBUG(dbgs() << "Reordering operands of: "; I->dump());
     for (auto &OP : I->operands())
       if (auto *IOP = dyn_cast<Instruction>(OP))
         reorderInstruction(IOP, I, Visited);
+  }
 }
 
 /// Reduces def-use distance or places instruction at the end of the basic
@@ -449,9 +451,12 @@ void IRNormalizer::reorderInstruction(
 
   if (Used->getParent() == User->getParent()) {
     // If Used and User share the same basic block move Used just before User.
+    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " before " << *User << "\n");
     Used->moveBefore(User);
   } else {
     // Otherwise move Used to the very end of its basic block.
+    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block " << 
+               Used->getParent()->getName() << "\n");
     Used->moveBefore(&Used->getParent()->back());
   }
 

>From 985135c64838d0df52128d331d89ac432035054b Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 12:17:32 -0800
Subject: [PATCH 22/40] Accepts F not M

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 378db63e0bb77e0..01f6c923dbfcfce 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -106,7 +106,7 @@ cl::opt<bool> IRNormalizer::ReorderOperands(
 
 /// Entry method to the IRNormalizer.
 ///
-/// \param M Module to normalize.
+/// \param F Function to normalize.
 bool IRNormalizer::runOnFunction(Function &F) {
   nameFunctionArguments(F);
   nameBasicBlocks(F);

>From a45e2e6efbae4b4245c571b77a710108e460af48 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 12:20:11 -0800
Subject: [PATCH 23/40] Fix nits

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 01f6c923dbfcfce..6b615ad729e7516 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -180,9 +180,7 @@ void IRNormalizer::nameInstruction(Instruction *I) {
   if (NamedInstructions.contains(I))
     return;
   NamedInstructions.insert(I);
-  // Determine the type of instruction to name.
   if (isInitialInstruction(I)) {
-    // This is an initial instruction.
     nameAsInitialInstruction(I);
   } else {
     // This must be a regular instruction.
@@ -245,9 +243,8 @@ void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
   if (const auto *CI = dyn_cast<CallInst>(I)) {
     Function *F = CI->getCalledFunction();
 
-    if (F != nullptr) {
+    if (F != nullptr)
       Name.append(F->getName());
-    }
   }
 
   Name.append("(");
@@ -294,7 +291,7 @@ void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
       // Walk down the use-def chain.
       nameInstruction(IOP);
       Operands.push_back(IOP->getName());
-    } else if (isa<Value>(OP) && !isa<Function>(OP)) {
+    } else if (!isa<Function>(OP)) {
       // This must be an immediate value.
       std::string TextRepresentation;
       raw_string_ostream Stream(TextRepresentation);

>From 97777fe1a42ecf571c527aed2cdfdd05aa8d1c0e Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 12:28:46 -0800
Subject: [PATCH 24/40] Spelling fix

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 6b615ad729e7516..956f0ff8799f3f0 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -47,7 +47,7 @@ class IRNormalizer {
   /// Renames all instructions (including user-named).
   static cl::opt<bool> RenameAll;
   /// Folds all regular instructions (including pre-outputs).
-  static cl::opt<bool> FoldPreoutputs;
+  static cl::opt<bool> FoldPreOutputs;
   /// Sorts and reorders operands in commutative instructions.
   static cl::opt<bool> ReorderOperands;
   /// @}
@@ -97,7 +97,7 @@ cl::opt<bool> IRNormalizer::PreserveOrder(
 cl::opt<bool> IRNormalizer::RenameAll(
     "rename-all", cl::Hidden,
     cl::desc("Renames all instructions (including user-named)"));
-cl::opt<bool> IRNormalizer::FoldPreoutputs(
+cl::opt<bool> IRNormalizer::FoldPreOutputs(
     "fold-all", cl::Hidden,
     cl::desc("Folds all regular instructions (including pre-outputs)"));
 cl::opt<bool> IRNormalizer::ReorderOperands(
@@ -362,7 +362,7 @@ void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
 void IRNormalizer::foldInstructionName(Instruction *I) {
   // If this flag is raised, fold all regular
   // instructions (including pre-outputs).
-  if (!FoldPreoutputs) {
+  if (!FoldPreOutputs) {
     // Don't fold if one of the users is an output instruction.
     for (auto *U : I->users())
       if (auto *IU = dyn_cast<Instruction>(U))

>From d11a6f38ef8f181a8bb319350fac600363831c2a Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 15:06:01 -0800
Subject: [PATCH 25/40] Only sort the first two commutative operands

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 32 ++++++++++++++++++----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 956f0ff8799f3f0..66013dcc206cd51 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -80,6 +80,10 @@ class IRNormalizer {
 
   /// \name Utility methods.
   /// @{
+  template<typename T>
+  void sortCommutativeOperands(T &Operands) const; 
+  template<typename T, typename Compare>
+  void sortCommutativeOperands(T &Operands, Compare Comp) const; 
   SmallVector<Instruction *, 16> collectOutputInstructions(Function &F);
   bool isOutput(const Instruction *I);
   bool isInitialInstruction(const Instruction *I);
@@ -188,6 +192,24 @@ void IRNormalizer::nameInstruction(Instruction *I) {
   }
 }
 
+template<typename T>
+void IRNormalizer::sortCommutativeOperands(T &Operands) const {
+  if (Operands.size() < 2)
+    return;
+  auto CommutativeEnd = Operands.begin();
+  std::advance(CommutativeEnd, 2);
+  llvm::sort(Operands.begin(), CommutativeEnd);
+}
+
+template<typename T, typename Compare>
+void IRNormalizer::sortCommutativeOperands(T &Operands, Compare Comp) const {
+  if (Operands.size() < 2)
+    return;
+  auto CommutativeEnd = Operands.begin();
+  std::advance(CommutativeEnd, 2);
+  llvm::sort(Operands.begin(), CommutativeEnd, Comp);
+}
+
 /// Names instruction following the scheme:
 /// vl00000Callee(Operands)
 ///
@@ -219,7 +241,7 @@ void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
   }
 
   if (I->isCommutative())
-    llvm::sort(Operands);
+    sortCommutativeOperands(Operands);
 
   // Initialize to a magic constant, so the state isn't zero.
   uint64_t Hash = MagicHashConstant;
@@ -301,7 +323,7 @@ void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
   }
 
   if (I->isCommutative())
-    llvm::sort(Operands.begin(), Operands.end());
+    sortCommutativeOperands(Operands);
 
   // Initialize to a magic constant, so the state isn't zero.
   uint64_t Hash = MagicHashConstant;
@@ -318,7 +340,7 @@ void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
       OperandsOpcodes.push_back(IOP->getOpcode());
 
   if (I->isCommutative())
-    llvm::sort(OperandsOpcodes.begin(), OperandsOpcodes.end());
+    sortCommutativeOperands(OperandsOpcodes);
 
   // Consider operand opcodes in the hash.
   for (const int Code : OperandsOpcodes)
@@ -388,7 +410,7 @@ void IRNormalizer::foldInstructionName(Instruction *I) {
   }
 
   if (I->isCommutative())
-    llvm::sort(Operands.begin(), Operands.end());
+    sortCommutativeOperands(Operands);
 
   SmallString<256> Name;
   Name.append(I->getName().substr(0, 7));
@@ -495,7 +517,7 @@ void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) {
   }
 
   // Sort operands.
-  llvm::sort(Operands.begin(), Operands.end(), llvm::less_first());
+  sortCommutativeOperands(Operands, llvm::less_first());
 
   // Reorder operands.
   unsigned Position = 0;

>From 8354e5508c3c815a8a8e6d95dcadf23c46c90318 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 15:19:11 -0800
Subject: [PATCH 26/40] Add LLVM_DEBUG for instruction renaming

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 66013dcc206cd51..7e609199482036d 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -226,6 +226,7 @@ void IRNormalizer::sortCommutativeOperands(T &Operands, Compare Comp) const {
 void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
   if (I->getType()->isVoidTy() || (!I->getName().empty() && !RenameAll))
     return;
+  LLVM_DEBUG(dbgs() << "Naming initial instruction: " << *I << "\n");
 
   // Instruction operands for further sorting.
   SmallVector<SmallString<64>, 4> Operands;
@@ -299,6 +300,8 @@ void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
 /// \see getOutputFootprint()
 /// \param I Instruction to be renamed.
 void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
+  LLVM_DEBUG(dbgs() << "Naming regular instruction: " << *I << "\n");
+  
   // Instruction operands for further sorting.
   SmallVector<SmallString<128>, 4> Operands;
 

>From ff4beb7e4d17278e003c1df41f5a039afd3f4d49 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 17:16:30 -0800
Subject: [PATCH 27/40] Canonical -> Normal

---
 llvm/docs/Passes.rst                              |  4 ++--
 llvm/docs/ReleaseNotes.rst                        |  2 +-
 llvm/include/llvm/Transforms/Utils/IRNormalizer.h |  2 +-
 llvm/lib/Transforms/Utils/IRNormalizer.cpp        | 12 ++++++------
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
index abfa36992be7c8d..93c86504ba39e13 100644
--- a/llvm/docs/Passes.rst
+++ b/llvm/docs/Passes.rst
@@ -543,10 +543,10 @@ variables with initializers are marked as internal.
 An interprocedural variant of :ref:`Sparse Conditional Constant Propagation
 <passes-sccp>`.
 
-``ir-normalizer``: Transforms IR into a canonical form that's easier to diff
+``ir-normalizer``: Transforms IR into a normal form that's easier to diff
 ----------------------------------------------------------------------------
 
-This pass aims to transform LLVM Modules into a canonical form by reordering and
+This pass aims to transform LLVM Modules into a normal form by reordering and
 renaming instructions while preserving the same semantics. The normalizer makes
 it easier to spot semantic differences while diffing two modules which have
 undergone two different passes.
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 5158711994c85e5..d571721090c827f 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -43,7 +43,7 @@ Non-comprehensive list of changes in this release
    for adding a new subsection.
 
 * Added a new IRNormalizer pass which aims to transform LLVM modules into
-  a canonical form by reordering and renaming instructions while preserving the
+  a normal form by reordering and renaming instructions while preserving the
   same semantics. The normalizer makes it easier to spot semantic differences
   when diffing two modules which have undergone different passes.
 
diff --git a/llvm/include/llvm/Transforms/Utils/IRNormalizer.h b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
index 2e3e23340bc5bc7..b5df02e6ac87cc0 100644
--- a/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
+++ b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
@@ -5,7 +5,7 @@
 
 namespace llvm {
 
-/// IRNormalizer aims to transform LLVM IR into canonical form.
+/// IRNormalizer aims to transform LLVM IR into normal form.
 struct IRNormalizerPass : public PassInfoMixin<IRNormalizerPass> {
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 7e609199482036d..42dad3d4eceb562 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 /// \file
 /// This file implements the IRNormalizer class which aims to transform LLVM
-/// Modules into a canonical form by reordering and renaming instructions while
+/// Modules into a normal form by reordering and renaming instructions while
 /// preserving the same semantics. The normalizer makes it easier to spot
 /// semantic differences while diffing two modules which have undergone
 /// different passes.
@@ -37,7 +37,7 @@
 using namespace llvm;
 
 namespace {
-/// IRNormalizer aims to transform LLVM IR into canonical form.
+/// IRNormalizer aims to transform LLVM IR into normal form.
 class IRNormalizer {
 public:
   /// \name Normalizer flags.
@@ -301,7 +301,7 @@ void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
 /// \param I Instruction to be renamed.
 void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
   LLVM_DEBUG(dbgs() << "Naming regular instruction: " << *I << "\n");
-  
+
   // Instruction operands for further sorting.
   SmallVector<SmallString<128>, 4> Operands;
 
@@ -404,10 +404,10 @@ void IRNormalizer::foldInstructionName(Instruction *I) {
 
   for (auto &OP : I->operands()) {
     if (const auto *IOP = dyn_cast<Instruction>(OP)) {
-      bool HasCanonicalName = I->getName().substr(0, 2) == "op" ||
+      bool HasNormalName = I->getName().substr(0, 2) == "op" ||
                               I->getName().substr(0, 2) == "vl";
 
-      Operands.push_back(HasCanonicalName ? IOP->getName().substr(0, 7)
+      Operands.push_back(HasNormalName ? IOP->getName().substr(0, 7)
                                           : IOP->getName());
     }
   }
@@ -533,7 +533,7 @@ void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) {
 /// Reorders PHI node's values according to the names of corresponding basic
 /// blocks.
 ///
-/// \param PN PHI node to canonicalize.
+/// \param PN PHI node to normalize.
 void IRNormalizer::reorderPHIIncomingValues(PHINode *PN) {
   // Values for further sorting.
   SmallVector<std::pair<Value *, BasicBlock *>, 2> Values;

>From 90613d036fd29ac4615c5a44c5fb98ad6a34051b Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 17:18:33 -0800
Subject: [PATCH 28/40] clang-format changes

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 42dad3d4eceb562..a93f1e2c30b7b50 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -80,9 +80,8 @@ class IRNormalizer {
 
   /// \name Utility methods.
   /// @{
-  template<typename T>
-  void sortCommutativeOperands(T &Operands) const; 
-  template<typename T, typename Compare>
+  template <typename T> void sortCommutativeOperands(T &Operands) const; 
+  template <typename T, typename Compare>
   void sortCommutativeOperands(T &Operands, Compare Comp) const; 
   SmallVector<Instruction *, 16> collectOutputInstructions(Function &F);
   bool isOutput(const Instruction *I);
@@ -192,7 +191,7 @@ void IRNormalizer::nameInstruction(Instruction *I) {
   }
 }
 
-template<typename T>
+template <typename T>
 void IRNormalizer::sortCommutativeOperands(T &Operands) const {
   if (Operands.size() < 2)
     return;
@@ -201,7 +200,7 @@ void IRNormalizer::sortCommutativeOperands(T &Operands) const {
   llvm::sort(Operands.begin(), CommutativeEnd);
 }
 
-template<typename T, typename Compare>
+template <typename T, typename Compare>
 void IRNormalizer::sortCommutativeOperands(T &Operands, Compare Comp) const {
   if (Operands.size() < 2)
     return;
@@ -477,8 +476,8 @@ void IRNormalizer::reorderInstruction(
     Used->moveBefore(User);
   } else {
     // Otherwise move Used to the very end of its basic block.
-    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block " << 
-               Used->getParent()->getName() << "\n");
+    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block " 
+                      << Used->getParent()->getName() << "\n");
     Used->moveBefore(&Used->getParent()->back());
   }
 

>From d9ae25253adf668fca1b4ff4f89c2f1203359c42 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 19:16:35 -0800
Subject: [PATCH 29/40] Prefix cli arguments with "norm"

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp                | 8 ++++----
 llvm/test/Transforms/IRNormalizer/infinite-loop.ll        | 4 ++--
 .../Transforms/IRNormalizer/naming-args-instr-blocks.ll   | 3 +--
 llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll  | 2 +-
 llvm/test/Transforms/IRNormalizer/naming-instructions.ll  | 2 +-
 5 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index a93f1e2c30b7b50..8d6ea64405495cb 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -95,16 +95,16 @@ class IRNormalizer {
 } // namespace
 
 cl::opt<bool> IRNormalizer::PreserveOrder(
-    "preserve-order", cl::Hidden,
+    "norm-preserve-order", cl::Hidden,
     cl::desc("Preserves original instruction order"));
 cl::opt<bool> IRNormalizer::RenameAll(
-    "rename-all", cl::Hidden,
+    "norm-rename-all", cl::Hidden,
     cl::desc("Renames all instructions (including user-named)"));
 cl::opt<bool> IRNormalizer::FoldPreOutputs(
-    "fold-all", cl::Hidden,
+    "norm-fold-all", cl::Hidden,
     cl::desc("Folds all regular instructions (including pre-outputs)"));
 cl::opt<bool> IRNormalizer::ReorderOperands(
-    "reorder-operands", cl::Hidden,
+    "norm-reorder-operands", cl::Hidden,
     cl::desc("Sorts and reorders operands in commutative instructions"));
 
 /// Entry method to the IRNormalizer.
diff --git a/llvm/test/Transforms/IRNormalizer/infinite-loop.ll b/llvm/test/Transforms/IRNormalizer/infinite-loop.ll
index 9b10e91e49b4de5..109858e97fd36a7 100644
--- a/llvm/test/Transforms/IRNormalizer/infinite-loop.ll
+++ b/llvm/test/Transforms/IRNormalizer/infinite-loop.ll
@@ -1,5 +1,5 @@
-; RUN: opt -passes=normalize -preserve-order=true < %s
-; RUN: opt -passes=normalize -preserve-order=false < %s
+; RUN: opt -passes=normalize -norm-preserve-order=true < %s
+; RUN: opt -passes=normalize -norm-preserve-order=false < %s
 
 define void @test(ptr, i32) {
 bb:
diff --git a/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll b/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
index afb99585db2ccf6..104ffc8dd6e39fd 100644
--- a/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-args-instr-blocks.ll
@@ -1,5 +1,4 @@
-; RUN: opt -S -passes=normalize --rename-all --preserve-order < %s | FileCheck %s
-
+; RUN: opt -S -passes=normalize -norm-rename-all -norm-preserve-order < %s | FileCheck %s
 
 ; CHECK: @foo(i32 %a0)
 define i32 @foo(i32) {
diff --git a/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll b/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
index f50c56bcca53f3a..9493b3f70ef763a 100644
--- a/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-basic-blocks.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=normalize --rename-all < %s | FileCheck %s
+; RUN: opt -S -passes=normalize -norm-rename-all < %s | FileCheck %s
 
 define i32 @foo(i32 %a0) {
 ; CHECK: bb{{([0-9]{5})}}
diff --git a/llvm/test/Transforms/IRNormalizer/naming-instructions.ll b/llvm/test/Transforms/IRNormalizer/naming-instructions.ll
index f1fe503f53ca1d1..c08ef18f948c83a 100644
--- a/llvm/test/Transforms/IRNormalizer/naming-instructions.ll
+++ b/llvm/test/Transforms/IRNormalizer/naming-instructions.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -passes=normalize --rename-all < %s | FileCheck %s
+; RUN: opt -S -passes=normalize -norm-rename-all < %s | FileCheck %s
 
 define i32 @foo(i32 %a0) {
 entry:

>From a70aae473aad4dd3467fe722560cc614fa8be83b Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Fri, 10 Nov 2023 19:18:16 -0800
Subject: [PATCH 30/40] clang-format changes

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 8d6ea64405495cb..7fed01e540d94ce 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -80,9 +80,9 @@ class IRNormalizer {
 
   /// \name Utility methods.
   /// @{
-  template <typename T> void sortCommutativeOperands(T &Operands) const; 
+  template <typename T> void sortCommutativeOperands(T &Operands) const;
   template <typename T, typename Compare>
-  void sortCommutativeOperands(T &Operands, Compare Comp) const; 
+  void sortCommutativeOperands(T &Operands, Compare Comp) const;
   SmallVector<Instruction *, 16> collectOutputInstructions(Function &F);
   bool isOutput(const Instruction *I);
   bool isInitialInstruction(const Instruction *I);
@@ -407,7 +407,7 @@ void IRNormalizer::foldInstructionName(Instruction *I) {
                               I->getName().substr(0, 2) == "vl";
 
       Operands.push_back(HasNormalName ? IOP->getName().substr(0, 7)
-                                          : IOP->getName());
+                                       : IOP->getName());
     }
   }
 
@@ -476,7 +476,7 @@ void IRNormalizer::reorderInstruction(
     Used->moveBefore(User);
   } else {
     // Otherwise move Used to the very end of its basic block.
-    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block " 
+    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block "
                       << Used->getParent()->getName() << "\n");
     Used->moveBefore(&Used->getParent()->back());
   }

>From 6cf54edc9f82cbf2e60499f1f9594074687f70e3 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 11 Nov 2023 13:37:20 -0800
Subject: [PATCH 31/40] clang-format changes

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 7fed01e540d94ce..61193c4b7948429 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -404,7 +404,7 @@ void IRNormalizer::foldInstructionName(Instruction *I) {
   for (auto &OP : I->operands()) {
     if (const auto *IOP = dyn_cast<Instruction>(OP)) {
       bool HasNormalName = I->getName().substr(0, 2) == "op" ||
-                              I->getName().substr(0, 2) == "vl";
+                           I->getName().substr(0, 2) == "vl";
 
       Operands.push_back(HasNormalName ? IOP->getName().substr(0, 7)
                                        : IOP->getName());

>From f57e0af527a9c7772ab8e05cabd07e20ab293175 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sat, 11 Nov 2023 17:32:07 -0800
Subject: [PATCH 32/40] Use const + WIP

---
 .../llvm/Transforms/Utils/IRNormalizer.h      |  2 +-
 llvm/lib/Transforms/Utils/IRNormalizer.cpp    | 81 +++++++++----------
 2 files changed, 41 insertions(+), 42 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/IRNormalizer.h b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
index b5df02e6ac87cc0..af1f715d4940d8d 100644
--- a/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
+++ b/llvm/include/llvm/Transforms/Utils/IRNormalizer.h
@@ -7,7 +7,7 @@ namespace llvm {
 
 /// IRNormalizer aims to transform LLVM IR into normal form.
 struct IRNormalizerPass : public PassInfoMixin<IRNormalizerPass> {
-  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) const;
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 61193c4b7948429..2ce155233df6bf7 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -59,23 +59,26 @@ class IRNormalizer {
   const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL;
   DenseSet<const Instruction *> NamedInstructions;
 
+  SmallVector<Instruction *, 16> Outputs;
+
   /// \name Naming.
   /// @{
-  void nameFunctionArguments(Function &F);
-  void nameBasicBlocks(Function &F);
+  void nameFunctionArguments(Function &F) const;
+  void nameBasicBlocks(Function &F) const;
   void nameInstruction(Instruction *I);
-  void nameAsInitialInstruction(Instruction *I);
+  void nameAsInitialInstruction(Instruction *I) const;
   void nameAsRegularInstruction(Instruction *I);
-  void foldInstructionName(Instruction *I);
+  void foldInstructionName(Instruction *I) const;
   /// @}
 
   /// \name Reordering.
   /// @{
-  void reorderInstructions(SmallVector<Instruction *, 16> &Outputs);
+  void reorderInstructions(Function &F) const;
+  void reorderInstructionsInBasicBlock(BasicBlock &BB) const;
   void reorderInstruction(Instruction *Used, Instruction *User,
-                          SmallPtrSet<const Instruction *, 32> &Visited);
-  void reorderInstructionOperandsByNames(Instruction *I);
-  void reorderPHIIncomingValues(PHINode *PN);
+                          SmallPtrSet<const Instruction *, 32> &Visited) const;
+  void reorderInstructionOperandsByNames(Instruction *I) const;
+  void reorderPHIIncomingValues(PHINode *PN) const;
   /// @}
 
   /// \name Utility methods.
@@ -83,13 +86,13 @@ class IRNormalizer {
   template <typename T> void sortCommutativeOperands(T &Operands) const;
   template <typename T, typename Compare>
   void sortCommutativeOperands(T &Operands, Compare Comp) const;
-  SmallVector<Instruction *, 16> collectOutputInstructions(Function &F);
-  bool isOutput(const Instruction *I);
-  bool isInitialInstruction(const Instruction *I);
-  bool hasOnlyImmediateOperands(const Instruction *I);
+  SmallVector<Instruction *, 16> collectOutputInstructions(Function &F) const;
+  bool isOutput(const Instruction *I) const;
+  bool isInitialInstruction(const Instruction *I) const;
+  bool hasOnlyImmediateOperands(const Instruction *I) const;
   SetVector<int>
   getOutputFootprint(Instruction *I,
-                     SmallPtrSet<const Instruction *, 32> &Visited);
+                     SmallPtrSet<const Instruction *, 32> &Visited) const;
   /// @}
 };
 } // namespace
@@ -114,10 +117,10 @@ bool IRNormalizer::runOnFunction(Function &F) {
   nameFunctionArguments(F);
   nameBasicBlocks(F);
 
-  SmallVector<Instruction *, 16> Outputs = collectOutputInstructions(F);
+  Outputs = collectOutputInstructions(F);
 
   if (!PreserveOrder)
-    reorderInstructions(Outputs);
+    reorderInstructions(F);
 
   for (auto &I : Outputs)
     nameInstruction(I);
@@ -140,7 +143,7 @@ bool IRNormalizer::runOnFunction(Function &F) {
 /// Numbers arguments.
 ///
 /// \param F Function whose arguments will be renamed.
-void IRNormalizer::nameFunctionArguments(Function &F) {
+void IRNormalizer::nameFunctionArguments(Function &F) const {
   int ArgumentCounter = 0;
   for (auto &A : F.args()) {
     if (RenameAll || A.getName().empty()) {
@@ -154,7 +157,7 @@ void IRNormalizer::nameFunctionArguments(Function &F) {
 /// a function considering the opcode and the order of output instructions.
 ///
 /// \param F Function containing basic blocks to rename.
-void IRNormalizer::nameBasicBlocks(Function &F) {
+void IRNormalizer::nameBasicBlocks(Function &F) const {
   for (auto &B : F) {
     // Initialize to a magic constant, so the state isn't zero.
     uint64_t Hash = MagicHashConstant;
@@ -222,7 +225,7 @@ void IRNormalizer::sortCommutativeOperands(T &Operands, Compare Comp) const {
 ///
 /// \see getOutputFootprint()
 /// \param I Instruction to be renamed.
-void IRNormalizer::nameAsInitialInstruction(Instruction *I) {
+void IRNormalizer::nameAsInitialInstruction(Instruction *I) const {
   if (I->getType()->isVoidTy() || (!I->getName().empty() && !RenameAll))
     return;
   LLVM_DEBUG(dbgs() << "Naming initial instruction: " << *I << "\n");
@@ -383,7 +386,7 @@ void IRNormalizer::nameAsRegularInstruction(Instruction *I) {
 /// does not affect user named instructions.
 ///
 /// \param I Instruction whose name will be folded.
-void IRNormalizer::foldInstructionName(Instruction *I) {
+void IRNormalizer::foldInstructionName(Instruction *I) const {
   // If this flag is raised, fold all regular
   // instructions (including pre-outputs).
   if (!FoldPreOutputs) {
@@ -436,21 +439,17 @@ void IRNormalizer::foldInstructionName(Instruction *I) {
 /// This method is a wrapper for recursive reorderInstruction().
 ///
 /// \see reorderInstruction()
-/// \param Outputs Vector of pointers to output instructions collected top-down.
-void IRNormalizer::reorderInstructions(
-    SmallVector<Instruction *, 16> &Outputs) {
-  // This method assumes output instructions were collected top-down,
-  // otherwise the def-use chain may be broken.
+void IRNormalizer::reorderInstructions(Function &F) const {
+  SmallPtrSet<const Instruction *, 32> UsedInFunction;
+  for (auto &BB : F) {
+    LLVM_DEBUG(dbgs() << "Reordering instructions of basic block: " 
+                      << BB.getName());
+    reorderInstructionsInBasicBlock(BB);
+  }
+}
 
-  SmallPtrSet<const Instruction *, 32> Visited;
+void IRNormalizer::reorderInstructionsInBasicBlock(BasicBlock &BB) const {
 
-  // Walk up the tree.
-  for (auto &I : Outputs) {
-    LLVM_DEBUG(dbgs() << "Reordering operands of: "; I->dump());
-    for (auto &OP : I->operands())
-      if (auto *IOP = dyn_cast<Instruction>(OP))
-        reorderInstruction(IOP, I, Visited);
-  }
 }
 
 /// Reduces def-use distance or places instruction at the end of the basic
@@ -463,7 +462,7 @@ void IRNormalizer::reorderInstructions(
 /// \param Visited Set of visited instructions.
 void IRNormalizer::reorderInstruction(
     Instruction *Used, Instruction *User,
-    SmallPtrSet<const Instruction *, 32> &Visited) {
+    SmallPtrSet<const Instruction *, 32> &Visited) const {
   if (isa<PHINode>(Used))
     return;
   if (Visited.contains(Used))
@@ -494,7 +493,7 @@ void IRNormalizer::reorderInstruction(
 /// in other instructions may change the semantics.
 ///
 /// \param I Instruction whose operands will be reordered.
-void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) {
+void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) const {
   // This method assumes that passed I is commutative,
   // changing the order of operands in other instructions
   // may change the semantics.
@@ -533,7 +532,7 @@ void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) {
 /// blocks.
 ///
 /// \param PN PHI node to normalize.
-void IRNormalizer::reorderPHIIncomingValues(PHINode *PN) {
+void IRNormalizer::reorderPHIIncomingValues(PHINode *PN) const {
   // Values for further sorting.
   SmallVector<std::pair<Value *, BasicBlock *>, 2> Values;
 
@@ -562,7 +561,7 @@ void IRNormalizer::reorderPHIIncomingValues(PHINode *PN) {
 /// \see isOutput()
 /// \param F Function to collect outputs from.
 SmallVector<Instruction *, 16>
-IRNormalizer::collectOutputInstructions(Function &F) {
+IRNormalizer::collectOutputInstructions(Function &F) const {
   // Output instructions are collected top-down in each function,
   // any change may break the def-use chain in reordering methods.
   SmallVector<Instruction *, 16> Outputs;
@@ -578,7 +577,7 @@ IRNormalizer::collectOutputInstructions(Function &F) {
 /// ReturnInst.
 ///
 /// \param I Considered instruction.
-bool IRNormalizer::isOutput(const Instruction *I) {
+bool IRNormalizer::isOutput(const Instruction *I) const {
   // Outputs are such instructions which may have side effects or is ReturnInst.
   if (I->mayHaveSideEffects() || isa<ReturnInst>(I))
     return true;
@@ -590,7 +589,7 @@ bool IRNormalizer::isOutput(const Instruction *I) {
 /// immediate operands.
 ///
 /// \param I Considered instruction.
-bool IRNormalizer::isInitialInstruction(const Instruction *I) {
+bool IRNormalizer::isInitialInstruction(const Instruction *I) const {
   // Initial instructions are such instructions whose values are used by
   // other instructions, yet they only depend on immediate values.
   return !I->user_empty() && hasOnlyImmediateOperands(I);
@@ -599,7 +598,7 @@ bool IRNormalizer::isInitialInstruction(const Instruction *I) {
 /// Helper method checking whether the instruction has only immediate operands.
 ///
 /// \param I Considered instruction.
-bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) {
+bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) const {
   for (const auto &OP : I->operands())
     if (isa<Instruction>(OP))
       return false; // Found non-immediate operand (instruction).
@@ -614,7 +613,7 @@ bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) {
 /// \param I Considered instruction.
 /// \param Visited Set of visited instructions.
 SetVector<int> IRNormalizer::getOutputFootprint(
-    Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) {
+    Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) const {
 
   // Vector containing indexes of outputs (no repetitions),
   // which use I in the order of walking down the def-use tree.
@@ -657,7 +656,7 @@ SetVector<int> IRNormalizer::getOutputFootprint(
 }
 
 PreservedAnalyses IRNormalizerPass::run(Function &F,
-                                        FunctionAnalysisManager &AM) {
+                                        FunctionAnalysisManager &AM) const {
   IRNormalizer{}.runOnFunction(F);
   return PreservedAnalyses::all();
 }

>From 21ffb91c3bcdd1e907fd579c340297970439fbca Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Tue, 14 Nov 2023 20:57:44 -0800
Subject: [PATCH 33/40] First draft of new reordering

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp    | 91 +++++++++++++++++--
 .../IRNormalizer/reordering-instructions.ll   |  4 +-
 2 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 2ce155233df6bf7..85230a8beb8fc29 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -30,7 +30,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils.h"
 #include <algorithm>
-#include <vector>
+#include <stack>
 
 #define DEBUG_TYPE "normalize"
 
@@ -74,7 +74,13 @@ class IRNormalizer {
   /// \name Reordering.
   /// @{
   void reorderInstructions(Function &F) const;
-  void reorderInstructionsInBasicBlock(BasicBlock &BB) const;
+  void reorderSourceInstruction(Instruction *I,
+      std::stack<Instruction *> &TopologicalSort, 
+      SmallPtrSet<const Instruction *, 32> &Visited) const;
+  void reorderDefinition(Instruction *Definition,
+      std::stack<Instruction *> &TopologicalSort,
+      SmallPtrSet<const Instruction *, 32> &Visited) const;
+  // TODO: Delete reorderInstruction
   void reorderInstruction(Instruction *Used, Instruction *User,
                           SmallPtrSet<const Instruction *, 32> &Visited) const;
   void reorderInstructionOperandsByNames(Instruction *I) const;
@@ -440,16 +446,87 @@ void IRNormalizer::foldInstructionName(Instruction *I) const {
 ///
 /// \see reorderInstruction()
 void IRNormalizer::reorderInstructions(Function &F) const {
-  SmallPtrSet<const Instruction *, 32> UsedInFunction;
   for (auto &BB : F) {
-    LLVM_DEBUG(dbgs() << "Reordering instructions of basic block: " 
-                      << BB.getName());
-    reorderInstructionsInBasicBlock(BB);
+    LLVM_DEBUG(dbgs() << "Reordering instructions in basic block: " 
+                      << BB.getName() << "\n");
+    // Find the source nodes of the DAG of instructions in this basic block.
+    // We must iterate from the first to the last instruction otherwise side 
+    // effecting instructions could be reordered. 
+
+    std::stack<Instruction *> TopologicalSort;
+    SmallPtrSet<const Instruction *, 32> Visited;
+    for (auto &I : BB) { 
+      if (!isOutput(&I) && !I.isTerminator()) 
+        continue; // I is not a source node. 
+      LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
+      reorderDefinition(&I, TopologicalSort, Visited);
+    }
+
+    for (auto &I : BB) { 
+      if (Visited.contains(&I)) 
+        continue; // I is not a source node. 
+      LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
+      reorderDefinition(&I, TopologicalSort, Visited);
+    }
+
+    LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
+                      << "\n");
+    // Reorder based on the topological sort. 
+    while (!TopologicalSort.empty()) {
+      auto *Instruction = TopologicalSort.top();
+      auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
+      // if (Instruction == FirstNonPHIOrDbgOrAlloca) {
+      //   // If the first instruction in the block is the instruction that we're
+      //   // currently trying to insert, then leave it at the top of the block
+      //   // and insert the next instruction above it. 
+      //   TopologicalSort.pop();
+      //   if (TopologicalSort.empty())
+      //     break;
+      //   auto *NextInstruction = TopologicalSort.top();
+      //   LLVM_DEBUG(dbgs() << "\tInserting "; NextInstruction->dump(); 
+      //              dbgs() << "\t\tbefore"; Instruction->dump());
+      //   NextInstruction->moveBefore(Instruction);
+      //   TopologicalSort.pop();
+      // } else {
+      //   LLVM_DEBUG(dbgs() << "\tInserting "; Instruction->dump(); 
+      //              dbgs() << "\t\tafter"; FirstNonPHIOrDbgOrAlloca->dump());
+      //   Instruction->moveAfter(FirstNonPHIOrDbgOrAlloca);
+      //   TopologicalSort.pop();
+      // }
+      Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
+        TopologicalSort.pop();
+    }
   }
 }
 
-void IRNormalizer::reorderInstructionsInBasicBlock(BasicBlock &BB) const {
+void IRNormalizer::reorderSourceInstruction(Instruction *I,
+    std::stack<Instruction *> &TopologicalSort,
+    SmallPtrSet<const Instruction *, 32> &Visited) const {
+  LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I->dump());
+}
+
+void IRNormalizer::reorderDefinition(Instruction *Definition,
+    std::stack<Instruction *> &TopologicalSort,
+    SmallPtrSet<const Instruction *, 32> &Visited) const {
+  if (Visited.contains(Definition))
+    return;
+  Visited.insert(Definition);
+
+  if (Definition->comesBefore(&*Definition->getParent()
+                                          ->getFirstNonPHIOrDbgOrAlloca()))
+    return; // TODO: Do some kind of ordering for these instructions. 
+
+  for (auto &Operand : Definition->operands()) {
+    if (auto *Op = dyn_cast<Instruction>(Operand)) {
+      if (Op->getParent() != Definition->getParent())
+        continue; // Only reorder instruction within the same basic block
+      reorderDefinition(Op, TopologicalSort, Visited);
+    }
+  }
 
+  LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
+  if (!Definition->isTerminator())
+    TopologicalSort.emplace(Definition);
 }
 
 /// Reduces def-use distance or places instruction at the end of the basic
diff --git a/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll b/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
index 8978b01c3caa6d4..338fbbe974cce7b 100644
--- a/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
+++ b/llvm/test/Transforms/IRNormalizer/reordering-instructions.ll
@@ -2,10 +2,10 @@
 
 define double @foo(double %a0, double %a1) {
 entry:
-; CHECK: %a
-; CHECK: %c
 ; CHECK: %b
 ; CHECK: %d
+; CHECK: %a
+; CHECK: %c
   %a = fmul double %a0, %a1
   %b = fmul double %a0, 2.000000e+00
   %c = fmul double %a, 6.000000e+00

>From 8b91dc0770893f186bc5945a5a30e040b200479d Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 17:01:47 -0800
Subject: [PATCH 34/40] New reordering

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 88 +++++-----------------
 1 file changed, 18 insertions(+), 70 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 85230a8beb8fc29..8220217cc6fe440 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -74,15 +74,9 @@ class IRNormalizer {
   /// \name Reordering.
   /// @{
   void reorderInstructions(Function &F) const;
-  void reorderSourceInstruction(Instruction *I,
-      std::stack<Instruction *> &TopologicalSort, 
-      SmallPtrSet<const Instruction *, 32> &Visited) const;
   void reorderDefinition(Instruction *Definition,
       std::stack<Instruction *> &TopologicalSort,
       SmallPtrSet<const Instruction *, 32> &Visited) const;
-  // TODO: Delete reorderInstruction
-  void reorderInstruction(Instruction *Used, Instruction *User,
-                          SmallPtrSet<const Instruction *, 32> &Visited) const;
   void reorderInstructionOperandsByNames(Instruction *I) const;
   void reorderPHIIncomingValues(PHINode *PN) const;
   /// @}
@@ -458,7 +452,8 @@ void IRNormalizer::reorderInstructions(Function &F) const {
     for (auto &I : BB) { 
       if (!isOutput(&I) && !I.isTerminator()) 
         continue; // I is not a source node. 
-      LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
+      LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 
+                 I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
@@ -475,36 +470,12 @@ void IRNormalizer::reorderInstructions(Function &F) const {
     while (!TopologicalSort.empty()) {
       auto *Instruction = TopologicalSort.top();
       auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
-      // if (Instruction == FirstNonPHIOrDbgOrAlloca) {
-      //   // If the first instruction in the block is the instruction that we're
-      //   // currently trying to insert, then leave it at the top of the block
-      //   // and insert the next instruction above it. 
-      //   TopologicalSort.pop();
-      //   if (TopologicalSort.empty())
-      //     break;
-      //   auto *NextInstruction = TopologicalSort.top();
-      //   LLVM_DEBUG(dbgs() << "\tInserting "; NextInstruction->dump(); 
-      //              dbgs() << "\t\tbefore"; Instruction->dump());
-      //   NextInstruction->moveBefore(Instruction);
-      //   TopologicalSort.pop();
-      // } else {
-      //   LLVM_DEBUG(dbgs() << "\tInserting "; Instruction->dump(); 
-      //              dbgs() << "\t\tafter"; FirstNonPHIOrDbgOrAlloca->dump());
-      //   Instruction->moveAfter(FirstNonPHIOrDbgOrAlloca);
-      //   TopologicalSort.pop();
-      // }
       Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
         TopologicalSort.pop();
     }
   }
 }
 
-void IRNormalizer::reorderSourceInstruction(Instruction *I,
-    std::stack<Instruction *> &TopologicalSort,
-    SmallPtrSet<const Instruction *, 32> &Visited) const {
-  LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I->dump());
-}
-
 void IRNormalizer::reorderDefinition(Instruction *Definition,
     std::stack<Instruction *> &TopologicalSort,
     SmallPtrSet<const Instruction *, 32> &Visited) const {
@@ -512,9 +483,14 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     return;
   Visited.insert(Definition);
 
-  if (Definition->comesBefore(&*Definition->getParent()
-                                          ->getFirstNonPHIOrDbgOrAlloca()))
-    return; // TODO: Do some kind of ordering for these instructions. 
+  {
+    const auto *BasicBlock = Definition->getParent();
+    const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
+    if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
+      return;
+    if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
+      return; // TODO: Do some kind of ordering for these instructions. 
+  }
 
   for (auto &Operand : Definition->operands()) {
     if (auto *Op = dyn_cast<Instruction>(Operand)) {
@@ -525,44 +501,16 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
   }
 
   LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
-  if (!Definition->isTerminator())
-    TopologicalSort.emplace(Definition);
-}
-
-/// Reduces def-use distance or places instruction at the end of the basic
-/// block. Continues to walk up the def-use tree recursively. Used by
-/// reorderInstructions().
-///
-/// \see reorderInstructions()
-/// \param Used Pointer to the instruction whose value is used by the \p User.
-/// \param User Pointer to the instruction which uses the \p Used.
-/// \param Visited Set of visited instructions.
-void IRNormalizer::reorderInstruction(
-    Instruction *Used, Instruction *User,
-    SmallPtrSet<const Instruction *, 32> &Visited) const {
-  if (isa<PHINode>(Used))
-    return;
-  if (Visited.contains(Used))
+  if (Definition->isTerminator())
     return;
-  Visited.insert(Used);
-
-  if (Used->getParent() == User->getParent()) {
-    // If Used and User share the same basic block move Used just before User.
-    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " before " << *User << "\n");
-    Used->moveBefore(User);
-  } else {
-    // Otherwise move Used to the very end of its basic block.
-    LLVM_DEBUG(dbgs() << "\tMoved " << *Used << " to end of block "
-                      << Used->getParent()->getName() << "\n");
-    Used->moveBefore(&Used->getParent()->back());
-  }
-
-  for (auto &OP : Used->operands()) {
-    if (auto *IOP = dyn_cast<Instruction>(OP)) {
-      // Walk up the def-use tree.
-      reorderInstruction(IOP, Used, Visited);
-    }
+  if (auto *Call = dyn_cast<CallInst>(Definition)) {
+    if (Call->isMustTailCall())
+      return;
+    if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize)
+      return;
   }
+  // TODO: return on llvm.experimental.deopt...
+  TopologicalSort.emplace(Definition);
 }
 
 /// Reorders instruction's operands alphabetically. This method assumes

>From b1d6ef875221c1a32481592c3c1d92abc2dd1126 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 17:47:57 -0800
Subject: [PATCH 35/40] Change the output ordering

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 47 +++++++++++++++-------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 8220217cc6fe440..045ef08c77ffe0f 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -77,6 +77,8 @@ class IRNormalizer {
   void reorderDefinition(Instruction *Definition,
       std::stack<Instruction *> &TopologicalSort,
       SmallPtrSet<const Instruction *, 32> &Visited) const;
+  void reorderBasedOnTopologicalSort(BasicBlock &BB, 
+      std::stack<Instruction *> &TopologicalSort) const;
   void reorderInstructionOperandsByNames(Instruction *I) const;
   void reorderPHIIncomingValues(PHINode *PN) const;
   /// @}
@@ -447,32 +449,35 @@ void IRNormalizer::reorderInstructions(Function &F) const {
     // We must iterate from the first to the last instruction otherwise side 
     // effecting instructions could be reordered. 
 
-    std::stack<Instruction *> TopologicalSort;
     SmallPtrSet<const Instruction *, 32> Visited;
+    std::stack<Instruction *> TopologicalSort;
     for (auto &I : BB) { 
       if (!isOutput(&I) && !I.isTerminator()) 
-        continue; // I is not a source node. 
-      LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 
+        continue; // I is not side effecting. 
+      LLVM_DEBUG(dbgs() << "\tReordering from effecting source instruction: "; 
                  I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
+    std::stack<Instruction *> UsedOutsideOfBBTopologicalSort;
+    for (auto &I : BB) { 
+      if (Visited.contains(&I) || !I.isUsedOutsideOfBlock(I.getParent())) 
+        continue;
+      LLVM_DEBUG(dbgs() << "\tReordering from source instruction that's used in another block: "; I.dump());
+      reorderDefinition(&I, UsedOutsideOfBBTopologicalSort, Visited);
+    }
+
     for (auto &I : BB) { 
       if (Visited.contains(&I)) 
-        continue; // I is not a source node. 
-      LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
+        continue;
+      LLVM_DEBUG(dbgs() << "\tReordering from dead source instruction: "; I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
     LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
                       << "\n");
-    // Reorder based on the topological sort. 
-    while (!TopologicalSort.empty()) {
-      auto *Instruction = TopologicalSort.top();
-      auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
-      Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
-        TopologicalSort.pop();
-    }
+    reorderBasedOnTopologicalSort(BB, UsedOutsideOfBBTopologicalSort);
+    reorderBasedOnTopologicalSort(BB, TopologicalSort);
   }
 }
 
@@ -488,7 +493,7 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
     if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
       return;
-    if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
+    else if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
       return; // TODO: Do some kind of ordering for these instructions. 
   }
 
@@ -500,7 +505,7 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     }
   }
 
-  LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
+  // Don't reorder certain instructions. 
   if (Definition->isTerminator())
     return;
   if (auto *Call = dyn_cast<CallInst>(Definition)) {
@@ -509,10 +514,22 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize)
       return;
   }
-  // TODO: return on llvm.experimental.deopt...
+
+  LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
   TopologicalSort.emplace(Definition);
 }
 
+void IRNormalizer::reorderBasedOnTopologicalSort(BasicBlock &BB, 
+    std::stack<Instruction *> &TopologicalSort) const {
+  // Reorder based on the topological sort. 
+  while (!TopologicalSort.empty()) {
+    auto *Instruction = TopologicalSort.top();
+    auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
+    Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
+      TopologicalSort.pop();
+  }
+}
+
 /// Reorders instruction's operands alphabetically. This method assumes
 /// that passed instruction is commutative. Changing the operand order
 /// in other instructions may change the semantics.

>From dd8d2846a62b099127fcb5cb2ba4b231f317747a Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 17:51:33 -0800
Subject: [PATCH 36/40] Add comments

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 045ef08c77ffe0f..f5371aafe321a88 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -474,6 +474,10 @@ void IRNormalizer::reorderInstructions(Function &F) const {
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
+    // Output order should be:
+    // 1 - Unused Instructions.
+    // 2 - Side effecting instructions .
+    // 3 - Instructions used outside of the basic block.
     LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
                       << "\n");
     reorderBasedOnTopologicalSort(BB, UsedOutsideOfBBTopologicalSort);
@@ -489,12 +493,14 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
   Visited.insert(Definition);
 
   {
+    // TODO: Do some kind of ordering for instructions that come before the 
+    // result of getFirstNonPHIOrDbgOrAlloca().
     const auto *BasicBlock = Definition->getParent();
     const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
     if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
       return;
     else if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
-      return; // TODO: Do some kind of ordering for these instructions. 
+      return; 
   }
 
   for (auto &Operand : Definition->operands()) {

>From 5754b6ca8db6be2a712bd9ffb4a290e53102e638 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 18:21:56 -0800
Subject: [PATCH 37/40] Revert "Add comments"

This reverts commit dd8d2846a62b099127fcb5cb2ba4b231f317747a.
---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index f5371aafe321a88..045ef08c77ffe0f 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -474,10 +474,6 @@ void IRNormalizer::reorderInstructions(Function &F) const {
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
-    // Output order should be:
-    // 1 - Unused Instructions.
-    // 2 - Side effecting instructions .
-    // 3 - Instructions used outside of the basic block.
     LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
                       << "\n");
     reorderBasedOnTopologicalSort(BB, UsedOutsideOfBBTopologicalSort);
@@ -493,14 +489,12 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
   Visited.insert(Definition);
 
   {
-    // TODO: Do some kind of ordering for instructions that come before the 
-    // result of getFirstNonPHIOrDbgOrAlloca().
     const auto *BasicBlock = Definition->getParent();
     const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
     if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
       return;
     else if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
-      return; 
+      return; // TODO: Do some kind of ordering for these instructions. 
   }
 
   for (auto &Operand : Definition->operands()) {

>From 06cfc2c337c6071f1ca82aac6172dc8cf7fa29e9 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 18:22:17 -0800
Subject: [PATCH 38/40] Revert "Change the output ordering"

This reverts commit b1d6ef875221c1a32481592c3c1d92abc2dd1126.
---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 47 +++++++---------------
 1 file changed, 15 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 045ef08c77ffe0f..8220217cc6fe440 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -77,8 +77,6 @@ class IRNormalizer {
   void reorderDefinition(Instruction *Definition,
       std::stack<Instruction *> &TopologicalSort,
       SmallPtrSet<const Instruction *, 32> &Visited) const;
-  void reorderBasedOnTopologicalSort(BasicBlock &BB, 
-      std::stack<Instruction *> &TopologicalSort) const;
   void reorderInstructionOperandsByNames(Instruction *I) const;
   void reorderPHIIncomingValues(PHINode *PN) const;
   /// @}
@@ -449,35 +447,32 @@ void IRNormalizer::reorderInstructions(Function &F) const {
     // We must iterate from the first to the last instruction otherwise side 
     // effecting instructions could be reordered. 
 
-    SmallPtrSet<const Instruction *, 32> Visited;
     std::stack<Instruction *> TopologicalSort;
+    SmallPtrSet<const Instruction *, 32> Visited;
     for (auto &I : BB) { 
       if (!isOutput(&I) && !I.isTerminator()) 
-        continue; // I is not side effecting. 
-      LLVM_DEBUG(dbgs() << "\tReordering from effecting source instruction: "; 
+        continue; // I is not a source node. 
+      LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 
                  I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
-    std::stack<Instruction *> UsedOutsideOfBBTopologicalSort;
-    for (auto &I : BB) { 
-      if (Visited.contains(&I) || !I.isUsedOutsideOfBlock(I.getParent())) 
-        continue;
-      LLVM_DEBUG(dbgs() << "\tReordering from source instruction that's used in another block: "; I.dump());
-      reorderDefinition(&I, UsedOutsideOfBBTopologicalSort, Visited);
-    }
-
     for (auto &I : BB) { 
       if (Visited.contains(&I)) 
-        continue;
-      LLVM_DEBUG(dbgs() << "\tReordering from dead source instruction: "; I.dump());
+        continue; // I is not a source node. 
+      LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
     LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
                       << "\n");
-    reorderBasedOnTopologicalSort(BB, UsedOutsideOfBBTopologicalSort);
-    reorderBasedOnTopologicalSort(BB, TopologicalSort);
+    // Reorder based on the topological sort. 
+    while (!TopologicalSort.empty()) {
+      auto *Instruction = TopologicalSort.top();
+      auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
+      Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
+        TopologicalSort.pop();
+    }
   }
 }
 
@@ -493,7 +488,7 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
     if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
       return;
-    else if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
+    if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
       return; // TODO: Do some kind of ordering for these instructions. 
   }
 
@@ -505,7 +500,7 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     }
   }
 
-  // Don't reorder certain instructions. 
+  LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
   if (Definition->isTerminator())
     return;
   if (auto *Call = dyn_cast<CallInst>(Definition)) {
@@ -514,22 +509,10 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
     if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize)
       return;
   }
-
-  LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump());
+  // TODO: return on llvm.experimental.deopt...
   TopologicalSort.emplace(Definition);
 }
 
-void IRNormalizer::reorderBasedOnTopologicalSort(BasicBlock &BB, 
-    std::stack<Instruction *> &TopologicalSort) const {
-  // Reorder based on the topological sort. 
-  while (!TopologicalSort.empty()) {
-    auto *Instruction = TopologicalSort.top();
-    auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
-    Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
-      TopologicalSort.pop();
-  }
-}
-
 /// Reorders instruction's operands alphabetically. This method assumes
 /// that passed instruction is commutative. Changing the operand order
 /// in other instructions may change the semantics.

>From 0b8f0317aca31f3798b9e978cd7199f3965c3291 Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 18:30:35 -0800
Subject: [PATCH 39/40] clang-format

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 39 +++++++++++-----------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 8220217cc6fe440..8608e6ff1593e07 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -75,8 +75,8 @@ class IRNormalizer {
   /// @{
   void reorderInstructions(Function &F) const;
   void reorderDefinition(Instruction *Definition,
-      std::stack<Instruction *> &TopologicalSort,
-      SmallPtrSet<const Instruction *, 32> &Visited) const;
+                         std::stack<Instruction *> &TopologicalSort,
+                         SmallPtrSet<const Instruction *, 32> &Visited) const;
   void reorderInstructionOperandsByNames(Instruction *I) const;
   void reorderPHIIncomingValues(PHINode *PN) const;
   /// @}
@@ -441,43 +441,43 @@ void IRNormalizer::foldInstructionName(Instruction *I) const {
 /// \see reorderInstruction()
 void IRNormalizer::reorderInstructions(Function &F) const {
   for (auto &BB : F) {
-    LLVM_DEBUG(dbgs() << "Reordering instructions in basic block: " 
+    LLVM_DEBUG(dbgs() << "Reordering instructions in basic block: "
                       << BB.getName() << "\n");
     // Find the source nodes of the DAG of instructions in this basic block.
-    // We must iterate from the first to the last instruction otherwise side 
-    // effecting instructions could be reordered. 
+    // We must iterate from the first to the last instruction otherwise side
+    // effecting instructions could be reordered.
 
     std::stack<Instruction *> TopologicalSort;
     SmallPtrSet<const Instruction *, 32> Visited;
-    for (auto &I : BB) { 
-      if (!isOutput(&I) && !I.isTerminator()) 
-        continue; // I is not a source node. 
-      LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 
+    for (auto &I : BB) {
+      if (!isOutput(&I) && !I.isTerminator())
+        continue; // I is not a source node.
+      LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: ";
                  I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
-    for (auto &I : BB) { 
-      if (Visited.contains(&I)) 
-        continue; // I is not a source node. 
+    for (auto &I : BB) {
+      if (Visited.contains(&I))
+        continue; // I is not a source node.
       LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump());
       reorderDefinition(&I, TopologicalSort, Visited);
     }
 
-    LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 
+    LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName()
                       << "\n");
-    // Reorder based on the topological sort. 
+    // Reorder based on the topological sort.
     while (!TopologicalSort.empty()) {
       auto *Instruction = TopologicalSort.top();
       auto *FirstNonPHIOrDbgOrAlloca = &*BB.getFirstNonPHIOrDbgOrAlloca();
       Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca);
-        TopologicalSort.pop();
+      TopologicalSort.pop();
     }
   }
 }
 
-void IRNormalizer::reorderDefinition(Instruction *Definition,
-    std::stack<Instruction *> &TopologicalSort,
+void IRNormalizer::reorderDefinition(
+    Instruction *Definition, std::stack<Instruction *> &TopologicalSort,
     SmallPtrSet<const Instruction *, 32> &Visited) const {
   if (Visited.contains(Definition))
     return;
@@ -485,11 +485,12 @@ void IRNormalizer::reorderDefinition(Instruction *Definition,
 
   {
     const auto *BasicBlock = Definition->getParent();
-    const auto FirstNonPHIOrDbgOrAlloca = BasicBlock->getFirstNonPHIOrDbgOrAlloca();
+    const auto FirstNonPHIOrDbgOrAlloca =
+        BasicBlock->getFirstNonPHIOrDbgOrAlloca();
     if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end())
       return;
     if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca))
-      return; // TODO: Do some kind of ordering for these instructions. 
+      return; // TODO: Do some kind of ordering for these instructions.
   }
 
   for (auto &Operand : Definition->operands()) {

>From 5ed67860fc832e6ed76f3125c66be08b2a75558a Mon Sep 17 00:00:00 2001
From: justinfargnoli <justinfargnoli at gmail.com>
Date: Sun, 19 Nov 2023 19:52:35 -0800
Subject: [PATCH 40/40] Don't reorder bitcasts the precede musttail

---
 llvm/lib/Transforms/Utils/IRNormalizer.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/IRNormalizer.cpp b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
index 8608e6ff1593e07..6bbe4106a517fdd 100644
--- a/llvm/lib/Transforms/Utils/IRNormalizer.cpp
+++ b/llvm/lib/Transforms/Utils/IRNormalizer.cpp
@@ -510,7 +510,13 @@ void IRNormalizer::reorderDefinition(
     if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize)
       return;
   }
-  // TODO: return on llvm.experimental.deopt...
+  if (auto *BitCast = dyn_cast<BitCastInst>(Definition)) {
+    if (auto *Call = dyn_cast<CallInst>(BitCast->getOperand(0))) {
+      if (Call->isMustTailCall())
+        return;
+    }
+  }
+
   TopologicalSort.emplace(Definition);
 }
 



More information about the cfe-commits mailing list