constexpr深度限制与clang(fconstexpr深度似乎工作) [英] constexpr depth limit with clang (fconstexpr-depth doesnt seem to work)

查看:531
本文介绍了constexpr深度限制与clang(fconstexpr深度似乎工作)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有配置constexpr实例化深度?
我运行-fconstexpr-depth = 4096(使用clang / XCode)。



但仍然无法编译此代码与错误:
Constexpr变量fib_1必须由常量表达式初始化。
无论选项-fconstexpr-depth = 4096是否设置,代码都会失败。



这是clang的错误或预期会这样。
注意:这个工作良好,直到fib_cxpr(26),27是当它开始失败。



代码:

  constexpr int fib_cxpr(int idx){
return idx == 0? 0:
idx == 1? 1:
fib_cxpr(idx-1)+ fib_cxpr(idx-2);
}

int main(){
constexpr auto fib_1 = fib_cxpr(27);
return 0;
}


解决方案

TL; DR: p>

对于clang,您希望命令行参数 -fconstexpr-steps = 1271242 ,且不需要超过 -fconstexpr-depth = 27






计算Fibonacci数字的递归方法不需要非常多的递归深度。 fib(n)所需的深度实际上不超过 n 。这是因为最长的调用链是通过 fib(i-1)递归调用。

  constexpr auto fib_1 = fib_cxpr(3); //与-fconstexpr-depth = 2失败,与-fconstexpr-depth = 3一起使用
constexpr auto fib_1 = fib_cxpr(4); // failed with -fconstexpr-depth = 3,works with -fconstexpr-depth = 4

可以断定 -fconstexpr-depth 不是重要的设置。



此外,错误消息还指示区别:

  constexpr auto fib_1 = fib_cxpr 

编译 -fconstexpr-depth = 26 ,确保我们达到这个限制,clang生成的消息:

 注意:constexpr评估超过最大深度26调用

但是使用 -fconstexpr-depth = 27 这是足够的深度,产生消息:

 注意:constexpr评估命中最大步限制;可能的无限循环? 

所以我们知道clang区分两个失败:递归深度和'步长限制' p>




clang maximum step limit的Google搜索结果导致了关于实现此功能的clang补丁的页面,包括命令行选项: -fconstexpr-steps 。进一步Googling这个选项表示没有用户级文档。



所以没有文档说明什么clang计数为一个'step'或多少' fib(27)。我们可以设置这个真的很高,但我认为这是一个坏主意。相反,一些实验显示:

  n:steps 
0:2
1:2
2:6
3:10
4:18

fib(n))== steps( fib(n-1))+ steps c> fib(n-2))+ 2.一点计算表明,根据这个, fib(27)应该需要1,271,242 ang的步骤。因此,使用 -fconstexpr-steps = 1271242 编译应允许程序编译,确实。使用 -fconstexpr-steps = 1271241 编译会导致与以前相同的错误,因此我们知道我们有一个确切的限制。



另一种不太精确的方法包括从补丁观察到默认步长限制是1,048,576(2 20 ),这显然足以满足 fib / code>。直观地,加倍应该是很多,从早期的分析,我们知道200万是充足的。严格的限制是⌈⌈·steps( fib(26))⌉(确实恰好是1,271,242)。


$ b $另一个需要注意的事情是,这些结果清楚地表明,clang没有对constexpr求值进行任何记忆。 GCC ,但似乎这并没有在俚语中实现。虽然记忆化增加了存储器需求,但有时可以大大减少评估所需的时间,如在这种情况下。我得出的两个结论是,编写constexpr代码,需要memoization的良好的编译时间是不是一个好的可移植代码,和clang可以通过支持constexpr memoization和一个命令行选项来启用/禁用它。


Is there anyway to configure constexpr instantiation depth? I am running with -fconstexpr-depth=4096 (using clang/XCode).

But still fail to compile this code with error: Constexpr variable fib_1 must be initialized by a constant expression. The code fails irrespective of whether option -fconstexpr-depth=4096 is set or not.

Is this a bug with clang or is expected to behave this way. Note: this works good till fib_cxpr(26), 27 is when it starts to fail.

Code:

constexpr int fib_cxpr(int idx) {
    return idx == 0 ? 0 :
           idx == 1 ? 1 :
           fib_cxpr(idx-1) + fib_cxpr(idx-2); 
}

int main() {
    constexpr auto fib_1 = fib_cxpr(27);
    return 0; 
}

解决方案

TL;DR:

For clang you want the command line argument -fconstexpr-steps=1271242 and you do not need more than -fconstexpr-depth=27


The recursive method of calculating Fibonacci numbers does not require very much recursion depth. The depth required for fib(n) is in fact no more than n. This is because the longest chain of calls is through the fib(i-1) recursive call.

constexpr auto fib_1 = fib_cxpr(3); // fails with -fconstexpr-depth=2, works with -fconstexpr-depth=3
constexpr auto fib_1 = fib_cxpr(4); // fails with -fconstexpr-depth=3, works with -fconstexpr-depth=4

So we can conclude that -fconstexpr-depth is not the setting that matters.

Furthermore, the error messages also indicate a difference:

constexpr auto fib_1 = fib_cxpr(27);

Compiled with -fconstexpr-depth=26, to be sure we hit that limit, clang produces the message:

note: constexpr evaluation exceeded maximum depth of 26 calls

But compiling with -fconstexpr-depth=27, which is enough depth, produces the message:

note: constexpr evaluation hit maximum step limit; possible infinite loop?

So we know that clang is distinguishing between two failures: recursion depth and 'step limit'.


The top Google results for 'clang maximum step limit' lead to pages about the clang patch implementing this feature, including the implementation of the command-line option: -fconstexpr-steps. Further Googling of this option indicates that there's no user-level documentation.

So there's no documentation about what clang counts as a 'step' or how many 'steps' clang requires for fib(27). We could just set this really high, but I think that's a bad idea. Instead some experimentation shows:

n : steps
0 : 2
1 : 2
2 : 6
3 : 10
4 : 18

Which indicates that steps(fib(n)) == steps(fib(n-1)) + steps(fib(n-2)) + 2. A bit of calculation shows that, according to this, fib(27) should require 1,271,242 of clang's steps. So compiling with -fconstexpr-steps=1271242 should allow the program to compile, which indeed it does. Compiling with -fconstexpr-steps=1271241 results in an error the same as before, so we know we have an exact limit.

An alternative, less exact method involves observing from the patch that the default step limit is 1,048,576 (220), which is obviously sufficient for fib(26). Intuitively, doubling that should be plenty, and from the earlier analysis we know that two million is plenty. A tight limit would be ⌈φ · steps(fib(26))⌉ (which does happen to be exactly 1,271,242).


Another thing to note is that these results clearly show that clang is not doing any memoization of constexpr evaluation. GCC does, but it appears that this is not implemented in clang at all. Although memoization increases the memory requirements it can sometimes, as in this case, vastly reduce the time required for evaluation. The two conclusions I draw from this are that writing constexpr code that requires memoization for good compile times is not a good idea for portable code, and that clang could be improved with support for constexpr memoization and a command line option to enable/disable it.

这篇关于constexpr深度限制与clang(fconstexpr深度似乎工作)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆