D / DLang:禁止模块私有内联函数的代码生成
D / DLang : Inhibiting code generation of module-private inlined functions
我有一个 D 模块,我希望它包含 public 和私有部分。我尝试在函数定义之前使用关键字 private 和 static 。我有一个函数,我希望使其成为外部可调用的 / public 并且理想情况下我希望它在调用站点内联。此函数调用其他旨在私有的模块内部函数,即不可从外部调用。对这些的调用已成功内联到模块中,并且 CTFE 加上已知常量传播处理了很多垃圾。然而,GDC 编译器也会生成这些内部例程的副本,即使它们已在需要的地方内联并且不应被外部调用。我正在使用 -O3 -frelease 进行编译。我应该做什么 - 即使我使用 static and/or private?
我也简单看了下这个希望有见识。
正如我之前提到的,我已经尝试在这些内部函数上同时使用 private 和 static,但我似乎无法抑制代码生成。如果调试器需要有这些例程的副本来设置断点,我可以理解这一点。我需要强调的是,据我所知,这可能会在 link 时间以某种方式解决。我还没有尝试 linking 程序,我只是在使用 GDC 查看 Matt Godbolt D Compiler Explorer 中生成的代码。一切都可以用零长度的模板参数列表制成模板(例如 auto my_fn()( in arg_t x ) ),尝试过,它没有帮助但没有害处。
其他一些尝试:我可以尝试制作一个带有私有部分的静态 class,作为实现包的一种方式,Ada 风格。 (严格要求是单一实例。)我从来没有做过任何 C++,只专业地做过大量的 asm 和 C。所以这将是一个学习曲线。
我唯一能想到的另一件事是使用嵌套函数定义,Pascal/Ada-style,将内部例程移动到调用者的体内。但这有很多缺点。
粗略示例
module junk;
auto my_public_fn() { return my_private_fn(); }
private
static // 'static' and/or 'private', tried both
auto my_private_fn() { xxx ; return whatever; }
我刚刚与 Iain 就此进行了简短的讨论,实施起来并不像看起来那么简单。
首先static
在D中有很多含义,但是翻译单元局部函数的C含义不是其中之一;-)
因此将这些函数标记为 private
似乎很直观。毕竟,如果您不能从翻译单元外部访问一个函数,并且您永远不会泄露函数的地址,为什么不删除它呢?在这种情况下,它可以完全未使用或内联到所有调用者中。
问题来了:我们无法确定函数是否未被使用:
private void fooPrivate() {}
/*template*/ void fooPublic()()
{
fooPrivate();
}
编译文件时,GDC 对 fooPublic
模板一无所知(因为模板只能在实例化时进行全面分析),因此 fooPrivate
似乎未被使用。稍后在不同的文件中使用 fooPublic
时,GDC 将依赖于 fooPrivate
已经在原始源中发出 - 毕竟它不是模板,所以它不会被发出到新模块中。
可能有解决方法,但整个问题似乎并不简单。我们还可以为此引入自定义 gcc.attribute
属性。它会导致与模板相同的问题,但由于它是针对一个用例的特定注释(与 private
不同),我们可以依靠用户做正确的事情。
我有一个 D 模块,我希望它包含 public 和私有部分。我尝试在函数定义之前使用关键字 private 和 static 。我有一个函数,我希望使其成为外部可调用的 / public 并且理想情况下我希望它在调用站点内联。此函数调用其他旨在私有的模块内部函数,即不可从外部调用。对这些的调用已成功内联到模块中,并且 CTFE 加上已知常量传播处理了很多垃圾。然而,GDC 编译器也会生成这些内部例程的副本,即使它们已在需要的地方内联并且不应被外部调用。我正在使用 -O3 -frelease 进行编译。我应该做什么 - 即使我使用 static and/or private?
我也简单看了下这个
正如我之前提到的,我已经尝试在这些内部函数上同时使用 private 和 static,但我似乎无法抑制代码生成。如果调试器需要有这些例程的副本来设置断点,我可以理解这一点。我需要强调的是,据我所知,这可能会在 link 时间以某种方式解决。我还没有尝试 linking 程序,我只是在使用 GDC 查看 Matt Godbolt D Compiler Explorer 中生成的代码。一切都可以用零长度的模板参数列表制成模板(例如 auto my_fn()( in arg_t x ) ),尝试过,它没有帮助但没有害处。
其他一些尝试:我可以尝试制作一个带有私有部分的静态 class,作为实现包的一种方式,Ada 风格。 (严格要求是单一实例。)我从来没有做过任何 C++,只专业地做过大量的 asm 和 C。所以这将是一个学习曲线。
我唯一能想到的另一件事是使用嵌套函数定义,Pascal/Ada-style,将内部例程移动到调用者的体内。但这有很多缺点。
粗略示例
module junk;
auto my_public_fn() { return my_private_fn(); }
private
static // 'static' and/or 'private', tried both
auto my_private_fn() { xxx ; return whatever; }
我刚刚与 Iain 就此进行了简短的讨论,实施起来并不像看起来那么简单。
首先static
在D中有很多含义,但是翻译单元局部函数的C含义不是其中之一;-)
因此将这些函数标记为 private
似乎很直观。毕竟,如果您不能从翻译单元外部访问一个函数,并且您永远不会泄露函数的地址,为什么不删除它呢?在这种情况下,它可以完全未使用或内联到所有调用者中。
问题来了:我们无法确定函数是否未被使用:
private void fooPrivate() {}
/*template*/ void fooPublic()()
{
fooPrivate();
}
编译文件时,GDC 对 fooPublic
模板一无所知(因为模板只能在实例化时进行全面分析),因此 fooPrivate
似乎未被使用。稍后在不同的文件中使用 fooPublic
时,GDC 将依赖于 fooPrivate
已经在原始源中发出 - 毕竟它不是模板,所以它不会被发出到新模块中。
可能有解决方法,但整个问题似乎并不简单。我们还可以为此引入自定义 gcc.attribute
属性。它会导致与模板相同的问题,但由于它是针对一个用例的特定注释(与 private
不同),我们可以依靠用户做正确的事情。