interesting clang issue with "floor"

I'm chasing down another issue with floor in llvm but noticed this strange behavior:

Consider the following code:

extern double floor(double);
extern double floor_(double);

double x = 1.5;
double y, y_;

void foo() {

   double y = floor(x);
   double y_ = floor_(x);
}

  /local/llvmpb_config/install/bin/clang floor1.c -o floor1.llc -emit-llvm -S

The attributes for floor and floor_ are different.

This is expected; we recognise ‘floor’ as a builtin.

Maybe there is some special C rule here that I don't understand but I am declaring floor and floor_.

consider floor1.c

extern double floor(double);
extern double floor_(double);

double x = 1.5;
double y, y_;

void foo() {

   y = floor(x);
   y_ = floor_(x);
}

and floor.c

#include <stdio.h>

extern double x, y, y_;

double floor(double x) {
   return 2*x;
}

double floor_(double x) {
   return 3*x;
}

extern void foo();

int main() {
   foo();
   printf("%e %e %e \n", x, y, y_);
   return 0;
}

  /local/llvmpb_config/install/bin/clang floor1.c floor.c

rkotler@ubuntu-rkotler:~/testmips16$ ./a.out
1.500000e+00 3.000000e+00 4.500000e+00

Hey Reed,

Maybe there is some special C rule here that I don't understand but I am
declaring floor and floor_.

consider floor1.c

extern double floor(double);
extern double floor_(double);

double x = 1.5;
double y, y_;

void foo() {

  y = floor(x);
  y_ = floor_(x);
}

and floor.c

#include <stdio.h>

extern double x, y, y_;

double floor(double x) {
  return 2*x;
}

double floor_(double x) {
  return 3*x;
}

extern void foo();

int main() {
  foo();
  printf("%e %e %e \n", x, y, y_);
  return 0;
}

/local/llvmpb_config/install/bin/clang floor1.c floor.c

rkotler@ubuntu-rkotler:~/testmips16$ ./a.out
1.500000e+00 3.000000e+00 4.500000e+00

This behaviour looks correct to me. I think you're battling a linkage issue.

When you define floor(...), you're creating a STRONG symbol. This
symbol *should* be linked instead of the WEAK floor(...) symbol that
is provided as a builtin.

If you remove your definition of floor(...), you should fall back to
the WEAK symbol.

But, maybe I am missing the real problem?

-Cameron

My point was that the function attributes for floor and floor_ are different, even though the definitions are the same.

This is a follow on email.

floor has nounwind and readnone whereas floor_ has neither of those.

But you can override them so how can it know that these attributes are valid for the ones that I create?

If you define your own floor function, your program has undefined
behavior. See 7.1.3 in the C standard.

-Eli

I trust your reading the C standard here.

I was looking at clang here to try and understand the nature of an llvm issue.

My main issue is with llvm (as opposed to clang) regarding floor.

the signature recorded for floor is void floor(void) .

whereas with sin and many others for example, it is as expected float sin(float)

I've posted that issue on the llvm dev list.

I trust your reading of the C standard here.

I was looking at clang here to try and understand the nature of an llvm issue.

My main issue is with llvm (as opposed to clang) regarding floor.

the signature recorded for floor is void floor(void) .

whereas with sin and many others for example, it is as expected float sin(float)

I've posted that issue on the llvm dev list.

I have been trying to build RPM packages for libc++ 3.3 on a RHEL 6.4 box. I need both static and shared libraries. So, I learned some basics of cmake and then modified the bundled CMakeList.txt. Got that part to work.

But since in RHEL 6.x, all 64-bit libraries should go to /usr/lib64 instead of /usr/lib, I have been attempting to use the following to get the job done:

(A) During building, I use
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX})
to have all library files (*.so* and *.a) located in lib64 rather than lib.

(B) Using a ADD_LIBRARY... command as shown below
ADD_LIBRARY(c++ STATIC ...
together with
set_target_properties(c++ PROPERTIES ARCHIVE_OUTPUT_DIRECTORY${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}) INSTALL(TARGETS c++ ARCHIVE DESTINATION lib${LIB_SUFFIX})
to get the static library installed in /usr/lib64.

(C) In addition, with
INSTALL(FILES ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libc++.so DESTINATION lib${LIB_SUFFIX})
INSTALL(FILES ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libc++.so.1 DESTINATION lib${LIB_SUFFIX})
INSTALL(FILES ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/libc++.so.1.0 DESTINATION lib${LIB_SUFFIX})
to have shared libary also installed in /usr/lib64 too.

But a copy of the shared library is still installed in /usr/lib in the resulting RPM; see below:

$ rpm -qlp libcxx-3-3-0.el6.x86_64.rpm
[...]
/usr/lib
/usr/lib/libc++.so
/usr/lib/libc++.so.1
/usr/lib/libc++.so.1.0
/usr/lib64
/usr/lib64/libc++.a

/usr/lib64/libc++.so
/usr/lib64/libc++.so.1
/usr/lib64/libc++.so.1.0

If I were to write a RPM spec file, the _libdir macro automatically handles this. With cmake, given the fact that I am still new to it, I would appreciate a hint/pointer as to the right directive to use.

-- Zack

Possible easier to spot if you post the whole CMakeLists.txt file.