Check that address is i32 for indirect calls.

Fixes bug where code did not check that the address of an indirect call must be i32.

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

Review URL: https://codereview.chromium.org/1363983002 .
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index d792865..ba9eabb 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -1598,7 +1598,7 @@
     std::string Buffer;
     raw_string_ostream StrBuf(Buffer);
     StrBuf << InstructionName << " address not " << PtrType
-           << ". Found: " << *Op;
+           << ". Found: " << Op->getType();
     Error(StrBuf.str());
     return false;
   }
@@ -2048,6 +2048,24 @@
       return LocalOperands.front();
     return Context->getGlobalConstantByID(0);
   }
+
+  void verifyCallArgTypeMatches(Ice::FunctionDeclaration *Fcn,
+                                Ice::SizeT Index, Ice::Type ArgType,
+                                Ice::Type ParamType) {
+    if (ArgType != ParamType) {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Argument " << (Index + 1)  << " of " << printName(Fcn)
+             << " expects " << ParamType << ". Found: " << ArgType;
+      Error(StrBuf.str());
+    }
+  }
+
+  const Ice::IceString printName(Ice::FunctionDeclaration *Fcn) {
+    if (Fcn)
+      return Fcn->getName();
+    return "function";
+  }
 };
 
 void FunctionParser::ExitBlock() {
@@ -2660,46 +2678,116 @@
       ParamsStartIndex = 3;
     }
 
-    // Extract out the called function and its return type.
     uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex);
     Ice::Operand *Callee = getOperand(CalleeIndex);
+
+    // Pull out signature/return type of call (if possible).
+    Ice::FunctionDeclaration *Fcn = nullptr;
     const Ice::FuncSigType *Signature = nullptr;
     Ice::Type ReturnType = Ice::IceType_void;
     const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
-    // Name of function if a direct call/intrinsic. Null otherwise.
-    Ice::FunctionDeclaration *Fcn = nullptr;
     if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
       Fcn = Context->getFunctionByID(CalleeIndex);
       Signature = &Fcn->getSignature();
       ReturnType = Signature->getReturnType();
+      Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
+      if (NumParams != Signature->getNumArgs()) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Call to " << printName(Fcn) << " has " << NumParams
+               << " parameters. Signature expects: " << Signature->getNumArgs();
+        Error(StrBuf.str());
+        if (ReturnType != Ice::IceType_void)
+          setNextLocalInstIndex(nullptr);
+        return;
+      }
 
       // Check if this direct call is to an Intrinsic (starts with "llvm.")
       bool BadIntrinsic;
-      const Ice::IceString &Name = Fcn->getName();
       IntrinsicInfo = getTranslator().getContext()->getIntrinsicsInfo().find(
-          Name, BadIntrinsic);
+          Fcn->getName(), BadIntrinsic);
       if (BadIntrinsic) {
         std::string Buffer;
         raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Invalid PNaCl intrinsic call to " << Name;
+        StrBuf << "Invalid PNaCl intrinsic call to " << Fcn->getName();
+        Error(StrBuf.str());
+        IntrinsicInfo = nullptr;
+      }
+      if (IntrinsicInfo && IntrinsicInfo->getNumArgs() != NumParams) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Call to " << printName(Fcn) << " has " << NumParams
+               << " parameters. Intrinsic expects: " << Signature->getNumArgs();
         Error(StrBuf.str());
         if (ReturnType != Ice::IceType_void)
-          appendErrorInstruction(ReturnType);
+          setNextLocalInstIndex(nullptr);
         return;
       }
-    } else {
+    } else { // Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL_INDIRECT
+      // There is no signature. Assume defined by parameter types.
       ReturnType = Context->getSimpleTypeByID(Values[2]);
+      if (!isIRGenerationDisabled() && Callee != nullptr)
+        isValidPointerType(Callee, "Call indirect");
+    }
+
+    if (Callee == nullptr && !isIRGenerationDisabled())
+      return;
+
+    // Extract out the the call parameters.
+    SmallVector<Ice::Operand*, 8> Params;
+    for (Ice::SizeT Index = ParamsStartIndex; Index < Values.size(); ++Index) {
+      Ice::Operand *Op = getRelativeOperand(Values[Index], BaseIndex);
+      if (isIRGenerationDisabled())
+        continue;
+      if (Op == nullptr) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Parameter " << (Index - ParamsStartIndex + 1)
+               << " of " << printName(Fcn) << " is not defined";
+        Error(StrBuf.str());
+        if (ReturnType != Ice::IceType_void)
+          setNextLocalInstIndex(nullptr);
+        return;
+      }
+      Params.push_back(Op);
     }
 
     // Check return type.
     if (IntrinsicInfo == nullptr && !isCallReturnType(ReturnType)) {
       std::string Buffer;
       raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Return type of called function is invalid: " << ReturnType;
+      StrBuf << "Return type of " << printName(Fcn) << " is invalid: "
+             << ReturnType;
       Error(StrBuf.str());
       ReturnType = Ice::IceType_i32;
     }
 
+    if (isIRGenerationDisabled()) {
+      if (ReturnType != Ice::IceType_void)
+        setNextLocalInstIndex(nullptr);
+      return;
+    }
+
+    // Type check call parameters.
+    for (Ice::SizeT Index = 0; Index < Params.size(); ++Index) {
+      Ice::Operand *Op = Params[Index];
+      Ice::Type OpType = Op->getType();
+      if (Signature)
+        verifyCallArgTypeMatches(
+            Fcn, Index, OpType, Signature->getArgType(Index));
+      if (IntrinsicInfo) {
+        verifyCallArgTypeMatches(Fcn, Index, OpType,
+                                 IntrinsicInfo->getArgType(Index));
+      } else if (!isCallParameterType(OpType)) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Argument " << *Op << " of " << printName(Fcn)
+               << " has invalid type: " << Op->getType();
+        Error(StrBuf.str());
+        appendErrorInstruction(ReturnType);
+      }
+    }
+
     // Extract call information.
     uint64_t CCInfo = Values[0];
     CallingConv::ID CallingConv;
@@ -2709,127 +2797,25 @@
       StrBuf << "Function call calling convention value " << (CCInfo >> 1)
              << " not understood.";
       Error(StrBuf.str());
-      if (ReturnType != Ice::IceType_void)
-        appendErrorInstruction(ReturnType);
+      appendErrorInstruction(ReturnType);
       return;
     }
     bool IsTailCall = static_cast<bool>(CCInfo & 1);
-    Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
-    if (Signature && NumParams != Signature->getNumArgs()) {
-      std::string Buffer;
-      raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Call has " << NumParams
-             << " parameters. Signature expects: " << Signature->getNumArgs();
-      Error(StrBuf.str());
-      // Error recover by only checking parameters in both signature and call.
-      NumParams = std::min(NumParams, Signature->getNumArgs());
-    }
-    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);
     std::unique_ptr<Ice::InstCall> Inst;
     if (IntrinsicInfo) {
-      Inst.reset(Ice::InstIntrinsicCall::create(Func.get(), NumParams, Dest,
+      Inst.reset(Ice::InstIntrinsicCall::create(Func.get(), Params.size(), Dest,
                                                 Callee, IntrinsicInfo->Info));
     } else {
-      Inst.reset(Ice::InstCall::create(Func.get(), NumParams, Dest, Callee,
+      Inst.reset(Ice::InstCall::create(Func.get(), Params.size(), Dest, Callee,
                                        IsTailCall));
     }
-
-    // Add parameters.
-    for (Ice::SizeT ParamIndex = 0; ParamIndex < NumParams; ++ParamIndex) {
-      Ice::Operand *Op =
-          getRelativeOperand(Values[ParamsStartIndex + ParamIndex], BaseIndex);
-      if (Op == nullptr) {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Parameter " << ParamIndex << " of call not defined";
-        Error(StrBuf.str());
-        if (ReturnType != Ice::IceType_void)
-          appendErrorInstruction(ReturnType);
-        return;
-      }
-
-      // Check that parameter type is valid.
-      if (Signature) {
-        if (Op->getType() != Signature->getArgType(ParamIndex)) {
-          std::string Buffer;
-          raw_string_ostream StrBuf(Buffer);
-          StrBuf << "Call argument " << *Op << " expects "
-                 << Signature->getArgType(ParamIndex)
-                 << ". Found: " << Op->getType();
-          Error(StrBuf.str());
-        } else if (IntrinsicInfo == nullptr &&
-                   !isCallParameterType(Op->getType())) {
-          // TODO(kschimpf): Move this check to the function declaration, so
-          // that it only needs to be checked once.
-          std::string Buffer;
-          raw_string_ostream StrBuf(Buffer);
-          StrBuf << "Call argument " << *Op
-                 << " matches declaration but has invalid type: "
-                 << Op->getType();
-          Error(StrBuf.str());
-        }
-      } else if (!isCallParameterType(Op->getType())) {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Call argument " << *Op
-               << " has invalid type: " << Op->getType();
-        Error(StrBuf.str());
-      }
-      Inst->addArg(Op);
-    }
-
-    // If intrinsic call, validate call signature.
-    if (IntrinsicInfo) {
-      Ice::SizeT ArgIndex = 0;
-      switch (IntrinsicInfo->validateCall(Inst.get(), ArgIndex)) {
-      case Ice::Intrinsics::IsValidCall:
-        break;
-      case Ice::Intrinsics::BadReturnType: {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Intrinsic " << Fcn->getName() << " expects return type"
-               << IntrinsicInfo->getReturnType()
-               << ". Found: " << Inst->getReturnType();
-        Error(StrBuf.str());
-        break;
-      }
-      case Ice::Intrinsics::WrongNumOfArgs: {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Intrinsic " << Fcn->getName() << " expects "
-               << IntrinsicInfo->getNumArgs()
-               << ". Found: " << Inst->getNumArgs();
-        Error(StrBuf.str());
-        break;
-      }
-      case Ice::Intrinsics::WrongCallArgType: {
-        std::string Buffer;
-        raw_string_ostream StrBuf(Buffer);
-        StrBuf << "Intrinsic " << Fcn->getName() << " expects "
-               << IntrinsicInfo->getArgType(ArgIndex) << " for argument "
-               << (ArgIndex + 1)
-               << ". Found: " << Inst->getArg(ArgIndex)->getType();
-        Error(StrBuf.str());
-        break;
-      }
-      }
-    }
-
+    for (Ice::Operand *Param : Params)
+      Inst->addArg(Param);
     CurrentNode->appendInst(Inst.release());
     return;
   }
diff --git a/tests_lit/llvm2ice_tests/Input/no-terminator-inst.tbc b/tests_lit/llvm2ice_tests/Input/no-terminator-inst.tbc
index 1f89762..112c372 100644
--- a/tests_lit/llvm2ice_tests/Input/no-terminator-inst.tbc
+++ b/tests_lit/llvm2ice_tests/Input/no-terminator-inst.tbc
@@ -24,7 +24,7 @@
 11,1,2,1;
 10,2;
 2,3,2,1;
-34,0,5,0;
+34,0,5,1;
 2,1,5,0;
 65534;
 5534;
diff --git a/tests_lit/parse_errs/Inputs/indirect-call-on-float.tbc b/tests_lit/parse_errs/Inputs/indirect-call-on-float.tbc
new file mode 100644
index 0000000..2dac5d4
--- /dev/null
+++ b/tests_lit/parse_errs/Inputs/indirect-call-on-float.tbc
@@ -0,0 +1,25 @@
+65535,8,2;
+1,1;
+65535,17,2;
+1,5;
+2;
+21,0,0;
+7,32;
+3;
+21,0,0,2,3;
+65534;
+8,1,0,1,0;
+8,4,0,0,0;
+65535,19,2;
+5,0;
+65534;
+65535,14,2;
+1,1,102;
+1,0,103;
+65534;
+65535,12,2;
+1,1;
+44,0,1,0;
+10;
+65534;
+65534;
diff --git a/tests_lit/parse_errs/bad-intrinsic-arg.test b/tests_lit/parse_errs/bad-intrinsic-arg.test
index 6b540e9..6063841 100644
--- a/tests_lit/parse_errs/bad-intrinsic-arg.test
+++ b/tests_lit/parse_errs/bad-intrinsic-arg.test
@@ -7,7 +7,7 @@
 ; RUN:     -bitcode-format=pnacl -notranslate -build-on-read 2>&1 \
 ; RUN:   | FileCheck %s
 
-; CHECK: Intrinsic llvm.nacl.setjmp expects i32 for argument 1. Found: double
+; CHECK: Argument 1 of llvm.nacl.setjmp expects i32. Found: double
 
 ; RUN: pnacl-bcfuzz -bitcode-as-text \
 ; RUN:     %p/Inputs/bad-intrinsic-arg.tbc -output - \
diff --git a/tests_lit/parse_errs/call-fcn-bad-param-type.ll b/tests_lit/parse_errs/call-fcn-bad-param-type.ll
index 2314732..46c3ab7 100644
--- a/tests_lit/parse_errs/call-fcn-bad-param-type.ll
+++ b/tests_lit/parse_errs/call-fcn-bad-param-type.ll
@@ -10,6 +10,6 @@
 define void @Test() {
 entry:
   call void @f(i8 1)
-; CHECK: Call argument 1 matches declaration but has invalid type: i8
+; CHECK: Argument 1 of f has invalid type: i8
   ret void
 }
diff --git a/tests_lit/parse_errs/call-fcn-bad-return-type.ll b/tests_lit/parse_errs/call-fcn-bad-return-type.ll
index b1c8cd8..4154c7d 100644
--- a/tests_lit/parse_errs/call-fcn-bad-return-type.ll
+++ b/tests_lit/parse_errs/call-fcn-bad-return-type.ll
@@ -10,7 +10,7 @@
 define void @Test() {
 entry:
   %v = call i1 @f()
-; CHECK: Return type of called function is invalid: i1
+; CHECK: Return type of f is invalid: i1
   ret void
 }
 
diff --git a/tests_lit/parse_errs/call-indirect-i8.ll b/tests_lit/parse_errs/call-indirect-i8.ll
index 0a3b2bc..2c46ba1 100644
--- a/tests_lit/parse_errs/call-indirect-i8.ll
+++ b/tests_lit/parse_errs/call-indirect-i8.ll
@@ -8,6 +8,6 @@
 entry:
   %f = inttoptr i32 %f_addr to i32(i8)*
   %r = call i32 %f(i8 1)
-; CHECK: Call argument 1 has invalid type: i8
+; CHECK: Argument 1 of function has invalid type: i8
   ret void
 }
diff --git a/tests_lit/parse_errs/indirect-call-on-float.test b/tests_lit/parse_errs/indirect-call-on-float.test
new file mode 100644
index 0000000..ef30de6
--- /dev/null
+++ b/tests_lit/parse_errs/indirect-call-on-float.test
@@ -0,0 +1,21 @@
+; Tests that we check the call address is a pointer on an indirect call.
+
+; REQUIRES: no_minimal_build
+
+; RUN: not %pnacl_sz -bitcode-as-text \
+; RUN:     %p/Inputs/indirect-call-on-float.tbc \
+; RUN:     -bitcode-format=pnacl -notranslate -build-on-read 2>&1 \
+; RUN:   | FileCheck %s
+
+; CHECK: Call indirect address not i32. Found: float
+
+; RUN: pnacl-bcfuzz -bitcode-as-text \
+; RUN:     %p/Inputs/indirect-call-on-float.tbc -output - \
+; RUN:   | not pnacl-bcdis -no-records | FileCheck -check-prefix=ASM %s
+
+; ASM:   function void @f1(i32 %p0, float %p1) {  // BlockID = 12
+; ASM:     blocks 1;
+; ASM:   %b0:
+; ASM:     call void %p1();
+; ASM:     ret void;
+; ASM:   }
diff --git a/tests_lit/parse_errs/symtab-after-fcn.test b/tests_lit/parse_errs/symtab-after-fcn.test
index 197c87b..4e519f1 100644
--- a/tests_lit/parse_errs/symtab-after-fcn.test
+++ b/tests_lit/parse_errs/symtab-after-fcn.test
@@ -9,11 +9,13 @@
 ; CHECK: Module valuesymtab not allowed after function blocks
 
 ; RUN: pnacl-bcfuzz -bitcode-as-text %p/Inputs/symtab-after-fcn.tbc \
-; RUN:   -output - | pnacl-bcdis -no-records | FileCheck -check-prefix=ASM %s
+; RUN:   -output - | not pnacl-bcdis -no-records \
+; RUN:             | FileCheck -check-prefix=ASM %s
 
 ; ASM: module {  // BlockID = 8
 ; ASM:   function void @f0() {  // BlockID = 12
 ; ASM:   }
 ; ASM:   valuesymtab {  // BlockID = 14
+; ASM: Error({{.*}}): Module symbol table must appear before function blocks
 ; ASM:   }
 ; ASM: }