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