1+ ; REQUIRES: arm
2+ ;; https://github.com/llvm/llvm-project/issues/127284
3+ ;; Test for LTO optimizing out references to symbols that are pulled in by
4+ ;; compiler-generated libcalls (post LTO).
5+ ;; The problem here is that the call to __aeabi_ldivmod is generated post-LTO,
6+ ;; during ISel, so aeabi_ldivmod.o is only marked as required afterwards but by
7+ ;; that time we have decided that all the callees of __aeabi_ldivmod are not
8+ ;; needed and have been marked as ABS zero symbols.
9+ ; RUN: rm -rf %t && split-file %s %t && cd %t
10+ ; RUN: llvm-as divmoddi4.ll -o divmoddi4.bc
11+ ; RUN: llvm-mc -filetype=obj -triple=armv7-none-unknown-eabi aeabi_ldivmod.s -o aeabi_ldivmod.o
12+ ;; With an explicit __aebi_ldivmod call in the input IR this works as expected:
13+ ; RUN: llvm-as main-explicit.ll -o main-explicit-ldivmod.bc
14+ ; RUN: ld.lld main-explicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o test.exe -Bstatic
15+ ; RUN: llvm-objdump -d -r -t test.exe | FileCheck %s --check-prefix=GOOD-DUMP
16+ ; GOOD-DUMP-LABEL: SYMBOL TABLE:
17+ ; GOOD-DUMP: [[#]] g F .text [[#]] _start
18+ ; GOOD-DUMP: [[#]] g F .text 00000024 __aeabi_ldivmod
19+ ; GOOD-DUMP: [[#]] g F .text [[#]] __divmoddi4
20+ ; GOOD-DUMP-LABEL: <__aeabi_ldivmod>:
21+ ; GOOD-DUMP: bl 0x20140 <__divmoddi4> @ imm = #0x28
22+
23+ ; But if the call is generated by ISel, we end up with an invalid reference:
24+ ; RUN: llvm-as main-implicit.ll -o main-implicit-ldivmod.bc
25+ ; RUN: ld.lld main-implicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o test.exe -Bstatic
26+ ; RUN: llvm-objdump -d -r -t test.exe | FileCheck %s --check-prefix=BAD-DUMP
27+ ;; We jump to address zero here and __divmoddi4 ends up being an absolute symbol:
28+ ; BAD-DUMP-LABEL: SYMBOL TABLE:
29+ ; BAD-DUMP: [[#]] g F .text [[#]] _start
30+ ; BAD-DUMP: [[#]] g F .text 00000024 __aeabi_ldivmod
31+ ; BAD-DUMP: [[#]] g *ABS* 00000000 __divmoddi4
32+ ; BAD-DUMP-LABEL: <__aeabi_ldivmod>:
33+ ; BAD-DUMP: bl 0x0 <__divmoddi4> @ imm = #-0x200fc
34+ ;; Linking with -pie complains about the invalid relocation (and even points back to the source files)
35+ ; RUN: not ld.lld main-implicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o test.exe --no-undefined -pie --no-dynamic-linker 2>&1 | FileCheck %s --check-prefix=PIE-ERROR
36+ PIE-ERROR: ld.lld: error: relocation R_ARM_CALL cannot refer to absolute symbol: __divmoddi4
37+ PIE-ERROR-NEXT: >>> defined in divmoddi4.bc
38+ PIE-ERROR-NEXT: >>> referenced by aeabi_ldivmod.o:(__aeabi_ldivmod)
39+
40+ ;; Interestingly, just declaring __aeabi_ldivmod is sufficient to not run into this issue.
41+ ; RUN: llvm-as main-declared.ll -o main-declared-ldivmod.bc
42+ ; RUN: ld.lld main-declared-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o test.exe -Bstatic
43+ ; RUN: llvm-objdump -d -r -t test.exe | FileCheck %s --check-prefix=GOOD-DUMP
44+
45+ ;--- divmoddi4.ll
46+ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
47+ target triple = "armv7-none-unknown-eabi"
48+
49+ ; Adding it to llvm.used does not appears to have any effect!
50+ ; @llvm.used = appending global [1 x ptr] [ptr @__divmoddi4], section "llvm.metadata"
51+
52+ ; Stub version of the real __divmoddi4
53+ define i64 @__divmoddi4 (i64 %a , i64 %b , ptr writeonly %rem ) #0 align 32 {
54+ entry:
55+ %sub = sub i64 %a , %b
56+ store i64 0 , ptr %rem , align 8
57+ ret i64 %sub
58+ }
59+
60+ attributes #0 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) "frame-pointer" ="non-leaf" "no-trapping-math" ="true" "stack-protector-buffer-size" ="8" "target-cpu" ="cortex-a15" }
61+
62+ ;--- aeabi_ldivmod.s
63+ .syntax unified
64+ .p2align 2
65+ .arm
66+ .globl __aeabi_ldivmod
67+ .type __aeabi_ldivmod,%function
68+ __aeabi_ldivmod:
69+ push {r6, lr}
70+ sub sp, sp, #16
71+ add r6, sp, #8
72+ str r6, [sp]
73+ bl __divmoddi4
74+ ldr r2, [sp, #8 ]
75+ ldr r3, [sp, #12 ]
76+ add sp, sp, #16
77+ pop {r6, pc}
78+ .size __aeabi_ldivmod, . - __aeabi_ldivmod
79+
80+ ;--- main-implicit.ll
81+ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
82+ target triple = "armv7-none-unknown-eabi"
83+
84+ define dso_local i64 @_start (i64 %num , i64 %denom ) local_unnamed_addr #0 {
85+ entry:
86+ %div = sdiv i64 %num , %denom
87+ %ret = add i64 %div , 2
88+ ret i64 %ret
89+ }
90+
91+ attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math" ="true" "stack-protector-buffer-size" ="8" "target-cpu" ="cortex-a15" }
92+
93+ ;--- main-explicit.ll
94+ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
95+ target triple = "armv7-none-unknown-eabi"
96+
97+ declare { i64 , i64 } @__aeabi_ldivmod (i64 , i64 )
98+
99+ define dso_local noundef i64 @_start (i64 noundef %num , i64 noundef %denom ) local_unnamed_addr #0 {
100+ entry:
101+ %quotrem = call { i64 , i64 } @__aeabi_ldivmod (i64 %num , i64 %denom )
102+ %div = extractvalue { i64 , i64 } %quotrem , 0
103+ %ret = add i64 %div , 2
104+ ret i64 %ret
105+ }
106+
107+ attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math" ="true" "stack-protector-buffer-size" ="8" "target-cpu" ="cortex-a15" }
108+
109+ ;--- main-declared.ll
110+ target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
111+ target triple = "armv7-none-unknown-eabi"
112+
113+ declare { i64 , i64 } @__aeabi_ldivmod (i64 , i64 )
114+
115+ define dso_local i64 @_start (i64 %num , i64 %denom ) local_unnamed_addr #0 {
116+ entry:
117+ %div = sdiv i64 %num , %denom
118+ %ret = add i64 %div , 2
119+ ret i64 %ret
120+ }
121+
122+ attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math" ="true" "stack-protector-buffer-size" ="8" "target-cpu" ="cortex-a15" }
0 commit comments