1
//===- README_X86_64.txt - Notes for X86-64 code gen ----------------------===//
3
AMD64 Optimization Manual 8.2 has some nice information about optimizing integer
4
multiplication by a constant. How much of it applies to Intel's X86-64
5
implementation? There are definite trade-offs to consider: latency vs. register
6
pressure vs. code size.
8
//===---------------------------------------------------------------------===//
10
Are we better off using branches instead of cmove to implement FP to
14
ucomiss LC0(%rip), %xmm0
15
cvttss2siq %xmm0, %rdx
17
subss LC0(%rip), %xmm0
18
movabsq $-9223372036854775808, %rax
19
cvttss2siq %xmm0, %rdx
28
movss LCPI1_0(%rip), %xmm1
29
cvttss2siq %xmm0, %rcx
32
cvttss2siq %xmm2, %rax
33
movabsq $-9223372036854775808, %rdx
39
Seems like the jb branch has high likelyhood of being taken. It would have
40
saved a few instructions.
42
//===---------------------------------------------------------------------===//
49
memset(X, b, 2*sizeof(X[0]));
53
movq _b@GOTPCREL(%rip), %rax
63
movq _X@GOTPCREL(%rip), %rdx
69
movq _b@GOTPCREL(%rip), %rax
70
movabsq $72340172838076673, %rdx
73
movq _X@GOTPCREL(%rip), %rdx
77
And the codegen is even worse for the following
78
(from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33103):
79
void fill1(char *s, int a)
81
__builtin_memset(s, a, 15);
84
For this version, we duplicate the computation of the constant to store.
86
//===---------------------------------------------------------------------===//
88
It's not possible to reference AH, BH, CH, and DH registers in an instruction
89
requiring REX prefix. However, divb and mulb both produce results in AH. If isel
90
emits a CopyFromReg which gets turned into a movb and that can be allocated a
93
To get around this, isel emits a CopyFromReg from AX and then right shift it
94
down by 8 and truncate it. It's not pretty but it works. We need some register
95
allocation magic to make the hack go away (e.g. putting additional constraints
96
on the result of the movb).
98
//===---------------------------------------------------------------------===//
100
The x86-64 ABI for hidden-argument struct returns requires that the
101
incoming value of %rdi be copied into %rax by the callee upon return.
103
The idea is that it saves callers from having to remember this value,
104
which would often require a callee-saved register. Callees usually
105
need to keep this value live for most of their body anyway, so it
106
doesn't add a significant burden on them.
108
We currently implement this in codegen, however this is suboptimal
109
because it means that it would be quite awkward to implement the
110
optimization for callers.
112
A better implementation would be to relax the LLVM IR rules for sret
113
arguments to allow a function with an sret argument to have a non-void
114
return type, and to have the front-end to set up the sret argument value
115
as the return value of the function. The front-end could more easily
116
emit uses of the returned struct value to be in terms of the function's
117
lowered return value, and it would free non-C frontends from a
118
complication only required by a C-based ABI.
120
//===---------------------------------------------------------------------===//
122
We get a redundant zero extension for code like this:
125
int foo(unsigned x) {
138
imull $78, %edi, %eax
140
movl %eax, %eax <----
141
movq _mask@GOTPCREL(%rip), %rcx
142
movl (%rcx,%rax,4), %eax
145
imull $45, %edi, %eax
148
Before regalloc, we have:
150
%reg1025<def> = IMUL32rri8 %reg1024, 45, %EFLAGS<imp-def>
151
JMP mbb<bb2,0x203afb0>
152
Successors according to CFG: 0x203afb0 (#3)
154
bb1: 0x203af60, LLVM BB @0x1e02310, ID#2:
155
Predecessors according to CFG: 0x203aec0 (#0)
156
%reg1026<def> = IMUL32rri8 %reg1024, 78, %EFLAGS<imp-def>
157
Successors according to CFG: 0x203afb0 (#3)
159
bb2: 0x203afb0, LLVM BB @0x1e02340, ID#3:
160
Predecessors according to CFG: 0x203af10 (#1) 0x203af60 (#2)
161
%reg1027<def> = PHI %reg1025, mbb<bb,0x203af10>,
162
%reg1026, mbb<bb1,0x203af60>
163
%reg1029<def> = MOVZX64rr32 %reg1027
165
so we'd have to know that IMUL32rri8 leaves the high word zero extended and to
166
be able to recognize the zero extend. This could also presumably be implemented
167
if we have whole-function selectiondags.
169
//===---------------------------------------------------------------------===//
171
Take the following C code
172
(from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43640):
180
float foo(struct u1 u)
185
Optimizes to the following IR:
186
define float @foo(double %u.0) nounwind readnone {
188
%tmp8 = bitcast double %u.0 to i64 ; <i64> [#uses=2]
189
%tmp6 = trunc i64 %tmp8 to i32 ; <i32> [#uses=1]
190
%tmp7 = bitcast i32 %tmp6 to float ; <float> [#uses=1]
191
%tmp2 = lshr i64 %tmp8, 32 ; <i64> [#uses=1]
192
%tmp3 = trunc i64 %tmp2 to i32 ; <i32> [#uses=1]
193
%tmp4 = bitcast i32 %tmp3 to float ; <float> [#uses=1]
194
%0 = fadd float %tmp7, %tmp4 ; <float> [#uses=1]
198
And current llvm-gcc/clang output:
206
We really shouldn't move the floats to RAX, only to immediately move them
207
straight back to the XMM registers.
209
There really isn't any good way to handle this purely in IR optimizers; it
210
could possibly be handled by changing the output of the fronted, though. It
211
would also be feasible to add a x86-specific DAGCombine to optimize the
212
bitcast+trunc+(lshr+)bitcast combination.
214
//===---------------------------------------------------------------------===//
216
Take the following code
217
(from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34653):
218
extern unsigned long table[];
219
unsigned long foo(unsigned char *p) {
220
unsigned long tag = *p;
221
return table[tag >> 4] + table[tag & 0xf];
224
Current code generated:
230
movq table(,%rax,8), %rax
231
addq table(%rcx), %rax
235
1. First movq should be movl; saves a byte.
236
2. Both andq's should be andl; saves another two bytes. I think this was
237
implemented at one point, but subsequently regressed.
238
3. shrq should be shrl; saves another byte.
239
4. The first andq can be completely eliminated by using a slightly more
240
expensive addressing mode.
242
//===---------------------------------------------------------------------===//
244
Consider the following (contrived testcase, but contains common factors):
247
int test(int x, ...) {
251
for (i = 0; i < x; i++)
252
sum += va_arg(l, int);
257
Testcase given in C because fixing it will likely involve changing the IR
258
generated for it. The primary issue with the result is that it doesn't do any
259
of the optimizations which are possible if we know the address of a va_list
260
in the current function is never taken:
261
1. We shouldn't spill the XMM registers because we only call va_arg with "int".
262
2. It would be nice if we could scalarrepl the va_list.
263
3. Probably overkill, but it'd be cool if we could peel off the first five
264
iterations of the loop.
266
Other optimizations involving functions which use va_arg on floats which don't
267
have the address of a va_list taken:
268
1. Conversely to the above, we shouldn't spill general registers if we only
269
call va_arg on "double".
270
2. If we know nothing more than 64 bits wide is read from the XMM registers,
271
we can change the spilling code to reduce the amount of stack used by half.
273
//===---------------------------------------------------------------------===//