Background

我有一个代码生成器,可以在Ruust中生成长表达式,但编译器似乎没有很好地处理这一点.在这些示例中,为了简单起见,我使用常量/加法,但在实践中,我希望支持涉及变量和其他编程构造的更复杂的表达式.

Example

fn main() {
  let _x = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
// ...
// 500 identical lines
// ...
+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
;
}

当我试图编译它时,它崩溃了Segmentation fault (core dumped).(它的中间行较少,所以我认为这只是由于表达式的长度造成的崩溃.)

What I've tried

额外的括号

我试过在不同的地方放上括号.在每一行的开始和结束处添加括号可以停止崩溃,但需要一个小时来编译(还会因为操作顺序不同而更改语义):

fn main() {
  let _x = 1+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)
+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)
+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)
// ...
// 8000 identical lines
// ...
+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)
+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)
;
}

♪Fasteval♪

Fsteval[https://docs.rs/♪Fasteval♪/latest/♪Fasteval♪/index.html]看起来可以更快地处理表达式,但只处理基本的变量操作和函数调用,因此不会处理表达式和更复杂的Ruust代码的混合.

变数

将每个表达式分解为许多生成的变量(每个二元运算符一个)也可以停止崩溃,但在变量数量上仍然有二次编译时间(例如,添加8000个数字需要9秒,添加16000个数字需要37秒).

将表达式分解为多个函数

这感觉应该可以工作,但在代码生成中要做的工作要多得多.

更改编译器

查看一下RUST编译器源代码,似乎是因为在进行树操作时对抽象语法 node 进行了大量克隆,所以速度很慢.感觉很多时候底层数据是不可变的,所以可以重用对现有不可变数据的引用,而不是复制所有树.然而,这感觉可能需要付出相当大的努力才能开始工作.

Question

有没有其他方法可以避免Ruust中大型表达式的编译时间很慢?(这是我的第一个Ruust程序,所以我可能遗漏了一些明显的东西,比如编译器标志或编写表达式的更惯用的方式).

更新

编译器的配置文件输出示例.

+-------------------------------------------------+-----------+-----------------+----------+------------+
| Item                                            | Self time | % of total time | Time     | Item count |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| typeck                                          | 4.99s     | 69.503          | 4.99s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| thir_body                                       | 1.73s     | 24.112          | 1.73s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| mir_built                                       | 328.48ms  | 4.572           | 2.06s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| run_linker                                      | 50.88ms   | 0.708           | 50.88ms  | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
...

Profile

更改为使用方括号和I32

正如Chayim Friedman在下面的回答中所建议的,使用1i32可以避免打字时间.配置文件现在大部分时间都花在thir_body中(来自3000行文件的配置文件):

+-------------------------------------------------+-----------+-----------------+----------+------------+
| Item                                            | Self time | % of total time | Time     | Item count |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| thir_body                                       | 6.49s     | 73.044          | 6.49s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| mir_built                                       | 1.02s     | 11.506          | 7.51s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| mir_borrowck                                    | 402.33ms  | 4.529           | 7.93s    | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| mir_drops_elaborated_and_const_checked          | 394.76ms  | 4.444           | 394.80ms | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| typeck                                          | 306.75ms  | 3.453           | 312.72ms | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| optimized_mir                                   | 118.45ms  | 1.333           | 513.32ms | 5          |
+-------------------------------------------------+-----------+-----------------+----------+------------+
| run_linker                                      | 52.22ms   | 0.588           | 52.22ms  | 1          |
+-------------------------------------------------+-----------+-----------------+----------+------------+

推荐答案

问题是,1不是固定类型,它是一个推理变量,可以是任何整数类型.要确定它是i32,编译器必须经过Add Impl的所有组合,并回退到回退类型i32.

使用带后缀的整数(1i32),编译速度会快得多.

Rust相关问答推荐

为什么在Rust struct 中只允许最后一个字段具有动态大小的类型

有没有更好的方法从HashMap的条目初始化 struct ?

具有对同一类型的另一个实例的可变引用的

为什么`Vec i64`的和不知道是`Option i64`?

如果LET;使用布尔表达式链接(&Q);

如何删除Mac Tauri上的停靠图标?

零拷贝按步骤引用一段字节

如何修复&q;无法返回引用函数参数的值在异步规则中返回引用当前函数&q;拥有的数据的值?

在Rust中声明和定义一个 struct 体有什么区别

Rust wasm 中的 Closure::new 和 Closure::wrap 有什么区别

Rust Option 的空显式泛型参数

如何为整数切片定义一个带有额外函数的特性别名?

在线程中运行时,TCPListener(服务器)在 ip 列表中的服务器实例之前没有从客户端接受所有客户端的请求

如何将 Rust 中的树状 struct 展平为 Vec<&mut ...>?

判断对象是 PyDatetime 还是 Pydate 的实例?

第 7.4 章片段中如何定义 `thread_rng`

从 Cranelift 发出 ASM

在空表达式语句中移动的值

TinyVec 如何与 Vec 大小相同?

在传输不可复制的值时实现就地枚举修改