1; RUN: %p2i -i %s --target=x8632 --filetype=obj --assemble --disassemble \
2; RUN:   --args -O2 -nonsfi=1 --ffunction-sections \
3; RUN:   | FileCheck --check-prefix=NONSFI %s
4; RUN: %p2i -i %s --target=x8632 --filetype=obj --assemble --disassemble \
5; RUN:   --args -O2 -nonsfi=0 --ffunction-sections \
6; RUN:   | FileCheck --check-prefix=DEFAULT %s
7
8; RUN: %p2i -i %s --target=arm32 --filetype=obj --assemble --disassemble \
9; RUN:   --args -O2 -nonsfi=1 --ffunction-sections \
10; RUN:   | FileCheck --check-prefix=ARM32-NONSFI %s
11
12@G1 = internal global [4 x i8] zeroinitializer, align 4
13@G2 = internal global [4 x i8] zeroinitializer, align 4
14
15define internal void @testCallRegular() {
16entry:
17  ; Make a call to a *different* function, plus use -ffunction-sections, to
18  ; force an appropriately-named relocation.
19  call i32 @testLoadBasic()
20  ret void
21}
22; Expect a simple direct call to testCallRegular.
23; NONSFI-LABEL: testCallRegular
24; NONSFI: call {{.*}} R_386_PC32 {{.*}}testLoadBasic
25; DEFAULT-LABEL: testCallRegular
26
27; ARM32-NONSFI-LABEL: testCallRegular
28; ARM32-NONSFI: bl {{.*}} R_ARM_CALL {{.*}}testLoadBasic
29
30define internal double @testCallBuiltin(double %val) {
31entry:
32  %result = frem double %val, %val
33  ret double %result
34}
35; Expect a simple direct call to fmod.
36; NONSFI-LABEL: testCallBuiltin
37; NONSFI: call {{.*}} R_386_PC32 fmod
38; DEFAULT-LABEL: testCallBuiltin
39
40; ARM32-NONSFI-LABEL: testCallBuiltin
41; ARM32-NONSFI: bl {{.*}} R_ARM_CALL {{.*}}fmod
42
43define internal i32 @testLoadBasic() {
44entry:
45  %a = bitcast [4 x i8]* @G1 to i32*
46  %b = load i32, i32* %a, align 1
47  ret i32 %b
48}
49; Expect a load with a R_386_GOTOFF relocation.
50; NONSFI-LABEL: testLoadBasic
51; NONSFI: mov {{.*}} R_386_GOTOFF {{G1|.bss}}
52; DEFAULT-LABEL: testLoadBasic
53
54; ARM32 PIC load.
55; ARM32-NONSFI-LABEL: testLoadBasic
56; ARM32-NONSFI:      movw {{.*}} R_ARM_MOVW_PREL_NC _GLOBAL_OFFSET_TABLE_
57; ARM32-NONSFI-NEXT: movt {{.*}} R_ARM_MOVT_PREL _GLOBAL_OFFSET_TABLE_
58; ARM32-NONSFI:      movw [[REG:r[0-9]+]], {{.*}} R_ARM_MOVW_PREL_NC {{.*}}G1
59; ARM32-NONSFI-NEXT: movt [[REG]], {{.*}} R_ARM_MOVT_PREL {{.*}}G1
60; ARM32-NONSFI-NEXT: ldr r{{[0-9]+}}, [pc, [[REG]]]
61
62define internal i32 @testLoadFixedOffset() {
63entry:
64  %a = ptrtoint [4 x i8]* @G1 to i32
65  %a1 = add i32 %a, 4
66  %a2 = inttoptr i32 %a1 to i32*
67  %b = load i32, i32* %a2, align 1
68  ret i32 %b
69}
70; Expect a load with a R_386_GOTOFF relocation plus an immediate offset.
71; NONSFI-LABEL: testLoadFixedOffset
72; NONSFI: mov {{.*}}+0x4] {{.*}} R_386_GOTOFF {{G1|.bss}}
73; DEFAULT-LABEL: testLoadFixedOffset
74
75; ARM32-NONSFI-LABEL: testLoadFixedOffset
76; ARM32-NONSFI:      movw [[GOT:r[0-9]+]], {{.*}} R_ARM_MOVW_PREL_NC _GLOBAL_OFFSET_TABLE_
77; ARM32-NONSFI-NEXT: movt [[GOT]], {{.*}} R_ARM_MOVT_PREL _GLOBAL_OFFSET_TABLE_
78; ARM32-NONSFI:      movw [[REG:r[0-9]+]], {{.*}} R_ARM_MOVW_PREL_NC {{.*}}G1
79; ARM32-NONSFI-NEXT: movt [[REG]], {{.*}} R_ARM_MOVT_PREL {{.*}}G1
80; ARM32-NONSFI-NEXT: ldr [[ADDR:r[0-9]+]], [pc, [[REG]]]
81; ARM32-NONSFI-NEXT: add [[G1BASE:r[0-9]+]], [[GOT]], [[ADDR]]
82; ARM32-NONSFI-NEXT: add {{.*}}, [[G1BASE]], #4
83
84define internal i32 @testLoadIndexed(i32 %idx) {
85entry:
86  %a = ptrtoint [4 x i8]* @G1 to i32
87  %a0 = mul i32 %idx, 4
88  %a1 = add i32 %a0, 12
89  %a2 = add i32 %a1, %a
90  %a3 = inttoptr i32 %a2 to i32*
91  %b = load i32, i32* %a3, align 1
92  ret i32 %b
93}
94; Expect a load with a R_386_GOTOFF relocation plus an immediate offset, plus a
95; scaled index register.
96; NONSFI-LABEL: testLoadIndexed
97; NONSFI: mov {{.*}}*4+0xc] {{.*}} R_386_GOTOFF {{G1|.bss}}
98; DEFAULT-LABEL: testLoadIndexed
99
100; ARM32-NONSFI-LABEL: testLoadIndexed
101; ARM32-NONSFI:      movw [[GOT:r[0-9]+]], {{.*}} R_ARM_MOVW_PREL_NC _GLOBAL_OFFSET_TABLE_
102; ARM32-NONSFI-NEXT: movt [[GOT]], {{.*}} R_ARM_MOVT_PREL _GLOBAL_OFFSET_TABLE_
103; ARM32-NONSFI:      movw [[REG:r[0-9]+]], {{.*}} R_ARM_MOVW_PREL_NC {{.*}}G1
104; ARM32-NONSFI-NEXT: movt [[REG]], {{.*}} R_ARM_MOVT_PREL {{.*}}G1
105; ARM32-NONSFI-NEXT: ldr [[ADDR:r[0-9]+]], [pc, [[REG]]]
106; ARM32-NONSFI-NEXT: add [[G1BASE:r[0-9]+]], [[GOT]], [[ADDR]]
107; ARaM32-NONSFI-NEXT: add {{.*}}, [[G1BASE]]
108
109define internal i32 @testLoadIndexedBase(i32 %base, i32 %idx) {
110entry:
111  %a = ptrtoint [4 x i8]* @G1 to i32
112  %a0 = mul i32 %idx, 4
113  %a1 = add i32 %a0, %base
114  %a2 = add i32 %a1, %a
115  %a3 = add i32 %a2, 12
116  %a4 = inttoptr i32 %a3 to i32*
117  %b = load i32, i32* %a4, align 1
118  ret i32 %b
119}
120; Expect a load with a R_386_GOTOFF relocation plus an immediate offset, but
121; without the scaled index.
122; NONSFI-LABEL: testLoadIndexedBase
123; NONSFI: mov {{.*}}*1+0xc] {{.*}} R_386_GOTOFF {{G1|.bss}}
124; By contrast, without -nonsfi, expect a load with a *R_386_32* relocation plus
125; an immediate offset, and *with* the scaled index.
126; DEFAULT-LABEL: testLoadIndexedBase
127; DEFAULT: mov {{.*}},DWORD PTR [{{.*}}+{{.*}}*4+0xc] {{.*}} R_386_32 {{G1|.bss}}
128
129define internal i32 @testLoadOpt() {
130entry:
131  %a = bitcast [4 x i8]* @G1 to i32*
132  %b = load i32, i32* %a, align 1
133  %c = bitcast [4 x i8]* @G2 to i32*
134  %d = load i32, i32* %c, align 1
135  %e = add i32 %b, %d
136  ret i32 %e
137}
138; Expect a load-folding optimization with a R_386_GOTOFF relocation.
139; NONSFI-LABEL: testLoadOpt
140; NONSFI: mov [[REG:e..]],{{.*}}+0x0] {{.*}} R_386_GOTOFF {{G1|.bss}}
141; NONSFI-NEXT: add [[REG]],{{.*}}+0x{{0|4}}] {{.*}} R_386_GOTOFF {{G2|.bss}}
142; DEFAULT-LABEL: testLoadOpt
143
144define internal void @testRMW() {
145entry:
146  %a = bitcast [4 x i8]* @G1 to i32*
147  %b = load i32, i32* %a, align 1
148  %c = add i32 %b, 1234
149  store i32 %c, i32* %a, align 1
150  ret void
151}
152; Expect an RMW optimization with a R_386_GOTOFF relocation.
153; NONSFI-LABEL: testRMW
154; NONSFI: add DWORD PTR {{.*}}+0x0],0x4d2 {{.*}} R_386_GOTOFF {{G1|.bss}}
155; DEFAULT-LABEL: testRMW
156