Add call instructions to Subzero's 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/577353003
diff --git a/src/IceConverter.cpp b/src/IceConverter.cpp
index 2db34e9..ec797c1 100644
--- a/src/IceConverter.cpp
+++ b/src/IceConverter.cpp
@@ -537,7 +537,8 @@
 
     // Not an intrinsic call.
     if (NewInst == NULL) {
-      NewInst = Ice::InstCall::create(Func, NumArgs, Dest, CallTarget);
+      NewInst = Ice::InstCall::create(Func, NumArgs, Dest, CallTarget,
+                                      Inst->isTailCall());
     }
     for (unsigned i = 0; i < NumArgs; ++i) {
       NewInst->addArg(convertOperand(Inst, i));
@@ -574,26 +575,38 @@
 
   void validateIntrinsicCall(const Ice::InstCall *Call,
                              const Ice::Intrinsics::FullIntrinsicInfo *I) {
-    assert(I->NumTypes >= 1);
-    if (I->Signature[0] == Ice::IceType_void) {
-      if (Call->getDest() != NULL) {
-        report_fatal_error(
-            "Return value for intrinsic func w/ void return type.");
-      }
-    } else {
-      if (I->Signature[0] != Call->getDest()->getType()) {
-        report_fatal_error("Mismatched return types.");
-      }
+    Ice::SizeT ArgIndex = 0;
+    switch (I->validateCall(Call, ArgIndex)) {
+    default:
+      report_fatal_error("Unknown validation error for intrinsic call");
+      break;
+    case Ice::Intrinsics::IsValidCall:
+      break;
+    case Ice::Intrinsics::BadReturnType: {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Intrinsic call expects return type " << I->getReturnType()
+             << ". Found: " << Call->getReturnType();
+      report_fatal_error(StrBuf.str());
+      break;
     }
-    if (Call->getNumArgs() + 1 != I->NumTypes) {
-      std::cerr << "Call->getNumArgs() " << (int)Call->getNumArgs()
-                << " I->NumTypes " << (int)I->NumTypes << "\n";
-      report_fatal_error("Mismatched # of args.");
+    case Ice::Intrinsics::WrongNumOfArgs: {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Intrinsic call expects " << I->getNumArgs()
+             << ". Found: " << Call->getNumArgs();
+      report_fatal_error(StrBuf.str());
+      break;
     }
-    for (size_t i = 1; i < I->NumTypes; ++i) {
-      if (Call->getArg(i - 1)->getType() != I->Signature[i]) {
-        report_fatal_error("Mismatched argument type.");
-      }
+    case Ice::Intrinsics::WrongCallArgType: {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Intrinsic call argument " << ArgIndex << " expects type "
+             << I->getArgType(ArgIndex)
+             << ". Found: " << Call->getArg(ArgIndex)->getType();
+      report_fatal_error(StrBuf.str());
+      break;
+    }
     }
   }
 
diff --git a/src/IceInst.cpp b/src/IceInst.cpp
index b84266a..d6e0f59 100644
--- a/src/IceInst.cpp
+++ b/src/IceInst.cpp
@@ -566,6 +566,12 @@
   Str << "label %" << getTargetFalse()->getName();
 }
 
+Type InstCall::getReturnType() const {
+  if (Dest == NULL)
+    return IceType_void;
+  return Dest->getType();
+}
+
 void InstCall::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
   if (getDest()) {
diff --git a/src/IceInst.h b/src/IceInst.h
index 18c38dd..cf507e6 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -296,32 +296,36 @@
 class InstCall : public Inst {
 public:
   static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
-                          Operand *CallTarget) {
+                          Operand *CallTarget, bool HasTailCall) {
     // Set HasSideEffects to true so that the call instruction can't be
     // dead-code eliminated. IntrinsicCalls can override this if the
     // particular intrinsic is deletable and has no side-effects.
     const bool HasSideEffects = true;
     const InstKind Kind = Inst::Call;
-    return new (Func->allocateInst<InstCall>())
-        InstCall(Func, NumArgs, Dest, CallTarget, HasSideEffects, Kind);
+    return new (Func->allocateInst<InstCall>()) InstCall(
+        Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind);
   }
   void addArg(Operand *Arg) { addSource(Arg); }
   Operand *getCallTarget() const { return getSrc(0); }
   Operand *getArg(SizeT I) const { return getSrc(I + 1); }
   SizeT getNumArgs() const { return getSrcSize() - 1; }
+  bool isTailcall() const { return HasTailCall; }
   virtual void dump(const Cfg *Func) const;
   static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
+  Type getReturnType() const;
 
 protected:
   InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget,
-           bool HasSideEff, InstKind Kind)
-      : Inst(Func, Kind, NumArgs + 1, Dest) {
+           bool HasTailCall, bool HasSideEff, InstKind Kind)
+      : Inst(Func, Kind, NumArgs + 1, Dest),
+        HasTailCall(HasTailCall) {
     HasSideEffects = HasSideEff;
     addSource(CallTarget);
   }
   virtual ~InstCall() {}
 
 private:
+  bool HasTailCall;
   InstCall(const InstCall &) LLVM_DELETED_FUNCTION;
   InstCall &operator=(const InstCall &) LLVM_DELETED_FUNCTION;
 };
@@ -475,7 +479,7 @@
 private:
   InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest,
                     Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info)
-      : InstCall(Func, NumArgs, Dest, CallTarget, Info.HasSideEffects,
+      : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects,
                  Inst::IntrinsicCall),
         Info(Info) {}
   InstIntrinsicCall(const InstIntrinsicCall &) LLVM_DELETED_FUNCTION;
diff --git a/src/IceIntrinsics.cpp b/src/IceIntrinsics.cpp
index e941ff9..757455f 100644
--- a/src/IceIntrinsics.cpp
+++ b/src/IceIntrinsics.cpp
@@ -14,6 +14,7 @@
 
 #include "IceCfg.h"
 #include "IceCfgNode.h"
+#include "IceInst.h"
 #include "IceIntrinsics.h"
 #include "IceLiveness.h"
 #include "IceOperand.h"
@@ -226,4 +227,33 @@
   return Order == Intrinsics::MemoryOrderSequentiallyConsistent;
 }
 
+Intrinsics::ValidateCallValue
+Intrinsics::FullIntrinsicInfo::validateCall(const Ice::InstCall *Call,
+                                            SizeT &ArgIndex) const {
+  assert(NumTypes >= 1);
+  Variable *Result = Call->getDest();
+  if (Result == NULL) {
+    if (Signature[0] != Ice::IceType_void)
+      return Intrinsics::BadReturnType;
+  } else if (Signature[0] != Result->getType()) {
+    return Intrinsics::BadReturnType;
+  }
+  if (Call->getNumArgs() + 1 != NumTypes) {
+    return Intrinsics::WrongNumOfArgs;
+  }
+  for (size_t i = 1; i < NumTypes; ++i) {
+    if (Call->getArg(i - 1)->getType() != Signature[i]) {
+      ArgIndex = i;
+      return Intrinsics::WrongCallArgType;
+    }
+  }
+  return Intrinsics::IsValidCall;
+}
+
+Type Intrinsics::FullIntrinsicInfo::getArgType(SizeT Index) const {
+  assert(NumTypes > 1);
+  assert(Index + 1 < NumTypes);
+  return Signature[Index + 1];
+}
+
 } // end of namespace Ice
diff --git a/src/IceIntrinsics.h b/src/IceIntrinsics.h
index d984b4c..bd0f118 100644
--- a/src/IceIntrinsics.h
+++ b/src/IceIntrinsics.h
@@ -19,6 +19,8 @@
 
 namespace Ice {
 
+class InstCall;
+
 static const size_t kMaxIntrinsicParameters = 6;
 
 class Intrinsics {
@@ -108,6 +110,14 @@
     enum ReturnsTwice ReturnsTwice : 1;
   };
 
+  // The types of validation values for FullIntrinsicInfo.validateCall.
+  enum ValidateCallValue {
+    IsValidCall,      // Valid use of instrinsic call.
+    BadReturnType,    // Return type invalid for intrinsic.
+    WrongNumOfArgs,   // Wrong number of arguments for intrinsic.
+    WrongCallArgType, // Argument of wrong type.
+  };
+
   // The complete set of information about an intrinsic.
   struct FullIntrinsicInfo {
     struct IntrinsicInfo Info; // Information that CodeGen would care about.
@@ -115,6 +125,27 @@
     // Sanity check during parsing.
     Type Signature[kMaxIntrinsicParameters];
     uint8_t NumTypes;
+
+    // Validates that type signature of call matches intrinsic.
+    // If WrongArgumentType is returned, ArgIndex is set to corresponding
+    // argument index.
+    ValidateCallValue validateCall(const Ice::InstCall *Call,
+                                   SizeT &ArgIndex) const;
+
+    // Returns the return type of the intrinsic.
+    Type getReturnType() const {
+      assert(NumTypes > 1);
+      return Signature[0];
+    }
+
+    // Returns number of arguments expected.
+    SizeT getNumArgs() const {
+      assert(NumTypes > 1);
+      return NumTypes - 1;
+    }
+
+    // Returns type of Index-th argument.
+    Type getArgType(SizeT Index) const;
   };
 
   // Find the information about a given intrinsic, based on function name.
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 4b87354..1b65b3f 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -161,7 +161,7 @@
     const Type FunctionPointerType = IceType_i32;
     Constant *CallTarget =
         Ctx->getConstantSym(FunctionPointerType, 0, Name, SuppressMangling);
-    InstCall *Call = InstCall::create(Func, MaxSrcs, Dest, CallTarget);
+    InstCall *Call = InstCall::create(Func, MaxSrcs, Dest, CallTarget, false);
     return Call;
   }
   static Type stackSlotType();
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index 1353b07..e87e0aa 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -63,6 +63,7 @@
         NumFunctionBlocks(0),
         GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
     Mod->setDataLayout(PNaClDataLayout);
+    setErrStream(Translator.getContext()->getStrDump());
   }
 
   virtual ~TopLevelParser() {}
@@ -146,6 +147,26 @@
     return ValueIDValues[ID];
   }
 
+  /// Returns the corresponding constant associated with a global value
+  /// (i.e. relocatable).
+  Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) {
+    // TODO(kschimpf): Can this be built when creating global initializers?
+    if (ID >= ValueIDConstants.size()) {
+      if (ID >= ValueIDValues.size())
+        return NULL;
+      ValueIDConstants.resize(ValueIDValues.size());
+    }
+    Ice::Constant *C = ValueIDConstants[ID];
+    if (C != NULL)
+      return C;
+    Value *V = ValueIDValues[ID];
+    assert(isa<GlobalValue>(V));
+    C = getTranslator().getContext()->getConstantSym(getIcePointerType(), 0,
+                                                     V->getName());
+    ValueIDConstants[ID] = C;
+    return C;
+  }
+
   /// Returns the number of function addresses (i.e. ID's) defined in
   /// the bitcode file.
   unsigned getNumFunctionIDs() const { return NumFunctionIds; }
@@ -247,6 +268,8 @@
   std::vector<Type *> TypeIDValues;
   // The (global) value IDs.
   std::vector<WeakVH> ValueIDValues;
+  // Relocatable constants associated with ValueIDValues.
+  std::vector<Ice::Constant *> ValueIDConstants;
   // The number of function IDs.
   unsigned NumFunctionIds;
   // The number of function blocks (processed so far).
@@ -973,8 +996,7 @@
   // Returns the value referenced by the given value Index.
   Ice::Operand *getOperand(uint32_t Index) {
     if (Index < CachedNumGlobalValueIDs) {
-      // TODO(kschimpf): Define implementation.
-      report_fatal_error("getOperand of global addresses not implemented");
+      return Context->getOrCreateGlobalConstantByID(Index);
     }
     uint32_t LocalIndex = Index - CachedNumGlobalValueIDs;
     if (LocalIndex >= LocalOperands.size()) {
@@ -1123,6 +1145,18 @@
   // is not understood.
   void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty);
 
+  // Returns true if the Str begins with Prefix.
+  bool isStringPrefix(Ice::IceString &Str, Ice::IceString &Prefix) {
+    const size_t PrefixSize = Prefix.size();
+    if (Str.size() < PrefixSize)
+      return false;
+    for (size_t i = 0; i < PrefixSize; ++i) {
+      if (Str[i] != Prefix[i])
+        return false;
+    }
+    return true;
+  }
+
   // Takes the PNaCl bitcode binary operator Opcode, and the opcode
   // type Ty, and sets Op to the corresponding ICE binary
   // opcode. Returns true if able to convert, false otherwise.
@@ -1834,6 +1868,143 @@
         Ice::InstStore::create(Func, Value, Address, Alignment));
     break;
   }
+  case naclbitc::FUNC_CODE_INST_CALL:
+  case naclbitc::FUNC_CODE_INST_CALL_INDIRECT: {
+    // CALL: [cc, fnid, arg0, arg1...]
+    // CALL_INDIRECT: [cc, fn, returnty, args...]
+    //
+    // Note: The difference between CALL and CALL_INDIRECT is that
+    // CALL has an explicit function address, while the CALL_INDIRECT
+    // is just an address. For CALL, we can infer the return type by
+    // looking up the type signature associated with the function
+    // address. For CALL_INDIRECT we can only infer the type signature
+    // via argument types, and the corresponding return type stored in
+    // CALL_INDIRECT record.
+    Ice::SizeT ParamsStartIndex = 2;
+    if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
+      if (!isValidRecordSizeAtLeast(2, "function block call"))
+        return;
+    } else {
+      if (!isValidRecordSizeAtLeast(3, "function block call indirect"))
+        return;
+      ParamsStartIndex = 3;
+    }
+
+    // Extract call information.
+    uint64_t CCInfo = Values[0];
+    CallingConv::ID CallingConv;
+    if (!naclbitc::DecodeCallingConv(CCInfo >> 1, CallingConv)) {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Function call calling convention value " << (CCInfo >> 1)
+             << " not understood.";
+      Error(StrBuf.str());
+      return;
+    }
+    bool IsTailCall = static_cast<bool>(CCInfo & 1);
+
+    // Extract out the called function and its return type.
+    uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex);
+    Ice::Operand *Callee = getOperand(CalleeIndex);
+    Ice::Type ReturnType = Ice::IceType_void;
+    const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = NULL;
+    if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
+      Function *Fcn =
+          dyn_cast<Function>(Context->getGlobalValueByID(CalleeIndex));
+      if (Fcn == NULL) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Function call to non-function: " << *Callee;
+        Error(StrBuf.str());
+        return;
+      }
+
+      FunctionType *FcnTy = Fcn->getFunctionType();
+      ReturnType = Context->convertToIceType(FcnTy->getReturnType());
+
+      // Check if this direct call is to an Intrinsic (starts with "llvm.")
+      static Ice::IceString LLVMPrefix("llvm.");
+      Ice::IceString Name = Fcn->getName();
+      if (isStringPrefix(Name, LLVMPrefix)) {
+        Ice::IceString Suffix = Name.substr(LLVMPrefix.size());
+        IntrinsicInfo =
+            getTranslator().getContext()->getIntrinsicsInfo().find(Suffix);
+        if (!IntrinsicInfo) {
+          std::string Buffer;
+          raw_string_ostream StrBuf(Buffer);
+          StrBuf << "Invalid PNaCl intrinsic call to " << Name;
+          Error(StrBuf.str());
+          return;
+        }
+      }
+    } else {
+      ReturnType = Context->convertToIceType(Context->getTypeByID(Values[2]));
+    }
+
+    // Create the call instruction.
+    Ice::Variable *Dest =
+        (ReturnType == Ice::IceType_void) ? NULL : getNextInstVar(ReturnType);
+    Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
+    Ice::InstCall *Inst = NULL;
+    if (IntrinsicInfo) {
+      Inst =
+          Ice::InstIntrinsicCall::create(Func, NumParams, Dest, Callee,
+                                         IntrinsicInfo->Info);
+    } else {
+      Inst = Ice::InstCall::create(Func, NumParams, Dest, Callee, IsTailCall);
+    }
+
+    // Add parameters.
+    for (Ice::SizeT ParamIndex = 0; ParamIndex < NumParams; ++ParamIndex) {
+      Inst->addArg(
+          getRelativeOperand(Values[ParamsStartIndex + ParamIndex], BaseIndex));
+    }
+
+    // If intrinsic call, validate call signature.
+    if (IntrinsicInfo) {
+      Ice::SizeT ArgIndex = 0;
+      switch (IntrinsicInfo->validateCall(Inst, ArgIndex)) {
+      default:
+        Error("Unknown validation error for intrinsic call");
+        // TODO(kschimpf) Remove error recovery once implementation complete.
+        break;
+      case Ice::Intrinsics::IsValidCall:
+        break;
+      case Ice::Intrinsics::BadReturnType: {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Intrinsic call expects return type "
+               << IntrinsicInfo->getReturnType()
+               << ". Found: " << Inst->getReturnType();
+        Error(StrBuf.str());
+        // TODO(kschimpf) Remove error recovery once implementation complete.
+        break;
+      }
+      case Ice::Intrinsics::WrongNumOfArgs: {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Intrinsic call expects " << IntrinsicInfo->getNumArgs()
+               << ". Found: " << Inst->getNumArgs();
+        Error(StrBuf.str());
+        // TODO(kschimpf) Remove error recovery once implementation complete.
+        break;
+      }
+      case Ice::Intrinsics::WrongCallArgType: {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Intrinsic call argument " << ArgIndex << " expects type "
+               << IntrinsicInfo->getArgType(ArgIndex)
+               << ". Found: " << Inst->getArg(ArgIndex)->getType();
+        Error(StrBuf.str());
+        // TODO(kschimpf) Remove error recovery once implementation complete.
+        break;
+      }
+      }
+    }
+
+    CurrentNode->appendInst(Inst);
+    return;
+  }
   case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: {
     // FORWARDTYPEREF: [opval, ty]
     if (!isValidRecordSize(2, "function block forward type ref"))
@@ -1842,8 +2013,6 @@
                               Context->getTypeByID(Values[1]))));
     break;
   }
-  case naclbitc::FUNC_CODE_INST_CALL:
-  case naclbitc::FUNC_CODE_INST_CALL_INDIRECT:
   default:
     // Generate error message!
     BlockParserBaseClass::ProcessRecord();