Skip to content

Conversation

@bjorn3
Copy link
Member

@bjorn3 bjorn3 commented Nov 5, 2025

LLVM intrinsics have weird requirements like requiring the fake "unadjusted" abi, not being callable through function pointers and for all codegen backends other than cg_llvm requiring special cases to redirect them to the correct backend specific intrinsic (or directly codegen their implementation inline without any intrinsic call). By splitting the LLVM intrinsic handling it becomes easier for backends to special case them and should in the future allow getting rid of the abi calculation for extern "unadjusted" in favor of computing the correct abi directly in the backend without depending on the exact way cg_ssa lowers types.

@rustbot
Copy link
Collaborator

rustbot commented Nov 5, 2025

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 5, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 5, 2025

r? @SparrowLii

rustbot has assigned @SparrowLii.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 5, 2025

cc @sayantn This should make #140763 much less intrusive for the non-intrinsic call handling and should allow you to localize all changes to cg_llvm without having to touch cg_ssa and cg_gcc.

@sayantn
Copy link
Contributor

sayantn commented Nov 5, 2025

this is awesome, thanks ❤️. I tested compiling stdarch with this branch (for x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu and riscv64gc-unknown-linux-gnu targets), it doesn't generate any errors

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 5, 2025

Thanks for testing! I hadn't thought about testing this on stdarch. Did you also test compiling the stdarch tests? Otherwise no llvm intrinsic calls are actually getting codegened I think due to all #[inline(always)].

@sayantn
Copy link
Contributor

sayantn commented Nov 5, 2025

yes, I did cargo build -p core_arch --tests, which will compile all intrinsics in x86 (due to all intrinsics having corresponding tests), I am not so sure about aarch64, there can be some intrinsics that are not tested.

@sayantn
Copy link
Contributor

sayantn commented Nov 10, 2025

@bjorn3 could you see if it's possible to split the function declaration of LLVM intrinsics too - after inspecting my PR I noticed that it modifies declaration more than calling. Thanks

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 10, 2025

I figured I would do that after this PR gets merged, but I can do it somewhere in the next couple of days too. In this PR if it hasn't been reviewed by then and otherwise in a separate PR.

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 10, 2025

Something like this @sayantn?

@antoyo @GuillaumeGomez would you mind reviewing the cg_gcc changes?

@sayantn
Copy link
Contributor

sayantn commented Nov 10, 2025

Thanks, It's nice, but do we need to cache the intrinsic instances? get_fn should be called only when declaring an intrinsic, and that's mostly one-time for an intrinsic

@antoyo
Copy link
Contributor

antoyo commented Nov 10, 2025

@antoyo @GuillaumeGomez would you mind reviewing the cg_gcc changes?

This does look good to me, but I would need to run the tests of cg_gcc to confirm.
@GuillaumeGomez: Is there an easy way to run all of cg_gcc's tests in the Rust repo?

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 10, 2025

It's nice, but do we need to cache the intrinsic instances?

codegen_llvm_intrinsic_call is called once per intrinsic call, not once per intrinsic declaration.

@GuillaumeGomez
Copy link
Member

@GuillaumeGomez: Is there an easy way to run all of cg_gcc's tests in the Rust repo?

./x.py test --test-codegen-backend=gcc should do it.

@antoyo
Copy link
Contributor

antoyo commented Nov 10, 2025

./x.py test --test-codegen-backend=gcc should do it.

Isn't that only running UI tests?

@GuillaumeGomez
Copy link
Member

No, any testsuite with this argument will use the GCC backend.

@antoyo
Copy link
Contributor

antoyo commented Nov 10, 2025

No, any testsuite with this argument will use the GCC backend.

I meant that this won't run the stdarch tests or other tests we have in the CI of the cg_gcc repo.
We need a test that uses LLVM intrinsics and I'm not sure if those we can run in the Rust repo has any.

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 10, 2025

Maybe you could build rustc with cg_gcc as default backend and then manually run the stdarch test suite using it?

@sayantn
Copy link
Contributor

sayantn commented Nov 10, 2025

Ah sorry, the current design looks nice. I will test it on stdarch locally when I get some time

@antoyo
Copy link
Contributor

antoyo commented Nov 10, 2025

Maybe you could build rustc with cg_gcc as default backend and then manually run the stdarch test suite using it?

I tried to build your branch locally and it seems it broke a stage-2 build with cg_gcc.
I get this error:

libgccjit.so: error: : bitcast with types of different sizes
input expression (size: 8):
 <integer_cst 0x7f9ff9560348 type <integer_type 0x7f9ff954b498 unsigned char> constant visited 0>
requested type (size: 32):
 <integer_type 0x7f9ff954bc78 int public SI
    size <integer_cst 0x7f9ff9560468 type <integer_type 0x7f9ff954b690 bitsizetype> constant 32>
    unit-size <integer_cst 0x7f9ff9560480 type <integer_type 0x7f9ff954b5e8 sizetype> constant 4>
    align:32 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7f9ff954bc78 precision:32 min <integer_cst 0x7f9ff9560420 -2147483648> max <integer_cst 0x7f9ff9560438 2147483647>
    pointer_to_this <pointer_type 0x7f9ff95691f8>>

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 10, 2025

Does it work with the last commit reverted?

@bjorn3 bjorn3 force-pushed the split_llvm_intrinsic_abi_handling branch from 0563b07 to 6d4eb0e Compare November 11, 2025 11:05
@bjorn3
Copy link
Member Author

bjorn3 commented Nov 11, 2025

Managed to reproduce it locally. I've added 4f4812f, split out be36d2f, removed all cg_gcc changes from 915af4f and finally changed 6d4eb0e to use a function pointer + bx.call() rather than a direct function call. It seems that there is some function signature casting logic in bx.call() that is load bearing here. I didn't manage to figure out exactly what though.

@antoyo
Copy link
Contributor

antoyo commented Nov 11, 2025

Nice. Were you able to also run the stdarch tests or do you want me to do it?

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 11, 2025

I haven't tried. I ran out of memory when building stage 2 rustc_middle several times forcing me to reboot.

@antoyo
Copy link
Contributor

antoyo commented Nov 11, 2025

Oh, let's hope that the next sync that reduced memory usage considerably in some cases would help here as well.
I'll try to run those tests locally.

Copy link
Contributor

@antoyo antoyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stdarch tests pass with this branch.

View changes since this review

@bors
Copy link
Collaborator

bors commented Nov 17, 2025

☔ The latest upstream changes (presumably #149013) made this pull request unmergeable. Please resolve the merge conflicts.

@bjorn3 bjorn3 force-pushed the split_llvm_intrinsic_abi_handling branch from 6d4eb0e to 94b9fa9 Compare November 17, 2025 14:34
@rustbot
Copy link
Collaborator

rustbot commented Nov 17, 2025

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

Intrinsics only need a fraction of the functionality offered by
BuilderMethods::call and in particular don't need the FnAbi to be
computed other than (currently) as step towards computing the function
value type.
This moves all LLVM intrinsic handling out of the regular call path for
cg_gcc and makes it easier to hook into this code for future cg_llvm
changes.
@bjorn3 bjorn3 force-pushed the split_llvm_intrinsic_abi_handling branch from 94b9fa9 to b32b232 Compare November 17, 2025 18:48
@bjorn3
Copy link
Member Author

bjorn3 commented Nov 17, 2025

Looks like I broke llvm.wasm.throw which afaik is the only unwinding LLVM intrinsic. @purplesyringa maybe we could make it a rust intrinsic?

@rust-log-analyzer
Copy link
Collaborator

The job pr-check-2 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)

---- [codegen] tests/codegen-llvm/wasm_exceptions.rs#WASMEXN stdout ----
------FileCheck stdout------------------------------

------FileCheck stderr------------------------------
/checkout/tests/codegen-llvm/wasm_exceptions.rs:94:14: error: WASMEXN: expected string not found in input
 // WASMEXN: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null)
             ^
/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll:53:99: note: scanning from here
define dso_local void @test_intrinsic() unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 {
                                                                                                  ^
/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll:55:4: note: possible intended match here
 tail call void @llvm.wasm.throw(i32 0, ptr null)
   ^

Input file: /checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll
Check file: /checkout/tests/codegen-llvm/wasm_exceptions.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ; ModuleID = 'wasm_exceptions.c220d53a0cdd662d-cgu.0' 
            2: source_filename = "wasm_exceptions.c220d53a0cdd662d-cgu.0" 
            3: target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" 
            4: target triple = "wasm32-unknown-wasip1" 
            5:  
            6: ; <wasm_exceptions::LogOnDrop as core::ops::drop::Drop>::drop 
            7: ; Function Attrs: nounwind uwtable 
            8: define dso_local void @"_ZN68_$LT$wasm_exceptions..LogOnDrop$u20$as$u20$core..ops..drop..Drop$GT$4drop17ha00ca227c1bcd8c3E"(ptr noalias noundef nonnull readnone align 1 captures(none) %self) unnamed_addr #0 { 
            9: start: 
           10:  tail call void @log_number(i32 noundef 0) #6 
           11:  ret void 
           12: } 
           13:  
           14: ; Function Attrs: uwtable 
           15: define dso_local void @test_cleanup() unnamed_addr #1 personality ptr @__gxx_wasm_personality_v0 { 
           16: start: 
           17:  invoke void @may_panic() 
           18:  to label %bb1 unwind label %funclet_bb3 
           19:  
           20: funclet_bb3: ; preds = %start 
           21:  %cleanuppad = cleanuppad within none [] 
           22:  call void @log_number(i32 noundef 0) #6 [ "funclet"(token %cleanuppad) ] 
           23:  cleanupret from %cleanuppad unwind to caller 
           24:  
           25: bb1: ; preds = %start 
           26:  tail call void @log_number(i32 noundef 0) #6 
           27:  ret void 
           28: } 
           29:  
           30: ; Function Attrs: uwtable 
           31: define dso_local void @test_rtry() unnamed_addr #1 personality ptr @__gxx_wasm_personality_v0 { 
           32: start: 
           33:  invoke void @may_panic() 
           34:  to label %__rust_try.exit unwind label %catchswitch.i 
           35:  
           36: catchswitch.i: ; preds = %start 
           37:  %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller 
           38:  
           39: catchpad.i: ; preds = %catchswitch.i 
           40:  %catchpad2.i = catchpad within %catchswitch1.i [ptr null] 
           41:  %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i) 
           42:  %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i) 
           43:  call void @log_number(i32 noundef 0) #6 [ "funclet"(token %catchpad2.i) ] 
           44:  %_7.i.i.i = ptrtoint ptr %0 to i32 
           45:  call void @log_number(i32 noundef %_7.i.i.i) #6 [ "funclet"(token %catchpad2.i) ] 
           46:  catchret from %catchpad2.i to label %__rust_try.exit 
           47:  
           48: __rust_try.exit: ; preds = %start, %catchpad.i 
           49:  ret void 
           50: } 
           51:  
           52: ; Function Attrs: noreturn uwtable 
           53: define dso_local void @test_intrinsic() unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 { 
check:94'0                                                                                                       X~~ error: no match found
           54: start: 
check:94'0     ~~~~~~~
           55:  tail call void @llvm.wasm.throw(i32 0, ptr null) 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:94'1        ?                                               possible intended match
           56:  unreachable 
check:94'0     ~~~~~~~~~~~~~
           57: } 
check:94'0     ~~
           58:  
check:94'0     ~
           59: declare i32 @__gxx_wasm_personality_v0(...) unnamed_addr #3 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           60:  
check:94'0     ~
           61: ; Function Attrs: nounwind uwtable 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           62: declare dso_local void @log_number(i32 noundef) unnamed_addr #0 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           63:  
check:94'0     ~
           64: ; Function Attrs: uwtable 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~
           65: declare dso_local void @may_panic() unnamed_addr #1 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           66:  
check:94'0     ~
           67: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           68: declare ptr @llvm.wasm.get.exception(token) #4 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           69:  
check:94'0     ~
           70: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           71: declare i32 @llvm.wasm.get.ehselector(token) #4 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           72:  
check:94'0     ~
           73: ; Function Attrs: noreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
           74: declare void @llvm.wasm.throw(i32 immarg, ptr) unnamed_addr #5 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           75:  
check:94'0     ~
           76: attributes #0 = { nounwind uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77: attributes #1 = { uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           78: attributes #2 = { noreturn uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           79: attributes #3 = { "target-cpu"="generic" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80: attributes #4 = { mustprogress nocallback nofree nosync nounwind willreturn } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           81: attributes #5 = { noreturn } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           82: attributes #6 = { nounwind } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           83:  
check:94'0     ~
           84: !llvm.ident = !{!0} 
check:94'0     ~~~~~~~~~~~~~~~~~~~~
           85:  
check:94'0     ~
           86: !0 = !{!"rustc version 1.93.0-nightly (5676727d5 2025-11-17)"} 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>

------------------------------------------

error in revision `WASMEXN`: verification with 'FileCheck' failed
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/ci-llvm/bin/FileCheck" "--input-file" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll" "/checkout/tests/codegen-llvm/wasm_exceptions.rs" "--check-prefix=CHECK" "--check-prefix" "WASMEXN" "--allow-unused-prefixes" "--dump-input-context" "100"
stdout: none
--- stderr -------------------------------
/checkout/tests/codegen-llvm/wasm_exceptions.rs:94:14: error: WASMEXN: expected string not found in input
 // WASMEXN: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null)
             ^
/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll:53:99: note: scanning from here
define dso_local void @test_intrinsic() unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 {
                                                                                                  ^
/checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll:55:4: note: possible intended match here
 tail call void @llvm.wasm.throw(i32 0, ptr null)
   ^

Input file: /checkout/obj/build/x86_64-unknown-linux-gnu/test/codegen-llvm/wasm_exceptions.WASMEXN/wasm_exceptions.ll
Check file: /checkout/tests/codegen-llvm/wasm_exceptions.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ; ModuleID = 'wasm_exceptions.c220d53a0cdd662d-cgu.0' 
            2: source_filename = "wasm_exceptions.c220d53a0cdd662d-cgu.0" 
            3: target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" 
            4: target triple = "wasm32-unknown-wasip1" 
            5:  
            6: ; <wasm_exceptions::LogOnDrop as core::ops::drop::Drop>::drop 
            7: ; Function Attrs: nounwind uwtable 
            8: define dso_local void @"_ZN68_$LT$wasm_exceptions..LogOnDrop$u20$as$u20$core..ops..drop..Drop$GT$4drop17ha00ca227c1bcd8c3E"(ptr noalias noundef nonnull readnone align 1 captures(none) %self) unnamed_addr #0 { 
            9: start: 
           10:  tail call void @log_number(i32 noundef 0) #6 
           11:  ret void 
           12: } 
           13:  
           14: ; Function Attrs: uwtable 
           15: define dso_local void @test_cleanup() unnamed_addr #1 personality ptr @__gxx_wasm_personality_v0 { 
           16: start: 
           17:  invoke void @may_panic() 
           18:  to label %bb1 unwind label %funclet_bb3 
           19:  
           20: funclet_bb3: ; preds = %start 
           21:  %cleanuppad = cleanuppad within none [] 
           22:  call void @log_number(i32 noundef 0) #6 [ "funclet"(token %cleanuppad) ] 
           23:  cleanupret from %cleanuppad unwind to caller 
           24:  
           25: bb1: ; preds = %start 
           26:  tail call void @log_number(i32 noundef 0) #6 
           27:  ret void 
           28: } 
           29:  
           30: ; Function Attrs: uwtable 
           31: define dso_local void @test_rtry() unnamed_addr #1 personality ptr @__gxx_wasm_personality_v0 { 
           32: start: 
           33:  invoke void @may_panic() 
           34:  to label %__rust_try.exit unwind label %catchswitch.i 
           35:  
           36: catchswitch.i: ; preds = %start 
           37:  %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller 
           38:  
           39: catchpad.i: ; preds = %catchswitch.i 
           40:  %catchpad2.i = catchpad within %catchswitch1.i [ptr null] 
           41:  %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i) 
           42:  %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i) 
           43:  call void @log_number(i32 noundef 0) #6 [ "funclet"(token %catchpad2.i) ] 
           44:  %_7.i.i.i = ptrtoint ptr %0 to i32 
           45:  call void @log_number(i32 noundef %_7.i.i.i) #6 [ "funclet"(token %catchpad2.i) ] 
           46:  catchret from %catchpad2.i to label %__rust_try.exit 
           47:  
           48: __rust_try.exit: ; preds = %start, %catchpad.i 
           49:  ret void 
           50: } 
           51:  
           52: ; Function Attrs: noreturn uwtable 
           53: define dso_local void @test_intrinsic() unnamed_addr #2 personality ptr @__gxx_wasm_personality_v0 { 
check:94'0                                                                                                       X~~ error: no match found
           54: start: 
check:94'0     ~~~~~~~
           55:  tail call void @llvm.wasm.throw(i32 0, ptr null) 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:94'1        ?                                               possible intended match
           56:  unreachable 
check:94'0     ~~~~~~~~~~~~~
           57: } 
check:94'0     ~~
           58:  
check:94'0     ~
           59: declare i32 @__gxx_wasm_personality_v0(...) unnamed_addr #3 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           60:  
check:94'0     ~
           61: ; Function Attrs: nounwind uwtable 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           62: declare dso_local void @log_number(i32 noundef) unnamed_addr #0 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           63:  
check:94'0     ~
           64: ; Function Attrs: uwtable 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~
           65: declare dso_local void @may_panic() unnamed_addr #1 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           66:  
check:94'0     ~
           67: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           68: declare ptr @llvm.wasm.get.exception(token) #4 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           69:  
check:94'0     ~
           70: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           71: declare i32 @llvm.wasm.get.ehselector(token) #4 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           72:  
check:94'0     ~
           73: ; Function Attrs: noreturn 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
           74: declare void @llvm.wasm.throw(i32 immarg, ptr) unnamed_addr #5 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           75:  
check:94'0     ~
           76: attributes #0 = { nounwind uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           77: attributes #1 = { uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           78: attributes #2 = { noreturn uwtable "target-cpu"="generic" "target-features"="+exception-handling" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           79: attributes #3 = { "target-cpu"="generic" } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           80: attributes #4 = { mustprogress nocallback nofree nosync nounwind willreturn } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           81: attributes #5 = { noreturn } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           82: attributes #6 = { nounwind } 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           83:  
check:94'0     ~
           84: !llvm.ident = !{!0} 
check:94'0     ~~~~~~~~~~~~~~~~~~~~
           85:  
check:94'0     ~
           86: !0 = !{!"rustc version 1.93.0-nightly (5676727d5 2025-11-17)"} 
check:94'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>
------------------------------------------

---- [codegen] tests/codegen-llvm/wasm_exceptions.rs#WASMEXN stdout end ----

failures:
    [codegen] tests/codegen-llvm/wasm_exceptions.rs#WASMEXN

test result: FAILED. 705 passed; 1 failed; 259 ignored; 0 measured; 0 filtered out; finished in 16.41s

@purplesyringa
Copy link
Contributor

That's probably a good idea, I'll see if I can make a PR for that in a bit. (Just to be clear, llvm.wasm.rethrow is also unwinding, we just never had a need to use it.)

@purplesyringa
Copy link
Contributor

purplesyringa commented Nov 18, 2025

I gave it a try, but it looks like we don't really support unwinding Rust intrinsics either... The only unwinding intrinsic is box_new, which we rewrite away during MIR construction. The codegen-side codegen_intrinsic_call method doesn't even receive the unwind target, so there's no way to codegen a valid invoke. I suppose I could update some APIs to pass it through, but I expect that to be more complicated than adjusting codegen_llvm_intrinsic_call.

I got as far as main...purplesyringa:rust:refs/heads/wasm-throw-intrinsic before realizing that, and I already had to hack in checks some for intrinsics because there was no support for always-unwinding intrinsics in ffi_unwind_calls, so I don't think that's a good path to pursue.

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 18, 2025

The other two options I can think of are: special case llvm.wasm.throw to take the regular call path or use inline asm in _Unwind_RaiseException to directly lower to .tagtype __cpp_exception i32; local.get 0; throw __cpp_exception, which is what llvm.wasm.throw effectively lowers to.

@bjorn3
Copy link
Member Author

bjorn3 commented Nov 20, 2025

Blocked on #149141

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 20, 2025
@bjorn3 bjorn3 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-blocked Status: Blocked on something else such as an RFC or other implementation work. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants