Обновить

Сокращаем длительность компиляции проекта на Rust c 30 до 2 минут — пример с 1000 крейтов

Время на прочтение9 мин
Охват и читатели16K
Всего голосов 15: ↑15 и ↓0+20
Комментарии6

Комментарии 6

лучше не выдавать один гигантский крейт, в котором содержится всё и сразу. Вместо этого мы откорректировали наш компилятор, преобразующий SQL в Rust, так, чтобы он распределял вывод на несколько более мелких крейтов.

Это первое, что пришло в голову, даже недочитав до этого места, ведь хорошо известно, что проект с сотней-другой крейтов при компиляции после cargo clean занимает многоядерник на всю катушку:

У меня возник вопрос — если тут транспилятор на другой язык, то почему именно Раст? Ведь можно с таким же успехом и в Си перегонять, но вижу, что это просто перевод.

Это же нужно было создать такой язык который 100к строк фигачит 30 минут. Жуть.
Есть же пример Free Pascal. Компиляция быстрейшая. Нельзя было какие то идеи позаимствовать.

Причём тут язык если все время уходит на llvm? И причём тут Free Pascal? Тут уж надо сравнивать с С++ с большим количеством вычислений на шаблонах

Не, я думаю там не на llvm основное время уходит, им-то многие компиляторы пользуются, и там всё резвее. Тут дело в том, что ещё до llvm производится несколько проходов. Если вы в курсе основных фишек Раста, я имею ввиду владение, заимствование, мутабельность и время жизни, вот это вот всё, то вы поймёте почему так, там всё это чекается на предварительных проходах.

Вот смотрите, допустим такой примитивный код, тут восемь строчек всего:

fn main() {
    let mut x = 10; // создаём изменяемую переменную x со значением 10
    add_one(&mut x);// передаём изменяемую ссылку на x (mutable borrow)
    println!("x after mod: {x}"); // выводим значение x после изменения
}

fn add_one(n: &mut i32) {
    *n += 1; // разыменовываем ссылку и увеличиваем значение на 1
}

Вначале при компиляции идёт стадия HIR (High‑Level IR) - преобразование в высоко-уровневое промежуточное представление. С некоторой натяжкой его можно назвать "препроцессор", тут разворачиваются макросы, код очищается от "сахара", вот что получится, это всё ещё Раст:

extern crate std;
#[attr = PreludeImport]
use std::prelude::rust_2024::*;
fn main() {
    let mut x =
        10; // создаём изменяемую переменную x со значением 10
    add_one(&mut x); // передаём изменяемую ссылку на x (mutable borrow)
    // выводим значение x после изменения

    // разыменовываем ссылку и увеличиваем значение на 1
    {
        ::std::io::_print({
                super let args = (&x,);
                super let args = [format_argument::new_display(args.0)];
                unsafe {
                    format_arguments::new(b"\rx after mod: \xc0\x01\n\x00",
                        &args)
                }
            });
    };
}
fn add_one(n: &'_ mut i32) { *n += 1; }

Затем идёт вторая стадия, THIR (Typed High‑Level IR), тоже высокоуровневая, тут я только кусочек покажу:

DefId(0:4 ~ r_test[ee7e]::add_one):
params: [
    Param {
        ty: &'{erased} mut i32
        ty_span: Some(src\main.rs:7:15: 7:23 (#0))
        self_kind: None
        hir_id: Some(HirId(DefId(0:4 ~ r_test[ee7e]::add_one).1))
        param: Some( 
            Pat {
                ty: &'{erased} mut i32
                span: src\main.rs:7:12: 7:13 (#0)
                kind: PatKind {
                    Binding {
                        name: "n"
                        mode: BindingMode(No, Not)
Так-то там восемьсот(!) с лишним строк
DefId(0:3 ~ r_test[ee7e]::main):
params: [
]
body:
    Expr {
        ty: ()
        temp_scope_id: 54
        span: src\main.rs:1:11: 5:2 (#0)
        kind: 
            Scope {
                region_scope: Node(54)
                hir_id: HirId(DefId(0:3 ~ r_test[ee7e]::main).54)
                value:
                    Expr {
                        ty: ()
                        temp_scope_id: 54
                        span: src\main.rs:1:11: 5:2 (#0)
                        kind: 
                            Block {
                                targeted_by_break: false
                                span: src\main.rs:1:11: 5:2 (#0)
                                region_scope: Node(1)
                                safety_mode: Safe
                                stmts: [
                                    Stmt {
                                        kind: Let {
                                            remainder_scope: Remainder { block: 1, first_statement_index: 0}
                                            init_scope: Node(2)
                                            pattern: 
                                                Pat {
                                                    ty: i32
                                                    span: src\main.rs:2:9: 2:14 (#0)
                                                    kind: PatKind {
                                                        Binding {
                                                            name: "x"
                                                            mode: BindingMode(No, Mut)
                                                            var: LocalVarId(HirId(DefId(0:3 ~ r_test[ee7e]::main).5))
                                                            ty: i32
                                                            is_primary: true
                                                            is_shorthand: false
                                                            subpattern: None
                                                        }
                                                    }
                                                }
                                            ,
                                            initializer: Some(
                                                Expr {
                                                    ty: i32
                                                    temp_scope_id: 3
                                                    span: src\main.rs:2:17: 2:19 (#0)
                                                    kind: 
                                                        Scope {
                                                            region_scope: Node(3)
                                                            hir_id: HirId(DefId(0:3 ~ r_test[ee7e]::main).3)
                                                            value:
                                                                Expr {
                                                                    ty: i32
                                                                    temp_scope_id: 3
                                                                    span: src\main.rs:2:17: 2:19 (#0)
                                                                    kind: 
                                                                        Literal( lit: Spanned { node: Int(Pu128(10), Unsuffixed), span: src\main.rs:2:17: 2:19 (#0) }, neg: false)

                                                                }
                                                        }
                                                }
                                            )
                                            else_block: None
                                            hir_id: HirId(DefId(0:3 ~ r_test[ee7e]::main).4)
                                            span: src\main.rs:2:5: 2:19 (#0)
                                        }
                                    }
                                    Stmt {
                                        kind: Expr {
                                            scope: Node(12)
                                            expr:
                                                Expr {
                                                    ty: ()
                                                    temp_scope_id: 6
                                                    span: src\main.rs:3:5: 3:20 (#0)
                                                    kind: 
                                                        Scope {
                                                            region_scope: Node(6)
                                                            hir_id: HirId(DefId(0:3 ~ r_test[ee7e]::main).6)
                                                            value:
                                                                Expr {
                                                                    ty: ()
                                                                    temp_scope_id: 6
                                         ... дальше Хабр не разрешает

Следом идёт средняя промежуточная стадия MIR (Mid‑Level Intermediate Representation), тут мы ближе к llvm, и как раз на этом этапе разбираются заимствования, владения, времена жизни, и Miri, кстати, работает как раз на этом уровне:

    let _11: &[core::fmt::rt::Argument<'_>; 1];
    let mut _12: &i32;
    scope 1 {
        debug x => _1;
        let _6: (&i32,);
        scope 2 {
            debug args => _6;
            let _8: [core::fmt::rt::Argument<'_>; 1];
            scope 3 {
                debug args => _8;
            }
        }
    }

    bb0: {
        _1 = const 10_i32;
        _3 = &mut _1;
        _2 = add_one(copy _3) -> [return: bb1, unwind continue];
    }
Полностью
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
// HINT: See also -Z dump-mir for MIR at specific points during compilation.
fn main() -> () {
    let mut _0: ();
    let mut _1: i32;
    let _2: ();
    let mut _3: &mut i32;
    let _4: ();
    let mut _5: std::fmt::Arguments<'_>;
    let mut _7: &i32;
    let mut _9: core::fmt::rt::Argument<'_>;
    let mut _10: &[u8; 27];
    let _11: &[core::fmt::rt::Argument<'_>; 1];
    let mut _12: &i32;
    scope 1 {
        debug x => _1;
        let _6: (&i32,);
        scope 2 {
            debug args => _6;
            let _8: [core::fmt::rt::Argument<'_>; 1];
            scope 3 {
                debug args => _8;
            }
        }
    }

    bb0: {
        _1 = const 10_i32;
        _3 = &mut _1;
        _2 = add_one(copy _3) -> [return: bb1, unwind continue];
    }

    bb1: {
        _7 = &_1;
        _6 = (move _7,);
        _12 = no_retag copy (_6.0: &i32);
        _9 = core::fmt::rt::Argument::<'_>::new_display::<i32>(copy _12) -> [return: bb2, unwind continue];
    }

    bb2: {
        _8 = [move _9];
        _10 = const b"\x16x after modification: \xc0\x01\n\x00";
        _11 = &_8;
        _5 = Arguments::<'_>::new::<27, 1>(move _10, copy _11) -> [return: bb3, unwind continue];
    }

    bb3: {
        _4 = std::io::_print(move _5) -> [return: bb4, unwind continue];
    }

    bb4: {
        return;
    }
}

alloc1 (size: 27, align: 1) {
    0x00 │ 16 78 20 61 66 74 65 72 20 6d 6f 64 69 66 69 63 │ .x after modific
    0x10 │ 61 74 69 6f 6e 3a 20 c0 01 0a 00                │ ation: ....
}

fn add_one(_1: &mut i32) -> () {
    debug n => _1;
    let mut _0: ();
    let mut _2: (i32, bool);

    bb0: {
        _2 = AddWithOverflow(copy (*_1), const 1_i32);
        assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", copy (*_1), const 1_i32) -> [success: bb1, unwind continue];
    }

    bb1: {
        (*_1) = move (_2.0: i32);
        return;
    }
}

И лишь затем идёт собственно llvm, это четвёртая стадия, там видно как наша константа 10 с инкрементом "сфолдилась" в 11:

  call void @llvm.lifetime.start.p0(ptr nonnull %x)
  store i32 11, ptr %x, align 4 ; 11 
  call void @llvm.lifetime.start.p0(ptr nonnull %args)
; ...
  call void __print(ptr noundef, ...

.LLVM полностью:

LLVM
; ModuleID = 'r_test.decfb7566f1495f6-cgu.0'
source_filename = "r_test.decfb7566f1495f6-cgu.0"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

@vtable.0 = private unnamed_addr constant <{ [24 x i8], ptr, ptr, ptr }> <{ [24 x i8] c"\00\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00\08\00\00\00\00\00\00\00", ptr @_RNSNvYNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0INtNtNtCsckEfzrs6Fp9_4core3ops8function6FnOnceuE9call_once6vtableCsj81e8EUiNGk_6r_test, ptr @_RNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0Csj81e8EUiNGk_6r_test, ptr @_RNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0Csj81e8EUiNGk_6r_test }>, align 8
@alloc_e5787bd0c3f1ea82bc1a90da9c1a53af = private unnamed_addr constant [27 x i8] c"\16x after modification: \C0\01\0A\00", align 1

; std::rt::lang_start::<()>
; Function Attrs: uwtable
define hidden noundef i64 @_RINvNtCscd1f6iWV66h_3std2rt10lang_startuECsj81e8EUiNGk_6r_test(ptr noundef nonnull %main, i64 noundef %argc, ptr noundef %argv, i8 noundef %sigpipe) unnamed_addr #0 {
start:
  %_7 = alloca [8 x i8], align 8
  call void @llvm.lifetime.start.p0(ptr nonnull %_7)
  store ptr %main, ptr %_7, align 8
; call std::rt::lang_start_internal
  %_0 = call noundef i64 @_RNvNtCscd1f6iWV66h_3std2rt19lang_start_internal(ptr noundef nonnull %_7, ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(48) @vtable.0, i64 noundef %argc, ptr noundef %argv, i8 noundef %sigpipe)
  call void @llvm.lifetime.end.p0(ptr nonnull %_7)
  ret i64 %_0
}

; std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
; Function Attrs: noinline uwtable
define internal fastcc void @_RINvNtNtCscd1f6iWV66h_3std3sys9backtrace28___rust_begin_short_backtraceFEuuECsj81e8EUiNGk_6r_test(ptr noundef nonnull readonly captures(none) %f) unnamed_addr #1 {
start:
  tail call void %f()
  tail call void asm sideeffect "", "~{memory}"() #6, !srcloc !4
  ret void
}

; std::rt::lang_start::<()>::{closure#0}
; Function Attrs: inlinehint uwtable
define internal noundef i32 @_RNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0Csj81e8EUiNGk_6r_test(ptr noalias nofree noundef readonly align 8 captures(none) dereferenceable(8) %_1) unnamed_addr #2 {
start:
  %_4 = load ptr, ptr %_1, align 8, !nonnull !5, !noundef !5
; call std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
  tail call fastcc void @_RINvNtNtCscd1f6iWV66h_3std3sys9backtrace28___rust_begin_short_backtraceFEuuECsj81e8EUiNGk_6r_test(ptr noundef nonnull %_4) #7
  ret i32 0
}

; <std::rt::lang_start<()>::{closure#0} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
; Function Attrs: inlinehint uwtable
define internal noundef i32 @_RNSNvYNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0INtNtNtCsckEfzrs6Fp9_4core3ops8function6FnOnceuE9call_once6vtableCsj81e8EUiNGk_6r_test(ptr noundef readonly captures(none) %_1) unnamed_addr #2 personality ptr @__CxxFrameHandler3 {
start:
  %0 = load ptr, ptr %_1, align 8, !nonnull !5, !noundef !5
; call std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
  tail call fastcc void @_RINvNtNtCscd1f6iWV66h_3std3sys9backtrace28___rust_begin_short_backtraceFEuuECsj81e8EUiNGk_6r_test(ptr noundef nonnull readonly %0) #7, !noalias !6
  ret i32 0
}

; r_test::main
; Function Attrs: uwtable
define hidden void @_RNvCsj81e8EUiNGk_6r_test4main() unnamed_addr #0 {
start:
  %args = alloca [16 x i8], align 8
  %x = alloca [4 x i8], align 4
  call void @llvm.lifetime.start.p0(ptr nonnull %x)
  store i32 11, ptr %x, align 4
  call void @llvm.lifetime.start.p0(ptr nonnull %args)
  store ptr %x, ptr %args, align 8
  %_6.sroa.4.0..sroa_idx = getelementptr inbounds nuw i8, ptr %args, i64 8
  store ptr @_RNvXs9_NtNtNtCsckEfzrs6Fp9_4core3fmt3num3implNtB9_7Display3fmt, ptr %_6.sroa.4.0..sroa_idx, align 8
; call std::io::stdio::_print
  call void @_RNvNtNtCscd1f6iWV66h_3std2io5stdio6__print(ptr noundef nonnull @alloc_e5787bd0c3f1ea82bc1a90da9c1a53af, ptr noundef nonnull %args)
  call void @llvm.lifetime.end.p0(ptr nonnull %args)
  call void @llvm.lifetime.end.p0(ptr nonnull %x)
  ret void
}

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(ptr captures(none)) #3

; std::rt::lang_start_internal
; Function Attrs: uwtable
declare noundef i64 @_RNvNtCscd1f6iWV66h_3std2rt19lang_start_internal(ptr noundef nonnull, ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(48), i64 noundef, ptr noundef, i8 noundef) unnamed_addr #0

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(ptr captures(none)) #3

; <i32 as core::fmt::Display>::fmt
; Function Attrs: uwtable
declare noundef zeroext i1 @_RNvXs9_NtNtNtCsckEfzrs6Fp9_4core3fmt3num3implNtB9_7Display3fmt(ptr noalias nofree noundef readonly align 4 captures(address, read_provenance) dereferenceable(4), ptr noalias nofree noundef align 8 dereferenceable(24)) unnamed_addr #0

; std::io::stdio::_print
; Function Attrs: uwtable
declare void @_RNvNtNtCscd1f6iWV66h_3std2io5stdio6__print(ptr noundef nonnull, ptr noundef nonnull) unnamed_addr #0

declare i32 @__CxxFrameHandler3(...) unnamed_addr #4

define noundef i32 @main(i32 %0, ptr %1) unnamed_addr #5 {
top:
  %_7.i = alloca [8 x i8], align 8
  %2 = sext i32 %0 to i64
  call void @llvm.lifetime.start.p0(ptr nonnull %_7.i)
  store ptr @_RNvCsj81e8EUiNGk_6r_test4main, ptr %_7.i, align 8
; call std::rt::lang_start_internal
  %_0.i = call noundef i64 @_RNvNtCscd1f6iWV66h_3std2rt19lang_start_internal(ptr noundef nonnull %_7.i, ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(48) @vtable.0, i64 noundef %2, ptr noundef %1, i8 noundef 0)
  call void @llvm.lifetime.end.p0(ptr nonnull %_7.i)
  %3 = trunc i64 %_0.i to i32
  ret i32 %3
}

attributes #0 = { uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse,+sse2,+sse3,+sahf" }
attributes #1 = { noinline uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse,+sse2,+sse3,+sahf" }
attributes #2 = { inlinehint uwtable "target-cpu"="x86-64" "target-features"="+cx16,+sse,+sse2,+sse3,+sahf" }
attributes #3 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #4 = { "target-cpu"="x86-64" }
attributes #5 = { "target-cpu"="x86-64" "target-features"="+cx16,+sse,+sse2,+sse3,+sahf" }
attributes #6 = { nounwind }
attributes #7 = { noinline }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{!"rustc version 1.99.0-nightly (375b1431b 2026-07-10)"}
!4 = !{i64 4735085480825446}
!5 = !{}
!6 = !{!7}
!7 = distinct !{!7, !8, !"_RNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0Csj81e8EUiNGk_6r_test: %_1"}
!8 = distinct !{!8, !"_RNCINvNtCscd1f6iWV66h_3std2rt10lang_startuE0Csj81e8EUiNGk_6r_test"}

На а дальше ассемблер, тут просто по итогу печатаем 11 в консоль, вот здесь:

	mov	dword ptr [rsp + 36], 11 загрузили 11
	lea	rax, [rsp + 36]
	mov	qword ptr [rsp + 40], rax
	lea	rax, [rip + Display3fmt]
	mov	qword ptr [rsp + 48], rax
	call __print ; напечатали

Ассемблер

полный листинг
	.def	@feat.00;
	.scl	3;
	.type	0;
	.endef
	.globl	@feat.00
@feat.00 = 0
	.intel_syntax noprefix
	.file	"r_test.f5a1b3f68eecb1a6-cgu.0"
	.def	_ZN3std2rt10lang_start17h28856b37936baaa7E;
	.scl	2;
	.type	32;
	.endef
	.section	.text,"xr",one_only,_ZN3std2rt10lang_start17h28856b37936baaa7E,unique,0
	.globl	_ZN3std2rt10lang_start17h28856b37936baaa7E
	.p2align	4
_ZN3std2rt10lang_start17h28856b37936baaa7E:
.seh_proc _ZN3std2rt10lang_start17h28856b37936baaa7E
	sub	rsp, 56
	.seh_stackalloc 56
	.seh_endprologue
	mov	rax, r8
	mov	r8, rdx
	mov	qword ptr [rsp + 48], rcx
	mov	byte ptr [rsp + 32], r9b
	lea	rdx, [rip + anon.e6415d161255c43dc2c05166e7cf7172.0]
	lea	rcx, [rsp + 48]
	mov	r9, rax
	call	_RNvNtCslk5dvTldH8g_3std2rt19lang_start_internal
	nop
	.seh_startepilogue
	add	rsp, 56
	.seh_endepilogue
	ret
	.seh_endproc

	.def	_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E;
	.scl	3;
	.type	32;
	.endef
	.section	.text,"xr",one_only,_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E,unique,1
	.p2align	4
_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E:
.seh_proc _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E
	sub	rsp, 40
	.seh_stackalloc 40
	.seh_endprologue
	mov	rcx, qword ptr [rcx]
	call	_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E
	xor	eax, eax
	.seh_startepilogue
	add	rsp, 40
	.seh_endepilogue
	ret
	.seh_endproc

	.def	_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E;
	.scl	3;
	.type	32;
	.endef
	.section	.text,"xr",one_only,_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E,unique,2
	.p2align	4
_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E:
.seh_proc _ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E
	sub	rsp, 40
	.seh_stackalloc 40
	.seh_endprologue
	call	rcx
	nop
	#APP
	#NO_APP
	.seh_startepilogue
	add	rsp, 40
	.seh_endepilogue
	ret
	.seh_endproc

	.def	_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hdd5ea432718ad0c1E;
	.scl	3;
	.type	32;
	.endef
	.section	.text,"xr",one_only,_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hdd5ea432718ad0c1E,unique,3
	.p2align	4
_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hdd5ea432718ad0c1E:
.seh_proc _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hdd5ea432718ad0c1E
	sub	rsp, 40
	.seh_stackalloc 40
	.seh_endprologue
	mov	rcx, qword ptr [rcx]
	call	_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h8d3554b6567cef64E
	xor	eax, eax
	.seh_startepilogue
	add	rsp, 40
	.seh_endepilogue
	ret
	.seh_endproc

	.def	_ZN6r_test4main17haba959300c4c510dE;
	.scl	2;
	.type	32;
	.endef
	.section	.text,"xr",one_only,_ZN6r_test4main17haba959300c4c510dE,unique,4
	.globl	_ZN6r_test4main17haba959300c4c510dE
	.p2align	4
_ZN6r_test4main17haba959300c4c510dE:
.seh_proc _ZN6r_test4main17haba959300c4c510dE
	sub	rsp, 56
	.seh_stackalloc 56
	.seh_endprologue
	mov	dword ptr [rsp + 36], 11
	lea	rax, [rsp + 36]
	mov	qword ptr [rsp + 40], rax
	lea	rax, [rip + _RNvXs9_NtNtNtCs9N2lWLRSIT9_4core3fmt3num3implNtB9_7Display3fmt]
	mov	qword ptr [rsp + 48], rax
	lea	rcx, [rip + anon.e6415d161255c43dc2c05166e7cf7172.1]
	lea	rdx, [rsp + 40]
	call	_RNvNtNtCslk5dvTldH8g_3std2io5stdio6__print
	nop
	.seh_startepilogue
	add	rsp, 56
	.seh_endepilogue
	ret
	.seh_endproc

	.def	main;
	.scl	2;
	.type	32;
	.endef
	.section	.text,"xr",one_only,main,unique,5
	.globl	main
	.p2align	4
main:
.seh_proc main
	sub	rsp, 56
	.seh_stackalloc 56
	.seh_endprologue
	mov	r9, rdx
	movsxd	r8, ecx
	lea	rax, [rip + _ZN6r_test4main17haba959300c4c510dE]
	mov	qword ptr [rsp + 48], rax
	mov	byte ptr [rsp + 32], 0
	lea	rdx, [rip + anon.e6415d161255c43dc2c05166e7cf7172.0]
	lea	rcx, [rsp + 48]
	call	_RNvNtCslk5dvTldH8g_3std2rt19lang_start_internal
	nop
	.seh_startepilogue
	add	rsp, 56
	.seh_endepilogue
	ret
	.seh_endproc

	.section	.rdata,"dr",one_only,anon.e6415d161255c43dc2c05166e7cf7172.0,unique,6
	.p2align	3, 0x0
anon.e6415d161255c43dc2c05166e7cf7172.0:
	.asciz	"\000\000\000\000\000\000\000\000\b\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
	.quad	_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hdd5ea432718ad0c1E
	.quad	_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E
	.quad	_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h3c899e35677daf87E

	.section	.rdata,"dr",one_only,anon.e6415d161255c43dc2c05166e7cf7172.1,unique,7
anon.e6415d161255c43dc2c05166e7cf7172.1:
	.asciz	"\026x after modification: \300\001\n"

Вот что происходит всего с восемью строчками кода. Я полагаю, что основное время затрачивается на этапе THIR, но как-то руки не доходили проверить, да и не знаю как.

Основное время уходит на LLVM - я проверял. Но тут нужно уточнить, что LLVM долго работает из-за того rustc генерирует много LLVM IR.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации