Vector types as function arguments and interfacing with C

Hi,

I want to be able to write a function like this

define <2 x double> @add(<2 x double> %a, <2 x double> %b) nounwind {
  %c = add <2 x double> %a, %b
  ret <2 x double> %c
}

and then call it from C code. What is the appropriate translation of the <2 x double> vector type into C? I've tried packed structs and "typedef double vec_double __attribute__ ((__vector_size__ (16)))" but in both cases, it seems that GCC passes these in as pointers rather than in registers.

Brendan Younger

Hi,

I want to be able to write a function like this

define <2 x double> @add(<2 x double> %a, <2 x double> %b) nounwind {
  %c = add <2 x double> %a, %b
  ret <2 x double> %c
}

and then call it from C code. What is the appropriate translation of
the <2 x double> vector type into C? I've tried packed structs and
"typedef double vec_double __attribute__ ((__vector_size__ (16)))" but
in both cases, it seems that GCC passes these in as pointers rather
than in registers.

try reading about the gcc vector extensions in the "C Extensions" chapter
of the gcc docs.

Ciao,

Duncan.

I have tried GCC's vector extensions, however, it seems that GCC and LLVM don't exactly agree on the ABI for these vector types. On x86, they both pass the arguments in xmm0 and xmm1 and everything is roses. However, on PPC, the following happens:

define <2 x double> @add(<2 x double> %a, <2 x double> %b) nounwind {
  %result = add <2 x double> %a, %b
  ret <2 x double> %result
}

compiles to (under the latest 2.4svn)

_add:
  fadd f2, f2, f4
  fadd f1, f1, f3
  blr

which means that LLVM very sensibly passes the doubles in registers f1, f2, f3, f4. However, on the C end, GCC compiles

typedef double interval_t __attribute__ ((__vector_size__(16)));

interval_t add(interval_t a, interval_t b) {
  return a + b;
}

to the following (under gcc version 4.0.1 (Apple Inc. build 5484))

_add:
  lfd f0,80(r1)
  lfd f12,64(r1)
  lfd f13,72(r1)
  fadd f12,f12,f0
  lfd f0,88(r1)
  fadd f13,f13,f0
  stfd f12,-32(r1)
  stfd f13,-24(r1)
  lwz r3,-32(r1)
  lwz r4,-28(r1)
  lwz r5,-24(r1)
  lwz r6,-20(r1)
  blr

which means that GCC is choosing to pass the doubles on the stack instead of in registers and so I cannot mix the LLVM code with the GCC code.

Now, I realize that __vector_size__ is a GCC extension and so they're allowed to do whatever they want as far as ABIs are concerned, but is there any plan to have GCC match LLVM's ABI or vice-versa?

And on a somewhat unrelated note, I have code that changes the floating point rounding mode to round-to-negative-infinity. Does LLVM reorder floating point computations or do any simplification which might be invalid with that rounding mode rather than the default round-to-nearest? I've looked at the various "opt" options and can't find any that deal with floating point optimizations so I assume no.

Brendan Younger

I have tried GCC's vector extensions, however, it seems that GCC and
LLVM don't exactly agree on the ABI for these vector types. On x86,
they both pass the arguments in xmm0 and xmm1 and everything is
roses. However, on PPC, the following happens:

define <2 x double> @add(<2 x double> %a, <2 x double> %b) nounwind {
  %result = add <2 x double> %a, %b
  ret <2 x double> %result
}

Hi Brendan,

PowerPC doesn't support the vector type of <2 x double>. If you stick with types supported by altivec, they will be passed in altivec registers. In general, handling ABI compatibility is a really nasty business, so I suggest sticking to simple types if you want to interoperate.

-Chris