Allow conditional lit tests in Subzero, based on build flags.

Adds conditionality to lit tests in two ways:

1) Allows the use of "; REQUIRES: XXX" lines in lit tests. In this
case, the tests defined by the file are only run if all REQUIRES are
met.

2) Allows the conditional running of RUN commands, based on build
flags. This comes in two subforms. There are predefined %ifX commands
that run the command defined by remaining arguments, if the
corresponding %X2i command is applicable. Alternatively, one can use
%if with explicit '--att' arguments to define what conditions should
be checked.

In any case, unlike REQUIRES, the %if commands RUN all the time, but
simply generate empty output, rather then output defined by the
following command, if the condition is not met. These latter tests are
useful when the same input is to be tested under different conditions,
since the REQUIRES form does not allow this.

Note that m2i, p2i, l2i, and lc2i are also conditionally controlled,
so that they do nothing if the build did not construct the appropriate
Subzero translator.

This CL replaces https://codereview.chromium.org/644143002

BUG=None
R=jvoung@chromium.org, stichnot@chromium.org

Review URL: https://codereview.chromium.org/659513005
diff --git a/src/IceTypes.cpp b/src/IceTypes.cpp
index 6b81d8a..7155baa 100644
--- a/src/IceTypes.cpp
+++ b/src/IceTypes.cpp
@@ -18,6 +18,12 @@
 
 namespace {
 
+const char *TargetArchName[] = {
+#define X(tag, str)  str ,
+  TARGETARCH_TABLE
+#undef X
+};
+
 // Show tags match between ICETYPE_TABLE and ICETYPE_PROPS_TABLE.
 
 // Define a temporary set of enum values based on ICETYPE_TABLE
@@ -116,6 +122,14 @@
 
 } // end anonymous namespace
 
+const char *targetArchString(const TargetArch Arch) {
+  size_t Index = static_cast<size_t>(Arch);
+  if (Index < TargetArch_NUM)
+    return TargetArchName[Index];
+  llvm_unreachable("Invalid target arch for targetArchString");
+  return "???";
+}
+
 size_t typeWidthInBytes(Type Ty) {
   size_t Index = static_cast<size_t>(Ty);
   if (Index < IceType_NUM)
diff --git a/src/IceTypes.def b/src/IceTypes.def
index 19175f0..3d4c9b1 100644
--- a/src/IceTypes.def
+++ b/src/IceTypes.def
@@ -15,6 +15,14 @@
 #ifndef SUBZERO_SRC_ICETYPES_DEF
 #define SUBZERO_SRC_ICETYPES_DEF
 
+#define TARGETARCH_TABLE                                                 \
+  /* enum value, printable string */                                     \
+  X(Target_X8632, "x86-32")                                              \
+  X(Target_X8664, "x86-64")                                              \
+  X(Target_ARM32, "arm32")                                               \
+  X(Target_ARM64, "arm64")                                               \
+//#define X(tag, str)
+
 #define ICETYPE_TABLE                                                    \
   /* enum value,  size, align, # elts, element type, printable string */ \
   /*   (size and alignment in bytes) */                                  \
diff --git a/src/IceTypes.h b/src/IceTypes.h
index 94d4dc0..1619523 100644
--- a/src/IceTypes.h
+++ b/src/IceTypes.h
@@ -28,12 +28,18 @@
 };
 
 enum TargetArch {
-  Target_X8632,
-  Target_X8664,
-  Target_ARM32,
-  Target_ARM64
+#define X(tag, str) tag,
+  TARGETARCH_TABLE
+#undef X
+  TargetArch_NUM
 };
 
+const char *targetArchString(TargetArch Arch);
+
+inline Ostream &operator<<(Ostream &Stream, TargetArch Arch) {
+  return Stream << targetArchString(Arch);
+}
+
 enum OptLevel {
   Opt_m1,
   Opt_0,
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 9897740..6573acd 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -16,6 +16,7 @@
 #include <fstream>
 #include <iostream>
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IRReader/IRReader.h"
 #include "llvm/Support/CommandLine.h"
@@ -164,12 +165,57 @@
     "exit-success", cl::desc("Exit with success status, even if errors found"),
     cl::init(false));
 
+static cl::opt<bool> GenerateBuildAtts(
+    "build-atts", cl::desc("Generate list of build attributes associated with "
+                           "this executable."),
+    cl::init(false));
+
 static int GetReturnValue(int Val) {
   if (AlwaysExitSuccess)
     return 0;
   return Val;
 }
 
+static struct {
+  const char *FlagName;
+  int FlagValue;
+} ConditionalBuildAttributes[] = {
+  { "text_asm", ALLOW_TEXT_ASM },
+  { "dump", ALLOW_DUMP },
+  { "llvm_cl", ALLOW_LLVM_CL },
+  { "llvm_ir", ALLOW_LLVM_IR },
+  { "llvm_ir_as_input", ALLOW_LLVM_IR_AS_INPUT }
+};
+
+// Validates values of build attributes. Prints them to Stream if
+// Stream is non-null.
+static void ValidateAndGenerateBuildAttributes(raw_os_ostream *Stream) {
+
+  if (Stream)
+    *Stream << TargetArch << "\n";
+
+  for (size_t i = 0; i < array_lengthof(ConditionalBuildAttributes); ++i) {
+    switch (ConditionalBuildAttributes[i].FlagValue) {
+    case 0:
+      if (Stream)
+        *Stream << "no_" << ConditionalBuildAttributes[i].FlagName << "\n";
+      break;
+    case 1:
+      if (Stream)
+        *Stream << "allow_" << ConditionalBuildAttributes[i].FlagName << "\n";
+      break;
+    default: {
+      std::string Buffer;
+      raw_string_ostream StrBuf(Buffer);
+      StrBuf << "Flag " << ConditionalBuildAttributes[i].FlagName
+             << " must be defined as 0/1. Found: "
+             << ConditionalBuildAttributes[i].FlagValue;
+      report_fatal_error(StrBuf.str());
+    }
+    }
+  }
+}
+
 int main(int argc, char **argv) {
 
   cl::ParseCommandLineOptions(argc, argv);
@@ -185,6 +231,11 @@
   raw_os_ostream *Os =
       new raw_os_ostream(OutputFilename == "-" ? std::cout : Ofs);
   Os->SetUnbuffered();
+
+  ValidateAndGenerateBuildAttributes(GenerateBuildAtts ? Os : nullptr);
+  if (GenerateBuildAtts)
+    return GetReturnValue(0);
+
   std::ofstream Lfs;
   if (LogFilename != "-") {
     Lfs.open(LogFilename.c_str(), std::ofstream::out);
@@ -212,6 +263,7 @@
 
   Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
                          Flags);
+
   Ice::TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
 
   int ErrorStatus = 0;