Add forward instruction declaration to Subzero bitcode reader.

BUG= https://code.google.com/p/nativeclient/issues/detail?id=3892
R=jvoung@chromium.org, stichnot@chromium.org

Review URL: https://codereview.chromium.org/576853002
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index eac0760..d63232f 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -814,6 +814,7 @@
         FcnId(Context->getNextFunctionBlockValueID()),
         LLVMFunc(cast<Function>(Context->getGlobalValueByID(FcnId))),
         CachedNumGlobalValueIDs(Context->getNumGlobalValueIDs()),
+        NextLocalInstIndex(Context->getNumGlobalValueIDs()),
         InstIsTerminating(false) {
     Func->setFunctionName(LLVMFunc->getName());
     Func->setReturnType(Context->convertToIceType(LLVMFunc->getReturnType()));
@@ -830,7 +831,9 @@
   ~FunctionParser() LLVM_OVERRIDE;
 
   // Set the next constant ID to the given constant C.
-  void setNextConstantID(Ice::Constant *C) { LocalOperands.push_back(C); }
+  void setNextConstantID(Ice::Constant *C) {
+    setOperand(NextLocalInstIndex++, C);
+  }
 
 private:
   // Timer for reading function bitcode and converting to ICE.
@@ -845,11 +848,14 @@
   unsigned FcnId;
   // The corresponding LLVM function.
   Function *LLVMFunc;
+  // Holds the dividing point between local and global absolute value indices.
+  uint32_t CachedNumGlobalValueIDs;
   // Holds operands local to the function block, based on indices
   // defined in the bitcode file.
   std::vector<Ice::Operand *> LocalOperands;
-  // Holds the dividing point between local and global absolute value indices.
-  uint32_t CachedNumGlobalValueIDs;
+  // Holds the index within LocalOperands corresponding to the next
+  // instruction that generates a value.
+  uint32_t NextLocalInstIndex;
   // True if the last processed instruction was a terminating
   // instruction.
   bool InstIsTerminating;
@@ -910,15 +916,42 @@
     return getBasicBlock(Index);
   }
 
-  // Generates the next available local variable using the given type.
-  Ice::Variable *getNextInstVar(Ice::Type Ty) {
+  // Generate an instruction variable with type Ty.
+  Ice::Variable *createInstVar(Ice::Type Ty) {
     if (Ty == Ice::IceType_void) {
       Error("Can't define instruction value using type void");
       // Recover since we can't throw an exception.
       Ty = Ice::IceType_i32;
     }
-    Ice::Variable *Var = Func->makeVariable(Ty, CurrentNode);
-    LocalOperands.push_back(Var);
+    return Func->makeVariable(Ty, CurrentNode);
+  }
+
+  // Generates the next available local variable using the given type.
+  Ice::Variable *getNextInstVar(Ice::Type Ty) {
+    assert(NextLocalInstIndex >= CachedNumGlobalValueIDs);
+    // Before creating one, see if a forwardtyperef has already defined it.
+    uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs;
+    if (LocalIndex < LocalOperands.size()) {
+      Ice::Operand *Op = LocalOperands[LocalIndex];
+      if (Op != NULL) {
+        if (Ice::Variable *Var = dyn_cast<Ice::Variable>(Op)) {
+          if (Var->getType() == Ty) {
+            ++NextLocalInstIndex;
+            return Var;
+          }
+        }
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Illegal forward referenced instruction ("
+               << NextLocalInstIndex << "): " << *Op;
+        Error(StrBuf.str());
+        // TODO(kschimpf) Remove error recovery once implementation complete.
+        ++NextLocalInstIndex;
+        return createInstVar(Ty);
+      }
+    }
+    Ice::Variable *Var = createInstVar(Ty);
+    setOperand(NextLocalInstIndex++, Var);
     return Var;
   }
 
@@ -947,12 +980,54 @@
     if (LocalIndex >= LocalOperands.size()) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Value index " << Index << " out of range. Must be less than "
-             << (LocalOperands.size() + CachedNumGlobalValueIDs);
+      StrBuf << "Value index " << Index << " not defined!";
       Error(StrBuf.str());
       report_fatal_error("Unable to continue");
     }
-    return LocalOperands[LocalIndex];
+    Ice::Operand *Op = LocalOperands[LocalIndex];
+    if (Op == NULL) {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Value index " << Index << " not defined!";
+      Error(StrBuf.str());
+      report_fatal_error("Unable to continue");
+    }
+    return Op;
+  }
+
+  // Sets element Index (in the local operands list) to Op.
+  void setOperand(uint32_t Index, Ice::Operand *Op) {
+    assert(Op);
+    // Check if simple push works.
+    uint32_t LocalIndex = Index - CachedNumGlobalValueIDs;
+    if (LocalIndex == LocalOperands.size()) {
+      LocalOperands.push_back(Op);
+      return;
+    }
+
+    // Must be forward reference, expand vector to accommodate.
+    if (LocalIndex >= LocalOperands.size())
+      LocalOperands.resize(LocalIndex+1);
+
+    // If element not defined, set it.
+    Ice::Operand *OldOp = LocalOperands[LocalIndex];
+    if (OldOp == NULL) {
+      LocalOperands[LocalIndex] = Op;
+      return;
+    }
+
+    // See if forward reference matches.
+    if (OldOp == Op)
+      return;
+
+    // Error has occurred.
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << "Multiple definitions for index " << Index
+           << ": " << *Op << " and " << *OldOp;
+    Error(StrBuf.str());
+    // TODO(kschimpf) Remove error recovery once implementation complete.
+    LocalOperands[LocalIndex] = Op;
   }
 
   // Returns the relative operand (wrt to BaseIndex) referenced by
@@ -963,7 +1038,7 @@
 
   // Returns the absolute index of the next value generating instruction.
   uint32_t getNextInstIndex() const {
-    return CachedNumGlobalValueIDs + LocalOperands.size();
+    return NextLocalInstIndex;
   }
 
   // Generates type error message for binary operator Op
@@ -1702,10 +1777,17 @@
         Ice::InstStore::create(Func, Value, Address, Alignment));
     break;
   }
+  case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: {
+    // FORWARDTYPEREF: [opval, ty]
+    if (!isValidRecordSize(2, "function block forward type ref"))
+      return;
+    setOperand(Values[0], createInstVar(
+        Context->convertToIceType(Context->getTypeByID(Values[1]))));
+    break;
+  }
   case naclbitc::FUNC_CODE_INST_SWITCH:
   case naclbitc::FUNC_CODE_INST_CALL:
   case naclbitc::FUNC_CODE_INST_CALL_INDIRECT:
-  case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF:
   default:
     // Generate error message!
     BlockParserBaseClass::ProcessRecord();