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/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;