Subzero: Embed the revision string into translated output.

Modify the Makefiles to pass in the current git hash, which is embedded into the translated output.  As a side effect, it is also embedded into the Subzero translator binary.  This is useful for two reasons:

1. The PNaCl component update process is somewhat manual, making it tricky long after the fact to know exactly which revision was pushed, e.g. when trying to reproduce a bug or crash.

2. A translated binary can be inspected to make sure Chrome used the expected revision of Subzero.  (And also to verify that pnacl-sz was used rather than pnacl-llc.)

The revision string is suppressed for lit tests, because a number of tests seem overly strict about global initializer expectations.

BUG= none
R=jpp@chromium.org

Review URL: https://codereview.chromium.org/2218363002 .
diff --git a/Makefile b/Makefile
index 52bfba3..e49eec3 100644
--- a/Makefile
+++ b/Makefile
@@ -31,3 +31,4 @@
 endif
 
 CPP.Defines += -DPNACL_LLVM
+CPP.Defines += -DSUBZERO_REVISION=$(shell git rev-parse HEAD)
diff --git a/Makefile.standalone b/Makefile.standalone
index a75ea94..56fd8a4 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -111,6 +111,7 @@
 endif
 
 BASE_CXX_DEFINES += -DPNACL_LLVM
+BASE_CXX_DEFINES += -DSUBZERO_REVISION=$(shell git rev-parse HEAD)
 
 CXX_DEFINES := $(BASE_CXX_DEFINES) -DPNACL_BROWSER_TRANSLATOR=0
 
@@ -320,6 +321,7 @@
   IceOperand.cpp \
   IceRangeSpec.cpp \
   IceRegAlloc.cpp \
+  IceRevision.cpp \
   IceRNG.cpp \
   IceSwitchLowering.cpp \
   IceThreading.cpp \
diff --git a/pydir/crosstest.py b/pydir/crosstest.py
index 3727d5c..2ca673e 100755
--- a/pydir/crosstest.py
+++ b/pydir/crosstest.py
@@ -165,9 +165,11 @@
         # definitions.)  This approach should be OK because cross tests are
         # currently the only situation where multiple translated files are
         # linked into the executable, but when PNaCl supports shared nexe
-        # libraries, this would need to change.
+        # libraries, this would need to change.  (Note: the same issue applies
+        # to the __Sz_revision symbol.)
         shellcmd(['{bin}/{objcopy}'.format(bin=bindir, objcopy=GetObjcopyCmd()),
                   '--weaken-symbol=__Sz_block_profile_info',
+                  '--weaken-symbol=__Sz_revision',
                   '--strip-symbol=nacl_tp_tdb_offset',
                   '--strip-symbol=nacl_tp_tls_offset',
                   obj_sz])
@@ -181,7 +183,6 @@
                   '-o=' + obj_llc,
                   bitcode] + llc_flags)
         shellcmd(['{bin}/{objcopy}'.format(bin=bindir, objcopy=GetObjcopyCmd()),
-                  '--weaken-symbol=__Sz_block_profile_info',
                   '--strip-symbol=nacl_tp_tdb_offset',
                   '--strip-symbol=nacl_tp_tls_offset',
                   obj_llc])
diff --git a/pydir/run-pnacl-sz.py b/pydir/run-pnacl-sz.py
index dc549e8..580d227 100755
--- a/pydir/run-pnacl-sz.py
+++ b/pydir/run-pnacl-sz.py
@@ -164,6 +164,7 @@
     else:
       cmd += ['--build-on-read=1']
     cmd += ['--filetype=' + args.filetype]
+    cmd += ['--emit-revision=0']
     script_name = os.path.basename(sys.argv[0])
     for _, arg in enumerate(args.args):
       # Redirecting the output file needs to be done through the script
diff --git a/src/IceClFlags.def b/src/IceClFlags.def
index f13afbe..bb9a181 100644
--- a/src/IceClFlags.def
+++ b/src/IceClFlags.def
@@ -153,6 +153,9 @@
       clEnumValN(Ice::LCSE_EnabledNoSSA, "no-ssa", "no-assume-ssa"),           \
       clEnumValEnd))                                                           \
                                                                                \
+  X(EmitRevision, bool, dev_opt_flag, "emit-revision",                         \
+    cl::desc("Emit Subzero revision string into the output"), cl::init(true))  \
+                                                                               \
   X(EnablePhiEdgeSplit, bool, dev_opt_flag, "phi-edge-split",                  \
     cl::desc("Enable edge splitting for Phi lowering"), cl::init(true))        \
                                                                                \
diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp
index 5ace25c..a021f8f 100644
--- a/src/IceCompileServer.cpp
+++ b/src/IceCompileServer.cpp
@@ -18,6 +18,7 @@
 #include "IceClFlags.h"
 #include "IceELFStreamer.h"
 #include "IceGlobalContext.h"
+#include "IceRevision.h"
 #include "LinuxMallocProfiling.h"
 
 #ifdef __clang__
@@ -163,6 +164,7 @@
     const auto &A = ConditionalBuildAttributes[i];
     Str << Prefix[A.FlagValue] << "_" << A.FlagName << "\n";
   }
+  Str << "revision_" << getSubzeroRevision() << "\n";
 }
 
 } // end of anonymous namespace
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 349db7c..678c521 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -23,6 +23,7 @@
 #include "IceGlobalInits.h"
 #include "IceLiveness.h"
 #include "IceOperand.h"
+#include "IceRevision.h"
 #include "IceTargetLowering.h"
 #include "IceTimerTree.h"
 #include "IceTypes.def"
@@ -357,6 +358,18 @@
 #undef X
 
   TargetLowering::staticInit(this);
+
+  if (getFlags().getEmitRevision()) {
+    // Embed the Subzero revision into the compiled binary by creating a special
+    // global variable initialized with the revision string.
+    auto *Revision = VariableDeclaration::create(&Globals, true);
+    Revision->setName(this, "__Sz_revision");
+    Revision->setIsConstant(true);
+    const char *RevisionString = getSubzeroRevision();
+    Revision->addInitializer(VariableDeclaration::DataInitializer::create(
+        &Globals, RevisionString, 1 + strlen(RevisionString)));
+    Globals.push_back(Revision);
+  }
 }
 
 void GlobalContext::translateFunctions() {
diff --git a/src/IceRevision.cpp b/src/IceRevision.cpp
new file mode 100644
index 0000000..b8233d0
--- /dev/null
+++ b/src/IceRevision.cpp
@@ -0,0 +1,28 @@
+//===- subzero/src/IceRevision.cpp - Revision string embedding ------------===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements the function for returning the Subzero revision string.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceRevision.h"
+
+#define XSTRINGIFY(x) STRINGIFY(x)
+#define STRINGIFY(x) #x
+
+#ifndef SUBZERO_REVISION
+#define SUBZERO_REVISION unknown
+#endif // !SUBZERO_REVISION
+
+namespace Ice {
+const char *getSubzeroRevision() {
+  return "Subzero_revision_" XSTRINGIFY(SUBZERO_REVISION);
+}
+} // end of namespace Ice
diff --git a/src/IceRevision.h b/src/IceRevision.h
new file mode 100644
index 0000000..170755b
--- /dev/null
+++ b/src/IceRevision.h
@@ -0,0 +1,32 @@
+//===- subzero/src/IceRevision.h - Revision string embedding ----*- C++ -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the function for returning the Subzero revision string.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEREVISION_H
+#define SUBZERO_SRC_ICEREVISION_H
+
+namespace Ice {
+
+// Returns the Subzero revision string, which is meant to be essentially the git
+// hash of the repo when Subzero was built.
+//
+// Note: It would be possible to declare this a constexpr char[] and put its
+// definition right here in the include file.  But since the git hash is passed
+// to the compiler on the command line, and compilation is directed through a
+// Makefile, lack of recompilation could lead to different files seeing
+// inconsistent revision strings.
+const char *getSubzeroRevision();
+
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEREVISION_H