Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mono][aot] Update nollvm methods to init themselves in its prolog #83377

Closed
2 of 3 tasks
Tracked by #82224
kotlarmilos opened this issue Mar 14, 2023 · 4 comments
Closed
2 of 3 tasks
Tracked by #82224

[mono][aot] Update nollvm methods to init themselves in its prolog #83377

kotlarmilos opened this issue Mar 14, 2023 · 4 comments
Assignees
Milestone

Comments

@kotlarmilos
Copy link
Member

kotlarmilos commented Mar 14, 2023

Description

This issue tracks progress on implementation of nollvm methods initialization without a PLT entry. The idea is to implement method initialization in its prolog.

Tasks

@vargaz
Copy link
Contributor

vargaz commented Mar 15, 2023

Some notes:
Here is how the relevant code looks in llvm:

define hidden void @mono_aot_HelloWorld_init_method(i64* %0) #1 {
ENTRY:
  %1 = bitcast i64* %0 to i32*
  %2 = getelementptr i32, i32* %1, i32 0
  %method_index = load i32, i32* %2, align 4
  %3 = getelementptr [0 x i8], [0 x i8]* bitcast ([1 x i8]* @mono_inited to [0 x i8]*), i32 0, i32 %method_index
  %is_inited = load i8, i8* %3, align 1
  %4 = icmp eq i8 %is_inited, 0
  br i1 %4, label %NOT_INITED, label %INITED

INITED:                                           ; preds = %NOT_INITED, %ENTRY
  ret void

NOT_INITED:                                       ; preds = %ENTRY
  %5 = load i64*, i64** @aotconst_aot_module, align 8, !invariant.load !13
  %6 = ptrtoint i64* %5 to i64
  %7 = load void (i64, i64, i64*, i64)*, void (i64, i64, i64*, i64)** @aotconst_jit_icall_mini_llvm_init_method, align 8, !invariant.load !13
  call void %7(i64 ptrtoint (%MonoAotFileInfo* @mono_aot_file_info to i64), i64 %6, i64* %0, i64 0)
  %8 = getelementptr [0 x i8], [0 x i8]* bitcast ([1 x i8]* @mono_inited to [0 x i8]*), i32 0, i32 %method_index
  store i8 1, i8* %8, align 1
  br label %INITED
}

define hidden monocc void @Test_Main() #2 gc "coreclr" {
BB0:
  br label %INIT_BB1

INIT_BB1:                                         ; preds = %BB0
  %is_inited = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @mono_inited, i32 0, i32 2), align 1
  %0 = call i8 @llvm.expect.i8(i8 %is_inited, i8 1)
  %1 = icmp eq i8 %0, 0
  br i1 %1, label %NOTINITED_BB3, label %INITED_BB2
...
NOTINITED_BB3:                                    ; preds = %INIT_BB1
  call void @mono_aot_HelloWorld_init_method(i64* bitcast ([6 x i8]* @info_Test_Main to i64*))
  store i8 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @mono_inited, i32 0, i32 2), align 1
  br label %INITED_BB2
}

The non-llvm methods should contain something similar.

  • The mono_inited is a byte array emitted by the aot compiler, with one entry for every method. On entry, the code
    needs to check whenever the entry belonging to the method is set. If not, it should branch to a piece of code to init
    the method (the NOT_INITED label).
  • The init code is emitted at the end of the method. It calls a helper function emitted by the AOT compiler with the address
    of a data structure describing what needs to be initialized (info_Test_Main in this case).
  • The helper function calls a helper function in the runtime to initialize the method.

@vargaz
Copy link
Contributor

vargaz commented Mar 15, 2023

Note that its much easier to emit this code with llvm, emitting it in the non-llvm case will be more complicated.

@kotlarmilos
Copy link
Member Author

Noticed that during llvm initialization there is a redundant check if a method is inited, probably for performance resons, not to invoke the init wrapper if the method is inited.

During AOT compilation, aot_assembly invokes mono_llvm_create_aot_module that invokes emit_init_func for each method. As you described, similar could be done for nollvm methods.

In such case, aot_assembly could invoke emit_nollvm_init_func for each method. The following should be done in case of nollvm methods:

  • Emit is_inited bitset into an AOT image in emit_aot_image
  • Emit init wrappers in emit_aot_image that is invoked
  • Change methods prolog to invoke the init wrapper

Init wrapper should have INIT and NOT_INITED basic blocks. INIT basic block should load method index from the start of the method info, retrieve is_inited bit from the bitset, and conditionally jump to not NOT_INITED basic block.
NOT_INITED basic block should load method index from the start of the method info, invoke init_method from the runtime, and set is_inited bit.

Frontend mono_method_to_ir could create init wrappers and new basic blocks. Backend mono_arch_emit_prolog could change method prolog to invoke the init wrapper.

@vargaz what would be a good approach for creating init wrappers?

@steveisok
Copy link
Member

Spoke with @kotlarmilos offline and his suggestion was to close this issue as it's no longer relevant.

@github-actions github-actions bot locked and limited conversation to collaborators Sep 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants