[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