[cfe-dev] Patch for review: enhancement to __builtin_strlen
Andy Gibbs
andyg1001 at hotmail.co.uk
Sat Jun 23 14:01:42 PDT 2012
On Saturday, June 23, 2012 1:34 AM, Richard Smith wrote:
> On Fri, Jun 22, 2012 at 3:46 PM, Andy Gibbs <andyg1001 at hotmail.co.uk>
> wrote:
>> Ok, attached then is a first patch towards this end. It works in most
>> scenarios, and I have found only one real place where it doesn't, which
>> is using __builtin_strlen inside a constexpr function with a function
>> parameter as the expression, but I am pretty sure this is not a fault
>> in my implementation, but rather that __builtin_strlen as it currently
>> stands doesn't work inside constexpr functions. I'll look into it.
>
> This will be because you're still using Expr::EvaluateAsRValue: that
> won't work for references to constexpr function parameters, because it
> doesn't operate in the same EvalInfo context.
Ok, I didn't realise this was the reason -- I'm still learning how the code
works!
>> I'd like to see if we can get this first patch committed, then I can
>> look at doing the next stage (otherwise, I just end up with massive
>> sets of patches that never get committed!...)
>>
>> I haven't followed exactly your suggestions, but maybe you will spot
>> some of them in the code anyway. I actually made the bold step of
>> splitting out the functionality into its own function, namely
>> Expr::EvaluateAsString which then returns a folded, truncated
>> std::string result on success. __builtin_strlen then calls this
>> and returns the length of this string.
>
> This approach has the downside of copying the string even when it's a
> string literal. This construct appears pretty frequently in code using
> various glibc functions which are implemented as macros, so that may
> be a significant issue for some code.
Yes, this is a fair point and it is the unfortunate side-effect of my
attempt to make what I saw as a useful feature out of the code. I have an
alternative suggestion, please see below.
>> I kept with EvaluateAsRValue,
>> since this works adequately and, I'm afraid to say, I couldn't get
>> EvaluatePointer to work at all.
>
> What sort of issues were you having?
There is an assert at the top of EvaluatePointer to ensure Expr is an
rvalue, which is not necessarily the case. I'm afraid I don't have the code
nor my test-cases in front of me right now so I can't give you an exact
example. Since I wasn't aware (as I said above) of the disadvantages of
using EvaluateAsRValue, and because I had found in my testing that using
EvaluatePointer actually did not work in any case in the function argument
case, I kept with EvaluateAsRValue since it worked in all other scenarios.
Hence my thought (erroneous, from what you say) that this issue with
function arguments was due to some other reason.
> [...]
>> If it is, then like the first corner case, it can only be evaluated
>> where the value is 0 (which doesn't have many applications!). But
>> if you want the following to work...
>>
>> struct X { int a; char b; char c; char d; float e; };
>> constexpr X x = { 1234, 'a', 'b', 0, 5.3f }
>> __builtin_strlen(&x.b);
>
> We don't allow this for a constexpr function, so we don't need to
> allow it here either. Indeed, there are simple cases where this would
> be impossible:
>
> struct X { char c[8]; void *p; };
> constexpr X x = { 1, 2, 3, 4, 5, 6, 7, 8, &x; };
> constexpr int n = __builtin_strlen(x.c); // ???
>
>> Beyond this, it would be as well to point out that I don't think
>> that you can do this with a constexpr function either...
>>
>> With this in mind, is it really worthwhile to pursue it?
>
> No, I don't think so.
Good, but you had me concerned by including it in your corner cases.
So, now for my suggestion. Actually, I have two. My first is this: as one
coming from the outside, ExprConstant.cpp is quite a difficult block of code
to follow, since a lot of different functionality is contained and
interwoven. My suggestion would be to separate out ExprConstant.cpp into
separate files in an ExprConstant subfolder. It could then be possible to
have the Expr member functions in one file, general purpose utility
functions in another (e.g. the IsGlobalLValue and similar), and then the
Visitor classes then split out into their own .h/.cpp files, and so on.
This approach would make it much easier for others to learn the intricacies
of this particular part of the compiler. Now, I would be quite willing to
undertake this work, *if* (and its a big if) I could feel that if I did the
work, that it would be appreciated, and more importantly, committed. So
please say. I don't mind either way, but I don't want to undertake it for
it to be simply rejected.
My suggestion, then, for an alternative to my previous patch would be to
implement a string length evaluation visitor class (sorry, I haven't thought
up a groovy class name for it yet!). This would then visit the Expr object,
calculating any pointer arithmetic operations as it goes, down to either a
StringLiteral expression, or a DeclRefExpr pointing to a StringLiteral
variable or constexpr char array. The length can be calculated direct from
this and the precalculated offset. No unnecessary string copying or LValue
generation! I should expect this is the most efficient way, better even
than EvaluatePointer and all the HandleLValueToRValueConversion operations
as per your previous suggestion?
As you know, I am still learning my way around the code; I really do
appreciate your time in all your advice and corrections.
Please let me know what you think of my two suggestions. I stand by ready
and willing...
Thanks again,
Andy
More information about the cfe-dev
mailing list