1
; RUN: llc < %s -mtriple=armv6-linux-gnueabi -arm-tail-calls | FileCheck %s -check-prefix=CHECKELF
2
; RUN: llc < %s -mtriple=thumbv7-apple-ios -arm-tail-calls | FileCheck %s -check-prefix=CHECKT2D
4
declare i16 @identity16(i16 returned %x)
5
declare i32 @identity32(i32 returned %x)
6
declare zeroext i16 @retzext16(i16 returned %x)
7
declare i16 @paramzext16(i16 zeroext returned %x)
8
declare zeroext i16 @bothzext16(i16 zeroext returned %x)
10
; The zeroext param attribute below is meant to have no effect
11
define i16 @test_identity(i16 zeroext %x) {
13
; CHECKELF: test_identity:
14
; CHECKELF: mov [[SAVEX:r[0-9]+]], r0
15
; CHECKELF: bl identity16
16
; CHECKELF: uxth r0, r0
17
; CHECKELF: bl identity32
18
; CHECKELF: mov r0, [[SAVEX]]
19
; CHECKT2D: test_identity:
20
; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0
21
; CHECKT2D: blx _identity16
22
; CHECKT2D: uxth r0, r0
23
; CHECKT2D: blx _identity32
24
; CHECKT2D: mov r0, [[SAVEX]]
25
%call = tail call i16 @identity16(i16 %x)
26
%b = zext i16 %call to i32
27
%call2 = tail call i32 @identity32(i32 %b)
31
; FIXME: This ought not to require register saving but currently does because
32
; x is not considered equal to %call (see SelectionDAGBuilder.cpp)
33
define i16 @test_matched_ret(i16 %x) {
35
; CHECKELF: test_matched_ret:
37
; This shouldn't be required
38
; CHECKELF: mov [[SAVEX:r[0-9]+]], r0
40
; CHECKELF: bl retzext16
41
; CHECKELF-NOT: uxth r0, {{r[0-9]+}}
42
; CHECKELF: bl identity32
44
; This shouldn't be required
45
; CHECKELF: mov r0, [[SAVEX]]
47
; CHECKT2D: test_matched_ret:
49
; This shouldn't be required
50
; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0
52
; CHECKT2D: blx _retzext16
53
; CHECKT2D-NOT: uxth r0, {{r[0-9]+}}
54
; CHECKT2D: blx _identity32
56
; This shouldn't be required
57
; CHECKT2D: mov r0, [[SAVEX]]
59
%call = tail call i16 @retzext16(i16 %x)
60
%b = zext i16 %call to i32
61
%call2 = tail call i32 @identity32(i32 %b)
65
define i16 @test_mismatched_ret(i16 %x) {
67
; CHECKELF: test_mismatched_ret:
68
; CHECKELF: mov [[SAVEX:r[0-9]+]], r0
69
; CHECKELF: bl retzext16
70
; CHECKELF: sxth r0, {{r[0-9]+}}
71
; CHECKELF: bl identity32
72
; CHECKELF: mov r0, [[SAVEX]]
73
; CHECKT2D: test_mismatched_ret:
74
; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0
75
; CHECKT2D: blx _retzext16
76
; CHECKT2D: sxth r0, {{r[0-9]+}}
77
; CHECKT2D: blx _identity32
78
; CHECKT2D: mov r0, [[SAVEX]]
79
%call = tail call i16 @retzext16(i16 %x)
80
%b = sext i16 %call to i32
81
%call2 = tail call i32 @identity32(i32 %b)
85
define i16 @test_matched_paramext(i16 %x) {
87
; CHECKELF: test_matched_paramext:
88
; CHECKELF: uxth r0, r0
89
; CHECKELF: bl paramzext16
90
; CHECKELF: uxth r0, r0
91
; CHECKELF: bl identity32
92
; CHECKELF: b paramzext16
93
; CHECKT2D: test_matched_paramext:
94
; CHECKT2D: uxth r0, r0
95
; CHECKT2D: blx _paramzext16
96
; CHECKT2D: uxth r0, r0
97
; CHECKT2D: blx _identity32
98
; CHECKT2D: b.w _paramzext16
99
%call = tail call i16 @paramzext16(i16 %x)
100
%b = zext i16 %call to i32
101
%call2 = tail call i32 @identity32(i32 %b)
102
%call3 = tail call i16 @paramzext16(i16 %call)
106
; FIXME: This theoretically ought to optimize to exact same output as the
107
; version above, but doesn't currently (see SelectionDAGBuilder.cpp)
108
define i16 @test_matched_paramext2(i16 %x) {
111
; Since there doesn't seem to be an unambiguous optimal selection and
112
; scheduling of uxth and mov instructions below in lieu of the 'returned'
113
; optimization, don't bother checking: just verify that the calls are made
114
; in the correct order as a basic sanity check
116
; CHECKELF: test_matched_paramext2:
117
; CHECKELF: bl paramzext16
118
; CHECKELF: bl identity32
119
; CHECKELF: b paramzext16
120
; CHECKT2D: test_matched_paramext2:
121
; CHECKT2D: blx _paramzext16
122
; CHECKT2D: blx _identity32
123
; CHECKT2D: b.w _paramzext16
124
%call = tail call i16 @paramzext16(i16 %x)
126
; Should make no difference if %x is used below rather than %call, but it does
127
%b = zext i16 %x to i32
129
%call2 = tail call i32 @identity32(i32 %b)
130
%call3 = tail call i16 @paramzext16(i16 %call)
134
define i16 @test_matched_bothext(i16 %x) {
136
; CHECKELF: test_matched_bothext:
137
; CHECKELF: uxth r0, r0
138
; CHECKELF: bl bothzext16
139
; CHECKELF-NOT: uxth r0, r0
141
; FIXME: Tail call should be OK here
142
; CHECKELF: bl identity32
144
; CHECKT2D: test_matched_bothext:
145
; CHECKT2D: uxth r0, r0
146
; CHECKT2D: blx _bothzext16
147
; CHECKT2D-NOT: uxth r0, r0
149
; FIXME: Tail call should be OK here
150
; CHECKT2D: blx _identity32
152
%call = tail call i16 @bothzext16(i16 %x)
153
%b = zext i16 %x to i32
154
%call2 = tail call i32 @identity32(i32 %b)
158
define i16 @test_mismatched_bothext(i16 %x) {
160
; CHECKELF: test_mismatched_bothext:
161
; CHECKELF: mov [[SAVEX:r[0-9]+]], r0
162
; CHECKELF: uxth r0, {{r[0-9]+}}
163
; CHECKELF: bl bothzext16
164
; CHECKELF: sxth r0, [[SAVEX]]
165
; CHECKELF: bl identity32
166
; CHECKELF: mov r0, [[SAVEX]]
167
; CHECKT2D: test_mismatched_bothext:
168
; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0
169
; CHECKT2D: uxth r0, {{r[0-9]+}}
170
; CHECKT2D: blx _bothzext16
171
; CHECKT2D: sxth r0, [[SAVEX]]
172
; CHECKT2D: blx _identity32
173
; CHECKT2D: mov r0, [[SAVEX]]
174
%call = tail call i16 @bothzext16(i16 %x)
175
%b = sext i16 %x to i32
176
%call2 = tail call i32 @identity32(i32 %b)