Fix initializers and add vector reflection support.

Bug: 10427951

This also fixes a bug with floating point initialization (where relevant
digits could be truncated because of C++ iostream operators).

Change-Id: I2761dea38dd6ad758ea31217744e45436596afce
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index 772545b..65b6b43 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -424,10 +424,10 @@
                                              const std::string &VarName,
                                              const clang::APValue &Val) {
   slangAssert(!Val.isUninit() && "Not a valid initializer");
+  slangAssert((Val.getKind() == clang::APValue::Int)
+              && "Bool type has wrong initial APValue");
 
   C.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = ";
-  slangAssert((Val.getKind() == clang::APValue::Int) &&
-              "Bool type has wrong initial APValue");
 
   C.out() << ((Val.getInt().getSExtValue() == 0) ? "false" : "true")
           << ";" << std::endl;
diff --git a/slang_rs_reflection.h b/slang_rs_reflection.h
index ded42b4..b309325 100644
--- a/slang_rs_reflection.h
+++ b/slang_rs_reflection.h
@@ -242,7 +242,6 @@
                                     const RSExportType *ET,
                                     const std::string &VarName,
                                     const clang::APValue &Val);
-  static void genInitValue(Context &C, const clang::APValue &Val);
   void genExportVariable(Context &C, const RSExportVar *EV);
   void genPrimitiveTypeExportVariable(Context &C, const RSExportVar *EV);
   void genPointerTypeExportVariable(Context &C, const RSExportVar *EV);
diff --git a/slang_rs_reflection_base.cpp b/slang_rs_reflection_base.cpp
index fe93054..7f1aa96 100644
--- a/slang_rs_reflection_base.cpp
+++ b/slang_rs_reflection_base.cpp
@@ -20,6 +20,7 @@
 #include <cctype>
 
 #include <algorithm>
+#include <limits>
 #include <sstream>
 #include <string>
 #include <utility>
@@ -161,6 +162,7 @@
       if(asBool) {
         tmp << ((api.getSExtValue() == 0) ? "false" : "true");
       } else {
+        // TODO: Handle unsigned possibly for C++ API.
         tmp << api.getSExtValue();
         if (api.getBitWidth() > 32) {
           tmp << "L";
@@ -171,10 +173,15 @@
 
     case clang::APValue::Float: {
       llvm::APFloat apf = Val.getFloat();
+      llvm::SmallString<30> s;
+      apf.toString(s);
+      tmp << s.c_str();
       if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) {
-        tmp << apf.convertToFloat() << "f";
-      } else {
-        tmp << apf.convertToDouble();
+        if (s.count('.') == 0) {
+          tmp << ".f";
+        } else {
+          tmp << "f";
+        }
       }
       break;
     }
@@ -204,4 +211,18 @@
   }
 }
 
+const char *RSReflectionBase::getVectorAccessor(unsigned Index) {
+  static const char *VectorAccessorMap[] = {
+    /* 0 */ "x",
+    /* 1 */ "y",
+    /* 2 */ "z",
+    /* 3 */ "w",
+  };
+
+  slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char*))) &&
+              "Out-of-bound index to access vector member");
+
+  return VectorAccessorMap[Index];
+}
+
 }
diff --git a/slang_rs_reflection_base.h b/slang_rs_reflection_base.h
index 100f5eb..3383ad1 100644
--- a/slang_rs_reflection_base.h
+++ b/slang_rs_reflection_base.h
@@ -70,6 +70,8 @@
 
     bool addTypeNameForElement(const std::string &TypeName);
 
+    static const char *getVectorAccessor(unsigned index);
+
 private:
 
 public:
diff --git a/slang_rs_reflection_cpp.cpp b/slang_rs_reflection_cpp.cpp
index ea4227d..f583148 100644
--- a/slang_rs_reflection_cpp.cpp
+++ b/slang_rs_reflection_cpp.cpp
@@ -173,9 +173,11 @@
          E = mRSContext->export_vars_end(); I != E; I++, slot++) {
     const RSExportVar *ev = *I;
     if (!ev->isConst()) {
-      write(GetTypeName(ev->getType()) + " __" + ev->getName() + ";");
+      write(GetTypeName(ev->getType()) + " " RS_EXPORT_VAR_PREFIX
+            + ev->getName() + ";");
     }
   }
+
   for (RSContext::const_export_foreach_iterator
            I = mRSContext->export_foreach_begin(),
            E = mRSContext->export_foreach_end(); I != E; I++) {
@@ -319,6 +321,7 @@
      << stripRS(mInputFileName) << "\", " << stripRS(mInputFileName).length()
      << ", \"/data/data/" << packageName << "/app\", sizeof(\"" << packageName << "\")) {";
   write(ss);
+  ss.str("");
   incIndent();
   for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
                                        E = mTypesToCheck.end();
@@ -326,6 +329,18 @@
        I++) {
     write(RS_ELEM_PREFIX + *I + " = android::RSC::Element::" + *I + "(mRS);");
   }
+
+  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
+                                            E = mRSContext->export_vars_end();
+       I != E;
+       I++) {
+    const RSExportVar *EV = *I;
+    if (!EV->getInit().isUninit()) {
+      genInitExportVariable(EV->getType(), EV->getName(), EV->getInit());
+    } else {
+      genZeroInitExportVariable(EV->getName());
+    }
+  }
   decIndent();
   write("}");
   write("");
@@ -499,7 +514,7 @@
     stringstream tmp;
     tmp << getNextExportVarSlot();
     write(string("    setVar(") + tmp.str() + ", &v, sizeof(v));");
-    write(string("    __") + EV->getName() + " = v;");
+    write(string("    " RS_EXPORT_VAR_PREFIX) + EV->getName() + " = v;");
     write("}");
   }
   write(string(rtd.type->c_name) + " get_" + EV->getName() + "() const {");
@@ -508,7 +523,7 @@
     bool isBool = !strcmp(rtd.type->c_name, "bool");
     write(string("    return ") + genInitValue(val, isBool) + ";");
   } else {
-    write(string("    return __") + EV->getName() + ";");
+    write(string("    return " RS_EXPORT_VAR_PREFIX) + EV->getName() + ";");
   }
   write("}");
   write("");
@@ -533,7 +548,7 @@
     stringstream tmp;
     tmp << slot;
     write(string("    bindAllocation(v, ") + tmp.str() + ");");
-    write(string("    __") + VarName + " = v;");
+    write(string("    " RS_EXPORT_VAR_PREFIX) + VarName + " = v;");
     write("}");
   }
   write(TypeName + " get_" + VarName + "() const {");
@@ -542,7 +557,7 @@
     bool isBool = !strcmp(TypeName.c_str(), "bool");
     write(string("    return ") + genInitValue(val, isBool) + ";");
   } else {
-    write(string("    return __") + VarName + ";");
+    write(string("    return " RS_EXPORT_VAR_PREFIX) + VarName + ";");
   }
   write("}");
   write("");
@@ -550,7 +565,41 @@
 }
 
 void RSReflectionCpp::genVectorTypeExportVariable(const RSExportVar *EV) {
-  slangAssert(false);
+  slangAssert((EV->getType()->getClass() == RSExportType::ExportClassVector) &&
+              "Variable should be type of vector here");
+
+  const RSExportVectorType *EVT =
+      static_cast<const RSExportVectorType*>(EV->getType());
+  slangAssert(EVT != NULL);
+
+  RSReflectionTypeData rtd;
+  EVT->convertToRTD(&rtd);
+
+  std::stringstream ss;
+
+  if (!EV->isConst()) {
+    ss << "void set_" << EV->getName() << "(" << rtd.type->rs_c_vector_prefix
+       << EVT->getNumElement() << " v) {";
+    write(ss);
+    ss.str("");
+    ss << getNextExportVarSlot();
+    write(string("    setVar(") + ss.str() + ", &v, sizeof(v));");
+    ss.str("");
+    write(string("    " RS_EXPORT_VAR_PREFIX) + EV->getName() + " = v;");
+    write("}");
+  }
+  ss << rtd.type->rs_c_vector_prefix << EVT->getNumElement() << " get_"
+     << EV->getName() << "() const {";
+  write(ss);
+  ss.str("");
+  if (EV->isConst()) {
+    const clang::APValue &val = EV->getInit();
+    write(string("    return ") + genInitValue(val, false) + ";");
+  } else {
+    write(string("    return " RS_EXPORT_VAR_PREFIX) + EV->getName() + ";");
+  }
+  write("}");
+  write("");
 }
 
 void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
@@ -802,6 +851,107 @@
   }
 }
 
+void RSReflectionCpp::genInitExportVariable(const RSExportType *ET,
+                                            const std::string &VarName,
+                                            const clang::APValue &Val) {
+  slangAssert(!Val.isUninit() && "Not a valid initializer");
 
+  switch (ET->getClass()) {
+    case RSExportType::ExportClassPrimitive: {
+      const RSExportPrimitiveType *EPT =
+          static_cast<const RSExportPrimitiveType*>(ET);
+      if (EPT->getType() == RSExportPrimitiveType::DataTypeBoolean) {
+        genInitBoolExportVariable(VarName, Val);
+      } else {
+        genInitPrimitiveExportVariable(VarName, Val);
+      }
+      break;
+    }
+    case RSExportType::ExportClassPointer: {
+      if (!Val.isInt() || Val.getInt().getSExtValue() != 0)
+        std::cerr << "Initializer which is non-NULL to pointer type variable "
+                     "will be ignored" << std::endl;
+      break;
+    }
+    case RSExportType::ExportClassVector: {
+      const RSExportVectorType *EVT =
+          static_cast<const RSExportVectorType*>(ET);
+      switch (Val.getKind()) {
+        case clang::APValue::Int:
+        case clang::APValue::Float: {
+          for (unsigned i = 0; i < EVT->getNumElement(); i++) {
+            std::string Name = VarName + "." + getVectorAccessor(i);
+            genInitPrimitiveExportVariable(Name, Val);
+          }
+          break;
+        }
+        case clang::APValue::Vector: {
+          unsigned NumElements =
+              std::min(static_cast<unsigned>(EVT->getNumElement()),
+                       Val.getVectorLength());
+          for (unsigned i = 0; i < NumElements; i++) {
+            const clang::APValue &ElementVal = Val.getVectorElt(i);
+            std::string Name = VarName + "." + getVectorAccessor(i);
+            genInitPrimitiveExportVariable(Name, ElementVal);
+          }
+          break;
+        }
+        case clang::APValue::MemberPointer:
+        case clang::APValue::Uninitialized:
+        case clang::APValue::ComplexInt:
+        case clang::APValue::ComplexFloat:
+        case clang::APValue::LValue:
+        case clang::APValue::Array:
+        case clang::APValue::Struct:
+        case clang::APValue::Union:
+        case clang::APValue::AddrLabelDiff: {
+          slangAssert(false && "Unexpected type of value of initializer.");
+        }
+      }
+      break;
+    }
+    case RSExportType::ExportClassMatrix:
+    case RSExportType::ExportClassConstantArray:
+    case RSExportType::ExportClassRecord: {
+      slangAssert(false && "Unsupported initializer for record/matrix/constant "
+                           "array type variable currently");
+      break;
+    }
+    default: {
+      slangAssert(false && "Unknown class of type");
+    }
+  }
+  return;
+}
+
+void RSReflectionCpp::genZeroInitExportVariable(const std::string &VarName) {
+  std::stringstream ss;
+  ss << "memset(&" RS_EXPORT_VAR_PREFIX << VarName << ", 0, sizeof("
+     << RS_EXPORT_VAR_PREFIX << VarName << "));";
+  write(ss);
+}
+
+void RSReflectionCpp::genInitPrimitiveExportVariable(
+    const std::string &VarName,
+    const clang::APValue &Val) {
+  slangAssert(!Val.isUninit() && "Not a valid initializer");
+
+  std::stringstream ss;
+  ss << RS_EXPORT_VAR_PREFIX << VarName << " = "
+     << RSReflectionBase::genInitValue(Val) << ";";
+  write(ss);
+}
+
+void RSReflectionCpp::genInitBoolExportVariable(const std::string &VarName,
+                                                const clang::APValue &Val) {
+  slangAssert(!Val.isUninit() && "Not a valid initializer");
+  slangAssert((Val.getKind() == clang::APValue::Int) &&
+              "Bool type has wrong initial APValue");
+
+  std::stringstream ss;
+  ss << RS_EXPORT_VAR_PREFIX << VarName << " = "
+     << ((Val.getInt().getSExtValue() == 0) ? "false" : "true") << ";";
+  write(ss);
+}
 
 }  // namespace slang
diff --git a/slang_rs_reflection_cpp.h b/slang_rs_reflection_cpp.h
index 948d624..b887ee7 100644
--- a/slang_rs_reflection_cpp.h
+++ b/slang_rs_reflection_cpp.h
@@ -22,6 +22,8 @@
 #include <set>
 #include <string>
 
+#define RS_EXPORT_VAR_PREFIX             "mExportVar_"
+
 namespace slang {
 
 class RSReflectionCpp : public RSReflectionBase {
@@ -66,6 +68,17 @@
 
   bool startScriptHeader();
 
+
+  // Write out code for an export variable initialization.
+  void genInitExportVariable(const RSExportType *ET,
+                             const std::string &VarName,
+                             const clang::APValue &Val);
+  void genZeroInitExportVariable(const std::string &VarName);
+  void genInitBoolExportVariable(const std::string &VarName,
+                                 const clang::APValue &Val);
+  void genInitPrimitiveExportVariable(const std::string &VarName,
+                                      const clang::APValue &Val);
+
   // Produce an argument string of the form "T1 t, T2 u, T3 v".
   void makeArgs(std::stringstream &ss, const ArgTy& Args);
 
diff --git a/tests/P_kernel_cpp/kernel_cpp.rs b/tests/P_kernel_cpp/kernel_cpp.rs
index 4474c9f..2a854c2 100644
--- a/tests/P_kernel_cpp/kernel_cpp.rs
+++ b/tests/P_kernel_cpp/kernel_cpp.rs
@@ -2,6 +2,14 @@
 #pragma version(1)
 #pragma rs java_package_name(foo)
 
+//int2 i2;
+
+int i1 = 5;
+bool bt = true;
+bool bf = false;
+int2 i2 = 2;
+int3 i3 = {1, 2, 3};
+
 int __attribute__((kernel)) root(uint32_t ain) {
   return 0;
 }