diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 99180e4..6fec969 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -664,11 +664,9 @@ def VectorSize : Attr {
   let ASTNode = 0;
 }
 
-def VecTypeHint : Attr {
+def VecTypeHint : InheritableAttr {
   let Spellings = [GNU<"vec_type_hint">];
-  let ASTNode = 0;
-  let SemaHandler = 0;
-  let Ignored = 1;
+  let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
 }
 
 def Visibility : InheritableAttr {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6d7b52e..6e918e3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1521,6 +1521,8 @@ def err_attribute_too_few_arguments : Error<
   "attribute takes at least %0 argument%s0">;
 def err_attribute_missing_parameter_name : Error<
   "attribute requires unquoted parameter">;
+def err_attribute_requires_type_parameter : Error<
+  "%0 attribute requires type parameter">;
 def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
 def err_attribute_bad_neon_vector_size : Error<
   "Neon vector size must be 64 or 128 bits">;
@@ -1538,6 +1540,8 @@ def err_attribute_argument_outof_range : Error<
 def err_init_priority_object_attr : Error<
   "can only use 'init_priority' attribute on file-scope definitions "
   "of objects of class type">;
+def err_attribute_argument_vec_type_hint : Error<
+  "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
 def err_attribute_argument_n_not_int : Error<
   "'%0' attribute requires parameter %1 to be an integer constant">;
 def err_attribute_argument_n_not_string : Error<
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 5239044..aab458c 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/VersionTuple.h"
+#include "clang/AST/Type.h"
 #include <cassert>
 
 namespace clang {
@@ -44,12 +45,18 @@ struct AvailabilityChange {
 };
 
 /// AttributeList - Represents GCC's __attribute__ declaration. There are
-/// 4 forms of this construct...they are:
+/// 5 forms of this construct which are:
 ///
-/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused.
-/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused.
-/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
-/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
+/// 1: __attribute__(( const )).
+///    ParmName/ParmType/Args/NumArgs unused.
+/// 2: __attribute__(( mode(byte) )).
+///    ParmName used, ParmType/Args/NumArgs unused.
+/// 3: __attribute__(( format(printf, 1, 2) )).
+///    ParmName/Args/NumArgs used, ParmType unused.
+/// 4: __attribute__(( aligned(16) )).
+///    ParmName/ParmType unused, Args/NumArgs used.
+/// 5: __attribute__(( vec_type_hint(int) )).
+///    ParmType used, ParmName/Args/NumArgs unused.
 ///
 class AttributeList { // TODO: This should really be called ParsedAttribute
 public:
@@ -70,6 +77,9 @@ private:
   SourceLocation ScopeLoc;
   SourceLocation ParmLoc;
 
+  /// The type parameter.
+  QualType ParmType;
+
   /// The number of expression arguments this attribute has.
   /// The expressions themselves are stored after the object.
   unsigned NumArgs : 16;
@@ -161,6 +171,19 @@ private:
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
 
+  AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
+                IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                QualType parmType, SourceLocation parmLoc,
+                Syntax syntaxUsed)
+    : AttrName(attrName), ScopeName(scopeName),
+      AttrRange(attrRange), ScopeLoc(scopeLoc),
+      ParmLoc(parmLoc), ParmType(parmType),
+      NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false),
+      UsedAsTypeAttr(false), IsAvailability(false),
+      NextInPosition(0), NextInPool(0) {
+      AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
+  }
+
   friend class AttributePool;
   friend class AttributeFactory;
 
@@ -183,6 +206,7 @@ public:
   
   IdentifierInfo *getParameterName() const { return ParmName; }
   SourceLocation getParameterLoc() const { return ParmLoc; }
+  QualType getParameterType() const { return ParmType; }
 
   /// Returns true if the attribute is a pure __declspec or a synthesized
   /// declspec representing a type specification (like __w64 or __ptr32).
@@ -211,6 +235,9 @@ public:
   /// or has a non empty argument expression list.
   bool hasParameterOrArguments() const { return ParmName || NumArgs; }
 
+  /// hasParameterType - Return true if this attribute has a type parameter.
+  bool hasParameterType() const { return !ParmType.isNull(); }
+
   /// getArg - Return the specified argument.
   Expr *getArg(unsigned Arg) const {
     assert(Arg < NumArgs && "Arg access out of range!");
@@ -409,6 +436,17 @@ public:
                                           unavailable, MessageExpr, syntax));
   }
 
+  AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
+                        IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                        QualType parmType, SourceLocation parmLoc,
+                        AttributeList::Syntax syntax) {
+    void *memory = allocate(sizeof(AttributeList));
+    return add(new (memory) AttributeList(attrName, attrRange,
+                                          scopeName, scopeLoc,
+                                          parmType, parmLoc,
+                                          syntax));
+  }
+
   AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
                                         SourceLocation TokLoc, int Arg);
 };
@@ -533,6 +571,17 @@ public:
     return attr;
   }
 
+  AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
+                        IdentifierInfo *scopeName, SourceLocation scopeLoc,
+                        QualType parmType, SourceLocation parmLoc,
+                        AttributeList::Syntax syntax) {
+    AttributeList *attr =
+      pool.create(attrName, attrRange, scopeName, scopeLoc, parmType, parmLoc,
+                  syntax);
+    add(attr);
+    return attr;
+  }
+
   AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
                                SourceLocation loc, int arg) {
     AttributeList *attr =
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 1d02861..81a49b7 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -292,6 +292,25 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
 
   if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
     GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs);
+
+  if (FD->hasAttr<VecTypeHintAttr>()) {
+    llvm::SmallVector <llvm::Value*, 3> attrMDArgs;
+    attrMDArgs.push_back(llvm::MDString::get(Context, "vec_type_hint"));
+
+    VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>();
+    QualType hintQTy = attr->getTypeHint();
+    llvm::Type *hintTy = CGM.getTypes().ConvertType(hintQTy);
+    attrMDArgs.push_back(llvm::UndefValue::get(hintTy));
+
+    const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>();
+    bool isSignedInteger = hintQTy->isSignedIntegerType() ||
+       (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
+    attrMDArgs.push_back(llvm::ConstantInt::get(
+       llvm::IntegerType::get(Context, 32),
+       llvm::APInt(32, (uint64_t) (isSignedInteger?1:0))));
+
+    kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+  }
   
   if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
     llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index ed3e43b..3581634 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1200,6 +1200,9 @@ private:
   /// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
   /// In the kernel metadata node, reference the kernel function and metadata 
   /// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
+  /// - A node for the vec_type_hint(<type>) qualifier contains string
+  ///   "vec_type_hint", an undefined value of the <type> data type,
+  ///   and a Boolean that is true if the <type> is integer and signed.
   /// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string 
   ///   "work_group_size_hint", and three 32-bit integers X, Y and Z.
   /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string 
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b830d9c..dda89f3 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -200,6 +200,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
   SourceLocation ParmLoc;
   bool BuiltinType = false;
 
+  TypeResult T;
+  SourceRange TypeRange;
+  bool TypeParsed = false;
+
   switch (Tok.getKind()) {
   case tok::kw_char:
   case tok::kw_wchar_t:
@@ -218,12 +222,17 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
   case tok::kw_void:
   case tok::kw_typeof:
     // __attribute__(( vec_type_hint(char) ))
-    // FIXME: Don't just discard the builtin type token.
-    ConsumeToken();
     BuiltinType = true;
+    T = ParseTypeName(&TypeRange);
+    TypeParsed = true;
     break;
 
   case tok::identifier:
+    if (AttrName->isStr("vec_type_hint")) {
+      T = ParseTypeName(&TypeRange);
+      TypeParsed = true;
+      break;
+    }
     ParmName = Tok.getIdentifierInfo();
     ParmLoc = ConsumeToken();
     break;
@@ -233,8 +242,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
   }
 
   ExprVector ArgExprs(Actions);
+  bool isInvalid = false;
+  bool isParmType = false;
 
-  if (!BuiltinType &&
+  if (!BuiltinType && !AttrName->isStr("vec_type_hint") &&
       (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
     // Eat the comma.
     if (ParmLoc.isValid())
@@ -270,15 +281,35 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
       SkipUntil(tok::r_paren, false, true); // skip until ')'
     }
   }
+  else if (AttrName->isStr("vec_type_hint")) {
+    if (T.get() && !T.isInvalid())
+      isParmType = true;
+    else {
+      if (Tok.is(tok::identifier)) ConsumeToken();
+      if (TypeParsed) isInvalid = true;
+    }
+
+    if (!Tok.is(tok::r_paren)) {
+      Diag(Tok, diag::err_expected_rparen);
+      ConsumeToken();
+      SkipUntil(tok::r_paren, false, true);
+    }
+  }
 
   SourceLocation RParen = Tok.getLocation();
-  if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
-    AttributeList *attr =
+  if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) && !isInvalid) {
+    if (isParmType) {
+      QualType ParmType = Sema::GetTypeFromParser(T.get());
       Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
-                   ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(),
-                   AttributeList::AS_GNU);
-    if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection)
-      Diag(Tok, diag::err_iboutletcollection_builtintype);
+                   ParmType, ParmLoc, AttributeList::AS_GNU);
+    } else {
+      AttributeList *attr =
+        Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
+                     ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(),
+                     AttributeList::AS_GNU);
+      if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection)
+        Diag(Tok, diag::err_iboutletcollection_builtintype);
+    }
   }
 }
 
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 29cb4f5..ce7bde9 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2514,6 +2514,37 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
                                        WGSize[0], WGSize[1], WGSize[2]));
 }
 
+static void handleVecTypeHint(Sema &S, Decl *D,
+                              const AttributeList &Attr) {
+  if (!Attr.hasParameterType()) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_requires_type_parameter) <<
+      Attr.getName();
+    return;
+  }
+
+  QualType QType = Attr.getParameterType();
+
+  if (!QType->isExtVectorType() &&
+      !QType->isFloatingType() &&
+      (QType->isBooleanType() || !QType->isIntegralType(S.getASTContext()))) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint) << QType;
+    return;
+  }
+
+  if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
+      D->hasAttr<VecTypeHintAttr>()) {
+      VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
+      if (A->getTypeHint() != QType) {
+        S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+          Attr.getName();
+        return;
+      }
+  }
+
+  D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
+                                                     QType, Attr.getLoc()));
+}
+
 SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
                                     StringRef Name) {
   if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
@@ -4182,6 +4213,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
   case AttributeList::AT_ReqdWorkGroupSize:
     handleWorkGroupSize(S, D, Attr); break;
 
+  case AttributeList::AT_VecTypeHint:
+    handleVecTypeHint(S, D, Attr); break;
+
   case AttributeList::AT_InitPriority: 
       handleInitPriorityAttr(S, D, Attr); break;
       
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index de16a41..bd6e22e 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -1,12 +1,16 @@
 // RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
+ 
+typedef int int4 __attribute__((ext_vector_type(4)));
 
-kernel __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+kernel  __attribute__((vec_type_hint(int))) __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
 
-kernel __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
+kernel __attribute__((vec_type_hint(int4))) __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
 
 // CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]}
 
-// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE1:![0-9]+]], metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE1]] = metadata !{metadata !"vec_type_hint", i32 undef, i32 1}
 // CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4}
-// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE4:![0-9]+]], metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE4]] = metadata !{metadata !"vec_type_hint", <4 x i32> undef, i32 0}
 // CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32}
diff --git a/test/SemaOpenCL/kernel-attributes-invalid.cl b/test/SemaOpenCL/kernel-attributes-invalid.cl
new file mode 100644
index 0000000..2620c41
--- /dev/null
+++ b/test/SemaOpenCL/kernel-attributes-invalid.cl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -verify %s 
+
+kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{'vec_type_hint' attribute requires type parameter}}
+
+kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
+
+kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{invalid attribute argument 'void' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{invalid attribute argument 'bool' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
+
+kernel __attribute__((work_group_size_hint(8,16,32,4))) void kernel6() {} //expected-error{{attribute requires exactly 3 arguments}}
+
+kernel __attribute__((work_group_size_hint(1,2,3))) __attribute__((work_group_size_hint(3,2,1))) void kernel7() {}  //expected-warning{{attribute 'work_group_size_hint' is already applied with different parameters}}
+
