Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

u128 atomic compare_and_set (cxchg) emits linker error #56798

Open
kprotty opened this issue Dec 14, 2018 · 11 comments
Open

u128 atomic compare_and_set (cxchg) emits linker error #56798

kprotty opened this issue Dec 14, 2018 · 11 comments
Labels
A-atomic Area: atomics, barriers, and sync primitives A-intrinsics Area: intrinsics A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kprotty
Copy link

kprotty commented Dec 14, 2018

On Rust 1.32.0 nightly for both x86_64-pc-linux-gnu & x86_64-pc-windows-gnu. undefined reference to '__sync_val_compare_and_swap_16' while also failing to link to libatomic if provided. Example: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9aeb9e2d8ce7e5b2cac9cdeaadd03ee2

@Centril Centril added the A-linkage Area: linking into static, shared libraries and binaries label Dec 15, 2018
@hanna-kruppe
Copy link
Contributor

I was initially confused by this issue: of course 128 bit compare-exchange doesn't exist so it has to be emulated in libatomic. But it appears that x86_64 has a 128 bit version of CMPXCHG. To clarify, is the issue that the compiler doesn't emit that instruction?

@kprotty
Copy link
Author

kprotty commented Dec 23, 2018

@rkruppe Yes, the compiler (at least on x86) doesnt emit cmpxchg16b. instead it emits what seems to be a call to __sync_val_compare_and_swap_16 which should be a libatomic function but that doesnt get linked into the executable.

@ericseppanen
Copy link
Contributor

This is still an issue with nightly-2019-11-20.

I see the same thing when trying to use core::arch::x86_64::cmpxchg16b, though for some reason only release mode is broken.

@kprotty : __sync_val_compare_and_swap_16 is not from libatomic; it's a gcc/llvm intrinsic.

I tried setting target-cpu=skylake and/or target-feature=cx16, but it didn't help.

@ericseppanen
Copy link
Contributor

Perhaps the label is wrong? Even though the error appears at the linker, it should have been resolved during the compile.

"A-intrinsics", perhaps?

@jonas-schievink jonas-schievink added C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-intrinsics Area: intrinsics labels Nov 22, 2019
@ericseppanen
Copy link
Contributor

Quick C example (this is the whole file):

unsigned __int128 x = 42;

void cas128()
{
    __sync_val_compare_and_swap(&x, 42, 43);
}

Compiling on x86_64 (clang -c -Wall -march=skylake test.c) results in the expected inline asm:

0000000000000000 <cas128>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	53                   	push   %rbx
   5:	b8 2a 00 00 00       	mov    $0x2a,%eax
   a:	31 c9                	xor    %ecx,%ecx
   c:	89 ca                	mov    %ecx,%edx
   e:	b9 2b 00 00 00       	mov    $0x2b,%ecx
  13:	89 cb                	mov    %ecx,%ebx
  15:	48 89 55 f0          	mov    %rdx,-0x10(%rbp)
  19:	48 8b 4d f0          	mov    -0x10(%rbp),%rcx
  1d:	f0 48 0f c7 0d 00 00 	lock cmpxchg16b 0x0(%rip)        # 26 <cas128+0x26>
  24:	00 00 
  26:	48 89 45 e8          	mov    %rax,-0x18(%rbp)
  2a:	48 89 55 e0          	mov    %rdx,-0x20(%rbp)
  2e:	5b                   	pop    %rbx
  2f:	5d                   	pop    %rbp
  30:	c3                   	retq   

gcc behaves the same. I take that as evidence that LLVM does consider this an intrinsic or builtin (at least on x86_64)

I think the question is, since llvm is building for the same arch/cpu/feature-set, why did it not replace this symbol with the same inline code, when building rust programs?

@ericseppanen
Copy link
Contributor

I wonder if this is relevant?
https://llvm.org/docs/Atomics.html#libcalls-sync

LLVM will emit a call to an appropriate sync* routine if the target ISelLowering code has set the corresponding ATOMIC_CMPXCHG, ATOMIC_SWAP, or ATOMIC_LOAD* operation to “Expand”, and if it has opted-into the availability of those library functions via a call to initSyncLibcalls().

How would I find out if rust is doing all those things?

@jonas-schievink jonas-schievink added the requires-nightly This issue requires a nightly compiler in some way. label Nov 22, 2019
@jonas-schievink
Copy link
Contributor

Those are controlled by the LLVM backend, not rustc

@ericseppanen
Copy link
Contributor

Yeah, I think that that snippet was off-topic anyway. Earlier in that page it says

Please note that both sets of library functions somewhat confusingly share the names of builtin functions defined by clang.

That threw me off... but I think this part of the hypothesis is still true: llvm has a builtin for this, but isn't using it for some reason.

@ericseppanen
Copy link
Contributor

ericseppanen commented Nov 22, 2019

I think this is user error. I figured out how to make it work, both for my code and the original example.

All you need is to run rustc with the right cpu feature enabled. Either of these will work:
-C target-feature=+cx16
-C target-cpu=haswell (or any of the other modern families; I haven't searched to find the minimum.)

My mistake was trying to do both, but missing the + in the target-feature:
-C target-cpu=haswell -C target-feature=cx16

Most target-feature typos are caught by rustc, but this one makes it all the way to the llvm-ir, where it does ... nothing helpful? Anyway, putting the right rustflags into .cargo/config solves this for me.

@ericseppanen
Copy link
Contributor

Seems like there should be a target_feature gate ("cmpxchg16b")? on
std::intrinsics::atomic_cxchg_relaxed<T> where T is a 128-bit type, and on core::arch::x86_64::cmpxchg16b.

But... core::arch::x86_64::cmpxchg16b does have one:

#[inline]
#[cfg_attr(test, assert_instr(cmpxchg16b, success = Ordering::SeqCst, failure = Ordering::SeqCst))]
#[target_feature(enable = "cmpxchg16b")]
pub unsafe fn cmpxchg16b(
    ...

I guess because libstd and stdarch are pre-compiled they already made it past the gate; but if those functions get inlined then rustc emits llvm-ir that llvm won't process correctly if the cpu/features aren't set correctly.

@the8472
Copy link
Member

the8472 commented Mar 15, 2021

I think this is user error.

I think this is a legitimate error when using runtime feature detection and compiling a specific method with #[target_feature(enable = "cmpxchg16b")]. When that method gets inlined into another one with the baseline target then it fails to link with the same error.

Abishek0398 added a commit to Abishek0398/AtomicDouble that referenced this issue Aug 28, 2021
@workingjubilee workingjubilee added the A-atomic Area: atomics, barriers, and sync primitives label Aug 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-atomic Area: atomics, barriers, and sync primitives A-intrinsics Area: intrinsics A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants