[llvm] r332739 - Add remarks describing when a pass changes the IR instruction count of a module

Jessica Paquette via llvm-commits llvm-commits at lists.llvm.org
Fri May 18 10:26:40 PDT 2018


Author: paquette
Date: Fri May 18 10:26:39 2018
New Revision: 332739

URL: http://llvm.org/viewvc/llvm-project?rev=332739&view=rev
Log:
Add remarks describing when a pass changes the IR instruction count of a module

This patch adds a remark which tells the user when a pass changes the number of
IR instructions in a module.

It can be enabled by using -Rpass-analysis=size-info.

The point of this is to make it easier to collect statistics on how passes
modify programs in terms of code size. This is similar in concept to timing
reports, but using a remark-based interface makes it easy to diff changes over
multiple compilations of the same program.

By adding functionality like this, we can see
  * Which passes impact code size the most
  * How passes impact code size at different optimization levels
  * Which pass might have contributed the most to an overall code size
    regression

The patch lives in the legacy pass manager, but since it's simply emitting
remarks, it shouldn't be too difficult to adapt the functionality to the new
pass manager as well. This can also be adapted to handle MachineInstr counts in
code gen passes.

https://reviews.llvm.org/D38768

Added:
    llvm/trunk/test/Other/size-remarks.ll
Modified:
    llvm/trunk/include/llvm/IR/Function.h
    llvm/trunk/include/llvm/IR/LegacyPassManagers.h
    llvm/trunk/include/llvm/IR/Module.h
    llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
    llvm/trunk/lib/Analysis/LoopPass.cpp
    llvm/trunk/lib/IR/Function.cpp
    llvm/trunk/lib/IR/LegacyPassManager.cpp
    llvm/trunk/lib/IR/Module.cpp

Modified: llvm/trunk/include/llvm/IR/Function.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Function.h (original)
+++ llvm/trunk/include/llvm/IR/Function.h Fri May 18 10:26:39 2018
@@ -141,6 +141,11 @@ public:
   // Provide fast operand accessors.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
 
+  /// Returns the number of non-debug IR instructions in this function.
+  /// This is equivalent to the sum of the sizes of each basic block contained
+  /// within this function.
+  unsigned getInstructionCount();
+
   /// Returns the FunctionType for me.
   FunctionType *getFunctionType() const {
     return cast<FunctionType>(getValueType());

Modified: llvm/trunk/include/llvm/IR/LegacyPassManagers.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/LegacyPassManagers.h?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/LegacyPassManagers.h (original)
+++ llvm/trunk/include/llvm/IR/LegacyPassManagers.h Fri May 18 10:26:39 2018
@@ -403,6 +403,15 @@ public:
       InheritedAnalysis[Index++] = (*I)->getAvailableAnalysis();
   }
 
+  /// Set the initial size of the module if the user has specified that they
+  /// want remarks for size.
+  /// Returns 0 if the remark was not requested.
+  unsigned initSizeRemarkInfo(Module &M);
+
+  /// Emit a remark signifying that the number of IR instructions in the module
+  /// changed.
+  void emitInstrCountChangedRemark(Pass *P, Module &M, unsigned CountBefore);
+
 protected:
   // Top level manager.
   PMTopLevelManager *TPM;

Modified: llvm/trunk/include/llvm/IR/Module.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Module.h?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Module.h (original)
+++ llvm/trunk/include/llvm/IR/Module.h Fri May 18 10:26:39 2018
@@ -207,6 +207,11 @@ public:
   /// @returns the module identifier as a string
   const std::string &getModuleIdentifier() const { return ModuleID; }
 
+  /// Returns the number of non-debug IR instructions in the module.
+  /// This is equivalent to the sum of the IR instruction counts of each
+  /// function contained in the module.
+  unsigned getInstructionCount();
+
   /// Get the module's original source file name. When compiling from
   /// bitcode, this is taken from a bitcode record where it was recorded.
   /// For other compiles it is the same as the ModuleID, which would

Modified: llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp (original)
+++ llvm/trunk/lib/Analysis/CallGraphSCCPass.cpp Fri May 18 10:26:39 2018
@@ -120,6 +120,7 @@ bool CGPassManager::RunPassOnSCC(Pass *P
                                  bool &DevirtualizedCall) {
   bool Changed = false;
   PMDataManager *PM = P->getAsPMDataManager();
+  Module &M = CG.getModule();
 
   if (!PM) {
     CallGraphSCCPass *CGSP = (CallGraphSCCPass*)P;
@@ -130,7 +131,12 @@ bool CGPassManager::RunPassOnSCC(Pass *P
 
     {
       TimeRegion PassTimer(getPassTimer(CGSP));
+      unsigned InstrCount = initSizeRemarkInfo(M);
       Changed = CGSP->runOnSCC(CurSCC);
+
+      // If the pass modified the module, it may have modified the instruction
+      // count of the module. Try emitting a remark.
+      emitInstrCountChangedRemark(P, M, InstrCount);
     }
     
     // After the CGSCCPass is done, when assertions are enabled, use

Modified: llvm/trunk/lib/Analysis/LoopPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPass.cpp?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopPass.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopPass.cpp Fri May 18 10:26:39 2018
@@ -151,6 +151,7 @@ void LPPassManager::markLoopAsDeleted(Lo
 bool LPPassManager::runOnFunction(Function &F) {
   auto &LIWP = getAnalysis<LoopInfoWrapperPass>();
   LI = &LIWP.getLoopInfo();
+  Module &M = *F.getParent();
 #if 0
   DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
 #endif
@@ -200,8 +201,9 @@ bool LPPassManager::runOnFunction(Functi
       {
         PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader());
         TimeRegion PassTimer(getPassTimer(P));
-
+        unsigned InstrCount = initSizeRemarkInfo(M);
         Changed |= P->runOnLoop(CurrentLoop, *this);
+        emitInstrCountChangedRemark(P, M, InstrCount);
       }
 
       if (Changed)

Modified: llvm/trunk/lib/IR/Function.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Function.cpp (original)
+++ llvm/trunk/lib/IR/Function.cpp Fri May 18 10:26:39 2018
@@ -194,6 +194,14 @@ LLVMContext &Function::getContext() cons
   return getType()->getContext();
 }
 
+unsigned Function::getInstructionCount() {
+  unsigned NumInstrs = 0;
+  for (BasicBlock &BB : BasicBlocks)
+    NumInstrs += std::distance(BB.instructionsWithoutDebug().begin(),
+                               BB.instructionsWithoutDebug().end());
+  return NumInstrs;
+}
+
 void Function::removeFromParent() {
   getParent()->getFunctionList().remove(getIterator());
 }

Modified: llvm/trunk/lib/IR/LegacyPassManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LegacyPassManager.cpp?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/lib/IR/LegacyPassManager.cpp (original)
+++ llvm/trunk/lib/IR/LegacyPassManager.cpp Fri May 18 10:26:39 2018
@@ -13,6 +13,7 @@
 
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LegacyPassManagers.h"
@@ -134,8 +135,65 @@ bool PMDataManager::isPassDebuggingExecu
   return PassDebugging >= Executions;
 }
 
+unsigned PMDataManager::initSizeRemarkInfo(Module &M) {
+  // Only calculate getInstructionCount if the size-info remark is requested.
+  if (M.getContext().getDiagHandlerPtr()->isAnalysisRemarkEnabled("size-info"))
+    return M.getInstructionCount();
+  return 0;
+}
+
+void PMDataManager::emitInstrCountChangedRemark(Pass *P, Module &M,
+                                                unsigned CountBefore) {
+  // Did the user request the remark? If not, quit.
+  if (!M.getContext().getDiagHandlerPtr()->isAnalysisRemarkEnabled("size-info"))
+    return;
+
+  // We need a function containing at least one basic block in order to output
+  // remarks. Since it's possible that the first function in the module doesn't
+  // actually contain a basic block, we have to go and find one that's suitable
+  // for emitting remarks.
+  auto It = std::find_if(M.begin(), M.end(),
+                         [](const Function &Fn) { return !Fn.empty(); });
 
+  // Didn't find a function. Quit.
+  if (It == M.end())
+    return;
+
+  // We found a function containing at least one basic block.
+  Function *F = &*It;
 
+  // How many instructions are in the module now?
+  unsigned CountAfter = M.getInstructionCount();
+
+  // If there was no change, don't emit a remark.
+  if (CountBefore == CountAfter)
+    return;
+
+  // If it's a pass manager, don't emit a remark. (This hinges on the assumption
+  // that the only passes that return non-null with getAsPMDataManager are pass
+  // managers.) The reason we have to do this is to avoid emitting remarks for
+  // CGSCC passes.
+  if (P->getAsPMDataManager())
+    return;
+
+  // Compute a possibly negative delta between the instruction count before
+  // running P, and after running P.
+  int64_t Delta = (int64_t)CountAfter - (int64_t)CountBefore;
+
+  BasicBlock &BB = *F->begin();
+  OptimizationRemarkAnalysis R("size-info", "IRSizeChange",
+                               DiagnosticLocation(), &BB);
+  // FIXME: Move ore namespace to DiagnosticInfo so that we can use it. This
+  // would let us use NV instead of DiagnosticInfoOptimizationBase::Argument.
+  R << DiagnosticInfoOptimizationBase::Argument("Pass", P->getPassName())
+    << ": IR instruction count changed from "
+    << DiagnosticInfoOptimizationBase::Argument("IRInstrsBefore", CountBefore)
+    << " to "
+    << DiagnosticInfoOptimizationBase::Argument("IRInstrsAfter", CountAfter)
+    << "; Delta: "
+    << DiagnosticInfoOptimizationBase::Argument("DeltaInstrCount", Delta);
+  F->getContext().diagnose(R); // Not using ORE for layering reasons.
+}
 
 void PassManagerPrettyStackEntry::print(raw_ostream &OS) const {
   if (!V && !M)
@@ -1284,6 +1342,7 @@ bool BBPassManager::runOnFunction(Functi
     return false;
 
   bool Changed = doInitialization(F);
+  Module &M = *F.getParent();
 
   for (BasicBlock &BB : F)
     for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
@@ -1299,8 +1358,9 @@ bool BBPassManager::runOnFunction(Functi
         // If the pass crashes, remember this.
         PassManagerPrettyStackEntry X(BP, BB);
         TimeRegion PassTimer(getPassTimer(BP));
-
+        unsigned InstrCount = initSizeRemarkInfo(M);
         LocalChanged |= BP->runOnBasicBlock(BB);
+        emitInstrCountChangedRemark(BP, M, InstrCount);
       }
 
       Changed |= LocalChanged;
@@ -1500,7 +1560,7 @@ bool FPPassManager::runOnFunction(Functi
     return false;
 
   bool Changed = false;
-
+  Module &M = *F.getParent();
   // Collect inherited analysis from Module level pass manager.
   populateInheritedAnalysis(TPM->activeStack);
 
@@ -1516,8 +1576,9 @@ bool FPPassManager::runOnFunction(Functi
     {
       PassManagerPrettyStackEntry X(FP, F);
       TimeRegion PassTimer(getPassTimer(FP));
-
+      unsigned InstrCount = initSizeRemarkInfo(M);
       LocalChanged |= FP->runOnFunction(F);
+      emitInstrCountChangedRemark(FP, M, InstrCount);
     }
 
     Changed |= LocalChanged;
@@ -1594,7 +1655,9 @@ MPPassManager::runOnModule(Module &M) {
       PassManagerPrettyStackEntry X(MP, M);
       TimeRegion PassTimer(getPassTimer(MP));
 
+      unsigned InstrCount = initSizeRemarkInfo(M);
       LocalChanged |= MP->runOnModule(M);
+      emitInstrCountChangedRemark(MP, M, InstrCount);
     }
 
     Changed |= LocalChanged;

Modified: llvm/trunk/lib/IR/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Module.cpp?rev=332739&r1=332738&r2=332739&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Module.cpp (original)
+++ llvm/trunk/lib/IR/Module.cpp Fri May 18 10:26:39 2018
@@ -464,6 +464,13 @@ unsigned Module::getCodeViewFlag() const
   return cast<ConstantInt>(Val->getValue())->getZExtValue();
 }
 
+unsigned Module::getInstructionCount() {
+  unsigned NumInstrs = 0;
+  for (Function &F : FunctionList)
+    NumInstrs += F.getInstructionCount();
+  return NumInstrs;
+}
+
 Comdat *Module::getOrInsertComdat(StringRef Name) {
   auto &Entry = *ComdatSymTab.insert(std::make_pair(Name, Comdat())).first;
   Entry.second.Name = &Entry;

Added: llvm/trunk/test/Other/size-remarks.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/size-remarks.ll?rev=332739&view=auto
==============================================================================
--- llvm/trunk/test/Other/size-remarks.ll (added)
+++ llvm/trunk/test/Other/size-remarks.ll Fri May 18 10:26:39 2018
@@ -0,0 +1,164 @@
+; Ensure that IR count remarks in the legacy pass manager work.
+; What this test should check for:
+; * Positive, nonzero sizes before/after
+; * Nonzero deltas
+; * Sizes are being tracked properly across multiple remarks. E.g, if we have
+;     original_count_1, final_count_1, and
+;     original_count_2, final_count_2,
+;  Then original_count_2 == final_count_1.
+
+; For these remarks, the "function" field in the YAML file doesn't matter.
+; Each of the testcases work by combining the output remarks with the
+; optimization record emit using -pass-remarks-output. This is done to prevent
+; test flakiness wrt instruction counts, but also ensure that the output values
+; are equivalent in both outputs.
+
+; RUN: opt < %s -inline -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=CGSCC
+; CGSCC: remark: <unknown>:0:0: Function Integration/Inlining:
+; CGSCC-SAME: IR instruction count changed from
+; CGSCC-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; CGSCC-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; CGSCC: --- !Analysis
+; CGSCC-NEXT: Pass:            size-info
+; CGSCC-NEXT: Name:            IRSizeChange
+; CGSCC-NEXT: Function:
+; CGSCC-NEXT: Args:            
+; CGSCC-NEXT:  - Pass:            Function Integration/Inlining
+; CGSCC-NEXT:  - String:          ': IR instruction count changed from '
+; CGSCC-NEXT:  - IRInstrsBefore:  '[[ORIG]]'
+; CGSCC-NEXT:  - String:          ' to '
+; CGSCC-NEXT:  - IRInstrsAfter:   '[[FINAL]]'
+; CGSCC-NEXT:  - String:          '; Delta: '
+; CGSCC-NEXT:  - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -instcombine -pass-remarks-analysis='size-info' \
+; RUN:-pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=FUNC
+; FUNC: remark: <unknown>:0:0: Combine redundant instructions:
+; FUNC-SAME: IR instruction count changed from
+; FUNC-SAME: [[SIZE1:[1-9][0-9]*]] to [[SIZE2:[1-9][0-9]*]];
+; FUNC-SAME: Delta: [[DELTA1:-?[1-9][0-9]*]]
+; FUNC-NEXT: remark: <unknown>:0:0: Combine redundant instructions:
+; FUNC-SAME: IR instruction count changed from
+; FUNC-SAME: [[SIZE2]] to [[SIZE3:[1-9][0-9]*]];
+; FUNC-SAME: Delta: [[DELTA2:-?[1-9][0-9]*]]
+; FUNC: --- !Analysis
+; FUNC-NEXT: Pass:            size-info
+; FUNC-NEXT: Name:            IRSizeChange
+; FUNC-NEXT: Function:
+; FUNC-NEXT: Args:            
+; FUNC-NEXT:  - Pass:            Combine redundant instructions
+; FUNC-NEXT:  - String:          ': IR instruction count changed from '
+; FUNC-NEXT:  - IRInstrsBefore:  '[[SIZE1]]'
+; FUNC-NEXT:  - String:          ' to '
+; FUNC-NEXT:  - IRInstrsAfter:   '[[SIZE2]]'
+; FUNC-NEXT:  - String:          '; Delta: '
+; FUNC-NEXT:  - DeltaInstrCount: '[[DELTA1]]'
+; FUNC: --- !Analysis
+; FUNC-NEXT: Pass:            size-info
+; FUNC-NEXT: Name:            IRSizeChange
+; FUNC-NEXT: Function:
+; FUNC-NEXT: Args:            
+; FUNC-NEXT:   - Pass:            Combine redundant instructions
+; FUNC-NEXT:   - String:          ': IR instruction count changed from '
+; FUNC-NEXT:   - IRInstrsBefore:  '[[SIZE2]]'
+; FUNC-NEXT:   - String:          ' to '
+; FUNC-NEXT:   - IRInstrsAfter:   '[[SIZE3]]'
+; FUNC-NEXT:   - String:          '; Delta: '
+; FUNC-NEXT:   - DeltaInstrCount: '[[DELTA2]]'
+
+; RUN: opt < %s -globaldce -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=MODULE
+; MODULE: remark:
+; MODULE-SAME: Dead Global Elimination:
+; MODULE-SAME: IR instruction count changed from
+; MODULE-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; MODULE-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; MODULE: --- !Analysis
+; MODULE-NEXT: Pass:            size-info
+; MODULE-NEXT: Name:            IRSizeChange
+; MODULE-NEXT: Function:
+; MODULE-NEXT: Args:            
+; MODULE-NEXT:   - Pass:            Dead Global Elimination
+; MODULE-NEXT:   - String:          ': IR instruction count changed from '
+; MODULE-NEXT:   - IRInstrsBefore:  '[[ORIG]]'
+; MODULE-NEXT:   - String:          ' to '
+; MODULE-NEXT:   - IRInstrsAfter:   '[[FINAL]]'
+; MODULE-NEXT:   - String:          '; Delta: '
+; MODULE-NEXT:   - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -dce -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=BB
+; BB: remark: <unknown>:0:0: Dead Code Elimination:
+; BB-SAME: IR instruction count changed from
+; BB-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; BB-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; BB: --- !Analysis
+; BB-NEXT: Pass:            size-info
+; BB-NEXT: Name:            IRSizeChange
+; BB-NEXT: Function:
+; BB-NEXT: Args:            
+; BB-NEXT:   - Pass:            Dead Code Elimination
+; BB-NEXT:   - String:          ': IR instruction count changed from '
+; BB-NEXT:   - IRInstrsBefore:  '[[ORIG]]'
+; BB-NEXT:   - String:          ' to '
+; BB-NEXT:   - IRInstrsAfter:   '[[FINAL]]'
+; BB-NEXT:   - String:          '; Delta: '
+; BB-NEXT:   - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -loop-unroll -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=LOOP
+; LOOP: remark: <unknown>:0:0: Unroll loops:
+; LOOP-SAME: IR instruction count changed from
+; LOOP-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; LOOP-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; LOOP: --- !Analysis
+; LOOP-NEXT: Pass:            size-info
+; LOOP-NEXT: Name:            IRSizeChange
+; LOOP-NEXT: Function:
+; LOOP-NEXT: Args:            
+; LOOP-DAG:   - Pass:            Unroll loops
+; LOOP-NEXT:   - String:          ': IR instruction count changed from '
+; LOOP-NEXT:   - IRInstrsBefore:  '[[ORIG]]'
+; LOOP-NEXT:   - String:          ' to '
+; LOOP-NEXT:   - IRInstrsAfter:   '[[FINAL]]'
+; LOOP-NEXT:   - String:          '; Delta: '
+; LOOP-NEXT:   - DeltaInstrCount: '[[DELTA]]'
+declare i1 ()* @boop()
+
+define internal i1 @pluto() {
+  %F = call i1 ()* () @boop( )
+  %c = icmp eq i1 ()* %F, @pluto
+  ret i1 %c
+}
+
+define i32 @foo(i32 %x) {
+entry:
+  %x.addr = alloca i32, align 4
+  store i32 %x, i32* %x.addr, align 4
+  %0 = load i32, i32* %x.addr, align 4
+  ret i32 %0
+}
+
+define i32 @bar(i32 %x) {
+entry:
+  %x.addr = alloca i32, align 4
+  store i32 %x, i32* %x.addr, align 4
+  %0 = load i32, i32* %x.addr, align 4
+  %call = call i32 @foo(i32 %0)
+  br label %for.body
+for.body:
+  %s.06 = phi i32 [ 0, %entry ], [ %add, %for.body ]
+  %i.05 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+  %add = add nsw i32 %i.05, 4
+  %inc = add nsw i32 %i.05, 1
+  %exitcond = icmp eq i32 %inc, 16
+  br i1 %exitcond, label %for.end, label %for.body
+for.end:
+  ret i32 %add
+}




More information about the llvm-commits mailing list