diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 00af4cb..3cd431f 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -791,6 +791,10 @@ public:
   /// replaced.
   QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
 
+  /// \brief Return the uniqued reference to the type for an image access
+  /// qualified type with the specified type and image access attribute.
+  QualType getImageAccessQualType(QualType T, unsigned Acc) const;
+
   /// \brief Return the uniqued reference to the type for an Objective-C
   /// gc-qualified type.
   ///
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index cc6c1fd..78a148f 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -147,10 +147,16 @@ public:
     OCL_Autoreleasing
   };
 
+  enum OpenCLImageAccess {
+    Image_ReadOnly,
+    Image_WriteOnly,
+    Image_ReadWrite
+  };
+
   enum {
     /// The maximum supported address space number.
-    /// 24 bits should be enough for anyone.
-    MaxAddressSpace = 0xffffffu,
+    /// 20 bits should be enough for anyone.
+    MaxAddressSpace = 0xfffffu,
 
     /// The width of the "fast" qualifier mask.
     FastWidth = 3,
@@ -196,6 +202,11 @@ public:
       L.removeAddressSpace();
       R.removeAddressSpace();
     }
+    if (L.getImageAccess() == R.getImageAccess()) {
+      Q.setImageAccess(L.getImageAccess());
+      L.removeImageAccess();
+      R.removeImageAccess();
+    }
     return Q;
   }
 
@@ -310,11 +321,11 @@ public:
   }
 
   bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
-  unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
+  unsigned getAddressSpace() const { return (Mask&AddressSpaceMask) >> AddressSpaceShift; }
   void setAddressSpace(unsigned space) {
     assert(space <= MaxAddressSpace);
     Mask = (Mask & ~AddressSpaceMask)
-         | (((uint32_t) space) << AddressSpaceShift);
+         | ((((uint32_t) space) << AddressSpaceShift) & AddressSpaceMask);
   }
   void removeAddressSpace() { setAddressSpace(0); }
   void addAddressSpace(unsigned space) {
@@ -322,6 +333,23 @@ public:
     setAddressSpace(space);
   }
 
+  bool hasImageAccess() const { return Mask & ImageAccessMask; }
+  unsigned getImageAccess() const { return (Mask&ImageAccessMask) >> ImageAccessShift; }
+
+  bool isImageReadOnly() const { return getImageAccess()==1; }
+  bool isImageWriteOnly() const { return getImageAccess()==2; }
+  bool isImageReadWrite() const { return getImageAccess()==3; }
+
+  void setImageAccess(unsigned acc) {
+    assert(acc <= 3);
+    Mask = (Mask & ~ImageAccessMask)
+         | ((((uint32_t) acc) << ImageAccessShift) & ImageAccessMask);
+  }
+  void removeImageAccess() { setImageAccess(0); }
+  void addImageAccess(unsigned acc) {
+    setImageAccess(acc);
+  }
+
   // Fast qualifiers are those that can be allocated directly
   // on a QualType object.
   bool hasFastQualifiers() const { return getFastQualifiers(); }
@@ -365,6 +393,8 @@ public:
       Mask |= (Q.Mask & CVRMask);
       if (Q.hasAddressSpace())
         addAddressSpace(Q.getAddressSpace());
+      if (Q.hasImageAccess())
+        addImageAccess(Q.getImageAccess());
       if (Q.hasObjCGCAttr())
         addObjCGCAttr(Q.getObjCGCAttr());
       if (Q.hasObjCLifetime())
@@ -386,12 +416,16 @@ public:
         removeObjCLifetime();
       if (getAddressSpace() == Q.getAddressSpace())
         removeAddressSpace();
+      if (getImageAccess() == Q.getImageAccess())
+        removeImageAccess();
     }
   }
 
   /// \brief Add the qualifiers from the given set to this set, given that
   /// they don't conflict.
   void addConsistentQualifiers(Qualifiers qs) {
+    assert(getImageAccess() == qs.getImageAccess() ||
+           !hasImageAccess() || !qs.hasImageAccess());
     assert(getAddressSpace() == qs.getAddressSpace() ||
            !hasAddressSpace() || !qs.hasAddressSpace());
     assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
@@ -407,6 +441,7 @@ public:
   bool compatiblyIncludes(Qualifiers other) const {
     return
       // Address spaces must match exactly.
+      getImageAccess() == other.getImageAccess() &&
       getAddressSpace() == other.getAddressSpace() &&
       // ObjC GC qualifiers can match, be added, or be removed, but can't be
       // changed.
@@ -479,15 +514,17 @@ public:
 
 private:
 
-  // bits:     |0 1 2|3 .. 4|5  ..  7|8   ...   31|
-  //           |C R V|GCAttr|Lifetime|AddressSpace|
+  // bits:     |0 1 2|3 .. 4|5  ..  7|8   ...   27| 28  ...  29 | 
+  //           |C R V|GCAttr|Lifetime|AddressSpace| ImageAccess |
   uint32_t Mask;
 
   static const uint32_t GCAttrMask = 0x18;
   static const uint32_t GCAttrShift = 3;
   static const uint32_t LifetimeMask = 0xE0;
   static const uint32_t LifetimeShift = 5;
-  static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask);
+  static const uint32_t ImageAccessMask = 0x30000000;
+  static const uint32_t ImageAccessShift = 28;
+  static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask|ImageAccessMask);
   static const uint32_t AddressSpaceShift = 8;
 };
 
@@ -926,6 +963,11 @@ public:
   /// getAddressSpace - Return the address space of this type.
   inline unsigned getAddressSpace() const;
 
+  inline unsigned getImageAccess() const;
+  inline bool isImageReadOnly() const;
+  inline bool isImageWriteOnly() const;
+  inline bool isImageReadWrite() const;
+
   /// getObjCGCAttr - Returns gc attribute of this type.
   inline Qualifiers::GC getObjCGCAttr() const;
 
@@ -1103,6 +1145,9 @@ public:
   bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
   unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
 
+  bool hasImageAccess() const { return Quals.hasImageAccess(); }
+  unsigned getImageAccess() const { return Quals.getImageAccess(); }
+
   const Type *getBaseType() const { return BaseType; }
 
 public:
@@ -1584,6 +1629,7 @@ public:
 
   bool isImageType() const;                     // Any OpenCL image type
 
+  bool isSamplerT() const;                      // OpenCL sampler_t
   bool isEventT() const;                        // OpenCL event_t
 
   bool isOpenCLSpecificType() const;            // Any OpenCL specific type
@@ -4683,6 +4729,19 @@ inline unsigned QualType::getAddressSpace() const {
   return getQualifiers().getAddressSpace();
 }
 
+inline unsigned QualType::getImageAccess() const {
+  return getQualifiers().getImageAccess();
+}
+inline bool QualType::isImageReadOnly() const {
+  return getQualifiers().isImageReadOnly();
+}
+inline bool QualType::isImageWriteOnly() const {
+  return getQualifiers().isImageWriteOnly();
+}
+inline bool QualType::isImageReadWrite() const {
+  return getQualifiers().isImageReadWrite();
+}
+
 /// getObjCGCAttr - Return the gc attribute of this type.
 inline Qualifiers::GC QualType::getObjCGCAttr() const {
   return getQualifiers().getObjCGCAttr();
diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h
index 4b1cea5..f24c993 100644
--- a/include/clang/Basic/AddressSpaces.h
+++ b/include/clang/Basic/AddressSpaces.h
@@ -25,7 +25,7 @@ namespace LangAS {
 /// This uses a high starting offset so as not to conflict with any address
 /// space used by a target.
 enum ID {
-  Offset = 0xFFFF00,
+  Offset = 0xFFF00,
 
   opencl_global = Offset,
   opencl_local,
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 002a126..a759950 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -191,7 +191,10 @@ public:
     InitializedEntity Entity;
     Entity.Kind = EK_Parameter;
     Entity.Type =
-      Context.getVariableArrayDecayedType(Type.getUnqualifiedType());
+      Context.getVariableArrayDecayedType(Context.getLangOpts().OpenCL?
+                                           Context.getImageAccessQualType(Type.getUnqualifiedType(),
+                                                                          Type.getImageAccess())
+                                          :Type.getUnqualifiedType());
     Entity.Parent = 0;
     Entity.Parameter
       = (static_cast<uintptr_t>(Consumed) | reinterpret_cast<uintptr_t>(Parm));
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7ba64e3..82ae361 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1887,9 +1894,11 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
     (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos);
   }
 
-  ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals);
-  ExtQualNodes.InsertNode(eq, insertPos);
-  return QualType(eq, fastQuals);
+  if (quals.hasNonFastQualifiers()) {
+    ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals);
+    ExtQualNodes.InsertNode(eq, insertPos);
+    return QualType(eq, fastQuals);
+  } else return QualType(baseType, fastQuals);
 }
 
 QualType
@@ -1912,6 +1921,30 @@ ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const {
   return getExtQualType(TypeNode, Quals);
 }
 
+QualType
+ASTContext::getImageAccessQualType(QualType T, unsigned Acc) const {
+  QualType CanT = getCanonicalType(T);
+  if (CanT.getImageAccess() == Acc)
+    return T;
+  
+  if (Acc == 0) {
+    Qualifiers Q = CanT.getQualifiers();
+    Q.removeImageAccess();
+    if (Q.getAsOpaqueValue() == 0) return T.getUnqualifiedType();
+  }
+  
+  // If we are composing extended qualifiers together, merge together
+  // into one ExtQuals node.
+  QualifierCollector Quals;
+  const Type *TypeNode = Quals.strip(T);
+
+  // We have to be able to override an image access qualifier, 
+  // since there is always a default read_only.
+  Quals.addImageAccess(Acc);
+
+  return getExtQualType(TypeNode, Quals);
+}
+
 QualType ASTContext::getObjCGCQualType(QualType T,
                                        Qualifiers::GC GCAttr) const {
   QualType CanT = getCanonicalType(T);
@@ -2635,9 +2668,15 @@ ASTContext::getFunctionType(QualType ResultTy,
   bool isCanonical =
     EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) &&
     !EPI.HasTrailingReturn;
-  for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
-    if (!ArgArray[i].isCanonicalAsParam())
+  for (unsigned i = 0; i != NumArgs && isCanonical; ++i) {
+    if (getLangOpts().OpenCL) {
+      if (!getImageAccessQualType(ArgArray[i],0).
+          isCanonicalAsParam()) {
+        isCanonical = false;
+      }
+    } else if (!ArgArray[i].isCanonicalAsParam())
       isCanonical = false;
+  }
 
   const CallingConv DefaultCC = EPI.ExtInfo.getCC();
   const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
@@ -3624,6 +3663,9 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
     Result = getArrayDecayedType(QualType(Ty,0));
   } else if (isa<FunctionType>(Ty)) {
     Result = getPointerType(QualType(Ty, 0));
+  } else if (getLangOpts().OpenCL) {
+    Result = QualType(Ty, 0);
+    Result = getImageAccessQualType(Result, T.getImageAccess());
   } else {
     Result = QualType(Ty, 0);
   }
@@ -4015,7 +4057,10 @@ QualType ASTContext::getAdjustedParameterType(QualType T) const {
 QualType ASTContext::getSignatureParameterType(QualType T) const {
   T = getVariableArrayDecayedType(T);
   T = getAdjustedParameterType(T);
-  return T.getUnqualifiedType();
+  if (getLangOpts().OpenCL)
+    return
+			getImageAccessQualType(T.getUnqualifiedType(), T.getImageAccess());
+  else return T.getUnqualifiedType();
 }
 
 /// getArrayDecayedType - Return the properly qualified result of decaying the
@@ -6763,6 +6808,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
     // mismatch.
     if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
         LQuals.getAddressSpace() != RQuals.getAddressSpace() ||
+        LQuals.getImageAccess() != RQuals.getImageAccess() ||
         LQuals.getObjCLifetime() != RQuals.getObjCLifetime())
       return QualType();
 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 524d005..2b17db4 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -35,6 +35,9 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
     // ObjC GC qualifiers superset
     ((getObjCGCAttr() == Other.getObjCGCAttr()) ||
      (hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
+    // Image access superset.
+    ((getImageAccess() == Other.getImageAccess()) ||
+     (hasImageAccess()&& !Other.hasImageAccess())) &&
     // Address space superset.
     ((getAddressSpace() == Other.getAddressSpace()) ||
      (hasAddressSpace()&& !Other.hasAddressSpace())) &&
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index c29230f..0d48acd 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -431,9 +431,11 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
                                       FunctionType::ExtInfo info,
                                       RequiredArgs required) {
 #ifndef NDEBUG
-  for (ArrayRef<CanQualType>::const_iterator
-         I = argTypes.begin(), E = argTypes.end(); I != E; ++I)
-    assert(I->isCanonicalAsParam());
+  if (!Context.getLangOpts().OpenCL) {
+    for (ArrayRef<CanQualType>::const_iterator
+           I = argTypes.begin(), E = argTypes.end(); I != E; ++I)
+      assert(I->isCanonicalAsParam());
+  }
 #endif
 
   unsigned CC = ClangCallConvToLLVMCallConv(info.getCC());
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 215d096..2dc0f4d 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -29,34 +29,53 @@ void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
   return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
 }
 
-llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
+llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const QualType QT) {
+  const Type *T = QT.getTypePtr();
   assert(T->isOpenCLSpecificType() &&
          "Not an OpenCL specific type!");
 
   switch (cast<BuiltinType>(T)->getKind()) {
   default: 
     llvm_unreachable("Unexpected opencl builtin type!");
     return 0;
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 7b675c3..45245d3 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -43,7 +43,7 @@ public:
   virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
                                          const VarDecl &D);
 
-  virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
+  virtual llvm::Type *convertOpenCLSpecificType(const QualType QT);
 };
 
 }
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index e78cbab..c7babff 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -16,12 +16,14 @@
 #include "CGCall.h"
 #include "CGOpenCLRuntime.h"
 #include "CGRecordLayout.h"
+#include "CGOpenCLRuntime.h"
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/Basic/AddressSpaces.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Module.h"
@@ -289,6 +291,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
   T = Context.getCanonicalType(T);
 
   const Type *Ty = T.getTypePtr();
 
   // RecordTypes are cached and processed specially.
   if (const RecordType *RT = dyn_cast<RecordType>(Ty))
@@ -378,8 +391,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
     case BuiltinType::OCLImage2d:
     case BuiltinType::OCLImage2dArray:
     case BuiltinType::OCLImage3d:
     case BuiltinType::OCLEvent:
-      ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
+      ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(T);
       break;
     
     case BuiltinType::Dependent:
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index fd165ac..46c3e7b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -493,8 +493,13 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   //   If the lvalue has qualified type, the value has the unqualified
   //   version of the type of the lvalue; otherwise, the value has the
   //   type of the lvalue.
-  if (T.hasQualifiers())
-    T = T.getUnqualifiedType();
+  if (T.hasQualifiers()) {
+    if (!getLangOpts().OpenCL) 
+      T = T.getUnqualifiedType();
+    else
+      T = Context.getImageAccessQualType(T.getUnqualifiedType(), 
+                                         T.getImageAccess());
+  }
 
   UpdateMarkingForLValueToRValue(E);
   
@@ -5634,6 +5639,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   QualType RHSType = RHS.get()->getType();
   QualType OrigLHSType = LHSType;
 
+  // For OpenCL image types, use the qualified types,
+  // so that the access qualifiers aren't ignored.
+  if (LHSType->isImageType() && RHSType->isImageType() &&
+			LHSType.getImageAccess() != RHSType.getImageAccess())
+    return Incompatible;
+
   // Get canonical types.  We're not formatting these types, just comparing
   // them.
   LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 22cb61e..00e53f6 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1467,7 +1467,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
     // cv-unqualified version of T. Otherwise, the type of the rvalue
     // is T (C++ 4.1p1). C++ can't get here with class types; in C, we
     // just strip the qualifiers because they don't matter.
-    FromType = FromType.getUnqualifiedType();
+    if (!S.getLangOpts().OpenCL)
+      FromType = FromType.getUnqualifiedType();
+    else {
+      FromType = S.Context.getImageAccessQualType(FromType.getUnqualifiedType(),
+                                                  FromType.getImageAccess());
+    }
   } else if (FromType->isArrayType()) {
     // Array-to-pointer conversion (C++ 4.2)
     SCS.First = ICK_Array_To_Pointer;
@@ -1594,6 +1599,9 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                              SCS, CStyle)) {
     SCS.Second = ICK_TransparentUnionConversion;
     FromType = ToType;
+  } else if (FromType->isIntegerType() && ToType->isEventT()) {
+    SCS.Second = ICK_Identity;
+    FromType = ToType.getUnqualifiedType();
   } else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
                                  CStyle)) {
     // tryAtomicConversion has updated the standard conversion sequence
@@ -8103,6 +8111,10 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
       MaybeEmitInheritedConstructorNote(S, Fn);
       return;
     }
+    
+    if (FromQs.getImageAccess() != ToQs.getImageAccess()) {
+      return;
+    }
 
     if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
       S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership)
