Ideas for enabling builtin fucntions to accept non-zero address spaces

Hi,

I'm looking for suggestions for how to get builtin functions to accept pointers
with non-zero address spaces. The reason I would like to do this is
so I can use __builtin_nanf() from OpenCL C.

This currently does not work, because in OpenCL all string literals are
stored in the constant address space. For example:

kernel void test(global float* out) {
  out[0] = __builtin_nanf("");
  }

test.cl:3:27: error: passing '__constant char *' to parameter of type
                     'const char *' changes address space of pointer

So far I have had two ideas. The first was this:

--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -422,7 +422,7 @@ public:
   /// Generally this answers the question of whether an object with the
   //other
   /// qualifiers can be safely used as an object with these qualifiers.
   bool compatiblyIncludes(Qualifiers other) const {
- return isAddressSpaceSupersetOf(other) &&
+ return (!hasAddressSpace() || isAddressSpaceSupersetOf(other)) &&
            // ObjC GC qualifiers can match, be added, or be removed,
            // but can't
            // be changed.
            (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||

This intention of this change was to make it so that pointer types with no
address space qualifier are considered compatible to pointers with
address space qualifiers. This fixed my example, but broke
several existing address space tests.

The second idea I had was to create a FunctionDecl for the builtin which
matched the arguments used in the CallExpr. This would have the effect
of creating an overloaded version of the builtin with the correct
address space on the fly. I thought I could do this in
Sema::LazilyCreateBuiltin(), but I couldn't figure out how to get
a reference to the CallExpr that triggered the FunctionDecl to be
created.

Do either of these approaches make sense? Does anyone have a better
idea for implementing this?

Thanks,
Tom

I used to hack around this with an address space cast on the "", but now I just use an integer NaN value bitcasted to a float to 'solve' this. A proper solution would be welcome though.

I think this change you are requesting could be generalized to more builtins though - for instance being able to use atomic intrinsics on multiple address spaces would also be really useful.

-Neil.

The idea of having a marker for a function which is generic w.r.t. the address space of a particular pointer has come up before. It would be generally useful, but isn't the simplest thing in the world to create.

We already have a bit of hacked generics mechanism used when defining intrinsics. (It's implemented by mangling the types into a suffix for the intrinsic name.) You could extend the "llvm_anyptr_ty" to handle address spaces, or introduce a new "llvm_asany_ty" with semantics that allow a single specified type, but any address space. (see IR/Intriniscs.td and Function.cpp for implementation)

I could be argued around to the idea that we need to support a generic address space mechanism in the IR. This can't be done by overloading an existing address space; that would break existing users. We could add a new keyword to the language. Something like "type addrspace(generic)*". We'd then have to implement a templating engine to specialize these based on call types. This is effectively just a slight generalization of the intrinsics only approach mentioned above.

p.s. I can't help with the clang code structure issues. I don't know that code at all. :slight_smile:

Philip

Hi Tom,

I feel like your first solution won't work because it will break address space conversion rules in OpenCL.

In my view one valid solution would be to extend builtins by either changing __builtin_nanf to have custom error checking (and then perform any possible check) or introduce a way to specify address spaces for builtins (or rather address space placeholder) in Builtins.def. Let's say we could have something like:

BUILTIN(__builtin_nanf, "fcCA*" , "ncF") where "A" in " fcCA*" would mean any address space. We could also add unique letter for each address space.

Otherwise, it might be easier to change current builtins checking to disregard address spaces of pointer completely. But it might be less generic solution.

CL2.0 generic address space won't help here because it doesn't allow conversion to/from constant address space (see Section 6.5.5).

Regards,
Anastasia

Hi Tom,

I feel like your first solution won't work because it will break address space conversion rules in OpenCL.

In my view one valid solution would be to extend builtins by either changing __builtin_nanf to have custom error checking (and then perform any possible check) or introduce a way to specify address spaces for builtins (or rather address space placeholder) in Builtins.def. Let's say we could have something like:

BUILTIN(__builtin_nanf, "fcCA*" , "ncF") where "A" in " fcCA*" would mean any address space. We could also add unique letter for each address space.

Otherwise, it might be easier to change current builtins checking to disregard address spaces of pointer completely. But it might be less generic solution.

I just posted a patch which disregards address space for builtins:

http://reviews.llvm.org/D8082

What do you think?

-Tom