summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2014-06-10 10:49:07 +0000
committerTim Northover <tnorthover@apple.com>2014-06-10 10:49:07 +0000
commit984ee6544580453320597d496f2a67adec8d1e93 (patch)
treef453f399972a362f1a91ffecd2357eff2cbcd39f /test
parent46b3076cd0b1e57e16cfe4ecaa517eb78863a92a (diff)
downloadllvm-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')
-rw-r--r--test/CodeGen/X86/cmpxchg-i1.ll82
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()