Check in LLVM r95781.
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
new file mode 100644
index 0000000..7c19bf6
--- /dev/null
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -0,0 +1,86 @@
+//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains semantic analysis implementation for target-specific
+// attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "TargetAttributesSema.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace clang;
+
+TargetAttributesSema::~TargetAttributesSema() {}
+bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
+                                    const AttributeList &Attr, Sema &S) const {
+  return false;
+}
+
+static void HandleMSP430InterruptAttr(Decl *d,
+                                      const AttributeList &Attr, Sema &S) {
+    // Check the attribute arguments.
+    if (Attr.getNumArgs() != 1) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+      return;
+    }
+
+    // FIXME: Check for decl - it should be void ()(void).
+
+    Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+    llvm::APSInt NumParams(32);
+    if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+        << "interrupt" << NumParamsExpr->getSourceRange();
+      return;
+    }
+
+    unsigned Num = NumParams.getLimitedValue(255);
+    if ((Num & 1) || Num > 30) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+        << "interrupt" << (int)NumParams.getSExtValue()
+        << NumParamsExpr->getSourceRange();
+      return;
+    }
+
+    d->addAttr(::new (S.Context) MSP430InterruptAttr(Num));
+    d->addAttr(::new (S.Context) UsedAttr());
+  }
+
+namespace {
+  class MSP430AttributesSema : public TargetAttributesSema {
+  public:
+    MSP430AttributesSema() { }
+    bool ProcessDeclAttribute(Scope *scope, Decl *D,
+                              const AttributeList &Attr, Sema &S) const {
+      if (Attr.getName()->getName() == "interrupt") {
+        HandleMSP430InterruptAttr(D, Attr, S);
+        return true;
+      }
+      return false;
+    }
+  };
+}
+
+const TargetAttributesSema &Sema::getTargetAttributesSema() const {
+  if (TheTargetAttributesSema)
+    return *TheTargetAttributesSema;
+
+  const llvm::Triple &Triple(Context.Target.getTriple());
+  switch (Triple.getArch()) {
+  default:
+    return *(TheTargetAttributesSema = new TargetAttributesSema);
+
+  case llvm::Triple::msp430:
+    return *(TheTargetAttributesSema = new MSP430AttributesSema);
+  }
+}
+