Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td	(revision 175389)
+++ include/clang/Basic/Attr.td	(working copy)
@@ -333,7 +333,6 @@
 def OpenCLImageAccess : Attr {
   let Spellings = [GNU<"opencl_image_access">];
   let Args = [IntArgument<"Access">];
-  let ASTNode = 0;
 }
 
 def Deprecated : InheritableAttr {
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp	(revision 175389)
+++ lib/CodeGen/CodeGenFunction.cpp	(working copy)
@@ -20,6 +20,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/Basic/OpenCL.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/IR/DataLayout.h"
@@ -276,25 +277,114 @@
 // FIXME: Add type, address, and access qualifiers.
 static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
                                  CodeGenModule &CGM,llvm::LLVMContext &Context,
-                                 SmallVector <llvm::Value*, 5> &kernelMDArgs) {
+                                 SmallVector <llvm::Value*, 5> &kernelMDArgs,
+                                 CGBuilderTy& Builder) {
+  // Main MDNode holding all the kernel arg metadata for a specific kernel.
+  SmallVector<llvm::Value*, 8> argInfo;
+  argInfo.push_back(llvm::MDString::get(Context, "cl-kernel-arg-info"));
 
   // Create MDNodes that represents the kernel arg metadata.
   // Each MDNode is a list in the form of "key", N number of values which is
   // the same number of values as their are kernel arguments.
 
+  // MDNode for the kernel argument address space qualifiers.
+  SmallVector<llvm::Value*, 8> addressQuals;
+  addressQuals.push_back(llvm::MDString::get(Context, "address_qualifiers"));
+
+  // MDNode for the kernel argument access qualifiers (images only).
+  SmallVector<llvm::Value*, 8> accessQuals;
+  accessQuals.push_back(llvm::MDString::get(Context, "access_qualifiers"));
+
+  // MDNode for the kernel argument type names.
+  SmallVector<llvm::Value*, 8> argTypeNames;
+  argTypeNames.push_back(llvm::MDString::get(Context, "arg_type_names"));
+
+  // MDNode for the kernel argument type qualifiers.
+  SmallVector<llvm::Value*, 8> argTypeQuals;
+  argTypeQuals.push_back(llvm::MDString::get(Context, "arg_type_qualifiers"));
+
   // MDNode for the kernel argument names.
   SmallVector<llvm::Value*, 8> argNames;
-  argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name"));
+  argNames.push_back(llvm::MDString::get(Context, "arg_names"));
 
   for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
     const ParmVarDecl *parm = FD->getParamDecl(i);
+    QualType ty = parm->getType();
+    int typeQuals = 0;
 
+    if (ty->isPointerType()) {
+      QualType pointeeTy = ty->getPointeeType();
+
+      // Get address qualifier.
+      if (pointeeTy.getAddressSpace() == 0)
+        addressQuals.push_back(Builder.getInt32(0));
+      else if (ty->getPointeeType().getAddressSpace() ==
+               LangAS::opencl_global)
+        addressQuals.push_back(Builder.getInt32(1));
+      else if (ty->getPointeeType().getAddressSpace() ==
+               LangAS::opencl_constant) {
+        addressQuals.push_back(Builder.getInt32(2));
+        typeQuals |= 1;
+      } else if (ty->getPointeeType().getAddressSpace() ==
+               LangAS::opencl_local)
+        addressQuals.push_back(Builder.getInt32(3));
+
+      // Get argument type name.
+      argTypeNames.push_back(
+        llvm::MDString::get(Context, 
+                            pointeeTy.getUnqualifiedType().getAsString() + "*"));
+
+      // Get argument type qualifiers:
+      // 1 - const.
+      // 2 - restrict.
+      // 4 - volatile.
+      if(ty.isRestrictQualified())        typeQuals |= 2;
+      if(pointeeTy.isConstQualified())    typeQuals |= 1;
+      if(pointeeTy.isVolatileQualified()) typeQuals |= 4;
+
+      argTypeQuals.push_back(Builder.getInt32(typeQuals));
+    } else {
+      addressQuals.push_back(Builder.getInt32(0));
+
+      // Get argument type name.
+      argTypeNames.push_back(
+        llvm::MDString::get(Context, ty.getUnqualifiedType().getAsString()));
+
+      // Get argument type qualifiers:
+      // 1 - const.
+      // 4 - volatile.
+      if(ty.isConstQualified())    typeQuals |= 1;
+      if(ty.isVolatileQualified()) typeQuals |= 4;
+
+      argTypeQuals.push_back(Builder.getInt32(typeQuals));
+    }
+    
+    // Get image access qualifier:
+    // 0 - read_only.
+    // 1 - write_only.
+    // 2 - reserved for read_write.
+    // 3 - none.
+    if (ty->isImageType()) {
+      if (parm->hasAttr<OpenCLImageAccessAttr>() &&
+          parm->getAttr<OpenCLImageAccessAttr>()->getAccess() == CLIA_write_only)
+        accessQuals.push_back(Builder.getInt32(1));  // write_only.
+      else
+        accessQuals.push_back(Builder.getInt32(0));  // read_only.
+    } else
+      accessQuals.push_back(Builder.getInt32(3));  // Non-image type.
+
     // Get argument name.
     argNames.push_back(llvm::MDString::get(Context, parm->getName()));
+  }
 
-  }
+  argInfo.push_back(llvm::MDNode::get(Context, addressQuals));
+  argInfo.push_back(llvm::MDNode::get(Context, accessQuals));
+  argInfo.push_back(llvm::MDNode::get(Context, argTypeNames));
+  argInfo.push_back(llvm::MDNode::get(Context, argTypeQuals));
+  argInfo.push_back(llvm::MDNode::get(Context, argNames));
+
   // Add MDNode to the list of all metadata.
-  kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames));
+  kernelMDArgs.push_back(llvm::MDNode::get(Context, argInfo));
 }
 
 void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
@@ -309,7 +399,7 @@
   kernelMDArgs.push_back(Fn);
 
   if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
-    GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs);
+    GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs, Builder);
 
   if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
     WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 175389)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -3879,6 +3879,22 @@
   D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
 }
 
+static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){
+  assert(!Attr.isInvalid());
+
+  Expr *E = Attr.getArg(0);
+  llvm::APSInt ArgNum(32);
+  if (E->isTypeDependent() || E->isValueDependent() ||
+      !E->isIntegerConstantExpr(ArgNum, S.Context)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+      << Attr.getName()->getName() << E->getSourceRange();
+    return;
+  }
+
+  D->addAttr(::new (S.Context) OpenCLImageAccessAttr(
+    Attr.getRange(), S.Context, ArgNum.getZExtValue()));
+}
+
 bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, 
                                 const FunctionDecl *FD) {
   if (attr.isInvalid())
@@ -4569,7 +4585,6 @@
   case AttributeList::AT_IBOutletCollection:
     handleIBOutletCollection(S, D, Attr); break;
   case AttributeList::AT_AddressSpace:
-  case AttributeList::AT_OpenCLImageAccess:
   case AttributeList::AT_ObjCGC:
   case AttributeList::AT_VectorSize:
   case AttributeList::AT_NeonVectorType:
@@ -4736,6 +4751,9 @@
   case AttributeList::AT_OpenCLKernel:
     handleOpenCLKernelAttr(S, D, Attr);
     break;
+  case AttributeList::AT_OpenCLImageAccess:
+    handleOpenCLImageAccessAttr(S, D, Attr);
+    break;
 
   // Microsoft attributes:
   case AttributeList::AT_MsStruct:
Index: test/CodeGenOpenCL/kernel-arg-info.cl
===================================================================
--- test/CodeGenOpenCL/kernel-arg-info.cl	(revision 175389)
+++ test/CodeGenOpenCL/kernel-arg-info.cl	(working copy)
@@ -1,7 +1,22 @@
 // RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - | FileCheck %s
 
-kernel void foo(int *X, int Y, int anotherArg) {
+kernel void foo(__global int * restrict X, const int Y, volatile int anotherArg) {
   *X = Y + anotherArg;
 }
 
-// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg"}
+// CHECK: metadata !"cl-kernel-arg-info"
+// CHECK: metadata !{metadata !"address_qualifiers", i32 1, i32 0, i32 0}
+// CHECK: metadata !{metadata !"access_qualifiers", i32 3, i32 3, i32 3}
+// CHECK: metadata !{metadata !"arg_type_names", metadata !"int*", metadata !"int", metadata !"int"}
+// CHECK: metadata !{metadata !"arg_type_qualifiers", i32 2, i32 1, i32 4}
+// CHECK: metadata !{metadata !"arg_names", metadata !"X", metadata !"Y", metadata !"anotherArg"}
+
+kernel void foo2(read_only image1d_t img1, image2d_t img2, write_only image2d_array_t img3) {
+}
+// CHECK: metadata !{metadata !"address_qualifiers", i32 0, i32 0, i32 0}
+// CHECK: metadata !{metadata !"access_qualifiers", i32 0, i32 0, i32 1}
+// CHECK: metadata !{metadata !"arg_type_names", metadata !"image1d_t", metadata !"image2d_t", metadata !"image2d_array_t"}
+// CHECK: metadata !{metadata !"arg_type_qualifiers", i32 0, i32 0, i32 0}
+// CHECK: metadata !{metadata !"arg_names", metadata !"img1", metadata !"img2", metadata !"img3"}
+
+
