Disable Subzero IR generation for performance testing.

This CL allows one to time Subzero's bitcode parsing without IR generation
(other than types, function declarations, and uninitialized global variables)
for performance testing.

BUG=None
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/696383004
diff --git a/Makefile.standalone b/Makefile.standalone
index 29fcef9..b5b2913 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -51,10 +51,12 @@
 ifdef MINIMAL
   OBJDIR := $(OBJDIR)+Min
   CXX_DEFINES += -DALLOW_TEXT_ASM=0 -DALLOW_DUMP=0 -DALLOW_LLVM_CL=0 \
-                 -DALLOW_LLVM_IR=0 -DALLOW_LLVM_IR_AS_INPUT=0
+                 -DALLOW_LLVM_IR=0 -DALLOW_LLVM_IR_AS_INPUT=0 \
+		 -DALLOW_DISABLE_IR_GEN=0
 else
   CXX_DEFINES += -DALLOW_TEXT_ASM=1 -DALLOW_DUMP=1 -DALLOW_LLVM_CL=1 \
-                 -DALLOW_LLVM_IR=1 -DALLOW_LLVM_IR_AS_INPUT=1
+                 -DALLOW_LLVM_IR=1 -DALLOW_LLVM_IR_AS_INPUT=1 \
+		 -DALLOW_DISABLE_IR_GEN=1
 endif
 
 ifdef NOASSERT
diff --git a/pydir/run-llvm2ice.py b/pydir/run-llvm2ice.py
index 3824673..72925cc 100755
--- a/pydir/run-llvm2ice.py
+++ b/pydir/run-llvm2ice.py
@@ -47,6 +47,7 @@
                            action='store_true',
                            help='Trace command that generates ICE instructions')
     argparser.add_argument('--args', '-a', nargs=argparse.REMAINDER,
+                           default=[],
                            help='Remaining arguments are passed to llvm2ice')
 
     args = argparser.parse_args()
@@ -78,8 +79,7 @@
       cmd += ['--build-on-read=0']
     else:
       cmd += ['--build-on-read=1']
-    if args.args:
-      cmd += args.args
+    cmd += args.args
     if args.llvm_source:
       cmd += [llfile]
 
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index bd1894c..8e73499 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -31,7 +31,10 @@
       VMetadata(new VariablesMetadata(this)),
       TargetAssembler(
           TargetLowering::createAssembler(Ctx->getTargetArch(), this)),
-      CurrentNode(NULL) {}
+      CurrentNode(NULL) {
+  assert(!Ctx->isIRGenerationDisabled() &&
+         "Attempt to build cfg when IR generation disabled");
+}
 
 Cfg::~Cfg() {}
 
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index 52b8f34..a1dcf68 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -26,8 +26,9 @@
         UseIntegratedAssembler(false), UseSandboxing(false),
         PhiEdgeSplit(false), DecorateAsm(false), DumpStats(false),
         AllowUninitializedGlobals(false), TimeEachFunction(false),
-        DefaultGlobalPrefix(""), DefaultFunctionPrefix(""), TimingFocusOn(""),
-        VerboseFocusOn(""), TranslateOnly("") {}
+        DisableIRGeneration(false), DefaultGlobalPrefix(""),
+        DefaultFunctionPrefix(""), TimingFocusOn(""), VerboseFocusOn(""),
+        TranslateOnly("") {}
   bool DisableInternal;
   bool SubzeroTimingEnabled;
   bool DisableTranslation;
@@ -40,6 +41,7 @@
   bool DumpStats;
   bool AllowUninitializedGlobals;
   bool TimeEachFunction;
+  bool DisableIRGeneration;
   IceString DefaultGlobalPrefix;
   IceString DefaultFunctionPrefix;
   IceString TimingFocusOn;
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index b0fd059..bdc461e 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -140,6 +140,10 @@
 
   const ClFlags &getFlags() const { return Flags; }
 
+  bool isIRGenerationDisabled() const {
+    return ALLOW_DISABLE_IR_GEN ? getFlags().DisableIRGeneration : false;
+  }
+
   // Allocate data of type T using the global allocator.
   template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
 
diff --git a/src/IceOperand.h b/src/IceOperand.h
index c0367cd..77fa7a3 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -137,6 +137,8 @@
 public:
   static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value,
                                    uint32_t PoolEntryID) {
+    assert(!Ctx->isIRGenerationDisabled() &&
+           "Attempt to build primitive constant when IR generation disabled");
     return new (Ctx->allocate<ConstantPrimitive>())
         ConstantPrimitive(Ty, Value, PoolEntryID);
   }
@@ -206,6 +208,8 @@
   static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
                                      const RelocatableTuple &Tuple,
                                      uint32_t PoolEntryID) {
+    assert(!Ctx->isIRGenerationDisabled() &&
+           "Attempt to build relocatable constant when IR generation disabled");
     return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable(
         Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID);
   }
@@ -246,6 +250,8 @@
 public:
   static ConstantUndef *create(GlobalContext *Ctx, Type Ty,
                                uint32_t PoolEntryID) {
+    assert(!Ctx->isIRGenerationDisabled() &&
+           "Attempt to build undefined constant when IR generation disabled");
     return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty, PoolEntryID);
   }
 
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index 68a1ebc..07fd5af 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -201,6 +201,12 @@
   /// Changes the size of the type list to the given size.
   void resizeTypeIDValues(unsigned NewSize) { TypeIDValues.resize(NewSize); }
 
+  /// Returns true if generation of Subzero IR is disabled.
+  bool isIRGenerationDisabled() const {
+    return ALLOW_DISABLE_IR_GEN ? Translator.getFlags().DisableIRGeneration
+                                : false;
+  }
+
   /// Returns the undefined type associated with type ID.
   /// Note: Returns extended type ready to be defined.
   ExtendedType *getTypeByIDForDefining(unsigned ID) {
@@ -284,6 +290,11 @@
     if (C != nullptr)
       return C;
 
+    if (isIRGenerationDisabled()) {
+      ValueIDConstants[ID] = nullptr;
+      return nullptr;
+    }
+
     // If reached, no such constant exists, create one.
     // TODO(kschimpf) Don't get addresses of intrinsic function declarations.
     Ice::GlobalDeclaration *Decl = nullptr;
@@ -523,6 +534,11 @@
 
   const Ice::ClFlags &getFlags() const { return getTranslator().getFlags(); }
 
+  bool isIRGenerationDisabled() const {
+    return ALLOW_DISABLE_IR_GEN ? getTranslator().getFlags().DisableIRGeneration
+                                : false;
+  }
+
   // Generates an error Message with the bit address prefixed to it.
   bool Error(const std::string &Message) override {
     uint64_t Bit = Record.GetStartBit() + Context->getHeaderSize() * 8;
@@ -811,6 +827,8 @@
             Ice::VariableDeclaration::create(getTranslator().getContext())),
         CurGlobalVar(DummyGlobalVar) {}
 
+  ~GlobalsParser() final {}
+
 private:
   Ice::TimerMarker Timer;
   // Keeps track of how many initializers are expected for the global variable
@@ -881,10 +899,12 @@
     if (!isValidRecordSize(2, "Globals variable"))
       return;
     verifyNoMissingInitializers();
-    InitializersNeeded = 1;
-    CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
-    CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
-    CurGlobalVar->setIsConstant(Values[1] != 0);
+    if (!isIRGenerationDisabled()) {
+      InitializersNeeded = 1;
+      CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
+      CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
+      CurGlobalVar->setIsConstant(Values[1] != 0);
+    }
     ++NextGlobalID;
     return;
   }
@@ -903,12 +923,16 @@
       Error(StrBuf.str());
       return;
     }
+    if (isIRGenerationDisabled())
+      return;
     InitializersNeeded = Values[0];
     return;
   case naclbitc::GLOBALVAR_ZEROFILL: {
     // ZEROFILL: [size]
     if (!isValidRecordSize(1, "Globals zerofill"))
       return;
+    if (isIRGenerationDisabled())
+      return;
     CurGlobalVar->addInitializer(
         new Ice::VariableDeclaration::ZeroInitializer(Values[0]));
     return;
@@ -917,6 +941,8 @@
     // DATA: [b0, b1, ...]
     if (!isValidRecordSizeAtLeast(1, "Globals data"))
       return;
+    if (isIRGenerationDisabled())
+      return;
     CurGlobalVar->addInitializer(
         new Ice::VariableDeclaration::DataInitializer(Values));
     return;
@@ -925,6 +951,8 @@
     // RELOC: [val, [addend]]
     if (!isValidRecordSizeInRange(1, 2, "Globals reloc"))
       return;
+    if (isIRGenerationDisabled())
+      return;
     unsigned Index = Values[0];
     Ice::SizeT Offset = 0;
     if (Values.size() == 2)
@@ -1011,36 +1039,48 @@
   FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
       : BlockParserBaseClass(BlockID, EnclosingParser),
         Timer(Ice::TimerStack::TT_parseFunctions, getTranslator().getContext()),
-        Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
-        FcnId(Context->getNextFunctionBlockValueID()),
+        Func(isIRGenerationDisabled()
+                 ? nullptr
+                 : new Ice::Cfg(getTranslator().getContext())),
+        CurrentBbIndex(0), FcnId(Context->getNextFunctionBlockValueID()),
         FuncDecl(Context->getFunctionByID(FcnId)),
         CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
         NextLocalInstIndex(Context->getNumGlobalIDs()),
         InstIsTerminating(false) {
-    Func->setFunctionName(FuncDecl->getName());
     if (getFlags().TimeEachFunction)
       getTranslator().getContext()->pushTimer(
           getTranslator().getContext()->getTimerID(
-              Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
+              Ice::GlobalContext::TSK_Funcs, FuncDecl->getName()),
           Ice::GlobalContext::TSK_Funcs);
     // TODO(kschimpf) Clean up API to add a function signature to
     // a CFG.
     const Ice::FuncSigType &Signature = FuncDecl->getSignature();
-    Func->setReturnType(Signature.getReturnType());
-    Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
-    CurrentNode = InstallNextBasicBlock();
-    Func->setEntryNode(CurrentNode);
-    for (Ice::Type ArgType : Signature.getArgList()) {
-      Func->addArg(getNextInstVar(ArgType));
+    if (isIRGenerationDisabled()) {
+      CurrentNode = nullptr;
+      for (Ice::Type ArgType : Signature.getArgList()) {
+        (void)ArgType;
+        setNextLocalInstIndex(nullptr);
+      }
+    } else {
+      Func->setFunctionName(FuncDecl->getName());
+      Func->setReturnType(Signature.getReturnType());
+      Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
+      CurrentNode = InstallNextBasicBlock();
+      Func->setEntryNode(CurrentNode);
+      for (Ice::Type ArgType : Signature.getArgList()) {
+        Func->addArg(getNextInstVar(ArgType));
+      }
     }
   }
 
-  ~FunctionParser() override {};
+  ~FunctionParser() final {}
+
+  void setNextLocalInstIndex(Ice::Operand *Op) {
+    setOperand(NextLocalInstIndex++, Op);
+  }
 
   // Set the next constant ID to the given constant C.
-  void setNextConstantID(Ice::Constant *C) {
-    setOperand(NextLocalInstIndex++, C);
-  }
+  void setNextConstantID(Ice::Constant *C) { setNextLocalInstIndex(C); }
 
 private:
   Ice::TimerMarker Timer;
@@ -1068,6 +1108,15 @@
   // Upper limit of alignment power allowed by LLVM
   static const uint64_t AlignPowerLimit = 29;
 
+  void popTimerIfTimingEachFunction() const {
+    if (getFlags().TimeEachFunction) {
+      getTranslator().getContext()->popTimer(
+          getTranslator().getContext()->getTimerID(
+              Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
+          Ice::GlobalContext::TSK_Funcs);
+    }
+  }
+
   // Extracts the corresponding Alignment to use, given the AlignPower
   // (i.e. 2**AlignPower, or 0 if AlignPower == 0). InstName is the
   // name of the instruction the alignment appears in.
@@ -1093,10 +1142,14 @@
   void ExitBlock() override;
 
   // Creates and appends a new basic block to the list of basic blocks.
-  Ice::CfgNode *InstallNextBasicBlock() { return Func->makeNode(); }
+  Ice::CfgNode *InstallNextBasicBlock() {
+    assert(!isIRGenerationDisabled());
+    return Func->makeNode();
+  }
 
   // Returns the Index-th basic block in the list of basic blocks.
   Ice::CfgNode *getBasicBlock(uint32_t Index) {
+    assert(!isIRGenerationDisabled());
     const Ice::NodeList &Nodes = Func->getNodes();
     if (Index >= Nodes.size()) {
       std::string Buffer;
@@ -1115,6 +1168,7 @@
   // the branch references the entry block, it also generates a
   // corresponding error.
   Ice::CfgNode *getBranchBasicBlock(uint32_t Index) {
+    assert(!isIRGenerationDisabled());
     if (Index == 0) {
       Error("Branch to entry block not allowed");
       // TODO(kschimpf) Remove error recovery once implementation complete.
@@ -1124,6 +1178,7 @@
 
   // Generate an instruction variable with type Ty.
   Ice::Variable *createInstVar(Ice::Type Ty) {
+    assert(!isIRGenerationDisabled());
     if (Ty == Ice::IceType_void) {
       Error("Can't define instruction value using type void");
       // Recover since we can't throw an exception.
@@ -1134,6 +1189,7 @@
 
   // Generates the next available local variable using the given type.
   Ice::Variable *getNextInstVar(Ice::Type Ty) {
+    assert(!isIRGenerationDisabled());
     assert(NextLocalInstIndex >= CachedNumGlobalValueIDs);
     // Before creating one, see if a forwardtyperef has already defined it.
     uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs;
@@ -1191,6 +1247,8 @@
     }
     Ice::Operand *Op = LocalOperands[LocalIndex];
     if (Op == nullptr) {
+      if (isIRGenerationDisabled())
+        return nullptr;
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Value index " << Index << " not defined!";
@@ -1202,7 +1260,7 @@
 
   // Sets element Index (in the local operands list) to Op.
   void setOperand(uint32_t Index, Ice::Operand *Op) {
-    assert(Op);
+    assert(Op || isIRGenerationDisabled());
     // Check if simple push works.
     uint32_t LocalIndex = Index - CachedNumGlobalValueIDs;
     if (LocalIndex == LocalOperands.size()) {
@@ -1633,6 +1691,10 @@
 }
 
 void FunctionParser::ExitBlock() {
+  if (isIRGenerationDisabled()) {
+    popTimerIfTimingEachFunction();
+    return;
+  }
   // Before translating, check for blocks without instructions, and
   // insert unreachable. This shouldn't happen, but be safe.
   unsigned Index = 0;
@@ -1654,11 +1716,7 @@
   // for such parsing errors.
   if (Context->getNumErrors() == 0)
     getTranslator().translateFcn(Func);
-  if (getFlags().TimeEachFunction)
-    getTranslator().getContext()->popTimer(
-        getTranslator().getContext()->getTimerID(Ice::GlobalContext::TSK_Funcs,
-                                                 Func->getFunctionName()),
-        Ice::GlobalContext::TSK_Funcs);
+  popTimerIfTimingEachFunction();
 }
 
 void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op,
@@ -1671,10 +1729,15 @@
 }
 
 void FunctionParser::ProcessRecord() {
+  // Note: To better separate parse/IR generation times, when IR generation
+  // is disabled we do the following:
+  // 1) Delay exiting until after we extract operands.
+  // 2) return before we access operands, since all operands will be a nullptr.
   const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
   if (InstIsTerminating) {
     InstIsTerminating = false;
-    CurrentNode = getBasicBlock(++CurrentBbIndex);
+    if (!isIRGenerationDisabled())
+      CurrentNode = getBasicBlock(++CurrentBbIndex);
   }
   // The base index for relative indexing.
   int32_t BaseIndex = getNextInstIndex();
@@ -1683,16 +1746,18 @@
     // DECLAREBLOCKS: [n]
     if (!isValidRecordSize(1, "function block count"))
       return;
-    if (Func->getNodes().size() != 1) {
-      Error("Duplicate function block count record");
-      return;
-    }
     uint32_t NumBbs = Values[0];
     if (NumBbs == 0) {
       Error("Functions must contain at least one basic block.");
       // TODO(kschimpf) Remove error recovery once implementation complete.
       NumBbs = 1;
     }
+    if (isIRGenerationDisabled())
+      return;
+    if (Func->getNodes().size() != 1) {
+      Error("Duplicate function block count record");
+      return;
+    }
     // Install the basic blocks, skipping bb0 which was created in the
     // constructor.
     for (size_t i = 1; i < NumBbs; ++i)
@@ -1705,6 +1770,11 @@
       return;
     Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex);
     Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex);
+    if (isIRGenerationDisabled()) {
+      assert(Op1 == nullptr && Op2 == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     Ice::Type Type1 = Op1->getType();
     Ice::Type Type2 = Op2->getType();
     if (Type1 != Type2) {
@@ -1740,6 +1810,11 @@
       appendErrorInstruction(CastType);
       return;
     }
+    if (isIRGenerationDisabled()) {
+      assert(Src == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     Ice::Type SrcType = Src->getType();
     if (!CastInst::castIsValid(LLVMCastOp, Context->convertToLLVMType(SrcType),
                                Context->convertToLLVMType(CastType))) {
@@ -1757,9 +1832,17 @@
   }
   case naclbitc::FUNC_CODE_INST_VSELECT: {
     // VSELECT: [opval, opval, pred]
+    if (!isValidRecordSize(3, "function block select"))
+      return;
     Ice::Operand *ThenVal = getRelativeOperand(Values[0], BaseIndex);
-    Ice::Type ThenType = ThenVal->getType();
     Ice::Operand *ElseVal = getRelativeOperand(Values[1], BaseIndex);
+    Ice::Operand *CondVal = getRelativeOperand(Values[2], BaseIndex);
+    if (isIRGenerationDisabled()) {
+      assert(ThenVal == nullptr && ElseVal == nullptr && CondVal == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
+    Ice::Type ThenType = ThenVal->getType();
     Ice::Type ElseType = ElseVal->getType();
     if (ThenType != ElseType) {
       std::string Buffer;
@@ -1770,7 +1853,6 @@
       appendErrorInstruction(ThenType);
       return;
     }
-    Ice::Operand *CondVal = getRelativeOperand(Values[2], BaseIndex);
     Ice::Type CondType = CondVal->getType();
     if (isVectorType(CondType)) {
       if (!isVectorType(ThenType) ||
@@ -1802,8 +1884,13 @@
     if (!isValidRecordSize(2, "function block extract element"))
       return;
     Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex);
-    Ice::Type VecType = Vec->getType();
     Ice::Operand *Index = getRelativeOperand(Values[1], BaseIndex);
+    if (isIRGenerationDisabled()) {
+      assert(Vec == nullptr && Index == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
+    Ice::Type VecType = Vec->getType();
     VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index);
     if (IndexCheckValue != VectorIndexValid) {
       std::string Buffer;
@@ -1824,9 +1911,14 @@
     if (!isValidRecordSize(3, "function block insert element"))
       return;
     Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex);
-    Ice::Type VecType = Vec->getType();
     Ice::Operand *Elt = getRelativeOperand(Values[1], BaseIndex);
     Ice::Operand *Index = getRelativeOperand(Values[2], BaseIndex);
+    if (isIRGenerationDisabled()) {
+      assert(Vec == nullptr && Elt == nullptr && Index == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
+    Ice::Type VecType = Vec->getType();
     VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index);
     if (IndexCheckValue != VectorIndexValid) {
       std::string Buffer;
@@ -1849,6 +1941,11 @@
       return;
     Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex);
     Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex);
+    if (isIRGenerationDisabled()) {
+      assert(Op1 == nullptr && Op2 == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     Ice::Type Op1Type = Op1->getType();
     Ice::Type Op2Type = Op2->getType();
     Ice::Type DestType = getCompareResultType(Op1Type);
@@ -1909,10 +2006,16 @@
     if (!isValidRecordSizeInRange(0, 1, "function block ret"))
       return;
     if (Values.empty()) {
+      if (isIRGenerationDisabled())
+        return;
       CurrentNode->appendInst(Ice::InstRet::create(Func));
     } else {
-      CurrentNode->appendInst(
-          Ice::InstRet::create(Func, getRelativeOperand(Values[0], BaseIndex)));
+      Ice::Operand *RetVal = getRelativeOperand(Values[0], BaseIndex);
+      if (isIRGenerationDisabled()) {
+        assert(RetVal == nullptr);
+        return;
+      }
+      CurrentNode->appendInst(Ice::InstRet::create(Func, RetVal));
     }
     InstIsTerminating = true;
     return;
@@ -1920,6 +2023,8 @@
   case naclbitc::FUNC_CODE_INST_BR: {
     if (Values.size() == 1) {
       // BR: [bb#]
+      if (isIRGenerationDisabled())
+        return;
       Ice::CfgNode *Block = getBranchBasicBlock(Values[0]);
       if (Block == nullptr)
         return;
@@ -1929,6 +2034,10 @@
       if (!isValidRecordSize(3, "function block branch"))
         return;
       Ice::Operand *Cond = getRelativeOperand(Values[2], BaseIndex);
+      if (isIRGenerationDisabled()) {
+        assert(Cond == nullptr);
+        return;
+      }
       if (Cond->getType() != Ice::IceType_i1) {
         std::string Buffer;
         raw_string_ostream StrBuf(Buffer);
@@ -1958,6 +2067,7 @@
     // already frozen when the problem was noticed.
     if (!isValidRecordSizeAtLeast(4, "function block switch"))
       return;
+
     Ice::Type CondTy = Context->getSimpleTypeByID(Values[0]);
     if (!Ice::isScalarIntegerType(CondTy)) {
       std::string Buffer;
@@ -1968,7 +2078,11 @@
     }
     Ice::SizeT BitWidth = Ice::getScalarIntBitWidth(CondTy);
     Ice::Operand *Cond = getRelativeOperand(Values[1], BaseIndex);
-    if (CondTy != Cond->getType()) {
+
+    const bool isIRGenDisabled = isIRGenerationDisabled();
+    if (isIRGenDisabled) {
+      assert(Cond == nullptr);
+    } else if (CondTy != Cond->getType()) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
       StrBuf << "Case condition expects type " << CondTy
@@ -1976,14 +2090,16 @@
       Error(StrBuf.str());
       return;
     }
-    Ice::CfgNode *DefaultLabel = getBranchBasicBlock(Values[2]);
+    Ice::CfgNode *DefaultLabel =
+        isIRGenDisabled ? nullptr : getBranchBasicBlock(Values[2]);
     unsigned NumCases = Values[3];
 
     // Now recognize each of the cases.
     if (!isValidRecordSize(4 + NumCases * 4, "Function block switch"))
       return;
     Ice::InstSwitch *Switch =
-        Ice::InstSwitch::create(Func, NumCases, Cond, DefaultLabel);
+        isIRGenDisabled ? nullptr : Ice::InstSwitch::create(Func, NumCases,
+                                                            Cond, DefaultLabel);
     unsigned ValCaseIndex = 4;  // index to beginning of case entry.
     for (unsigned CaseIndex = 0; CaseIndex < NumCases;
          ++CaseIndex, ValCaseIndex += 4) {
@@ -1998,9 +2114,13 @@
       APInt Value(BitWidth,
                   NaClDecodeSignRotatedValue(Values[ValCaseIndex + 2]),
                   true);
+      if (isIRGenDisabled)
+        continue;
       Ice::CfgNode *Label = getBranchBasicBlock(Values[ValCaseIndex + 3]);
       Switch->addBranch(CaseIndex, Value.getSExtValue(), Label);
     }
+    if (isIRGenDisabled)
+      return;
     CurrentNode->appendInst(Switch);
     InstIsTerminating = true;
     return;
@@ -2009,6 +2129,8 @@
     // UNREACHABLE: []
     if (!isValidRecordSize(0, "function block unreachable"))
       return;
+    if (isIRGenerationDisabled())
+      return;
     CurrentNode->appendInst(
         Ice::InstUnreachable::create(Func));
     InstIsTerminating = true;
@@ -2032,6 +2154,15 @@
       Error("Phi record using type void not allowed");
       return;
     }
+    if (isIRGenerationDisabled()) {
+      // Verify arguments are defined before quitting.
+      for (unsigned i = 1; i < Values.size(); i += 2) {
+        assert(getRelativeOperand(NaClDecodeSignRotatedValue(Values[i]),
+                                  BaseIndex) == nullptr);
+      }
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     Ice::Variable *Dest = getNextInstVar(Ty);
     Ice::InstPhi *Phi = Ice::InstPhi::create(Func, Values.size() >> 1, Dest);
     for (unsigned i = 1; i < Values.size(); i += 2) {
@@ -2056,6 +2187,13 @@
     if (!isValidRecordSize(2, "function block alloca"))
       return;
     Ice::Operand *ByteCount = getRelativeOperand(Values[0], BaseIndex);
+    unsigned Alignment;
+    extractAlignment("Alloca", Values[1], Alignment);
+    if (isIRGenerationDisabled()) {
+      assert(ByteCount == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     Ice::Type PtrTy = Context->getIcePointerType();
     if (ByteCount->getType() != Ice::IceType_i32) {
       std::string Buffer;
@@ -2065,8 +2203,6 @@
       appendErrorInstruction(PtrTy);
       return;
     }
-    unsigned Alignment;
-    extractAlignment("Alloca", Values[1], Alignment);
     CurrentNode->appendInst(Ice::InstAlloca::create(Func, ByteCount, Alignment,
                                                     getNextInstVar(PtrTy)));
     return;
@@ -2077,12 +2213,17 @@
       return;
     Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex);
     Ice::Type Ty = Context->getSimpleTypeByID(Values[2]);
+    unsigned Alignment;
+    extractAlignment("Load", Values[1], Alignment);
+    if (isIRGenerationDisabled()) {
+      assert(Address == nullptr);
+      setNextLocalInstIndex(nullptr);
+      return;
+    }
     if (!isValidPointerType(Address, "Load")) {
       appendErrorInstruction(Ty);
       return;
     }
-    unsigned Alignment;
-    extractAlignment("Load", Values[1], Alignment);
     if (!isValidLoadStoreAlignment(Alignment, Ty, "Load")) {
       appendErrorInstruction(Ty);
       return;
@@ -2096,11 +2237,15 @@
     if (!isValidRecordSize(3, "function block store"))
       return;
     Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex);
-    if (!isValidPointerType(Address, "Store"))
-      return;
     Ice::Operand *Value = getRelativeOperand(Values[1], BaseIndex);
     unsigned Alignment;
     extractAlignment("Store", Values[2], Alignment);
+    if (isIRGenerationDisabled()) {
+      assert(Address == nullptr && Value == nullptr);
+      return;
+    }
+    if (!isValidPointerType(Address, "Store"))
+      return;
     if (!isValidLoadStoreAlignment(Alignment, Value->getType(), "Store"))
       return;
     CurrentNode->appendInst(
@@ -2172,12 +2317,25 @@
       return;
     }
     bool IsTailCall = static_cast<bool>(CCInfo & 1);
+    Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
+
+    if (isIRGenerationDisabled()) {
+      assert(Callee == nullptr);
+      // Check that parameters are defined.
+      for (Ice::SizeT ParamIndex = 0; ParamIndex < NumParams; ++ParamIndex) {
+        assert(getRelativeOperand(Values[ParamsStartIndex + ParamIndex],
+                                  BaseIndex) == nullptr);
+      }
+      // Define value slot only if value returned.
+      if (ReturnType != Ice::IceType_void)
+        setNextLocalInstIndex(nullptr);
+      return;
+    }
 
     // Create the call instruction.
     Ice::Variable *Dest = (ReturnType == Ice::IceType_void)
                               ? nullptr
                               : getNextInstVar(ReturnType);
-    Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
     Ice::InstCall *Inst = nullptr;
     if (IntrinsicInfo) {
       Inst =
@@ -2242,7 +2400,9 @@
     // FORWARDTYPEREF: [opval, ty]
     if (!isValidRecordSize(2, "function block forward type ref"))
       return;
-    setOperand(Values[0], createInstVar(Context->getSimpleTypeByID(Values[1])));
+    Ice::Type OpType = Context->getSimpleTypeByID(Values[1]);
+    setOperand(Values[0],
+               isIRGenerationDisabled() ? nullptr : createInstVar(OpType));
     return;
   }
   default:
@@ -2304,6 +2464,10 @@
       return;
     if (!isValidNextConstantType())
       return;
+    if (isIRGenerationDisabled()) {
+      FuncParser->setNextConstantID(nullptr);
+      return;
+    }
     FuncParser->setNextConstantID(
         getContext()->getConstantUndef(NextConstantType));
     return;
@@ -2314,6 +2478,10 @@
       return;
     if (!isValidNextConstantType())
       return;
+    if (isIRGenerationDisabled()) {
+      FuncParser->setNextConstantID(nullptr);
+      return;
+    }
     if (IntegerType *IType = dyn_cast<IntegerType>(
             Context->convertToLLVMType(NextConstantType))) {
       APInt Value(IType->getBitWidth(), NaClDecodeSignRotatedValue(Values[0]));
@@ -2338,6 +2506,10 @@
       return;
     if (!isValidNextConstantType())
       return;
+    if (isIRGenerationDisabled()) {
+      FuncParser->setNextConstantID(nullptr);
+      return;
+    }
     switch (NextConstantType) {
     case Ice::IceType_f32: {
       APFloat Value(APFloat::IEEEsingle,
@@ -2410,6 +2582,8 @@
     // TODO(kschimpf) Remove error recovery once implementation complete.
     return;
   }
+  if (isIRGenerationDisabled())
+    return;
   Ice::Operand *Op = getFunctionParser()->getOperand(Index);
   if (Ice::Variable *V = dyn_cast<Ice::Variable>(Op)) {
     std::string Nm(Name.data(), Name.size());
@@ -2420,6 +2594,8 @@
 }
 
 void FunctionValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
+  if (isIRGenerationDisabled())
+    return;
   if (Index >= getFunctionParser()->Func->getNumNodes()) {
     reportUnableToAssign("block", Index, Name);
     return;
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index fd0cc30..4dd2444 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -94,6 +94,10 @@
                 cl::desc("Externalize all symbols"));
 static cl::opt<bool>
 DisableTranslation("notranslate", cl::desc("Disable Subzero translation"));
+// Note: Modifiable only if ALLOW_DISABLE_IR_GEN.
+static cl::opt<bool>
+    DisableIRGeneration("no-ir-gen",
+                        cl::desc("Disable generating Subzero IR."));
 static cl::opt<std::string>
 TranslateOnly("translate-only", cl::desc("Translate only the given function"),
               cl::init(""));
@@ -188,12 +192,12 @@
 static struct {
   const char *FlagName;
   int FlagValue;
-} ConditionalBuildAttributes[] = { { "text_asm", ALLOW_TEXT_ASM },
-                                   { "dump", ALLOW_DUMP },
-                                   { "llvm_cl", ALLOW_LLVM_CL },
-                                   { "llvm_ir", ALLOW_LLVM_IR },
-                                   { "llvm_ir_as_input",
-                                     ALLOW_LLVM_IR_AS_INPUT } };
+} ConditionalBuildAttributes[] = {{"text_asm", ALLOW_TEXT_ASM},
+                                  {"dump", ALLOW_DUMP},
+                                  {"llvm_cl", ALLOW_LLVM_CL},
+                                  {"llvm_ir", ALLOW_LLVM_IR},
+                                  {"llvm_ir_as_input", ALLOW_LLVM_IR_AS_INPUT},
+                                  {"disable_ir_gen", ALLOW_DISABLE_IR_GEN}};
 
 // Validates values of build attributes. Prints them to Stream if
 // Stream is non-null.
@@ -228,6 +232,9 @@
 
   cl::ParseCommandLineOptions(argc, argv);
 
+  if (DisableIRGeneration)
+    DisableTranslation = true;
+
   Ice::VerboseMask VMask = Ice::IceV_None;
   for (unsigned i = 0; i != VerboseList.size(); ++i)
     VMask |= VerboseList[i];
@@ -251,6 +258,12 @@
   raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
   Ls->SetUnbuffered();
 
+  if (!ALLOW_DISABLE_IR_GEN && DisableIRGeneration) {
+    *Ls << "Error: Build doesn't allow --no-ir-gen when not "
+        << "ALLOW_DISABLE_IR_GEN!\n";
+    return GetReturnValue(1);
+  }
+
   Ice::ClFlags Flags;
   Flags.DisableInternal = DisableInternal;
   Flags.SubzeroTimingEnabled = SubzeroTimingEnabled;
@@ -269,6 +282,7 @@
   Flags.TimingFocusOn = TimingFocusOn;
   Flags.VerboseFocusOn = VerboseFocusOn;
   Flags.TranslateOnly = TranslateOnly;
+  Flags.DisableIRGeneration = DisableIRGeneration;
 
   Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
                          Flags);
diff --git a/tests_lit/lit.cfg b/tests_lit/lit.cfg
index d431d1f..3c70753 100644
--- a/tests_lit/lit.cfg
+++ b/tests_lit/lit.cfg
@@ -79,8 +79,7 @@
 
 # shell conditional commands.
 if_atts = [os.path.join(pydir, 'if.py')]
-if_atts_cmd = if_atts + ['--have=' + att
-                         for att in llvm2iceatts] + ['--command']
+if_atts_cmd = if_atts + ['--have=' + att for att in llvm2iceatts]
 ifl2i_atts_cmd = if_atts + [if_cond_flag('allow_llvm_ir' in llvm2iceatts),
                             '--command']
 iflc2i_atts_cmd = if_atts + [if_cond_flag('allow_llvm_ir_as_input'
diff --git a/tests_lit/reader_tests/alloca.ll b/tests_lit/reader_tests/alloca.ll
index fd1dea3..0a314e0 100644
--- a/tests_lit/reader_tests/alloca.ll
+++ b/tests_lit/reader_tests/alloca.ll
@@ -1,6 +1,10 @@
 ; Test if we can read alloca instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 ; Show examples where size is defined by a constant.
 
@@ -159,3 +163,5 @@
 ; CHECK-NEXT:   %array = alloca i8, i32 %n, align 16
 ; CHECK-NEXT:   ret i32 %array
 }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/binops.ll b/tests_lit/reader_tests/binops.ll
index 785d482..65ed55e 100644
--- a/tests_lit/reader_tests/binops.ll
+++ b/tests_lit/reader_tests/binops.ll
@@ -3,6 +3,10 @@
 ; RUN: %p2i -i %s --insts | FileCheck %s
 ; RUN: %l2i -i %s --insts | %ifl FileCheck %s
 ; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 ; TODO(kschimpf): add i8/i16. Needs bitcasts.
 
@@ -965,3 +969,5 @@
 ; CHECK-NEXT:   %lshr = lshr <4 x i32> %b, %a
 ; CHECK-NEXT:   ret <4 x i32> %lshr
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/branch.ll b/tests_lit/reader_tests/branch.ll
index 46b7ffa..b68a016 100644
--- a/tests_lit/reader_tests/branch.ll
+++ b/tests_lit/reader_tests/branch.ll
@@ -1,6 +1,10 @@
 ; Tests if we handle a branch instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @SimpleBranch() {
 entry:
@@ -43,3 +47,5 @@
 ; CHECK-NEXT: b2:
 ; CHECK-NEXT:   br i1 %test, label %b2, label %b1
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/call-indirect.ll b/tests_lit/reader_tests/call-indirect.ll
index 35f73e3..3da87dd 100644
--- a/tests_lit/reader_tests/call-indirect.ll
+++ b/tests_lit/reader_tests/call-indirect.ll
@@ -1,6 +1,10 @@
 ; Test parsing indirect calls in Subzero.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define internal void @CallIndirectVoid(i32 %f_addr) {
 entry:
@@ -27,3 +31,5 @@
 ; CHECK-NEXT:   %r = call i32 %f_addr(i8 1, i1 false)
 ; CHECK-NEXT:   ret i32 %r
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/call.ll b/tests_lit/reader_tests/call.ll
index ffe5e04..95227a6 100644
--- a/tests_lit/reader_tests/call.ll
+++ b/tests_lit/reader_tests/call.ll
@@ -1,6 +1,10 @@
 ; Test handling of call instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define i32 @fib(i32 %n) {
 entry:
@@ -106,3 +110,4 @@
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/casts.ll b/tests_lit/reader_tests/casts.ll
index 26dc8b7..2bf76eb 100644
--- a/tests_lit/reader_tests/casts.ll
+++ b/tests_lit/reader_tests/casts.ll
@@ -1,6 +1,10 @@
 ; Tests if we can read cast operations.
 
 ; RUN: %p2i -i %s --insts --no-local-syms | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 ; TODO(kschimpf) Find way to test pointer conversions (since they in general
 ; get removed by pnacl-freeze).
@@ -532,3 +536,5 @@
 ; CHECK-NEXT:   %__3 = bitcast <16 x i8> %__0 to <8 x i16>
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/compare.ll b/tests_lit/reader_tests/compare.ll
index 51eb581..7c92f51 100644
--- a/tests_lit/reader_tests/compare.ll
+++ b/tests_lit/reader_tests/compare.ll
@@ -1,6 +1,10 @@
 ; Test if we can read compare instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define i1 @IcmpI1(i32 %p1, i32 %p2) {
 entry:
@@ -469,3 +473,5 @@
 ; CHECK-NEXT:   %vtrue = fcmp true <4 x float> %a1, %a2
 ; CHECK-NEXT:   ret <4 x i1> %voeq
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/constants.ll b/tests_lit/reader_tests/constants.ll
index feb7dcd..d8127e6 100644
--- a/tests_lit/reader_tests/constants.ll
+++ b/tests_lit/reader_tests/constants.ll
@@ -1,6 +1,10 @@
 ; Test handling of constants in function blocks.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @TestIntegers() {
 entry:
@@ -152,3 +156,5 @@
   ret void
 ; CHECK-NEXT:   ret void
 }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/forwardref.ll b/tests_lit/reader_tests/forwardref.ll
index b938b6c..86b41b7 100644
--- a/tests_lit/reader_tests/forwardref.ll
+++ b/tests_lit/reader_tests/forwardref.ll
@@ -1,9 +1,12 @@
 ; Test use forward type references in function blocks.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
-
 ; RUN: llvm-as < %s | pnacl-freeze | pnacl-bcdis -no-records \
 ; RUN:              | FileCheck --check-prefix=DUMP %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @LoopCarriedDep() {
 b0:
@@ -116,3 +119,5 @@
 ; DUMP-NEXT:   %b6:
 ; DUMP-NEXT:     ret void; <@a3>
 ; DUMP-NEXT:   }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/globalinit.pnacl.ll b/tests_lit/reader_tests/globalinit.pnacl.ll
index 6d4c9aa..0d92351 100644
--- a/tests_lit/reader_tests/globalinit.pnacl.ll
+++ b/tests_lit/reader_tests/globalinit.pnacl.ll
@@ -3,6 +3,10 @@
 ; RUN: %p2i -i %s --insts | FileCheck %s
 ; RUN: %l2i -i %s --insts | %ifl FileCheck %s
 ; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 @PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
 ; CHECK: @PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
@@ -74,3 +78,5 @@
   %result = sub i32 0, %size
   ret i32 %result
 }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/globalrelocs.ll b/tests_lit/reader_tests/globalrelocs.ll
index 6634890..a6a44f7 100644
--- a/tests_lit/reader_tests/globalrelocs.ll
+++ b/tests_lit/reader_tests/globalrelocs.ll
@@ -3,6 +3,10 @@
 ; RUN: %p2i -i %s --insts | FileCheck %s
 ; RUN: %l2i -i %s --insts | %ifl FileCheck %s
 ; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 @bytes = internal global [7 x i8] c"abcdefg"
 ; CHECK: @bytes = internal global [7 x i8] c"abcdefg"
@@ -95,3 +99,4 @@
 
 ; CHECK-NEXT: define void @func() {
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/insertextract.ll b/tests_lit/reader_tests/insertextract.ll
index 7116109..ca01469 100644
--- a/tests_lit/reader_tests/insertextract.ll
+++ b/tests_lit/reader_tests/insertextract.ll
@@ -3,6 +3,10 @@
 ; RUN: %p2i -i %s --insts | FileCheck %s
 ; RUN: %l2i -i %s --insts | %ifl FileCheck %s
 ; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @ExtractV4xi1(<4 x i1> %v) {
 entry:
@@ -377,3 +381,5 @@
 ; CHECK-NEXT:   %r3 = insertelement <4 x float> %v, float %e, i32 3
 ; CHECK-NEXT:   ret <4 x float> %r3
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/load.ll b/tests_lit/reader_tests/load.ll
index 7b579d3..75591ae 100644
--- a/tests_lit/reader_tests/load.ll
+++ b/tests_lit/reader_tests/load.ll
@@ -1,6 +1,10 @@
 ; Test if we can read load instructions.
 
 ; RUN: %p2i --no-local-syms -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define i32 @load_i8(i32 %addr) {
 entry:
@@ -144,3 +148,4 @@
 ; CHECK-NEXT:   ret <4 x float> %__1
 }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/nacl-atomic-intrinsics.ll b/tests_lit/reader_tests/nacl-atomic-intrinsics.ll
index bc9011e..b59b380 100644
--- a/tests_lit/reader_tests/nacl-atomic-intrinsics.ll
+++ b/tests_lit/reader_tests/nacl-atomic-intrinsics.ll
@@ -1,6 +1,10 @@
 ; Test parsing NaCl atomic instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32)
 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32)
@@ -638,3 +642,4 @@
 ; CHECK-NEXT:   ret i32 %r
 ; CHECK-NEXT: }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/nacl-other-intrinsics.ll b/tests_lit/reader_tests/nacl-other-intrinsics.ll
index eda03a3..aac2c25 100644
--- a/tests_lit/reader_tests/nacl-other-intrinsics.ll
+++ b/tests_lit/reader_tests/nacl-other-intrinsics.ll
@@ -1,6 +1,10 @@
 ; This tests parsing NaCl intrinsics not related to atomic operations.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 declare i8* @llvm.nacl.read.tp()
 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
@@ -339,3 +343,4 @@
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/phi.ll b/tests_lit/reader_tests/phi.ll
index 3799d4b..a90bc4c 100644
--- a/tests_lit/reader_tests/phi.ll
+++ b/tests_lit/reader_tests/phi.ll
@@ -1,6 +1,10 @@
 ; Test reading phi instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 ; TODO(kschimpf) Add forward reference examples.
 
@@ -28,3 +32,4 @@
 ; CHECK-NEXT:   ret i32 %result
 ; CHECK-NEXT: }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/select.ll b/tests_lit/reader_tests/select.ll
index 8177fa3..8421084 100644
--- a/tests_lit/reader_tests/select.ll
+++ b/tests_lit/reader_tests/select.ll
@@ -1,6 +1,10 @@
 ; Tests if we can read select instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @Seli1(i32 %p) {
 entry:
@@ -293,3 +297,5 @@
 ; CHECK-NEXT:   %r = select <4 x i1> %pc, <4 x float> %pt, <4 x float> %pe
 ; CHECK-NEXT:   ret <4 x float> %r
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/store.ll b/tests_lit/reader_tests/store.ll
index c507175..091e763 100644
--- a/tests_lit/reader_tests/store.ll
+++ b/tests_lit/reader_tests/store.ll
@@ -1,6 +1,10 @@
 ; Test if we can read store instructions.
 
 ; RUN: %p2i -i %s --insts --no-local-syms | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @store_i8(i32 %addr) {
 entry:
@@ -133,3 +137,5 @@
 ; CHECK-NEXT:   store <4 x float> %__1, <4 x float>* %__0, align 4
 ; CHECK-NEXT:   ret void
 }
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/switch.ll b/tests_lit/reader_tests/switch.ll
index bb60e55..0bbbf88 100644
--- a/tests_lit/reader_tests/switch.ll
+++ b/tests_lit/reader_tests/switch.ll
@@ -1,6 +1,10 @@
 ; Test switch instructions.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define void @testDefaultSwitch(i32 %a) {
 entry:
@@ -490,3 +494,4 @@
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
 
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/unnamed.ll b/tests_lit/reader_tests/unnamed.ll
index 87dccd6..3f84b01 100644
--- a/tests_lit/reader_tests/unnamed.ll
+++ b/tests_lit/reader_tests/unnamed.ll
@@ -12,6 +12,11 @@
 ; RUN:      -default-function-prefix=h -default-global-prefix=g \
 ; RUN:      | FileCheck --check-prefix=BAD %s
 
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
+
 ; TODO(kschimpf) Check global variable declarations, once generated.
 
 @0 = internal global [4 x i8] zeroinitializer, align 4
@@ -57,3 +62,5 @@
 
 ; BAD: Warning : Default global prefix 'g' potentially conflicts with name 'g'.
 ; BAD: Warning : Default function prefix 'h' potentially conflicts with name 'h5'.
+
+; NOIR: Total across all functions
diff --git a/tests_lit/reader_tests/unreachable.ll b/tests_lit/reader_tests/unreachable.ll
index 4cd2f9d..7f12187 100644
--- a/tests_lit/reader_tests/unreachable.ll
+++ b/tests_lit/reader_tests/unreachable.ll
@@ -1,6 +1,10 @@
 ; Test parsing unreachable instruction.
 
 ; RUN: %p2i -i %s --insts | FileCheck %s
+; RUN: %if --need=allow_disable_ir_gen --command \
+; RUN:   %p2i -i %s --args -notranslate -timing -no-ir-gen \
+; RUN: | %if --need=allow_disable_ir_gen --command \
+; RUN:   FileCheck --check-prefix=NOIR %s
 
 define internal i32 @divide(i32 %num, i32 %den) {
 entry:
@@ -25,3 +29,5 @@
 ; CHECK-NEXT:   %div = sdiv i32 %num, %den
 ; CHECK-NEXT:   ret i32 %div
 ; CHECK-NEXT: }
+
+; NOIR: Total across all functions