From 984ee6544580453320597d496f2a67adec8d1e93 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Tue, 10 Jun 2014 10:49:07 +0000 Subject: 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 --- test/CodeGen/X86/cmpxchg-i1.ll | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 test/CodeGen/X86/cmpxchg-i1.ll (limited to 'test') 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() -- cgit v1.2.3