[llvm-commits] [llvm] r105303 - /llvm/trunk/lib/Target/X86/README-X86-64.txt
Chris Lattner
clattner at apple.com
Mon Jun 14 08:59:48 PDT 2010
On Jun 14, 2010, at 12:11 AM, Eli Friedman wrote:
>>
>> GCC compiles this to an empty function, we... don't. IIRC, the original justification for this was in functions like libc's "open".
>
> Added some va_arg optimization stuff in r105934; I don't think the old
> entry was very clear, so I rewrote it from scratch.
Thanks!
>>>>> -For problem 4, the parameter 'd' would be moved to the front of the parameter
>>>>> -list so it will be passed in register:
>>>>> - void %test(int %d,
>>>>> - long %undef1, long %undef2, long %undef3, long %undef4,
>>>>> - long %undef5, long %undef6,
>>>>> - long %s.i, byte %s.j, long %s.d);
>>>>> -
>>>
>>> I'm pretty sure argument passing on x86-64 works. :) And we have a
>>> bug on adding an ABI-lowering library to LLVM.
>>
>> Ah ok. We still do many things that are terrible for code quality, but if this was about correctness, I'm all for removing it. Thanks Eli!
>
> Hmm, all I can find is http://llvm.org/bugs/show_bug.cgi?id=6194 and a
> README entry; are there code-quality issues for anything other than
> structs with floats in XMM registers?
The biggest ones are that clang (for example) compiles these functions into gross IR:
struct foo { float a, b, c, d };
struct StringRef { char *X; long len; };
struct foo test1(float a) {
struct foo r;
r.a = r.b = r.c = r.d = a;
return r;
}
void test2a(struct StringRef X);
void test2(struct StringRef *X) { test2a(*X); }
$ clang t.c -S -o - -emit-llvm -O
target triple = "x86_64-apple-darwin10.0.0"
%0 = type { double, double }
%1 = type { i64, i64 }
%struct.StringRef = type { i8*, i64 }
define %0 @test1(float %a) nounwind readnone ssp {
entry:
%tmp29 = bitcast float %a to i32 ; <i32> [#uses=1]
%tmp30 = zext i32 %tmp29 to i128 ; <i128> [#uses=4]
%tmp25 = shl i128 %tmp30, 32 ; <i128> [#uses=1]
%ins27 = or i128 %tmp25, %tmp30 ; <i128> [#uses=1]
%tmp19 = shl i128 %tmp30, 64 ; <i128> [#uses=1]
%tmp15 = shl i128 %tmp30, 96 ; <i128> [#uses=1]
%ins = or i128 %tmp19, %tmp15 ; <i128> [#uses=1]
%tmp34 = trunc i128 %ins27 to i64 ; <i64> [#uses=1]
%tmp35 = bitcast i64 %tmp34 to double ; <double> [#uses=1]
%tmp36 = insertvalue %0 undef, double %tmp35, 0 ; <%0> [#uses=1]
%tmp37 = lshr i128 %ins, 64 ; <i128> [#uses=1]
%tmp38 = trunc i128 %tmp37 to i64 ; <i64> [#uses=1]
%tmp39 = bitcast i64 %tmp38 to double ; <double> [#uses=1]
%tmp40 = insertvalue %0 %tmp36, double %tmp39, 1 ; <%0> [#uses=1]
ret %0 %tmp40
}
define void @test2(%struct.StringRef* nocapture %X) nounwind ssp {
entry:
%0 = bitcast %struct.StringRef* %X to i128* ; <i128*> [#uses=1]
%srcval = load i128* %0, align 8 ; <i128> [#uses=2]
%tmp3 = trunc i128 %srcval to i64 ; <i64> [#uses=1]
%tmp4 = insertvalue %1 undef, i64 %tmp3, 0 ; <%1> [#uses=1]
%tmp5 = lshr i128 %srcval, 64 ; <i128> [#uses=1]
%tmp6 = trunc i128 %tmp5 to i64 ; <i64> [#uses=1]
%tmp7 = insertvalue %1 %tmp4, i64 %tmp6, 1 ; <%1> [#uses=1]
tail call void @test2a(%1 %tmp7) nounwind noredzone
ret void
}
declare void @test2a(%1)
The former should compile into something that returns two <4 x float>'s and insertelement 'a' into the low two elements of each. This would give us a few shuffles instead of this gross code:
_test1: ## @test1
## BB#0: ## %entry
movd %xmm0, %eax
movq %rax, %rcx
shlq $32, %rcx
addq %rax, %rcx
movd %rcx, %xmm0
movapd %xmm0, %xmm1
ret
test2 should pass around stringref as {i8*, i64} not an {i64,i64}. The gyrations it goes through makes the inliner's life harder.
-Chris
More information about the llvm-commits
mailing list