[cfe-dev] How to create a new builtin in clang?

Andy Gibbs andyg1001 at hotmail.co.uk
Sat May 19 03:18:10 PDT 2012


Hi Jonathan,

On Friday, May 18, 2012 9:32 PM, Jonathan Sauer wrote:

> Hello Andy,
>
>>> Maybe I'm missing something, but constexpr does exactly that
>>
>> It does and it doesn't.  If you declare a variable 'constexpr'
>> then you can expect that a compile-time-evaluated constant is
>> assigned to it.  However, a 'constexpr'-declared variable is
>> forever immutable [...]
>
> So far, so good. Although I don't see why the immutability should
> be a problem; after all, you can simply say:
>
> constexpr int firstValue = ...;
> int i = firstValue;
> ...
> constexpr int secondValue = ...;
> i = secondValue;
>
> [...] When using constexpr on a variable, this means that the
> variable's value must be a compile-time constant [...]

Yes, you are right: this is a work-around and certainly works.  However, I 
wouldn't call it a clean solution, I'm afraid.  In effect, it requires that 
every time we want to ensure something is compile-time folded (I'm trying to 
use the terms as Richard Smith in his post [1] defines them), we have to 
remember to explicitly declare a constexpr variable to hold the value and 
then assign the "working" variable to this value.

Let's extend the field of the problem a bit.  Let's say, for arguments sake, 
we have a constexpr function which takes a string and calculates an 
arbitrary CRC value from it.  Such a function may have a signature similar 
to:

    template <long Polynomial>
    constexpr auto calc_CRC(const char* string)
        -> poly_to_width<Polynomial>::type;

The function here takes the CRC polynomial as a template parameter, 
calculates the appropriate CRC from the provided string and returns the 
value in a suitably-sized integer (calculated by a helper struct named 
poly_to_width).

Since the polynomial can change, then a pre-calculated lookup table approach 
is not practical: instead the algorithm must use a bit-based approach.  This 
is much, much less efficient than the lookup table method and wouldn't want 
to be used at runtime.  However, there is nothing in the C++11 standard, 
that I know of, that stops someone using this algorithm in a non-constexpr 
way.  As the library writer, I can say to my users, you must use this 
function this way:

constexpr int temp_value = calc_CRC<32>("string");
int value = temp_value;

but I can't stop them from simply doing:

char* string = ...
int value = calc_CRC<32>(string);

This is what I meant in my previous post regarding 'constexpr' being little 
more than a hint to the compiler like 'inline'.  With constexpr you get the 
additional benefit of being able to use that function at compile-time (as 
long as you can rework your algorithm in a way that complies with the 
restrictions of a constexpr function) but you don't have a way of limiting 
its use solely to compile-time.  Note that even the following is a runtime 
evaluation when compiled with clang without optimisations switched on:

int value = calc_CRC<32>("string");

Now at this point, we can start doing some tricks.  We can hide the 
implementation behind a macro:

template <typename T, T V> struct Constant { static constexpr T value = 
V; };
#define calc_CRC(N,S) Constant<poly_to_width<N>::type, 
calc_CRC_impl<N>(S)>::value

Now the following use:

char* string = ...
int value = calc_CRC(32, string);

will result in a compiler error since string is not a constant expression.

In this case, our work-around works.  However, it works because calc_CRC 
returns an integer type.  If we had a constexpr function which returned a 
floating point value, or one wrapped in a struct, this work-around would 
fail.  What I wish to create is the generic solution which works for all 
return types, such that the macro becomes:

#define my_func(...) __builtin_fold(my_func_impl(...))

In Richard Smith's post [1] is a really intriguing macro solution involving 
folding via __builtin_constant_p and ?: which I believe is a gcc 
extension(?), but I need to think this through thoroughly and test it.

Regards,
Andy

[1] http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-May/021549.html

 




More information about the cfe-dev mailing list