1 //===--------------- IRNormalizer.cpp - IR Normalizer ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file implements the IRNormalizer class which aims to transform LLVM 10 /// Modules into a normal form by reordering and renaming instructions while 11 /// preserving the same semantics. The normalizer makes it easier to spot 12 /// semantic differences while diffing two modules which have undergone 13 /// different passes. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/Transforms/Utils/IRNormalizer.h" 18 #include "llvm/ADT/SetVector.h" 19 #include "llvm/ADT/SmallPtrSet.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/IR/BasicBlock.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/IRBuilder.h" 25 #include "llvm/IR/InstIterator.h" 26 #include "llvm/IR/Module.h" 27 #include "llvm/InitializePasses.h" 28 #include "llvm/Pass.h" 29 #include "llvm/PassRegistry.h" 30 #include "llvm/Support/CommandLine.h" 31 #include "llvm/Transforms/Utils.h" 32 #include <algorithm> 33 #include <stack> 34 35 #define DEBUG_TYPE "normalize" 36 37 using namespace llvm; 38 39 namespace { 40 /// IRNormalizer aims to transform LLVM IR into normal form. 41 class IRNormalizer { 42 public: 43 /// \name Normalizer flags. 44 /// @{ 45 /// Preserves original order of instructions. 46 static cl::opt<bool> PreserveOrder; 47 /// Renames all instructions (including user-named). 48 static cl::opt<bool> RenameAll; // TODO: Don't rename on empty name 49 /// Folds all regular instructions (including pre-outputs). 50 static cl::opt<bool> FoldPreOutputs; 51 /// Sorts and reorders operands in commutative instructions. 52 static cl::opt<bool> ReorderOperands; 53 /// @} 54 55 bool runOnFunction(Function &F); 56 57 private: 58 // Random constant for hashing, so the state isn't zero. 59 const uint64_t MagicHashConstant = 0x6acaa36bef8325c5ULL; 60 DenseSet<const Instruction *> NamedInstructions; 61 62 SmallVector<Instruction *, 16> Outputs; 63 64 /// \name Naming. 65 /// @{ 66 void nameFunctionArguments(Function &F) const; 67 void nameBasicBlocks(Function &F) const; 68 void nameInstruction(Instruction *I); 69 void nameAsInitialInstruction(Instruction *I) const; 70 void nameAsRegularInstruction(Instruction *I); 71 void foldInstructionName(Instruction *I) const; 72 /// @} 73 74 /// \name Reordering. 75 /// @{ 76 void reorderInstructions(Function &F) const; 77 void reorderDefinition(Instruction *Definition, 78 std::stack<Instruction *> &TopologicalSort, 79 SmallPtrSet<const Instruction *, 32> &Visited) const; 80 void reorderInstructionOperandsByNames(Instruction *I) const; 81 void reorderPHIIncomingValues(PHINode *Phi) const; 82 /// @} 83 84 /// \name Utility methods. 85 /// @{ 86 template <typename T> 87 void sortCommutativeOperands(Instruction *I, T &Operands) const; 88 SmallVector<Instruction *, 16> collectOutputInstructions(Function &F) const; 89 bool isOutput(const Instruction *I) const; 90 bool isInitialInstruction(const Instruction *I) const; 91 bool hasOnlyImmediateOperands(const Instruction *I) const; 92 SetVector<int> 93 getOutputFootprint(Instruction *I, 94 SmallPtrSet<const Instruction *, 32> &Visited) const; 95 /// @} 96 }; 97 } // namespace 98 99 cl::opt<bool> IRNormalizer::PreserveOrder( 100 "norm-preserve-order", cl::Hidden, cl::init(false), 101 cl::desc("Preserves original instruction order")); 102 cl::opt<bool> IRNormalizer::RenameAll( 103 "norm-rename-all", cl::Hidden, cl::init(true), 104 cl::desc("Renames all instructions (including user-named)")); 105 cl::opt<bool> IRNormalizer::FoldPreOutputs( 106 "norm-fold-all", cl::Hidden, cl::init(true), 107 cl::desc("Folds all regular instructions (including pre-outputs)")); 108 cl::opt<bool> IRNormalizer::ReorderOperands( 109 "norm-reorder-operands", cl::Hidden, cl::init(true), 110 cl::desc("Sorts and reorders operands in commutative instructions")); 111 112 /// Entry method to the IRNormalizer. 113 /// 114 /// \param F Function to normalize. 115 bool IRNormalizer::runOnFunction(Function &F) { 116 nameFunctionArguments(F); 117 nameBasicBlocks(F); 118 119 Outputs = collectOutputInstructions(F); 120 121 if (!PreserveOrder) 122 reorderInstructions(F); 123 124 // TODO: Reorder basic blocks via a topological sort. 125 126 for (auto &I : Outputs) 127 nameInstruction(I); 128 129 for (auto &I : instructions(F)) { 130 if (!PreserveOrder) { 131 if (ReorderOperands) 132 reorderInstructionOperandsByNames(&I); 133 134 if (auto *Phi = dyn_cast<PHINode>(&I)) 135 reorderPHIIncomingValues(Phi); 136 } 137 foldInstructionName(&I); 138 } 139 140 return true; 141 } 142 143 /// Numbers arguments. 144 /// 145 /// \param F Function whose arguments will be renamed. 146 void IRNormalizer::nameFunctionArguments(Function &F) const { 147 int ArgumentCounter = 0; 148 for (auto &A : F.args()) { 149 if (RenameAll || A.getName().empty()) { 150 A.setName("a" + Twine(ArgumentCounter)); 151 ArgumentCounter += 1; 152 } 153 } 154 } 155 156 /// Names basic blocks using a generated hash for each basic block in 157 /// a function considering the opcode and the order of output instructions. 158 /// 159 /// \param F Function containing basic blocks to rename. 160 void IRNormalizer::nameBasicBlocks(Function &F) const { 161 for (auto &B : F) { 162 // Initialize to a magic constant, so the state isn't zero. 163 uint64_t Hash = MagicHashConstant; 164 165 // Hash considering output instruction opcodes. 166 for (auto &I : B) 167 if (isOutput(&I)) 168 Hash = hashing::detail::hash_16_bytes(Hash, I.getOpcode()); 169 170 if (RenameAll || B.getName().empty()) { 171 // Name basic block. Substring hash to make diffs more readable. 172 B.setName("bb" + std::to_string(Hash).substr(0, 5)); 173 } 174 } 175 } 176 177 /// Names instructions graphically (recursive) in accordance with the 178 /// def-use tree, starting from the initial instructions (defs), finishing at 179 /// the output (top-most user) instructions (depth-first). 180 /// 181 /// \param I Instruction to be renamed. 182 void IRNormalizer::nameInstruction(Instruction *I) { 183 // Ensure instructions are not renamed. This is done 184 // to prevent situation where instructions are used 185 // before their definition (in phi nodes) 186 if (NamedInstructions.contains(I)) 187 return; 188 NamedInstructions.insert(I); 189 if (isInitialInstruction(I)) { 190 nameAsInitialInstruction(I); 191 } else { 192 // This must be a regular instruction. 193 nameAsRegularInstruction(I); 194 } 195 } 196 197 template <typename T> 198 void IRNormalizer::sortCommutativeOperands(Instruction *I, T &Operands) const { 199 if (!(I->isCommutative() && Operands.size() >= 2)) 200 return; 201 auto CommutativeEnd = Operands.begin(); 202 std::advance(CommutativeEnd, 2); 203 llvm::sort(Operands.begin(), CommutativeEnd); 204 } 205 206 /// Names instruction following the scheme: 207 /// vl00000Callee(Operands) 208 /// 209 /// Where 00000 is a hash calculated considering instruction's opcode and output 210 /// footprint. Callee's name is only included when instruction's type is 211 /// CallInst. In cases where instruction is commutative, operands list is also 212 /// sorted. 213 /// 214 /// Renames instruction only when RenameAll flag is raised or instruction is 215 /// unnamed. 216 /// 217 /// \see getOutputFootprint() 218 /// \param I Instruction to be renamed. 219 void IRNormalizer::nameAsInitialInstruction(Instruction *I) const { 220 if (I->getType()->isVoidTy()) 221 return; 222 if (!(I->getName().empty() || RenameAll)) 223 return; 224 LLVM_DEBUG(dbgs() << "Naming initial instruction: " << *I << "\n"); 225 226 // Instruction operands for further sorting. 227 SmallVector<SmallString<64>, 4> Operands; 228 229 // Collect operands. 230 for (auto &Op : I->operands()) { 231 if (!isa<Function>(Op)) { 232 std::string TextRepresentation; 233 raw_string_ostream Stream(TextRepresentation); 234 Op->printAsOperand(Stream, false); 235 Operands.push_back(StringRef(Stream.str())); 236 } 237 } 238 239 sortCommutativeOperands(I, Operands); 240 241 // Initialize to a magic constant, so the state isn't zero. 242 uint64_t Hash = MagicHashConstant; 243 244 // Consider instruction's opcode in the hash. 245 Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode()); 246 247 SmallPtrSet<const Instruction *, 32> Visited; 248 // Get output footprint for I. 249 SetVector<int> OutputFootprint = getOutputFootprint(I, Visited); 250 251 // Consider output footprint in the hash. 252 for (const int &Output : OutputFootprint) 253 Hash = hashing::detail::hash_16_bytes(Hash, Output); 254 255 // Base instruction name. 256 SmallString<256> Name; 257 Name.append("vl" + std::to_string(Hash).substr(0, 5)); 258 259 // In case of CallInst, consider callee in the instruction name. 260 if (const auto *CI = dyn_cast<CallInst>(I)) { 261 Function *F = CI->getCalledFunction(); 262 263 if (F != nullptr) 264 Name.append(F->getName()); 265 } 266 267 Name.append("("); 268 for (size_t i = 0; i < Operands.size(); ++i) { 269 Name.append(Operands[i]); 270 271 if (i < Operands.size() - 1) 272 Name.append(", "); 273 } 274 Name.append(")"); 275 276 I->setName(Name); 277 } 278 279 /// Names instruction following the scheme: 280 /// op00000Callee(Operands) 281 /// 282 /// Where 00000 is a hash calculated considering instruction's opcode, its 283 /// operands' opcodes and order. Callee's name is only included when 284 /// instruction's type is CallInst. In cases where instruction is commutative, 285 /// operand list is also sorted. 286 /// 287 /// Names instructions recursively in accordance with the def-use tree, 288 /// starting from the initial instructions (defs), finishing at 289 /// the output (top-most user) instructions (depth-first). 290 /// 291 /// Renames instruction only when RenameAll flag is raised or instruction is 292 /// unnamed. 293 /// 294 /// \see getOutputFootprint() 295 /// \param I Instruction to be renamed. 296 void IRNormalizer::nameAsRegularInstruction(Instruction *I) { 297 LLVM_DEBUG(dbgs() << "Naming regular instruction: " << *I << "\n"); 298 299 // Instruction operands for further sorting. 300 SmallVector<SmallString<128>, 4> Operands; 301 302 // The name of a regular instruction depends 303 // on the names of its operands. Hence, all 304 // operands must be named first in the use-def 305 // walk. 306 307 // Collect operands. 308 for (auto &Op : I->operands()) { 309 if (auto *I = dyn_cast<Instruction>(Op)) { 310 // Walk down the use-def chain. 311 nameInstruction(I); 312 Operands.push_back(I->getName()); 313 } else if (!isa<Function>(Op)) { 314 // This must be an immediate value. 315 std::string TextRepresentation; 316 raw_string_ostream Stream(TextRepresentation); 317 Op->printAsOperand(Stream, false); 318 Operands.push_back(StringRef(Stream.str())); 319 } 320 } 321 322 sortCommutativeOperands(I, Operands); 323 324 // Initialize to a magic constant, so the state isn't zero. 325 uint64_t Hash = MagicHashConstant; 326 327 // Consider instruction opcode in the hash. 328 Hash = hashing::detail::hash_16_bytes(Hash, I->getOpcode()); 329 330 // Operand opcodes for further sorting (commutative). 331 SmallVector<int, 4> OperandsOpcodes; 332 333 // Collect operand opcodes for hashing. 334 for (auto &Op : I->operands()) 335 if (auto *I = dyn_cast<Instruction>(Op)) 336 OperandsOpcodes.push_back(I->getOpcode()); 337 338 sortCommutativeOperands(I, OperandsOpcodes); 339 340 // Consider operand opcodes in the hash. 341 for (const int Code : OperandsOpcodes) 342 Hash = hashing::detail::hash_16_bytes(Hash, Code); 343 344 // Base instruction name. 345 SmallString<512> Name; 346 Name.append("op" + std::to_string(Hash).substr(0, 5)); 347 348 // In case of CallInst, consider callee in the instruction name. 349 if (const auto *CI = dyn_cast<CallInst>(I)) 350 if (const Function *F = CI->getCalledFunction()) 351 Name.append(F->getName()); 352 353 Name.append("("); 354 for (size_t i = 0; i < Operands.size(); ++i) { 355 Name.append(Operands[i]); 356 357 if (i < Operands.size() - 1) 358 Name.append(", "); 359 } 360 Name.append(")"); 361 362 if ((I->getName().empty() || RenameAll) && !I->getType()->isVoidTy()) 363 I->setName(Name); 364 } 365 366 /// Shortens instruction's name. This method removes called function name from 367 /// the instruction name and substitutes the call chain with a corresponding 368 /// list of operands. 369 /// 370 /// Examples: 371 /// op00000Callee(op00001Callee(...), vl00000Callee(1, 2), ...) -> 372 /// op00000(op00001, vl00000, ...) vl00000Callee(1, 2) -> vl00000(1, 2) 373 /// 374 /// This method omits output instructions and pre-output (instructions directly 375 /// used by an output instruction) instructions (by default). By default it also 376 /// does not affect user named instructions. 377 /// 378 /// \param I Instruction whose name will be folded. 379 void IRNormalizer::foldInstructionName(Instruction *I) const { 380 // If this flag is raised, fold all regular 381 // instructions (including pre-outputs). 382 if (!FoldPreOutputs) { 383 // Don't fold if one of the users is an output instruction. 384 for (auto *U : I->users()) 385 if (auto *IU = dyn_cast<Instruction>(U)) 386 if (isOutput(IU)) 387 return; 388 } 389 390 // Don't fold if it is an output instruction or has no op prefix. 391 if (isOutput(I) || I->getName().substr(0, 2) != "op") 392 return; 393 394 // Instruction operands. 395 SmallVector<SmallString<64>, 4> Operands; 396 397 for (auto &Op : I->operands()) { 398 if (const auto *I = dyn_cast<Instruction>(Op)) { 399 bool HasNormalName = I->getName().substr(0, 2) == "op" || 400 I->getName().substr(0, 2) == "vl"; 401 402 Operands.push_back(HasNormalName ? I->getName().substr(0, 7) 403 : I->getName()); 404 } 405 } 406 407 sortCommutativeOperands(I, Operands); 408 409 SmallString<256> Name; 410 Name.append(I->getName().substr(0, 7)); 411 412 Name.append("("); 413 for (size_t i = 0; i < Operands.size(); ++i) { 414 Name.append(Operands[i]); 415 416 if (i < Operands.size() - 1) 417 Name.append(", "); 418 } 419 Name.append(")"); 420 421 I->setName(Name); 422 } 423 424 /// Reorders instructions by walking up the tree from each operand of an output 425 /// instruction and reducing the def-use distance. 426 /// This method assumes that output instructions were collected top-down, 427 /// otherwise the def-use chain may be broken. 428 /// This method is a wrapper for recursive reorderInstruction(). 429 /// 430 /// \see reorderInstruction() 431 void IRNormalizer::reorderInstructions(Function &F) const { 432 for (auto &BB : F) { 433 LLVM_DEBUG(dbgs() << "Reordering instructions in basic block: " 434 << BB.getName() << "\n"); 435 // Find the source nodes of the DAG of instructions in this basic block. 436 // Source nodes are instructions that have side effects, are terminators, or 437 // don't have a parent in the DAG of instructions. 438 // 439 // We must iterate from the first to the last instruction otherwise side 440 // effecting instructions could be reordered. 441 442 std::stack<Instruction *> TopologicalSort; 443 SmallPtrSet<const Instruction *, 32> Visited; 444 for (auto &I : BB) { 445 // First process side effecting and terminating instructions. 446 if (!(isOutput(&I) || I.isTerminator())) 447 continue; 448 LLVM_DEBUG(dbgs() << "\tReordering from source effecting instruction: "; 449 I.dump()); 450 reorderDefinition(&I, TopologicalSort, Visited); 451 } 452 453 for (auto &I : BB) { 454 // Process the remaining instructions. 455 // 456 // TODO: Do more a intelligent sorting of these instructions. For example, 457 // seperate between dead instructinos and instructions used in another 458 // block. Use properties of the CFG the order instructions that are used 459 // in another block. 460 if (Visited.contains(&I)) 461 continue; 462 LLVM_DEBUG(dbgs() << "\tReordering from source instruction: "; I.dump()); 463 reorderDefinition(&I, TopologicalSort, Visited); 464 } 465 466 LLVM_DEBUG(dbgs() << "Inserting instructions into: " << BB.getName() 467 << "\n"); 468 // Reorder based on the topological sort. 469 while (!TopologicalSort.empty()) { 470 auto *Instruction = TopologicalSort.top(); 471 auto FirstNonPHIOrDbgOrAlloca = BB.getFirstNonPHIOrDbgOrAlloca(); 472 if (auto *Call = dyn_cast<CallInst>(&*FirstNonPHIOrDbgOrAlloca)) { 473 if (Call->getIntrinsicID() == 474 Intrinsic::experimental_convergence_entry || 475 Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop) 476 FirstNonPHIOrDbgOrAlloca++; 477 } 478 Instruction->moveBefore(FirstNonPHIOrDbgOrAlloca); 479 TopologicalSort.pop(); 480 } 481 } 482 } 483 484 void IRNormalizer::reorderDefinition( 485 Instruction *Definition, std::stack<Instruction *> &TopologicalSort, 486 SmallPtrSet<const Instruction *, 32> &Visited) const { 487 if (Visited.contains(Definition)) 488 return; 489 Visited.insert(Definition); 490 491 { 492 const auto *BasicBlock = Definition->getParent(); 493 const auto FirstNonPHIOrDbgOrAlloca = 494 BasicBlock->getFirstNonPHIOrDbgOrAlloca(); 495 if (FirstNonPHIOrDbgOrAlloca == BasicBlock->end()) 496 return; // TODO: Is this necessary? 497 if (Definition->comesBefore(&*FirstNonPHIOrDbgOrAlloca)) 498 return; // TODO: Do some kind of ordering for these instructions. 499 } 500 501 for (auto &Operand : Definition->operands()) { 502 if (auto *Op = dyn_cast<Instruction>(Operand)) { 503 if (Op->getParent() != Definition->getParent()) 504 continue; // Only reorder instruction within the same basic block 505 reorderDefinition(Op, TopologicalSort, Visited); 506 } 507 } 508 509 LLVM_DEBUG(dbgs() << "\t\tNext in topological sort: "; Definition->dump()); 510 if (Definition->isTerminator()) 511 return; 512 if (auto *Call = dyn_cast<CallInst>(Definition)) { 513 if (Call->isMustTailCall()) 514 return; 515 if (Call->getIntrinsicID() == Intrinsic::experimental_deoptimize) 516 return; 517 if (Call->getIntrinsicID() == Intrinsic::experimental_convergence_entry) 518 return; 519 if (Call->getIntrinsicID() == Intrinsic::experimental_convergence_loop) 520 return; 521 } 522 if (auto *BitCast = dyn_cast<BitCastInst>(Definition)) { 523 if (auto *Call = dyn_cast<CallInst>(BitCast->getOperand(0))) { 524 if (Call->isMustTailCall()) 525 return; 526 } 527 } 528 529 TopologicalSort.emplace(Definition); 530 } 531 532 /// Reorders instruction's operands alphabetically. This method assumes 533 /// that passed instruction is commutative. Changing the operand order 534 /// in other instructions may change the semantics. 535 /// 536 /// \param I Instruction whose operands will be reordered. 537 void IRNormalizer::reorderInstructionOperandsByNames(Instruction *I) const { 538 // This method assumes that passed I is commutative, 539 // changing the order of operands in other instructions 540 // may change the semantics. 541 542 // Instruction operands for further sorting. 543 SmallVector<std::pair<std::string, Value *>, 4> Operands; 544 545 // Collect operands. 546 for (auto &Op : I->operands()) { 547 if (auto *V = dyn_cast<Value>(Op)) { 548 if (isa<Instruction>(V)) { 549 // This is an an instruction. 550 Operands.push_back(std::pair<std::string, Value *>(V->getName(), V)); 551 } else { 552 std::string TextRepresentation; 553 raw_string_ostream Stream(TextRepresentation); 554 Op->printAsOperand(Stream, false); 555 Operands.push_back(std::pair<std::string, Value *>(Stream.str(), V)); 556 } 557 } 558 } 559 560 // Sort operands. 561 sortCommutativeOperands(I, Operands); 562 563 // Reorder operands. 564 unsigned Position = 0; 565 for (auto &Op : I->operands()) { 566 Op.set(Operands[Position].second); 567 Position += 1; 568 } 569 } 570 571 /// Reorders PHI node's values according to the names of corresponding basic 572 /// blocks. 573 /// 574 /// \param Phi PHI node to normalize. 575 void IRNormalizer::reorderPHIIncomingValues(PHINode *Phi) const { 576 // Values for further sorting. 577 SmallVector<std::pair<Value *, BasicBlock *>, 2> Values; 578 579 // Collect blocks and corresponding values. 580 for (auto &BB : Phi->blocks()) { 581 Value *V = Phi->getIncomingValueForBlock(BB); 582 Values.push_back(std::pair<Value *, BasicBlock *>(V, BB)); 583 } 584 585 // Sort values according to the name of a basic block. 586 llvm::sort(Values, [](const std::pair<Value *, BasicBlock *> &LHS, 587 const std::pair<Value *, BasicBlock *> &RHS) { 588 return LHS.second->getName() < RHS.second->getName(); 589 }); 590 591 // Swap. 592 for (unsigned i = 0; i < Values.size(); ++i) { 593 Phi->setIncomingBlock(i, Values[i].second); 594 Phi->setIncomingValue(i, Values[i].first); 595 } 596 } 597 598 /// Returns a vector of output instructions. An output is an instruction which 599 /// has side-effects or is ReturnInst. Uses isOutput(). 600 /// 601 /// \see isOutput() 602 /// \param F Function to collect outputs from. 603 SmallVector<Instruction *, 16> 604 IRNormalizer::collectOutputInstructions(Function &F) const { 605 // Output instructions are collected top-down in each function, 606 // any change may break the def-use chain in reordering methods. 607 SmallVector<Instruction *, 16> Outputs; 608 for (auto &I : instructions(F)) 609 if (isOutput(&I)) 610 Outputs.push_back(&I); 611 return Outputs; 612 } 613 614 /// Helper method checking whether the instruction may have side effects or is 615 /// ReturnInst. 616 /// 617 /// \param I Considered instruction. 618 bool IRNormalizer::isOutput(const Instruction *I) const { 619 // Outputs are such instructions which may have side effects or is ReturnInst. 620 return I->mayHaveSideEffects() || isa<ReturnInst>(I); 621 } 622 623 /// Helper method checking whether the instruction has users and only 624 /// immediate operands. 625 /// 626 /// \param I Considered instruction. 627 bool IRNormalizer::isInitialInstruction(const Instruction *I) const { 628 // Initial instructions are such instructions whose values are used by 629 // other instructions, yet they only depend on immediate values. 630 return !I->user_empty() && hasOnlyImmediateOperands(I); 631 } 632 633 /// Helper method checking whether the instruction has only immediate operands. 634 /// 635 /// \param I Considered instruction. 636 bool IRNormalizer::hasOnlyImmediateOperands(const Instruction *I) const { 637 for (const auto &Op : I->operands()) 638 if (isa<Instruction>(Op)) 639 return false; // Found non-immediate operand (instruction). 640 return true; 641 } 642 643 /// Helper method returning indices (distance from the beginning of the basic 644 /// block) of outputs using the \p I (eliminates repetitions). Walks down the 645 /// def-use tree recursively. 646 /// 647 /// \param I Considered instruction. 648 /// \param Visited Set of visited instructions. 649 SetVector<int> IRNormalizer::getOutputFootprint( 650 Instruction *I, SmallPtrSet<const Instruction *, 32> &Visited) const { 651 652 // Vector containing indexes of outputs (no repetitions), 653 // which use I in the order of walking down the def-use tree. 654 SetVector<int> Outputs; 655 656 if (!Visited.count(I)) { 657 Visited.insert(I); 658 659 if (isOutput(I)) { 660 // Gets output instruction's parent function. 661 Function *Func = I->getParent()->getParent(); 662 663 // Finds and inserts the index of the output to the vector. 664 unsigned Count = 0; 665 for (const auto &B : *Func) { 666 for (const auto &E : B) { 667 if (&E == I) 668 Outputs.insert(Count); 669 Count += 1; 670 } 671 } 672 673 // Returns to the used instruction. 674 return Outputs; 675 } 676 677 for (auto *U : I->users()) { 678 if (auto *UI = dyn_cast<Instruction>(U)) { 679 // Vector for outputs which use UI. 680 SetVector<int> OutputsUsingUI = getOutputFootprint(UI, Visited); 681 // Insert the indexes of outputs using UI. 682 Outputs.insert(OutputsUsingUI.begin(), OutputsUsingUI.end()); 683 } 684 } 685 } 686 687 // Return to the used instruction. 688 return Outputs; 689 } 690 691 PreservedAnalyses IRNormalizerPass::run(Function &F, 692 FunctionAnalysisManager &AM) const { 693 IRNormalizer{}.runOnFunction(F); 694 PreservedAnalyses PA; 695 PA.preserveSet<CFGAnalyses>(); 696 return PA; 697 } 698