Support -malign-double option

While LLVM supports the `-malign-double` option, Clang does not.
Passing in `-mllvm -malign-double` cannot be used as a workaround
as it will result in different machine description being used
by Clang and LLVM.

This change adds support for `-malign-double` option directly into
Clang and sets the machine description accordingly.

BUG=none
R=dschuff@chromium.org

Review URL: https://codereview.chromium.org/1310173005 .
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 714943d..42b3a41 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1227,6 +1227,8 @@
 def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>;
 def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>;
 def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>;
+def malign_double : Flag<["-"], "malign-double">,  Group<m_x86_Features_Group>; // @LOCALMOD
+def mnoalign_double : Flag<["-"], "mno-align-double">,  Group<m_x86_Features_Group>; // @LOCALMOD
 
 def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
   HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f8a2882..4cfd0cf 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -758,8 +758,7 @@
     if (Triple.getArch() == llvm::Triple::arm) {
       // Handled in ARM's setABI().
     } else if (Triple.getArch() == llvm::Triple::x86) {
-      // @LOCALMOD MERGETODO: upstream this if it actually works.
-      this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128";
+      // Handled in X86_32's setDescriptionString.
     } else if (Triple.getArch() == llvm::Triple::x86_64) {
       this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128";
     } else if (Triple.getArch() == llvm::Triple::mipsel) {
@@ -3460,13 +3459,23 @@
 
 // X86-32 generic target
 class X86_32TargetInfo : public X86TargetInfo {
+  // @LOCALMOD-START
+  virtual void setDescriptionString() {
+    if (getTriple().isOSNaCl())
+      DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128";
+    else if (HasAlignedDouble)
+      DescriptionString = "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S128";
+    else
+      DescriptionString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128";
+  }
+  bool HasAlignedDouble;
+  // @LOCALMOD-END
 public:
   X86_32TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) {
     DoubleAlign = LongLongAlign = 32;
     LongDoubleWidth = 96;
     LongDoubleAlign = 32;
     SuitableAlign = 128;
-    DescriptionString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128";
     SizeType = UnsignedInt;
     PtrDiffType = SignedInt;
     IntPtrType = SignedInt;
@@ -3511,6 +3520,21 @@
 
     return X86TargetInfo::validateOperandSize(Constraint, Size);
   }
+  // @LOCALMOD-START
+  bool handleTargetFeatures(std::vector<std::string> &Features,
+                            DiagnosticsEngine &Diags) override {
+    HasAlignedDouble = false;
+    auto it = std::find(Features.begin(), Features.end(), "+align-double");
+    if (it != Features.end()) {
+      HasAlignedDouble = true;
+      Features.erase(it);
+    }
+
+    setDescriptionString();
+
+    return X86TargetInfo::handleTargetFeatures(Features, Diags);
+  }
+  // @LOCALMOD-END
 };
 
 class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> {
@@ -3550,6 +3574,11 @@
 };
 
 class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> {
+  // @LOCALMOD-START
+  void setDescriptionString() override {
+    DescriptionString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128";
+  }
+  // @LOCALMOD-END
 public:
   DarwinI386TargetInfo(const llvm::Triple &Triple)
       : DarwinTargetInfo<X86_32TargetInfo>(Triple) {
@@ -3559,7 +3588,6 @@
     MaxVectorAlign = 256;
     SizeType = UnsignedLong;
     IntPtrType = SignedLong;
-    DescriptionString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128";
     HasAlignMac68kSupport = true;
   }
 
@@ -3567,15 +3595,19 @@
 
 // x86-32 Windows target
 class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
+  // @LOCALMOD-START
+  void setDescriptionString() override {
+    if (getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF())
+      DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
+    else
+      DescriptionString = "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S32";
+  }
+  // @LOCALMOD-END
 public:
   WindowsX86_32TargetInfo(const llvm::Triple &Triple)
       : WindowsTargetInfo<X86_32TargetInfo>(Triple) {
     WCharType = UnsignedShort;
     DoubleAlign = LongLongAlign = 64;
-    bool IsWinCOFF =
-        getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
-    DescriptionString = IsWinCOFF ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32"
-                                  : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S32";
   }
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override {
@@ -3648,13 +3680,17 @@
 
 // x86-32 Cygwin target
 class CygwinX86_32TargetInfo : public X86_32TargetInfo {
+  // @LOCALMOD-START
+  void setDescriptionString() override {
+    DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
+  }
+  // @LOCALMOD-END
 public:
   CygwinX86_32TargetInfo(const llvm::Triple &Triple)
       : X86_32TargetInfo(Triple) {
     TLSSupported = false;
     WCharType = UnsignedShort;
     DoubleAlign = LongLongAlign = 64;
-    DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32";
   }
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 567fd8c..05e81f5 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1712,6 +1712,13 @@
           << A->getOption().getName() << Value;
     }
   }
+
+  // @LOCALMOD-START
+  if (Args.getLastArg(options::OPT_malign_double)) {
+    CmdArgs.push_back("-mllvm");
+    CmdArgs.push_back("-malign-double");
+  }
+  // @LOCALMOD-END
 }
 
 static inline bool HasPICArg(const ArgList &Args) {
diff --git a/test/Driver/malign-double.c b/test/Driver/malign-double.c
new file mode 100644
index 0000000..81c0879
--- /dev/null
+++ b/test/Driver/malign-double.c
@@ -0,0 +1,13 @@
+// RUN: %clang -### -c -malign-double %s -target i686-unknown-linux 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-I686 %s
+
+// CHECK-I686: -cc1
+// CHECK-I686: +align-double
+// CHECK-I686: "-mllvm" "-malign-double"
+
+// RUN: %clang -### -c -malign-double %s -target x86-64-unknown-linux 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-X86_64 %s
+
+// CHECK-X86_64: -cc1
+// CHECK-X86_64-NOT: +align-double
+// CHECK-X86_64-NOT: "-mllvm" "-malign-double"