On Jun 22, 2012, at 9:21 AM, Douglas Gregor wrote:

> 
> On Jun 21, 2012, at 4:51 PM, Tanya Lattner wrote:
> 
>> Attached is a patch that adds the OpenCL sampler type to clang. This is a 
>> combined patch from the one submitted by Anton Lokhmotov, changes from my 
>> tree, and correcting some issues that I saw. 
>> 
>> I've purposely separated out the event and image types from the original 
>> patch as they should be made in other separate patches.
>> 
>> Please review.
> 
> Index: include/clang/AST/Type.h
> ===================================================================
> --- include/clang/AST/Type.h  (revision 158757)
> +++ include/clang/AST/Type.h  (working copy)
> @@ -4533,6 +4533,21 @@
>   QualType apply(const ASTContext &Context, const Type* T) const;
> };
> 
> +// OpenCL specific types.
> +class OpenCLSamplerType : public Type {
> +public:
> +  OpenCLSamplerType() :  Type(OpenCLSampler, QualType(), false, false,
> +                              /*VariablyModified=*/false,
> +                              /*Unexpanded parameter pack=*/false) { }
> +  bool isSugared() const { return false; }
> +  QualType desugar() const { return QualType(this, 0); }
> +  
> +  static bool classof(const Type *T) {
> +    return T->getTypeClass() == OpenCLSampler;
> +  }
> +  
> +  static bool classof(const OpenCLSamplerType *) { return true; }
> +};
> 
> // Inline function definitions.
> 
> Apologies if I've missed/forgotten the discussion, but why is this a separate 
> type rather than simply another kind of BuiltinType?
> 


I'll just comment on this before I go through the rest of your comments. This 
is from Anton back when we were trying to converge on sampler_t in Clang. I had 
it as a builtin type but from his perspective it should not be one:

"Hi Tanya,

I've invested a lot of time trying to understand the sampler type.  Here's a
summary.

The sampler type (sampler_t) is used for sampler objects, either created via
the OpenCL API and set as a kernel argument, or declared in the program
source (6.11.13.1).  A sampler value is a 32-bit unsigned integer constant,
interpreted as a bit-field for the image read properties: addressing mode,
filtering mode, normalised coordinates.

== Allowed use ==
* The sampler type can be used as the type of a function argument.
* The sampler type can be used to declare a variable in the program scope.
* The sampler type can be used to declare a variable in a kernel function
scope.

== Disallowed use ==
* The sampler type cannot be used to declare an array of samplers.
* The sampler type cannot be used to declare a pointer to a sampler.
* The sampler type cannot be the return type of a function.
* A sampler function argument cannot be modified.
* A sampler variable cannot be modified.

All in all, the sampler type does not behave like a normal integer.  It's
actually an opaque type which backends can implement in a target-specific
way.

I'm going to submit our first patch for the image and sampler types shortly.
Hope we can do a merge in some way.

Best regards,
Anton."

Some other references:
My original patch and discussion:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-March/013865.html
Anton's response:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-March/014118.html
His patch:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-March/014121.html

Let me know what you think and if this makes sense to you. 

-Tanya





> Index: include/clang/AST/TypeLoc.h
> ===================================================================
> --- include/clang/AST/TypeLoc.h       (revision 158757)
> +++ include/clang/AST/TypeLoc.h       (working copy)
> @@ -1360,6 +1360,12 @@
>                                                         ComplexType> {
> };
> 
> +// FIXME: location of the OpenCL sampler type.
> +class OpenCLSamplerTypeLoc : public 
> InheritingConcreteTypeLoc<TypeSpecTypeLoc,
> +                                                        OpenCLSamplerTypeLoc,
> +                                                        OpenCLSamplerType> {
> +};
> +  
> 
> TypeSpecTypeLoc has the right storage already for the sampler_t type, so 
> there really isn't anything to FIXME here. (Or, you'd get this for free if 
> sampler_t was jut another builtin type).
> 
> Index: lib/Sema/TreeTransform.h
> ===================================================================
> --- lib/Sema/TreeTransform.h  (revision 158757)
> +++ lib/Sema/TreeTransform.h  (working copy)
> @@ -4524,6 +4524,13 @@
> }
> 
> template<typename Derived>
> +QualType TreeTransform<Derived>::TransformOpenCLSamplerType(TypeLocBuilder 
> &TLB,
> +                                                    OpenCLSamplerTypeLoc TL) 
> {
> +  QualType Result = TL.getType();
> +  return Result;
> +}
> +  
> 
> You'll actually have to push an OpenCLSamplerTypeLoc into TLB here; 
> otherwise, the TypeLocBuilder won't actually have the type-location 
> information, and anything based on tree transformation will break with 
> sampler_t types. See TransformBuiltinType for an indication of how to fix 
> this.
> 
> Index: lib/Sema/SemaDecl.cpp
> ===================================================================
> --- lib/Sema/SemaDecl.cpp     (revision 158759)
> +++ lib/Sema/SemaDecl.cpp     (working copy)
> @@ -4098,6 +4098,33 @@
>     // OpenCL __local address space.
>     if (R.getAddressSpace() == LangAS::opencl_local)
>       SC = SC_OpenCLWorkGroupLocal;
> +    
> +    if (isa<OpenCLSamplerType>(R.getTypePtr())) {
> 
> isa<> doesn't look through sugar. Please use R->getAs<OpenCLSamplerType>() to 
> test.
> 
> +      //  The sampler type can be used to declare a variable only
> +      //  in the scope of a kernel function or in the program scope.
> +      if (DC->isFunctionOrMethod()) {
> +        FunctionDecl *FD = dyn_cast<FunctionDecl>(DC);
> +        if (FD->hasAttr<OpenCLKernelAttr>()) {
> +          valid = true;
> +        }
> +      } else if (DC->isTranslationUnit()) {
> +        valid = true;
> +      }
> 
> I know OpenCL doesn't have namespaces or ObjC methods, but I think this code 
> should still be robust against those possibilities. In the 
> hasAttr<OpenCLKernelAttr>() check, please check that 'FD' is non-NULL first 
> (to catch the ObjC method case). I also suggest replacing the 
> DC->isTranslationUnit() check with DC->isFileContext() (to handle namespaces).
> 
> +        if (R.hasQualifiers()
> +            && !((R.getAddressSpace() == LangAS::opencl_constant)
> +            || R.isConstQualified())) {
> +          Diag(D.getIdentifierLoc(), diag::err_opencl_sampler_qualifier);
> +          D.setInvalidType();
> +        }
> 
> This is a very generic diagnostic, although it's testing for something very 
> specific: why not emit something like 'non-const sampler type can only be in 
> the constant address space (not address space %0)'?
> 
> @@ -9222,6 +9249,14 @@
>     }
>   }
> 
> +  if (!InvalidDecl) {
> +    // Sampler types cannot be used to declare a field.
> +    if (isa<OpenCLSamplerType>(T)) {
> +      Diag(Loc, diag::err_opencl_type_field) << II << T;
> +      InvalidDecl = true;
> +    }
> +  }
> +  
> 
> isa -> getAs
> 
> Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td        (revision 158759)
> +++ include/clang/Basic/DiagnosticSemaKinds.td        (working copy)
> @@ -5626,6 +5626,13 @@
>   "kernel functions cannot be declared static">;
> def err_static_function_scope : Error<
>   "variables in function scope cannot be declared static">;
> +def err_opencl_sampler_declaration : Error<
> +  "declaring sampler variable in this context is not allowed">;
> +def err_opencl_sampler_qualifier : Error<"using invalid qualifier with 
> sampler type">;
> +def err_opencl_type_pointer : Error<"%0: declaring pointer to type %1 is not 
> allowed">;
> +def err_opencl_type_array : Error<"%0: declaring array of type %1 is not 
> allowed">;
> +def err_opencl_type_return : Error<"declaring return value of type %0 is not 
> allowed">;
> +  def err_opencl_type_field : Error<"%0: declaring field of type %1 is not 
> allowed">;
> 
> I find the prefixing of '%0:' in these diagnostics to be a bit awkward, for 
> two reasons: first, Clang tends to put the names of things in their English 
> context when it uses names, e.g., 'variable %0 declared as a pointer to type 
> %1'. Moreover, in most of the cases where these diagnostics are emitted, 
> there may not be any name, which is going to leave a very awkward ':'. Why 
> not drop the names entirely, and follow what other things in SemaType do, 
> e.g., "cannot declare field of type %0" or "cannot declare an array of type 
> %0"?
> 
> @@ -1132,6 +1135,13 @@
>     return QualType();
>   }
> 
> +  // Using the sampler types to declare a pointer is not allowed.
> +  if (isa<OpenCLSamplerType>(T)) {
> +    Diag(Loc, diag::err_opencl_type_pointer)
> +    << getPrintableNameForEntity(Entity) << T;
> +    return QualType();
> +  }
> 
> isa -> getAs
> 
> @@ -1281,6 +1291,13 @@
>     return QualType();
>   }
> 
> +  // Using the image and sampler types to declare an array is not allowed
> +  if (isa<OpenCLSamplerType>(T)) {
> +    Diag(Loc, diag::err_opencl_type_array)
> +    << getPrintableNameForEntity(Entity) << T;
> +    return QualType();
> +  }
> +  
> 
> isa -> getAs
> 
> @@ -2411,6 +2428,14 @@
>           // Only the outermost chunk is marked noexcept, of course.
>           EPI.ExceptionSpecType = EST_BasicNoexcept;
>         }
> +        
> +        // Using the sampler types to declare a return value
> +        // is not allowed.
> +        if (LangOpts.OpenCL) {
> +          if (isa<OpenCLSamplerType>(T.getTypePtr())) {
> +            S.Diag(DeclType.Loc, diag::err_opencl_type_return) << T;
> +          }
> +        }
> 
> There's no need for the OpenCL check here; also, isa -> getAs
> 
> Index: lib/Sema/SemaExpr.cpp
> ===================================================================
> --- lib/Sema/SemaExpr.cpp     (revision 158757)
> +++ lib/Sema/SemaExpr.cpp     (working copy)
> @@ -5511,6 +5511,12 @@
>   LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
>   RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
> 
> +  // A special case: sampler constructor.
> +  if (getLangOpts().OpenCL) {
> +    if (isa<OpenCLSamplerType>(LHSType)) {
> +      if (RHSType->isIntegerType()) return Compatible;
> +    }
> +  }
> 
> No need for the OpenCL check. isa -> getAs. Also, should there be an 
> equivalent standard conversion on the C++ side of the world?
> 
> @@ -7466,6 +7472,10 @@
>   case Expr::MLV_ConstQualified:
>     Diag = diag::err_typecheck_assign_const;
> 
> +    // OpenCL sampler check, no need to do anything further.
> +    if (S.getLangOpts().OpenCL && isa<OpenCLSamplerType>(E->getType()))
> +      break;
> +
> 
> No need for the OpenCL check. isa -> getAs.
> 
> Index: lib/Sema/Sema.cpp
> ===================================================================
> --- lib/Sema/Sema.cpp (revision 158757)
> +++ lib/Sema/Sema.cpp (working copy)
> @@ -273,6 +273,15 @@
>   if (ExprTy == TypeTy)
>     return Owned(E);
> 
> +  // A special case: attempting to initialize a sampler.
> +  if (getLangOpts().OpenCL) {
> +    const OpenCLSamplerType *tp = 
> Ty.getTypePtr()->getAs<OpenCLSamplerType>();
> +    if (tp != NULL) {
> +      // Casting is not required - CodeGen will take care of it
> +      return Owned(E); 
> +    }
> +  }
> +
> 
> We don't want to do this. It's a conversion in the language, and should be 
> represented in the AST. The meta-point here is that CodeGen is supposed to be 
> "simple", in the sense that it doesn't have to reason about language 
> semantics. The cast kind is there to tell CodeGen what to do.
> 
> @@ -2063,6 +2064,10 @@
>   mangleType(T->getElementType());
> }
> 
> +void CXXNameMangler::mangleType(const OpenCLSamplerType *T) {
> +  Out << "uSampler";
> +}
> 
> This should be "u7Sampler", because 'Sampler' is not a source-name.
> 
> 'twould be nice if the libc++abi demangler knew about this mangling, but 
> that's just gravy.
> 
> +  // OpenCL specific types.
> +  if (Ctx.getLangOpts().OpenCL) {
> +    const QualType ETy = E->getType();
> +    const Type *ETyP = ETy.getTypePtr();
> +    if (isa<OpenCLSamplerType>(ETyP)) {
> +      return Cl::CM_ConstQualified;
> +    }
> +  }
> 
> This has the isa -> getAs issue.
> 
> However, I don't understand the purpose, because it seems like this should 
> fall out from the fact that the lvalue will either have 'const' type (which 
> is handled above) or is in the constant address space (which seems like a 
> missing general case in this code). 
> 
> Index: lib/CodeGen/CGRTTI.cpp
> ===================================================================
> --- lib/CodeGen/CGRTTI.cpp    (revision 158757)
> +++ lib/CodeGen/CGRTTI.cpp    (working copy)
> @@ -397,6 +397,9 @@
> #include "clang/AST/TypeNodes.def"
>     llvm_unreachable("Non-canonical and dependent types shouldn't get here");
> 
> +  case Type::OpenCLSampler:
> +    llvm_unreachable("OpenCL types shouldn't get here");
> +      
>   case Type::LValueReference:
>   case Type::RValueReference:
>     llvm_unreachable("References shouldn't get here");
> 
> OpenCL and RTTI, like oil and water.
> 
> Index: lib/CodeGen/CGDebugInfo.cpp
> ===================================================================
> --- lib/CodeGen/CGDebugInfo.cpp       (revision 158757)
> +++ lib/CodeGen/CGDebugInfo.cpp       (working copy)
> @@ -1769,6 +1769,10 @@
>   case Type::Atomic:
>     return CreateType(cast<AtomicType>(Ty), Unit);
> 
> +      
> +  case Type::OpenCLSampler:
> +      llvm_unreachable("unsupported");
> +      
> 
> Rather than aborting, could we simply use 'Int32' here and add a FIXME if 
> anyone ever cares to improve the situation? 
> 
> Index: lib/CodeGen/CGDecl.cpp
> ===================================================================
> --- lib/CodeGen/CGDecl.cpp    (revision 158757)
> +++ lib/CodeGen/CGDecl.cpp    (working copy)
> @@ -111,6 +111,12 @@
>   case SC_None:
>   case SC_Auto:
>   case SC_Register:
> +      if (isa<OpenCLSamplerType>(D.getType())) {
> +        // Emit a global "static" sampler declaration.
> +        llvm::GlobalValue::LinkageTypes Linkage =
> +        llvm::GlobalValue::InternalLinkage;
> +        return EmitStaticVarDecl(D, Linkage);
> +      }
>     return EmitAutoVarDecl(D);
>   case SC_Static: {
>     llvm::GlobalValue::LinkageTypes Linkage =
> 
> CodeGen shouldn't be making this decision. I suspect there's a more general 
> rule at work here that should be handled by Sema and encoded in the AST. For 
> example, perhaps local variables in the __constant address space effectively 
> have 'static' storage? And that a 'const sampler_t' local variable is 
> effectively in the __constant address space?
> 
> Also, isa -> getAs.
> 
> @@ -184,7 +190,20 @@
>     Name = GetStaticDeclName(*this, D, Separator);
> 
>   llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
> -  llvm::GlobalVariable *GV =
> +  llvm::GlobalVariable *GV = 0;
> +  
> +  // Handle OpenCL sampler types.
> +  if (getLangOpts().OpenCL) {
> +    if (isa<OpenCLSamplerType>(D.getType().getTypePtr())) {
> +      GV = new llvm::GlobalVariable(CGM.getModule(), LTy,
> +                                    true, llvm::GlobalValue::ExternalLinkage,
> +                                    0, Name, 0,
> +                                    D.isThreadSpecified(),
> +                                    
> CGM.getContext().getTargetAddressSpace(Ty));
> +    }
> +  }
> +  
> 
> Unnecessary OpenCL check; isa -> getAs.
> 
> However, I suspect this code shouldn't be needed at all, if we modeled the 
> storage of variables of type sampler_t in the AST (as mentioned above). 
> However, I could certainly be missing something.
> 
>       - Doug

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to