12e9f8696SJustin Fargnoli //===--------------- IRNormalizer.cpp - IR Normalizer ---------------===// 22e9f8696SJustin Fargnoli // 32e9f8696SJustin Fargnoli // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42e9f8696SJustin Fargnoli // See https://llvm.org/LICENSE.txt for license information. 52e9f8696SJustin Fargnoli // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62e9f8696SJustin Fargnoli // 72e9f8696SJustin Fargnoli //===----------------------------------------------------------------------===// 82e9f8696SJustin Fargnoli /// \file 92e9f8696SJustin Fargnoli /// This file implements the IRNormalizer class which aims to transform LLVM 102e9f8696SJustin Fargnoli /// Modules into a normal form by reordering and renaming instructions while 112e9f8696SJustin Fargnoli /// preserving the same semantics. The normalizer makes it easier to spot 122e9f8696SJustin Fargnoli /// semantic differences while diffing two modules which have undergone 132e9f8696SJustin Fargnoli /// different passes. 142e9f8696SJustin Fargnoli /// 152e9f8696SJustin Fargnoli //===----------------------------------------------------------------------===// 162e9f8696SJustin Fargnoli 172e9f8696SJustin Fargnoli #include "llvm/Transforms/Utils/IRNormalizer.h" 182e9f8696SJustin Fargnoli #include "llvm/ADT/SetVector.h" 192e9f8696SJustin Fargnoli #include "llvm/ADT/SmallPtrSet.h" 202e9f8696SJustin Fargnoli #include "llvm/ADT/SmallString.h" 212e9f8696SJustin Fargnoli #include "llvm/ADT/SmallVector.h" 222e9f8696SJustin Fargnoli #include "llvm/IR/BasicBlock.h" 232e9f8696SJustin Fargnoli #include "llvm/IR/Function.h" 242e9f8696SJustin Fargnoli #include "llvm/IR/IRBuilder.h" 252e9f8696SJustin Fargnoli #include "llvm/IR/InstIterator.h" 262e9f8696SJustin Fargnoli #include "llvm/IR/Module.h" 272e9f8696SJustin Fargnoli #include "llvm/InitializePasses.h" 282e9f8696SJustin Fargnoli #include "llvm/Pass.h" 292e9f8696SJustin Fargnoli #include "llvm/PassRegistry.h" 302e9f8696SJustin Fargnoli #include "llvm/Support/CommandLine.h" 312e9f8696SJustin Fargnoli #include "llvm/Transforms/Utils.h" 322e9f8696SJustin Fargnoli #include <algorithm> 332e9f8696SJustin Fargnoli #include <stack> 342e9f8696SJustin Fargnoli 352e9f8696SJustin Fargnoli #define DEBUG_TYPE "normalize" 362e9f8696SJustin Fargnoli 372e9f8696SJustin Fargnoli using namespace llvm; 382e9f8696SJustin Fargnoli 392e9f8696SJustin Fargnoli namespace { 402e9f8696SJustin Fargnoli /// IRNormalizer aims to transform LLVM IR into normal form. 412e9f8696SJustin Fargnoli class IRNormalizer { 422e9f8696SJustin Fargnoli public: 432e9f8696SJustin Fargnoli /// \name Normalizer flags. 442e9f8696SJustin Fargnoli /// @{ 452e9f8696SJustin Fargnoli /// Preserves original order of instructions. 462e9f8696SJustin Fargnoli static cl::opt<bool> PreserveOrder; 472e9f8696SJustin Fargnoli /// Renames all instructions (including user-named). 482e9f8696SJustin Fargnoli static cl::opt<bool> RenameAll; // TODO: Don't rename on empty name 492e9f8696SJustin Fargnoli /// Folds all regular instructions (including pre-outputs). 502e9f8696SJustin Fargnoli static cl::opt<bool> FoldPreOutputs; 512e9f8696SJustin Fargnoli /// Sorts and reorders operands in commutative instructions. 522e9f8696SJustin Fargnoli static cl::opt<bool> ReorderOperands; 532e9f8696SJustin Fargnoli /// @} 542e9f8696SJustin Fargnoli 552e9f8696SJustin Fargnoli bool runOnFunction(Function &F); 562e9f8696SJustin Fargnoli 572e9f8696SJustin Fargnoli private: 582e9f8696SJustin Fargnoli // Random constant for hashing, so the state isn't zero. 592e9f8696SJustin Fargnoli const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; 602e9f8696SJustin Fargnoli DenseSet<const Instruction *> NamedInstructions; 612e9f8696SJustin Fargnoli 622e9f8696SJustin Fargnoli SmallVector<Instruction *, 16> Outputs; 632e9f8696SJustin Fargnoli 642e9f8696SJustin Fargnoli /// \name Naming. 652e9f8696SJustin Fargnoli /// @{ 662e9f8696SJustin Fargnoli void nameFunctionArguments(Function &F) const; 672e9f8696SJustin Fargnoli void nameBasicBlocks(Function &F) const; 682e9f8696SJustin Fargnoli void nameInstruction(Instruction *I); 692e9f8696SJustin Fargnoli void nameAsInitialInstruction(Instruction *I) const; 702e9f8696SJustin Fargnoli void nameAsRegularInstruction(Instruction *I); 712e9f8696SJustin Fargnoli void foldInstructionName(Instruction *I) const; 722e9f8696SJustin Fargnoli /// @} 732e9f8696SJustin Fargnoli 742e9f8696SJustin Fargnoli /// \name Reordering. 752e9f8696SJustin Fargnoli /// @{ 762e9f8696SJustin Fargnoli void reorderInstructions(Function &F) const; 772e9f8696SJustin Fargnoli void reorderDefinition(Instruction *Definition, 782e9f8696SJustin Fargnoli std::stack<Instruction *> &TopologicalSort, 792e9f8696SJustin Fargnoli SmallPtrSet<const Instruction *, 32> &Visited) const; 802e9f8696SJustin Fargnoli void reorderInstructionOperandsByNames(Instruction *I) const; 812e9f8696SJustin Fargnoli void reorderPHIIncomingValues(PHINode *Phi) const; 822e9f8696SJustin Fargnoli /// @} 832e9f8696SJustin Fargnoli 842e9f8696SJustin Fargnoli /// \name Utility methods. 852e9f8696SJustin Fargnoli /// @{ 862e9f8696SJustin Fargnoli template <typename T> 872e9f8696SJustin Fargnoli void sortCommutativeOperands(Instruction *I, T &Operands) const; 882e9f8696SJustin Fargnoli SmallVector<Instruction *, 16> collectOutputInstructions(Function &F) const; 892e9f8696SJustin Fargnoli bool isOutput(const Instruction *I) const; 902e9f8696SJustin Fargnoli bool isInitialInstruction(const Instruction *I) const; 912e9f8696SJustin Fargnoli bool hasOnlyImmediateOperands(const Instruction *I) const; 922e9f8696SJustin Fargnoli SetVector<int> 932e9f8696SJustin Fargnoli getOutputFootprint(Instruction *I, 942e9f8696SJustin Fargnoli SmallPtrSet<const Instruction *, 32> &Visited) const; 952e9f8696SJustin Fargnoli /// @} 962e9f8696SJustin Fargnoli }; 972e9f8696SJustin Fargnoli } // namespace 982e9f8696SJustin Fargnoli 992e9f8696SJustin Fargnoli cl::opt<bool> IRNormalizer::PreserveOrder( 1002e9f8696SJustin Fargnoli "norm-preserve-order", cl::Hidden, cl::init(false), 1012e9f8696SJustin Fargnoli cl::desc("Preserves original instruction order")); 1022e9f8696SJustin Fargnoli cl::opt<bool> IRNormalizer::RenameAll( 1032e9f8696SJustin Fargnoli "norm-rename-all", cl::Hidden, cl::init(true), 1042e9f8696SJustin Fargnoli cl::desc("Renames all instructions (including user-named)")); 1052e9f8696SJustin Fargnoli cl::opt<bool> IRNormalizer::FoldPreOutputs( 1062e9f8696SJustin Fargnoli "norm-fold-all", cl::Hidden, cl::init(true), 1072e9f8696SJustin Fargnoli cl::desc("Folds all regular instructions (including pre-outputs)")); 1082e9f8696SJustin Fargnoli cl::opt<bool> IRNormalizer::ReorderOperands( 1092e9f8696SJustin Fargnoli "norm-reorder-operands", cl::Hidden, cl::init(true), 1102e9f8696SJustin Fargnoli cl::desc("Sorts and reorders operands in commutative instructions")); 1112e9f8696SJustin Fargnoli 1122e9f8696SJustin Fargnoli /// Entry method to the IRNormalizer. 1132e9f8696SJustin Fargnoli /// 1142e9f8696SJustin Fargnoli /// \param F Function to normalize. 1152e9f8696SJustin Fargnoli bool IRNormalizer::runOnFunction(Function &F) { 1162e9f8696SJustin Fargnoli nameFunctionArguments(F); 1172e9f8696SJustin Fargnoli nameBasicBlocks(F); 1182e9f8696SJustin Fargnoli 1192e9f8696SJustin Fargnoli Outputs = collectOutputInstructions(F); 1202e9f8696SJustin Fargnoli 1212e9f8696SJustin Fargnoli if (!PreserveOrder) 1222e9f8696SJustin Fargnoli reorderInstructions(F); 1232e9f8696SJustin Fargnoli 1242e9f8696SJustin Fargnoli // TODO: Reorder basic blocks via a topological sort. 1252e9f8696SJustin Fargnoli 1262e9f8696SJustin Fargnoli for (auto &I : Outputs) 1272e9f8696SJustin Fargnoli nameInstruction(I); 1282e9f8696SJustin Fargnoli 1292e9f8696SJustin Fargnoli for (auto &I : instructions(F)) { 1302e9f8696SJustin Fargnoli if (!PreserveOrder) { 1312e9f8696SJustin Fargnoli if (ReorderOperands) 1322e9f8696SJustin Fargnoli reorderInstructionOperandsByNames(&I); 1332e9f8696SJustin Fargnoli 1342e9f8696SJustin Fargnoli if (auto *Phi = dyn_cast<PHINode>(&I)) 1352e9f8696SJustin Fargnoli reorderPHIIncomingValues(Phi); 1362e9f8696SJustin Fargnoli } 1372e9f8696SJustin Fargnoli foldInstructionName(&I); 1382e9f8696SJustin Fargnoli } 1392e9f8696SJustin Fargnoli 1402e9f8696SJustin Fargnoli return true; 1412e9f8696SJustin Fargnoli } 1422e9f8696SJustin Fargnoli 1432e9f8696SJustin Fargnoli /// Numbers arguments. 1442e9f8696SJustin Fargnoli /// 1452e9f8696SJustin Fargnoli /// \param F Function whose arguments will be renamed. 1462e9f8696SJustin Fargnoli void IRNormalizer::nameFunctionArguments(Function &F) const { 1472e9f8696SJustin Fargnoli int ArgumentCounter = 0; 1482e9f8696SJustin Fargnoli for (auto &A : F.args()) { 1492e9f8696SJustin Fargnoli if (RenameAll || A.getName().empty()) { 1502e9f8696SJustin Fargnoli A.setName("a" + Twine(ArgumentCounter)); 1512e9f8696SJustin Fargnoli ArgumentCounter += 1; 1522e9f8696SJustin Fargnoli } 1532e9f8696SJustin Fargnoli } 1542e9f8696SJustin Fargnoli } 1552e9f8696SJustin Fargnoli 1562e9f8696SJustin Fargnoli /// Names basic blocks using a generated hash for each basic block in 1572e9f8696SJustin Fargnoli /// a function considering the opcode and the order of output instructions. 1582e9f8696SJustin Fargnoli /// 1592e9f8696SJustin Fargnoli /// \param F Function containing basic blocks to rename. 1602e9f8696SJustin Fargnoli void IRNormalizer::nameBasicBlocks(Function &F) const { 1612e9f8696SJustin Fargnoli for (auto &B : F) { 1622e9f8696SJustin Fargnoli // Initialize to a magic constant, so the state isn't zero. 1632e9f8696SJustin Fargnoli uint64_t Hash = MagicHashConstant; 1642e9f8696SJustin Fargnoli 1652e9f8696SJustin Fargnoli // Hash considering output instruction opcodes. 1662e9f8696SJustin Fargnoli for (auto &I : B) 1672e9f8696SJustin Fargnoli if (isOutput(&I)) 1682e9f8696SJustin Fargnoli Hash = hashing::detail::hash_16_bytes(Hash, I.getOpcode()); 1692e9f8696SJustin Fargnoli 1702e9f8696SJustin Fargnoli if (RenameAll || B.getName().empty()) { 1712e9f8696SJustin Fargnoli // Name basic block. Substring hash to make diffs more readable. 1722e9f8696SJustin Fargnoli B.setName("bb" + std::to_string(Hash).substr(0, 5)); 1732e9f8696SJustin Fargnoli } 1742e9f8696SJustin Fargnoli } 1752e9f8696SJustin Fargnoli } 1762e9f8696SJustin Fargnoli 1772e9f8696SJustin Fargnoli /// Names instructions graphically (recursive) in accordance with the 1782e9f8696SJustin Fargnoli /// def-use tree, starting from the initial instructions (defs), finishing at 1792e9f8696SJustin Fargnoli /// the output (top-most user) instructions (depth-first). 1802e9f8696SJustin Fargnoli /// 1812e9f8696SJustin Fargnoli /// \param I Instruction to be renamed. 1822e9f8696SJustin Fargnoli void IRNormalizer::nameInstruction(Instruction *I) { 1832e9f8696SJustin Fargnoli // Ensure instructions are not renamed. This is done 1842e9f8696SJustin Fargnoli // to prevent situation where instructions are used 1852e9f8696SJustin Fargnoli // before their definition (in phi nodes) 1862e9f8696SJustin Fargnoli if (NamedInstructions.contains(I)) 1872e9f8696SJustin Fargnoli return; 1882e9f8696SJustin Fargnoli NamedInstructions.insert(I); 1892e9f8696SJustin Fargnoli if (isInitialInstruction(I)) { 1902e9f8696SJustin Fargnoli nameAsInitialInstruction(I); 1912e9f8696SJustin Fargnoli } else { 1922e9f8696SJustin Fargnoli // This must be a regular instruction. 1932e9f8696SJustin Fargnoli nameAsRegularInstruction(I); 1942e9f8696SJustin Fargnoli } 1952e9f8696SJustin Fargnoli } 1962e9f8696SJustin Fargnoli 1972e9f8696SJustin Fargnoli template <typename T> 1982e9f8696SJustin Fargnoli void IRNormalizer::sortCommutativeOperands(Instruction *I, T &Operands) const { 1992e9f8696SJustin Fargnoli if (!(I->isCommutative() && Operands.size() >= 2)) 2002e9f8696SJustin Fargnoli return; 2012e9f8696SJustin Fargnoli auto CommutativeEnd = Operands.begin(); 2022e9f8696SJustin Fargnoli std::advance(CommutativeEnd, 2); 2032e9f8696SJustin Fargnoli llvm::sort(Operands.begin(), CommutativeEnd); 2042e9f8696SJustin Fargnoli } 2052e9f8696SJustin Fargnoli 2062e9f8696SJustin Fargnoli /// Names instruction following the scheme: 2072e9f8696SJustin Fargnoli /// vl00000Callee(Operands) 2082e9f8696SJustin Fargnoli /// 2092e9f8696SJustin Fargnoli /// Where 00000 is a hash calculated considering instruction's opcode and output 2102e9f8696SJustin Fargnoli /// footprint. Callee's name is only included when instruction's type is 2112e9f8696SJustin Fargnoli /// CallInst. In cases where instruction is commutative, operands list is also 2122e9f8696SJustin Fargnoli /// sorted. 2132e9f8696SJustin Fargnoli /// 2142e9f8696SJustin Fargnoli /// Renames instruction only when RenameAll flag is raised or instruction is 2152e9f8696SJustin Fargnoli /// unnamed. 2162e9f8696SJustin Fargnoli /// 2172e9f8696SJustin Fargnoli /// \see getOutputFootprint() 2182e9f8696SJustin Fargnoli /// \param I Instruction to be renamed. 2192e9f8696SJustin Fargnoli void IRNormalizer::nameAsInitialInstruction(Instruction *I) const { 2202e9f8696SJustin Fargnoli if (I->getType()->isVoidTy()) 2212e9f8696SJustin Fargnoli return; 2222e9f8696SJustin Fargnoli if (!(I->getName().empty() || RenameAll)) 2232e9f8696SJustin Fargnoli return; 2242e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "Naming initial instruction: " << *I << "\n"); 2252e9f8696SJustin Fargnoli 2262e9f8696SJustin Fargnoli // Instruction operands for further sorting. 2272e9f8696SJustin Fargnoli SmallVector<SmallString<64>, 4> Operands; 2282e9f8696SJustin Fargnoli 2292e9f8696SJustin Fargnoli // Collect operands. 2302e9f8696SJustin Fargnoli for (auto &Op : I->operands()) { 2312e9f8696SJustin Fargnoli if (!isa<Function>(Op)) { 2322e9f8696SJustin Fargnoli std::string TextRepresentation; 2332e9f8696SJustin Fargnoli raw_string_ostream Stream(TextRepresentation); 2342e9f8696SJustin Fargnoli Op->printAsOperand(Stream, false); 2352e9f8696SJustin Fargnoli Operands.push_back(StringRef(Stream.str())); 2362e9f8696SJustin Fargnoli } 2372e9f8696SJustin Fargnoli } 2382e9f8696SJustin Fargnoli 2392e9f8696SJustin Fargnoli sortCommutativeOperands(I, Operands); 2402e9f8696SJustin Fargnoli 2412e9f8696SJustin Fargnoli // Initialize to a magic constant, so the state isn't zero. 2422e9f8696SJustin Fargnoli uint64_t Hash = MagicHashConstant; 2432e9f8696SJustin Fargnoli 2442e9f8696SJustin Fargnoli // Consider instruction's opcode in the hash. 2452e9f8696SJustin Fargnoli Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode()); 2462e9f8696SJustin Fargnoli 2472e9f8696SJustin Fargnoli SmallPtrSet<const Instruction *, 32> Visited; 2482e9f8696SJustin Fargnoli // Get output footprint for I. 2492e9f8696SJustin Fargnoli SetVector<int> OutputFootprint = getOutputFootprint(I, Visited); 2502e9f8696SJustin Fargnoli 2512e9f8696SJustin Fargnoli // Consider output footprint in the hash. 2522e9f8696SJustin Fargnoli for (const int &Output : OutputFootprint) 2532e9f8696SJustin Fargnoli Hash = hashing::detail::hash_16_bytes(Hash, Output); 2542e9f8696SJustin Fargnoli 2552e9f8696SJustin Fargnoli // Base instruction name. 2562e9f8696SJustin Fargnoli SmallString<256> Name; 2572e9f8696SJustin Fargnoli Name.append("vl" + std::to_string(Hash).substr(0, 5)); 2582e9f8696SJustin Fargnoli 2592e9f8696SJustin Fargnoli // In case of CallInst, consider callee in the instruction name. 2602e9f8696SJustin Fargnoli if (const auto *CI = dyn_cast<CallInst>(I)) { 2612e9f8696SJustin Fargnoli Function *F = CI->getCalledFunction(); 2622e9f8696SJustin Fargnoli 2632e9f8696SJustin Fargnoli if (F != nullptr) 2642e9f8696SJustin Fargnoli Name.append(F->getName()); 2652e9f8696SJustin Fargnoli } 2662e9f8696SJustin Fargnoli 2672e9f8696SJustin Fargnoli Name.append("("); 2682e9f8696SJustin Fargnoli for (size_t i = 0; i < Operands.size(); ++i) { 2692e9f8696SJustin Fargnoli Name.append(Operands[i]); 2702e9f8696SJustin Fargnoli 2712e9f8696SJustin Fargnoli if (i < Operands.size() - 1) 2722e9f8696SJustin Fargnoli Name.append(", "); 2732e9f8696SJustin Fargnoli } 2742e9f8696SJustin Fargnoli Name.append(")"); 2752e9f8696SJustin Fargnoli 2762e9f8696SJustin Fargnoli I->setName(Name); 2772e9f8696SJustin Fargnoli } 2782e9f8696SJustin Fargnoli 2792e9f8696SJustin Fargnoli /// Names instruction following the scheme: 2802e9f8696SJustin Fargnoli /// op00000Callee(Operands) 2812e9f8696SJustin Fargnoli /// 2822e9f8696SJustin Fargnoli /// Where 00000 is a hash calculated considering instruction's opcode, its 2832e9f8696SJustin Fargnoli /// operands' opcodes and order. Callee's name is only included when 2842e9f8696SJustin Fargnoli /// instruction's type is CallInst. In cases where instruction is commutative, 2852e9f8696SJustin Fargnoli /// operand list is also sorted. 2862e9f8696SJustin Fargnoli /// 2872e9f8696SJustin Fargnoli /// Names instructions recursively in accordance with the def-use tree, 2882e9f8696SJustin Fargnoli /// starting from the initial instructions (defs), finishing at 2892e9f8696SJustin Fargnoli /// the output (top-most user) instructions (depth-first). 2902e9f8696SJustin Fargnoli /// 2912e9f8696SJustin Fargnoli /// Renames instruction only when RenameAll flag is raised or instruction is 2922e9f8696SJustin Fargnoli /// unnamed. 2932e9f8696SJustin Fargnoli /// 2942e9f8696SJustin Fargnoli /// \see getOutputFootprint() 2952e9f8696SJustin Fargnoli /// \param I Instruction to be renamed. 2962e9f8696SJustin Fargnoli void IRNormalizer::nameAsRegularInstruction(Instruction *I) { 2972e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "Naming regular instruction: " << *I << "\n"); 2982e9f8696SJustin Fargnoli 2992e9f8696SJustin Fargnoli // Instruction operands for further sorting. 3002e9f8696SJustin Fargnoli SmallVector<SmallString<128>, 4> Operands; 3012e9f8696SJustin Fargnoli 3022e9f8696SJustin Fargnoli // The name of a regular instruction depends 3032e9f8696SJustin Fargnoli // on the names of its operands. Hence, all 3042e9f8696SJustin Fargnoli // operands must be named first in the use-def 3052e9f8696SJustin Fargnoli // walk. 3062e9f8696SJustin Fargnoli 3072e9f8696SJustin Fargnoli // Collect operands. 3082e9f8696SJustin Fargnoli for (auto &Op : I->operands()) { 3092e9f8696SJustin Fargnoli if (auto *I = dyn_cast<Instruction>(Op)) { 3102e9f8696SJustin Fargnoli // Walk down the use-def chain. 3112e9f8696SJustin Fargnoli nameInstruction(I); 3122e9f8696SJustin Fargnoli Operands.push_back(I->getName()); 3132e9f8696SJustin Fargnoli } else if (!isa<Function>(Op)) { 3142e9f8696SJustin Fargnoli // This must be an immediate value. 3152e9f8696SJustin Fargnoli std::string TextRepresentation; 3162e9f8696SJustin Fargnoli raw_string_ostream Stream(TextRepresentation); 3172e9f8696SJustin Fargnoli Op->printAsOperand(Stream, false); 3182e9f8696SJustin Fargnoli Operands.push_back(StringRef(Stream.str())); 3192e9f8696SJustin Fargnoli } 3202e9f8696SJustin Fargnoli } 3212e9f8696SJustin Fargnoli 3222e9f8696SJustin Fargnoli sortCommutativeOperands(I, Operands); 3232e9f8696SJustin Fargnoli 3242e9f8696SJustin Fargnoli // Initialize to a magic constant, so the state isn't zero. 3252e9f8696SJustin Fargnoli uint64_t Hash = MagicHashConstant; 3262e9f8696SJustin Fargnoli 3272e9f8696SJustin Fargnoli // Consider instruction opcode in the hash. 3282e9f8696SJustin Fargnoli Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode()); 3292e9f8696SJustin Fargnoli 3302e9f8696SJustin Fargnoli // Operand opcodes for further sorting (commutative). 3312e9f8696SJustin Fargnoli SmallVector<int, 4> OperandsOpcodes; 3322e9f8696SJustin Fargnoli 3332e9f8696SJustin Fargnoli // Collect operand opcodes for hashing. 3342e9f8696SJustin Fargnoli for (auto &Op : I->operands()) 3352e9f8696SJustin Fargnoli if (auto *I = dyn_cast<Instruction>(Op)) 3362e9f8696SJustin Fargnoli OperandsOpcodes.push_back(I->getOpcode()); 3372e9f8696SJustin Fargnoli 3382e9f8696SJustin Fargnoli sortCommutativeOperands(I, OperandsOpcodes); 3392e9f8696SJustin Fargnoli 3402e9f8696SJustin Fargnoli // Consider operand opcodes in the hash. 3412e9f8696SJustin Fargnoli for (const int Code : OperandsOpcodes) 3422e9f8696SJustin Fargnoli Hash = hashing::detail::hash_16_bytes(Hash, Code); 3432e9f8696SJustin Fargnoli 3442e9f8696SJustin Fargnoli // Base instruction name. 3452e9f8696SJustin Fargnoli SmallString<512> Name; 3462e9f8696SJustin Fargnoli Name.append("op" + std::to_string(Hash).substr(0, 5)); 3472e9f8696SJustin Fargnoli 3482e9f8696SJustin Fargnoli // In case of CallInst, consider callee in the instruction name. 3492e9f8696SJustin Fargnoli if (const auto *CI = dyn_cast<CallInst>(I)) 3502e9f8696SJustin Fargnoli if (const Function *F = CI->getCalledFunction()) 3512e9f8696SJustin Fargnoli Name.append(F->getName()); 3522e9f8696SJustin Fargnoli 3532e9f8696SJustin Fargnoli Name.append("("); 3542e9f8696SJustin Fargnoli for (size_t i = 0; i < Operands.size(); ++i) { 3552e9f8696SJustin Fargnoli Name.append(Operands[i]); 3562e9f8696SJustin Fargnoli 3572e9f8696SJustin Fargnoli if (i < Operands.size() - 1) 3582e9f8696SJustin Fargnoli Name.append(", "); 3592e9f8696SJustin Fargnoli } 3602e9f8696SJustin Fargnoli Name.append(")"); 3612e9f8696SJustin Fargnoli 3622e9f8696SJustin Fargnoli if ((I->getName().empty() || RenameAll) && !I->getType()->isVoidTy()) 3632e9f8696SJustin Fargnoli I->setName(Name); 3642e9f8696SJustin Fargnoli } 3652e9f8696SJustin Fargnoli 3662e9f8696SJustin Fargnoli /// Shortens instruction's name. This method removes called function name from 3672e9f8696SJustin Fargnoli /// the instruction name and substitutes the call chain with a corresponding 3682e9f8696SJustin Fargnoli /// list of operands. 3692e9f8696SJustin Fargnoli /// 3702e9f8696SJustin Fargnoli /// Examples: 3712e9f8696SJustin Fargnoli /// op00000Callee(op00001Callee(...), vl00000Callee(1, 2), ...) -> 3722e9f8696SJustin Fargnoli /// op00000(op00001, vl00000, ...) vl00000Callee(1, 2) -> vl00000(1, 2) 3732e9f8696SJustin Fargnoli /// 3742e9f8696SJustin Fargnoli /// This method omits output instructions and pre-output (instructions directly 3752e9f8696SJustin Fargnoli /// used by an output instruction) instructions (by default). By default it also 3762e9f8696SJustin Fargnoli /// does not affect user named instructions. 3772e9f8696SJustin Fargnoli /// 3782e9f8696SJustin Fargnoli /// \param I Instruction whose name will be folded. 3792e9f8696SJustin Fargnoli void IRNormalizer::foldInstructionName(Instruction *I) const { 3802e9f8696SJustin Fargnoli // If this flag is raised, fold all regular 3812e9f8696SJustin Fargnoli // instructions (including pre-outputs). 3822e9f8696SJustin Fargnoli if (!FoldPreOutputs) { 3832e9f8696SJustin Fargnoli // Don't fold if one of the users is an output instruction. 3842e9f8696SJustin Fargnoli for (auto *U : I->users()) 3852e9f8696SJustin Fargnoli if (auto *IU = dyn_cast<Instruction>(U)) 3862e9f8696SJustin Fargnoli if (isOutput(IU)) 3872e9f8696SJustin Fargnoli return; 3882e9f8696SJustin Fargnoli } 3892e9f8696SJustin Fargnoli 3902e9f8696SJustin Fargnoli // Don't fold if it is an output instruction or has no op prefix. 3912e9f8696SJustin Fargnoli if (isOutput(I) || I->getName().substr(0, 2) != "op") 3922e9f8696SJustin Fargnoli return; 3932e9f8696SJustin Fargnoli 3942e9f8696SJustin Fargnoli // Instruction operands. 3952e9f8696SJustin Fargnoli SmallVector<SmallString<64>, 4> Operands; 3962e9f8696SJustin Fargnoli 3972e9f8696SJustin Fargnoli for (auto &Op : I->operands()) { 3982e9f8696SJustin Fargnoli if (const auto *I = dyn_cast<Instruction>(Op)) { 3992e9f8696SJustin Fargnoli bool HasNormalName = I->getName().substr(0, 2) == "op" || 4002e9f8696SJustin Fargnoli I->getName().substr(0, 2) == "vl"; 4012e9f8696SJustin Fargnoli 4022e9f8696SJustin Fargnoli Operands.push_back(HasNormalName ? I->getName().substr(0, 7) 4032e9f8696SJustin Fargnoli : I->getName()); 4042e9f8696SJustin Fargnoli } 4052e9f8696SJustin Fargnoli } 4062e9f8696SJustin Fargnoli 4072e9f8696SJustin Fargnoli sortCommutativeOperands(I, Operands); 4082e9f8696SJustin Fargnoli 4092e9f8696SJustin Fargnoli SmallString<256> Name; 4102e9f8696SJustin Fargnoli Name.append(I->getName().substr(0, 7)); 4112e9f8696SJustin Fargnoli 4122e9f8696SJustin Fargnoli Name.append("("); 4132e9f8696SJustin Fargnoli for (size_t i = 0; i < Operands.size(); ++i) { 4142e9f8696SJustin Fargnoli Name.append(Operands[i]); 4152e9f8696SJustin Fargnoli 4162e9f8696SJustin Fargnoli if (i < Operands.size() - 1) 4172e9f8696SJustin Fargnoli Name.append(", "); 4182e9f8696SJustin Fargnoli } 4192e9f8696SJustin Fargnoli Name.append(")"); 4202e9f8696SJustin Fargnoli 4212e9f8696SJustin Fargnoli I->setName(Name); 4222e9f8696SJustin Fargnoli } 4232e9f8696SJustin Fargnoli 4242e9f8696SJustin Fargnoli /// Reorders instructions by walking up the tree from each operand of an output 4252e9f8696SJustin Fargnoli /// instruction and reducing the def-use distance. 4262e9f8696SJustin Fargnoli /// This method assumes that output instructions were collected top-down, 4272e9f8696SJustin Fargnoli /// otherwise the def-use chain may be broken. 4282e9f8696SJustin Fargnoli /// This method is a wrapper for recursive reorderInstruction(). 4292e9f8696SJustin Fargnoli /// 4302e9f8696SJustin Fargnoli /// \see reorderInstruction() 4312e9f8696SJustin Fargnoli void IRNormalizer::reorderInstructions(Function &F) const { 4322e9f8696SJustin Fargnoli for (auto &BB : F) { 4332e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "Reordering instructions in basic block: " 4342e9f8696SJustin Fargnoli << BB.getName() << "\n"); 4352e9f8696SJustin Fargnoli // Find the source nodes of the DAG of instructions in this basic block. 4362e9f8696SJustin Fargnoli // Source nodes are instructions that have side effects, are terminators, or 4372e9f8696SJustin Fargnoli // don't have a parent in the DAG of instructions. 4382e9f8696SJustin Fargnoli // 4392e9f8696SJustin Fargnoli // We must iterate from the first to the last instruction otherwise side 4402e9f8696SJustin Fargnoli // effecting instructions could be reordered. 4412e9f8696SJustin Fargnoli 4422e9f8696SJustin Fargnoli std::stack<Instruction *> TopologicalSort; 4432e9f8696SJustin Fargnoli SmallPtrSet<const Instruction *, 32> Visited; 4442e9f8696SJustin Fargnoli for (auto &I : BB) { 4452e9f8696SJustin Fargnoli // First process side effecting and terminating instructions. 4462e9f8696SJustin Fargnoli if (!(isOutput(&I) || I.isTerminator())) 4472e9f8696SJustin Fargnoli continue; 4482e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 4492e9f8696SJustin Fargnoli I.dump()); 4502e9f8696SJustin Fargnoli reorderDefinition(&I, TopologicalSort, Visited); 4512e9f8696SJustin Fargnoli } 4522e9f8696SJustin Fargnoli 4532e9f8696SJustin Fargnoli for (auto &I : BB) { 4542e9f8696SJustin Fargnoli // Process the remaining instructions. 4552e9f8696SJustin Fargnoli // 4562e9f8696SJustin Fargnoli // TODO: Do more a intelligent sorting of these instructions. For example, 4572e9f8696SJustin Fargnoli // seperate between dead instructinos and instructions used in another 4582e9f8696SJustin Fargnoli // block. Use properties of the CFG the order instructions that are used 4592e9f8696SJustin Fargnoli // in another block. 4602e9f8696SJustin Fargnoli if (Visited.contains(&I)) 4612e9f8696SJustin Fargnoli continue; 4622e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump()); 4632e9f8696SJustin Fargnoli reorderDefinition(&I, TopologicalSort, Visited); 4642e9f8696SJustin Fargnoli } 4652e9f8696SJustin Fargnoli 4662e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 4672e9f8696SJustin Fargnoli << "\n"); 4682e9f8696SJustin Fargnoli // Reorder based on the topological sort. 4692e9f8696SJustin Fargnoli while (!TopologicalSort.empty()) { 4702e9f8696SJustin Fargnoli auto *Instruction = TopologicalSort.top(); 4712e9f8696SJustin Fargnoli auto FirstNonPHIOrDbgOrAlloca = BB.getFirstNonPHIOrDbgOrAlloca(); 4722e9f8696SJustin Fargnoli if (auto *Call = dyn_cast<CallInst>(&*FirstNonPHIOrDbgOrAlloca)) { 4732e9f8696SJustin Fargnoli if (Call->getIntrinsicID() == 4742e9f8696SJustin Fargnoli Intrinsic::experimental_convergence_entry || 4752e9f8696SJustin Fargnoli Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop) 4762e9f8696SJustin Fargnoli FirstNonPHIOrDbgOrAlloca++; 4772e9f8696SJustin Fargnoli } 478*81d18ad8SJeremy Morse Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca); 4792e9f8696SJustin Fargnoli TopologicalSort.pop(); 4802e9f8696SJustin Fargnoli } 4812e9f8696SJustin Fargnoli } 4822e9f8696SJustin Fargnoli } 4832e9f8696SJustin Fargnoli 4842e9f8696SJustin Fargnoli void IRNormalizer::reorderDefinition( 4852e9f8696SJustin Fargnoli Instruction *Definition, std::stack<Instruction *> &TopologicalSort, 4862e9f8696SJustin Fargnoli SmallPtrSet<const Instruction *, 32> &Visited) const { 4872e9f8696SJustin Fargnoli if (Visited.contains(Definition)) 4882e9f8696SJustin Fargnoli return; 4892e9f8696SJustin Fargnoli Visited.insert(Definition); 4902e9f8696SJustin Fargnoli 4912e9f8696SJustin Fargnoli { 4922e9f8696SJustin Fargnoli const auto *BasicBlock = Definition->getParent(); 4932e9f8696SJustin Fargnoli const auto FirstNonPHIOrDbgOrAlloca = 4942e9f8696SJustin Fargnoli BasicBlock->getFirstNonPHIOrDbgOrAlloca(); 4952e9f8696SJustin Fargnoli if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end()) 4962e9f8696SJustin Fargnoli return; // TODO: Is this necessary? 4972e9f8696SJustin Fargnoli if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca)) 4982e9f8696SJustin Fargnoli return; // TODO: Do some kind of ordering for these instructions. 4992e9f8696SJustin Fargnoli } 5002e9f8696SJustin Fargnoli 5012e9f8696SJustin Fargnoli for (auto &Operand : Definition->operands()) { 5022e9f8696SJustin Fargnoli if (auto *Op = dyn_cast<Instruction>(Operand)) { 5032e9f8696SJustin Fargnoli if (Op->getParent() != Definition->getParent()) 5042e9f8696SJustin Fargnoli continue; // Only reorder instruction within the same basic block 5052e9f8696SJustin Fargnoli reorderDefinition(Op, TopologicalSort, Visited); 5062e9f8696SJustin Fargnoli } 5072e9f8696SJustin Fargnoli } 5082e9f8696SJustin Fargnoli 5092e9f8696SJustin Fargnoli LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump()); 5102e9f8696SJustin Fargnoli if (Definition->isTerminator()) 5112e9f8696SJustin Fargnoli return; 5122e9f8696SJustin Fargnoli if (auto *Call = dyn_cast<CallInst>(Definition)) { 5132e9f8696SJustin Fargnoli if (Call->isMustTailCall()) 5142e9f8696SJustin Fargnoli return; 5152e9f8696SJustin Fargnoli if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize) 5162e9f8696SJustin Fargnoli return; 5172e9f8696SJustin Fargnoli if (Call->getIntrinsicID() == Intrinsic::experimental_convergence_entry) 5182e9f8696SJustin Fargnoli return; 5192e9f8696SJustin Fargnoli if (Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop) 5202e9f8696SJustin Fargnoli return; 5212e9f8696SJustin Fargnoli } 5222e9f8696SJustin Fargnoli if (auto *BitCast = dyn_cast<BitCastInst>(Definition)) { 5232e9f8696SJustin Fargnoli if (auto *Call = dyn_cast<CallInst>(BitCast->getOperand(0))) { 5242e9f8696SJustin Fargnoli if (Call->isMustTailCall()) 5252e9f8696SJustin Fargnoli return; 5262e9f8696SJustin Fargnoli } 5272e9f8696SJustin Fargnoli } 5282e9f8696SJustin Fargnoli 5292e9f8696SJustin Fargnoli TopologicalSort.emplace(Definition); 5302e9f8696SJustin Fargnoli } 5312e9f8696SJustin Fargnoli 5322e9f8696SJustin Fargnoli /// Reorders instruction's operands alphabetically. This method assumes 5332e9f8696SJustin Fargnoli /// that passed instruction is commutative. Changing the operand order 5342e9f8696SJustin Fargnoli /// in other instructions may change the semantics. 5352e9f8696SJustin Fargnoli /// 5362e9f8696SJustin Fargnoli /// \param I Instruction whose operands will be reordered. 5372e9f8696SJustin Fargnoli void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) const { 5382e9f8696SJustin Fargnoli // This method assumes that passed I is commutative, 5392e9f8696SJustin Fargnoli // changing the order of operands in other instructions 5402e9f8696SJustin Fargnoli // may change the semantics. 5412e9f8696SJustin Fargnoli 5422e9f8696SJustin Fargnoli // Instruction operands for further sorting. 5432e9f8696SJustin Fargnoli SmallVector<std::pair<std::string, Value *>, 4> Operands; 5442e9f8696SJustin Fargnoli 5452e9f8696SJustin Fargnoli // Collect operands. 5462e9f8696SJustin Fargnoli for (auto &Op : I->operands()) { 5472e9f8696SJustin Fargnoli if (auto *V = dyn_cast<Value>(Op)) { 5482e9f8696SJustin Fargnoli if (isa<Instruction>(V)) { 5492e9f8696SJustin Fargnoli // This is an an instruction. 5502e9f8696SJustin Fargnoli Operands.push_back(std::pair<std::string, Value *>(V->getName(), V)); 5512e9f8696SJustin Fargnoli } else { 5522e9f8696SJustin Fargnoli std::string TextRepresentation; 5532e9f8696SJustin Fargnoli raw_string_ostream Stream(TextRepresentation); 5542e9f8696SJustin Fargnoli Op->printAsOperand(Stream, false); 5552e9f8696SJustin Fargnoli Operands.push_back(std::pair<std::string, Value *>(Stream.str(), V)); 5562e9f8696SJustin Fargnoli } 5572e9f8696SJustin Fargnoli } 5582e9f8696SJustin Fargnoli } 5592e9f8696SJustin Fargnoli 5602e9f8696SJustin Fargnoli // Sort operands. 5612e9f8696SJustin Fargnoli sortCommutativeOperands(I, Operands); 5622e9f8696SJustin Fargnoli 5632e9f8696SJustin Fargnoli // Reorder operands. 5642e9f8696SJustin Fargnoli unsigned Position = 0; 5652e9f8696SJustin Fargnoli for (auto &Op : I->operands()) { 5662e9f8696SJustin Fargnoli Op.set(Operands[Position].second); 5672e9f8696SJustin Fargnoli Position += 1; 5682e9f8696SJustin Fargnoli } 5692e9f8696SJustin Fargnoli } 5702e9f8696SJustin Fargnoli 5712e9f8696SJustin Fargnoli /// Reorders PHI node's values according to the names of corresponding basic 5722e9f8696SJustin Fargnoli /// blocks. 5732e9f8696SJustin Fargnoli /// 5742e9f8696SJustin Fargnoli /// \param Phi PHI node to normalize. 5752e9f8696SJustin Fargnoli void IRNormalizer::reorderPHIIncomingValues(PHINode *Phi) const { 5762e9f8696SJustin Fargnoli // Values for further sorting. 5772e9f8696SJustin Fargnoli SmallVector<std::pair<Value *, BasicBlock *>, 2> Values; 5782e9f8696SJustin Fargnoli 5792e9f8696SJustin Fargnoli // Collect blocks and corresponding values. 5802e9f8696SJustin Fargnoli for (auto &BB : Phi->blocks()) { 5812e9f8696SJustin Fargnoli Value *V = Phi->getIncomingValueForBlock(BB); 5822e9f8696SJustin Fargnoli Values.push_back(std::pair<Value *, BasicBlock *>(V, BB)); 5832e9f8696SJustin Fargnoli } 5842e9f8696SJustin Fargnoli 5852e9f8696SJustin Fargnoli // Sort values according to the name of a basic block. 5862e9f8696SJustin Fargnoli llvm::sort(Values, [](const std::pair<Value *, BasicBlock *> &LHS, 5872e9f8696SJustin Fargnoli const std::pair<Value *, BasicBlock *> &RHS) { 5882e9f8696SJustin Fargnoli return LHS.second->getName() < RHS.second->getName(); 5892e9f8696SJustin Fargnoli }); 5902e9f8696SJustin Fargnoli 5912e9f8696SJustin Fargnoli // Swap. 5922e9f8696SJustin Fargnoli for (unsigned i = 0; i < Values.size(); ++i) { 5932e9f8696SJustin Fargnoli Phi->setIncomingBlock(i, Values[i].second); 5942e9f8696SJustin Fargnoli Phi->setIncomingValue(i, Values[i].first); 5952e9f8696SJustin Fargnoli } 5962e9f8696SJustin Fargnoli } 5972e9f8696SJustin Fargnoli 5982e9f8696SJustin Fargnoli /// Returns a vector of output instructions. An output is an instruction which 5992e9f8696SJustin Fargnoli /// has side-effects or is ReturnInst. Uses isOutput(). 6002e9f8696SJustin Fargnoli /// 6012e9f8696SJustin Fargnoli /// \see isOutput() 6022e9f8696SJustin Fargnoli /// \param F Function to collect outputs from. 6032e9f8696SJustin Fargnoli SmallVector<Instruction *, 16> 6042e9f8696SJustin Fargnoli IRNormalizer::collectOutputInstructions(Function &F) const { 6052e9f8696SJustin Fargnoli // Output instructions are collected top-down in each function, 6062e9f8696SJustin Fargnoli // any change may break the def-use chain in reordering methods. 6072e9f8696SJustin Fargnoli SmallVector<Instruction *, 16> Outputs; 6082e9f8696SJustin Fargnoli for (auto &I : instructions(F)) 6092e9f8696SJustin Fargnoli if (isOutput(&I)) 6102e9f8696SJustin Fargnoli Outputs.push_back(&I); 6112e9f8696SJustin Fargnoli return Outputs; 6122e9f8696SJustin Fargnoli } 6132e9f8696SJustin Fargnoli 6142e9f8696SJustin Fargnoli /// Helper method checking whether the instruction may have side effects or is 6152e9f8696SJustin Fargnoli /// ReturnInst. 6162e9f8696SJustin Fargnoli /// 6172e9f8696SJustin Fargnoli /// \param I Considered instruction. 6182e9f8696SJustin Fargnoli bool IRNormalizer::isOutput(const Instruction *I) const { 6192e9f8696SJustin Fargnoli // Outputs are such instructions which may have side effects or is ReturnInst. 6202e9f8696SJustin Fargnoli return I->mayHaveSideEffects() || isa<ReturnInst>(I); 6212e9f8696SJustin Fargnoli } 6222e9f8696SJustin Fargnoli 6232e9f8696SJustin Fargnoli /// Helper method checking whether the instruction has users and only 6242e9f8696SJustin Fargnoli /// immediate operands. 6252e9f8696SJustin Fargnoli /// 6262e9f8696SJustin Fargnoli /// \param I Considered instruction. 6272e9f8696SJustin Fargnoli bool IRNormalizer::isInitialInstruction(const Instruction *I) const { 6282e9f8696SJustin Fargnoli // Initial instructions are such instructions whose values are used by 6292e9f8696SJustin Fargnoli // other instructions, yet they only depend on immediate values. 6302e9f8696SJustin Fargnoli return !I->user_empty() && hasOnlyImmediateOperands(I); 6312e9f8696SJustin Fargnoli } 6322e9f8696SJustin Fargnoli 6332e9f8696SJustin Fargnoli /// Helper method checking whether the instruction has only immediate operands. 6342e9f8696SJustin Fargnoli /// 6352e9f8696SJustin Fargnoli /// \param I Considered instruction. 6362e9f8696SJustin Fargnoli bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) const { 6372e9f8696SJustin Fargnoli for (const auto &Op : I->operands()) 6382e9f8696SJustin Fargnoli if (isa<Instruction>(Op)) 6392e9f8696SJustin Fargnoli return false; // Found non-immediate operand (instruction). 6402e9f8696SJustin Fargnoli return true; 6412e9f8696SJustin Fargnoli } 6422e9f8696SJustin Fargnoli 6432e9f8696SJustin Fargnoli /// Helper method returning indices (distance from the beginning of the basic 6442e9f8696SJustin Fargnoli /// block) of outputs using the \p I (eliminates repetitions). Walks down the 6452e9f8696SJustin Fargnoli /// def-use tree recursively. 6462e9f8696SJustin Fargnoli /// 6472e9f8696SJustin Fargnoli /// \param I Considered instruction. 6482e9f8696SJustin Fargnoli /// \param Visited Set of visited instructions. 6492e9f8696SJustin Fargnoli SetVector<int> IRNormalizer::getOutputFootprint( 6502e9f8696SJustin Fargnoli Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) const { 6512e9f8696SJustin Fargnoli 6522e9f8696SJustin Fargnoli // Vector containing indexes of outputs (no repetitions), 6532e9f8696SJustin Fargnoli // which use I in the order of walking down the def-use tree. 6542e9f8696SJustin Fargnoli SetVector<int> Outputs; 6552e9f8696SJustin Fargnoli 6562e9f8696SJustin Fargnoli if (!Visited.count(I)) { 6572e9f8696SJustin Fargnoli Visited.insert(I); 6582e9f8696SJustin Fargnoli 6592e9f8696SJustin Fargnoli if (isOutput(I)) { 6602e9f8696SJustin Fargnoli // Gets output instruction's parent function. 6612e9f8696SJustin Fargnoli Function *Func = I->getParent()->getParent(); 6622e9f8696SJustin Fargnoli 6632e9f8696SJustin Fargnoli // Finds and inserts the index of the output to the vector. 6642e9f8696SJustin Fargnoli unsigned Count = 0; 6652e9f8696SJustin Fargnoli for (const auto &B : *Func) { 6662e9f8696SJustin Fargnoli for (const auto &E : B) { 6672e9f8696SJustin Fargnoli if (&E == I) 6682e9f8696SJustin Fargnoli Outputs.insert(Count); 6692e9f8696SJustin Fargnoli Count += 1; 6702e9f8696SJustin Fargnoli } 6712e9f8696SJustin Fargnoli } 6722e9f8696SJustin Fargnoli 6732e9f8696SJustin Fargnoli // Returns to the used instruction. 6742e9f8696SJustin Fargnoli return Outputs; 6752e9f8696SJustin Fargnoli } 6762e9f8696SJustin Fargnoli 6772e9f8696SJustin Fargnoli for (auto *U : I->users()) { 6782e9f8696SJustin Fargnoli if (auto *UI = dyn_cast<Instruction>(U)) { 6792e9f8696SJustin Fargnoli // Vector for outputs which use UI. 6802e9f8696SJustin Fargnoli SetVector<int> OutputsUsingUI = getOutputFootprint(UI, Visited); 6812e9f8696SJustin Fargnoli // Insert the indexes of outputs using UI. 6822e9f8696SJustin Fargnoli Outputs.insert(OutputsUsingUI.begin(), OutputsUsingUI.end()); 6832e9f8696SJustin Fargnoli } 6842e9f8696SJustin Fargnoli } 6852e9f8696SJustin Fargnoli } 6862e9f8696SJustin Fargnoli 6872e9f8696SJustin Fargnoli // Return to the used instruction. 6882e9f8696SJustin Fargnoli return Outputs; 6892e9f8696SJustin Fargnoli } 6902e9f8696SJustin Fargnoli 6912e9f8696SJustin Fargnoli PreservedAnalyses IRNormalizerPass::run(Function &F, 6922e9f8696SJustin Fargnoli FunctionAnalysisManager &AM) const { 6932e9f8696SJustin Fargnoli IRNormalizer{}.runOnFunction(F); 6942e9f8696SJustin Fargnoli PreservedAnalyses PA; 6952e9f8696SJustin Fargnoli PA.preserveSet<CFGAnalyses>(); 6962e9f8696SJustin Fargnoli return PA; 6972e9f8696SJustin Fargnoli } 698