diff options
author | Tim Northover <tnorthover@apple.com> | 2014-06-10 10:49:07 +0000 |
---|---|---|
committer | Tim Northover <tnorthover@apple.com> | 2014-06-10 10:49:07 +0000 |
commit | 984ee6544580453320597d496f2a67adec8d1e93 (patch) | |
tree | f453f399972a362f1a91ffecd2357eff2cbcd39f /test/CodeGen/X86 | |
parent | 46b3076cd0b1e57e16cfe4ecaa517eb78863a92a (diff) | |
download | llvm-984ee6544580453320597d496f2a67adec8d1e93.tar.gz llvm-984ee6544580453320597d496f2a67adec8d1e93.tar.bz2 llvm-984ee6544580453320597d496f2a67adec8d1e93.tar.xz |
X86: elide comparisons after cmpxchg instructions.
The C++ and C semantics of the compare_and_swap operations actually
require us to return a boolean "success" value. In LLVM terms this
means a second comparison of the output of "cmpxchg" against the input
desired value.
However, x86's "cmpxchg" instruction sets all flags for the comparison
formed, so we can skip any secondary comparison. (N.b. this isn't true
for cmpxchg8b/16b, which only set ZF).
rdar://problem/13201607
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210523 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGen/X86')
-rw-r--r-- | test/CodeGen/X86/cmpxchg-i1.ll | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/test/CodeGen/X86/cmpxchg-i1.ll b/test/CodeGen/X86/cmpxchg-i1.ll new file mode 100644 index 0000000000..53cf3e300f --- /dev/null +++ b/test/CodeGen/X86/cmpxchg-i1.ll @@ -0,0 +1,82 @@ +; RUN: llc -mtriple=x86_64 -o - %s | FileCheck %s + +define i1 @try_cmpxchg(i32* %addr, i32 %desired, i32 %new) { +; CHECK-LABEL: try_cmpxchg: +; CHECK: cmpxchgl +; CHECK-NOT: cmp +; CHECK: sete %al +; CHECK: retq + %old = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst seq_cst + %success = icmp eq i32 %old, %desired + ret i1 %success +} + +define void @cmpxchg_flow(i64* %addr, i64 %desired, i64 %new) { +; CHECK-LABEL: cmpxchg_flow: +; CHECK: cmpxchgq +; CHECK-NOT: cmp +; CHECK-NOT: set +; CHECK: {{jne|jeq}} + %old = cmpxchg i64* %addr, i64 %desired, i64 %new seq_cst seq_cst + %success = icmp eq i64 %old, %desired + br i1 %success, label %true, label %false + +true: + call void @foo() + ret void + +false: + call void @bar() + ret void +} + +define i1 @cmpxchg_arithcmp(i16* %addr, i16 %desired, i16 %new) { +; CHECK-LABEL: cmpxchg_arithcmp: +; CHECK: cmpxchgw +; CHECK-NOT: cmp +; CHECK: setbe %al +; CHECK: retq + %old = cmpxchg i16* %addr, i16 %desired, i16 %new seq_cst seq_cst + %success = icmp uge i16 %old, %desired + ret i1 %success +} + +define i1 @cmpxchg_arithcmp_swapped(i8* %addr, i8 %desired, i8 %new) { +; CHECK-LABEL: cmpxchg_arithcmp_swapped: +; CHECK: cmpxchgb +; CHECK-NOT: cmp +; CHECK: setge %al +; CHECK: retq + %old = cmpxchg i8* %addr, i8 %desired, i8 %new seq_cst seq_cst + %success = icmp sge i8 %desired, %old + ret i1 %success +} + +define i64 @cmpxchg_sext(i32* %addr, i32 %desired, i32 %new) { +; CHECK-LABEL: cmpxchg_sext: +; CHECK-DAG: cmpxchgl +; CHECK-DAG: movq $-1, %rax +; CHECK-DAG: xorl %e[[ZERO:[a-z0-9]+]], %e[[ZERO]] +; CHECK-NOT: cmpl +; CHECK: cmovneq %r[[ZERO]], %rax +; CHECK: retq + %old = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst seq_cst + %success = icmp eq i32 %old, %desired + %mask = sext i1 %success to i64 + ret i64 %mask +} + +define i32 @cmpxchg_zext(i32* %addr, i32 %desired, i32 %new) { +; CHECK-LABEL: cmpxchg_zext: +; CHECK: cmpxchgl +; CHECK-NOT: cmp +; CHECK: sete [[BYTE:%[a-z0-9]+]] +; CHECK: movzbl [[BYTE]], %eax + %old = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst seq_cst + %success = icmp eq i32 %old, %desired + %mask = zext i1 %success to i32 + ret i32 %mask +} + +declare void @foo() +declare void @bar() |