blob: bf215461ddb3d5c3ea71668ff3a038ba607d762d [file]
; RUN: llc -mtriple=bpfel -mcpu=v4 -filetype=asm -o - %s | FileCheck --check-prefix=ASM %s
; RUN: llc -mtriple=bpfel -mcpu=v4 -filetype=obj -o %t %s
; RUN: llvm-readelf -S %t | FileCheck --check-prefix=SECTIONS %s
; RUN: llvm-readelf -r %t | FileCheck --check-prefix=RELOCS %s
; Verify that invoke/landingpad with cleanup produces a .bpf_cleanup section
; containing (call_site, landing_pad) pairs with R_BPF_64_NODYLD32 relocations.
; Models a Rust BTreeMap insertion that may fail, with Drop cleanup
; calling bpf_free to release allocated nodes.
declare ptr @bpf_alloc(i64, i64)
declare void @bpf_free(ptr)
declare void @btree_insert(ptr, ptr, i64)
declare i32 @rust_personality(i32, i64, ptr, ptr)
; SECTIONS: .bpf_cleanup
define void @stat_inc(ptr %map, ptr %key, i64 %val) personality ptr @rust_personality {
entry:
%node = call ptr @bpf_alloc(i64 256, i64 0)
%null = icmp eq ptr %node, null
br i1 %null, label %oom, label %insert
insert:
invoke void @btree_insert(ptr %map, ptr %node, i64 %val)
to label %done unwind label %cleanup
done:
ret void
cleanup:
%lp = landingpad { ptr, i32 } cleanup
call void @bpf_free(ptr %node)
resume { ptr, i32 } %lp
oom:
ret void
}
; ASM-LABEL: stat_inc:
; ASM: r1 = 256
; ASM: call bpf_alloc
; ASM: if r0 == 0 goto
; Normal path: call btree_insert then exit
; ASM: .Ltmp0:
; ASM: call btree_insert
; ASM: .Ltmp1:
; ASM: exit
; Cleanup landing pad: free the node, then resume unwinding
; ASM: .Ltmp2:
; ASM: r1 = r7
; ASM: call bpf_free
; ASM: call _Unwind_Resume
; .bpf_cleanup entry: [.Ltmp0, .Ltmp1) -> .Ltmp2
; ASM: .section .bpf_cleanup,"a",@progbits
; ASM-NEXT: .long .Ltmp0
; ASM-NEXT: .long .Ltmp1
; ASM-NEXT: .long .Ltmp2
define void @two_allocs(ptr %map) personality ptr @rust_personality {
entry:
%n1 = call ptr @bpf_alloc(i64 256, i64 0)
invoke void @btree_insert(ptr %map, ptr %n1, i64 1)
to label %second unwind label %clean1
second:
%n2 = call ptr @bpf_alloc(i64 512, i64 0)
invoke void @btree_insert(ptr %map, ptr %n2, i64 2)
to label %done unwind label %clean2
done:
ret void
clean2:
; Must free both n2 and n1
%lp2 = landingpad { ptr, i32 } cleanup
call void @bpf_free(ptr %n2)
call void @bpf_free(ptr %n1)
resume { ptr, i32 } %lp2
clean1:
; Only n1 allocated at this point
%lp1 = landingpad { ptr, i32 } cleanup
call void @bpf_free(ptr %n1)
resume { ptr, i32 } %lp1
}
; ASM-LABEL: two_allocs:
; First alloc + invoke
; ASM: r1 = 256
; ASM: call bpf_alloc
; ASM: .Ltmp3:
; ASM: call btree_insert
; ASM: .Ltmp4:
; Second alloc + invoke
; ASM: r1 = 512
; ASM: call bpf_alloc
; ASM: .Ltmp6:
; ASM: call btree_insert
; ASM: .Ltmp7:
; ASM: exit
; clean2: free n2, then fall through to free n1
; ASM: .Ltmp8:
; ASM: call bpf_free
; clean1 entry point, shared tail: free n1 then resume
; ASM: .Ltmp5:
; ASM: call bpf_free
; ASM: call _Unwind_Resume
; .bpf_cleanup entries: two triples
; ASM: .section .bpf_cleanup,"a",@progbits
; ASM-NEXT: .long .Ltmp3
; ASM-NEXT: .long .Ltmp4
; ASM-NEXT: .long .Ltmp5
; ASM-NEXT: .long .Ltmp6
; ASM-NEXT: .long .Ltmp7
; ASM-NEXT: .long .Ltmp8
; Models std::panic::catch_unwind: catch the exception, free resources,
; and return normally. The landing pad uses "catch ptr null" (catch-all)
; instead of "cleanup", and does NOT call _Unwind_Resume — unwinding stops here.
define i64 @with_catch_unwind(ptr %map, i64 %val) personality ptr @rust_personality {
entry:
%node = call ptr @bpf_alloc(i64 128, i64 0)
invoke void @btree_insert(ptr %map, ptr %node, i64 %val)
to label %ok unwind label %caught
ok:
ret i64 0
caught:
%lp = landingpad { ptr, i32 }
catch ptr null
call void @bpf_free(ptr %node)
ret i64 1
}
; ASM-LABEL: with_catch_unwind:
; ASM: r1 = 128
; ASM: call bpf_alloc
; ASM: .Ltmp9:
; ASM: call btree_insert
; ASM: .Ltmp10:
; ASM: r0 = 0
; ASM: exit
; Catch block: free the node, return 1 (no _Unwind_Resume)
; ASM: .Ltmp11:
; ASM: call bpf_free
; ASM: r0 = 1
; ASM: exit
; .bpf_cleanup entry for the catch
; ASM: .section .bpf_cleanup,"a",@progbits
; ASM-NEXT: .long .Ltmp9
; ASM-NEXT: .long .Ltmp10
; ASM-NEXT: .long .Ltmp11
; .bpf_cleanup should have R_BPF_64_NODYLD32 relocations
; 4 entries x 3 fields = 12 relocs
; RELOCS: .rel.bpf_cleanup
; RELOCS-COUNT-12: R_BPF_64_NODYLD32 {{.*}} .text