Subzero: Partial implementation of global initializers.

This is still missing a couple things:

1. It only supports flat arrays and zeroinitializers.  Arrays of structs are not yet supported.

2. Initializers can't yet contain relocatables, e.g. the address of another global.Mod

Some changes are made to work around an llvm-mc assembler bug.  When assembling using intel syntax, llvm-mc doesn't correctly parse symbolic constants or add relocation entries in some circumstances.  Call instructions work, and use in a memory operand works, e.g. mov eax, [ArrayBase+4*ecx].  To work around this, we adjust legalize() to not allow ConstantRelocatable by default, except for memory operands and when called from lowerCall(), so the relocatable ends up being the source operand of a mov instruction.  Then, the mov emit routine actually emits an lea instruction for such moves.

A few lit tests needed to be adjusted to make szdiff work properly with respect to global initializers.

In the new cross test, the driver calls test code that returns a pointer to an array with a global initializer, and the driver compares the arrays returned by llc and Subzero.

BUG= none
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/358013003
diff --git a/crosstest/runtests.sh b/crosstest/runtests.sh
index d89e1b9..0bc4cf2 100755
--- a/crosstest/runtests.sh
+++ b/crosstest/runtests.sh
@@ -51,6 +51,13 @@
     ./crosstest.py -O${optlevel} --prefix=Subzero_ --target=x8632 \
         --dir="${OUTDIR}" \
         --llvm-bin-path="${LLVM_BIN_PATH}" \
+        --test=test_global.cpp \
+        --driver=test_global_main.cpp \
+        --output=test_global_O${optlevel}
+
+    ./crosstest.py -O${optlevel} --prefix=Subzero_ --target=x8632 \
+        --dir="${OUTDIR}" \
+        --llvm-bin-path="${LLVM_BIN_PATH}" \
         --test=test_icmp.cpp \
         --driver=test_icmp_main.cpp \
         --output=test_icmp_O${optlevel}
@@ -63,5 +70,6 @@
     "${OUTDIR}"/test_arith_O${optlevel}
     "${OUTDIR}"/test_cast_O${optlevel}
     "${OUTDIR}"/test_fcmp_O${optlevel}
+    "${OUTDIR}"/test_global_O${optlevel}
     "${OUTDIR}"/test_icmp_O${optlevel}
 done
diff --git a/crosstest/test_global.cpp b/crosstest/test_global.cpp
new file mode 100644
index 0000000..a5a2f61
--- /dev/null
+++ b/crosstest/test_global.cpp
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include <cstdlib>
+
+#include "test_global.h"
+
+// Partially initialized array
+int ArrayInitPartial[10] = { 60, 70, 80, 90, 100 };
+int ArrayInitFull[] = { 10, 20, 30, 40, 50 };
+const int ArrayConst[] = { -10, -20, -30 };
+static double ArrayDouble[10] = { 0.5, 1.5, 2.5, 3.5 };
+
+#if 0
+#define ARRAY(a)                                                               \
+  { (uint8_t *)(a), sizeof(a) }
+
+struct {
+  uint8_t *ArrayAddress;
+  size_t ArraySizeInBytes;
+} Arrays[] = {
+  ARRAY(ArrayInitPartial),
+  ARRAY(ArrayInitFull),
+  ARRAY(ArrayConst),
+  ARRAY(ArrayDouble),
+};
+size_t NumArraysElements = sizeof(Arrays) / sizeof(*Arrays);
+#endif // 0
+
+size_t getNumArrays() {
+  return 4;
+  // return NumArraysElements;
+}
+
+const uint8_t *getArray(size_t WhichArray, size_t &Len) {
+  // Using a switch statement instead of a table lookup because such a
+  // table is represented as a kind of initializer that Subzero
+  // doesn't yet support.  Specifically, the table becomes constant
+  // aggregate data, and it contains relocations.  TODO(stichnot):
+  // switch over to the cleaner table-based method when global
+  // initializers are fully implemented.
+  switch (WhichArray) {
+  default:
+    Len = -1;
+    return NULL;
+  case 0:
+    Len = sizeof(ArrayInitPartial);
+    return (uint8_t *)&ArrayInitPartial;
+  case 1:
+    Len = sizeof(ArrayInitFull);
+    return (uint8_t *)&ArrayInitFull;
+  case 2:
+    Len = sizeof(ArrayConst);
+    return (uint8_t *)&ArrayConst;
+  case 3:
+    Len = sizeof(ArrayDouble);
+    return (uint8_t *)&ArrayDouble;
+  }
+#if 0
+  if (WhichArray >= NumArraysElements) {
+    Len = -1;
+    return NULL;
+  }
+  Len = Arrays[WhichArray].ArraySizeInBytes;
+  return Arrays[WhichArray].ArrayAddress;
+#endif // 0
+}
diff --git a/crosstest/test_global.h b/crosstest/test_global.h
new file mode 100644
index 0000000..dc7ff75
--- /dev/null
+++ b/crosstest/test_global.h
@@ -0,0 +1,2 @@
+size_t getNumArrays();
+const uint8_t *getArray(size_t WhichArray, size_t &Len);
diff --git a/crosstest/test_global_main.cpp b/crosstest/test_global_main.cpp
new file mode 100644
index 0000000..e533f99
--- /dev/null
+++ b/crosstest/test_global_main.cpp
@@ -0,0 +1,50 @@
+/* crosstest.py --test=test_global.cpp \
+   --driver=test_global_main.cpp --prefix=Subzero_ --output=test_global */
+
+#include <stdint.h>
+#include <cstdlib>
+#include <iostream>
+
+#include "test_global.h"
+namespace Subzero_ {
+#include "test_global.h"
+}
+
+int main(int argc, char **argv) {
+  size_t TotalTests = 0;
+  size_t Passes = 0;
+  size_t Failures = 0;
+
+  const uint8_t *SzArray, *LlcArray;
+  size_t SzArrayLen, LlcArrayLen;
+
+  size_t NumArrays = getNumArrays();
+  for (size_t i = 0; i < NumArrays; ++i) {
+    LlcArrayLen = -1;
+    SzArrayLen = -2;
+    LlcArray = getArray(i, LlcArrayLen);
+    SzArray = Subzero_::getArray(i, SzArrayLen);
+    if (LlcArrayLen == SzArrayLen) {
+      ++Passes;
+    } else {
+      std::cout << i << ":LlcArrayLen=" << LlcArrayLen
+                << ", SzArrayLen=" << SzArrayLen << std::endl;
+      ++Failures;
+    }
+
+    for (size_t i = 0; i < LlcArrayLen; ++i) {
+      if (LlcArray[i] == SzArray[i]) {
+        ++Passes;
+      } else {
+        ++Failures;
+        std::cout << i << ":LlcArray[" << i << "] = " << (int)LlcArray[i]
+                  << ", SzArray[" << i << "] = " << (int)SzArray[i]
+                  << std::endl;
+      }
+    }
+  }
+
+  std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
+            << " Failures=" << Failures << "\n";
+  return Failures;
+}