[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