blob: c3c1af48422b77c7a37a2aac84f21cc5b9395d82 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=X64
; RUN: llc < %s -mtriple=i686-unknown-linux-gnu | FileCheck %s --check-prefix=X86
; Compares of atomic loads should fold the load into the compare's memory
; operand, like compares of regular loads do: the folded form still performs
; a single full-width load, and on x86 an ordinary load already provides
; every ordering up to seq_cst.
define i1 @cmp8_eq0_monotonic(ptr %p) {
; X64-LABEL: cmp8_eq0_monotonic:
; X64: # %bb.0:
; X64-NEXT: cmpb $0, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp8_eq0_monotonic:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpb $0, (%eax)
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i8, ptr %p monotonic, align 1
%c = icmp eq i8 %v, 0
ret i1 %c
}
define i1 @cmp16_eq0_acquire(ptr %p) {
; X64-LABEL: cmp16_eq0_acquire:
; X64: # %bb.0:
; X64-NEXT: cmpw $0, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp16_eq0_acquire:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpw $0, (%eax)
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i16, ptr %p acquire, align 2
%c = icmp eq i16 %v, 0
ret i1 %c
}
define i1 @cmp32_eq0_seq_cst(ptr %p) {
; X64-LABEL: cmp32_eq0_seq_cst:
; X64: # %bb.0:
; X64-NEXT: cmpl $0, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_eq0_seq_cst:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpl $0, (%eax)
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p seq_cst, align 4
%c = icmp eq i32 %v, 0
ret i1 %c
}
define i1 @cmp64_eq0_unordered(ptr %p) {
; X64-LABEL: cmp64_eq0_unordered:
; X64: # %bb.0:
; X64-NEXT: cmpq $0, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp64_eq0_unordered:
; X86: # %bb.0:
; X86-NEXT: subl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 16
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: fildll (%eax)
; X86-NEXT: fistpll (%esp)
; X86-NEXT: movl (%esp), %eax
; X86-NEXT: orl {{[0-9]+}}(%esp), %eax
; X86-NEXT: sete %al
; X86-NEXT: addl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 4
; X86-NEXT: retl
%v = load atomic i64, ptr %p unordered, align 8
%c = icmp eq i64 %v, 0
ret i1 %c
}
define i1 @cmp32_imm_acquire(ptr %p) {
; X64-LABEL: cmp32_imm_acquire:
; X64: # %bb.0:
; X64-NEXT: cmpl $42, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_imm_acquire:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpl $42, (%eax)
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p acquire, align 4
%c = icmp eq i32 %v, 42
ret i1 %c
}
define i1 @cmp32_imm_large(ptr %p) {
; X64-LABEL: cmp32_imm_large:
; X64: # %bb.0:
; X64-NEXT: cmpl $305419896, (%rdi) # imm = 0x12345678
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_imm_large:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpl $305419896, (%eax) # imm = 0x12345678
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p monotonic, align 4
%c = icmp eq i32 %v, 305419896 ; 0x12345678
ret i1 %c
}
define i1 @cmp64_imm_sext32(ptr %p) {
; X64-LABEL: cmp64_imm_sext32:
; X64: # %bb.0:
; X64-NEXT: cmpq $-100, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp64_imm_sext32:
; X86: # %bb.0:
; X86-NEXT: subl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 16
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: fildll (%eax)
; X86-NEXT: fistpll (%esp)
; X86-NEXT: movl (%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: notl %ecx
; X86-NEXT: xorl $-100, %eax
; X86-NEXT: orl %ecx, %eax
; X86-NEXT: sete %al
; X86-NEXT: addl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 4
; X86-NEXT: retl
%v = load atomic i64, ptr %p monotonic, align 8
%c = icmp eq i64 %v, -100
ret i1 %c
}
; The immediate does not fit CMP64mi32, so the load stays in a register.
define i1 @cmp64_imm_too_wide(ptr %p) {
; X64-LABEL: cmp64_imm_too_wide:
; X64: # %bb.0:
; X64-NEXT: movabsq $4886718345, %rax # imm = 0x123456789
; X64-NEXT: cmpq %rax, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp64_imm_too_wide:
; X86: # %bb.0:
; X86-NEXT: subl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 16
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: fildll (%eax)
; X86-NEXT: fistpll (%esp)
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl $591751049, %ecx # imm = 0x23456789
; X86-NEXT: xorl (%esp), %ecx
; X86-NEXT: xorl $1, %eax
; X86-NEXT: orl %ecx, %eax
; X86-NEXT: sete %al
; X86-NEXT: addl $12, %esp
; X86-NEXT: .cfi_def_cfa_offset 4
; X86-NEXT: retl
%v = load atomic i64, ptr %p monotonic, align 8
%c = icmp eq i64 %v, 4886718345 ; 0x123456789
ret i1 %c
}
define i1 @cmp32_reg(ptr %p, i32 %x) {
; X64-LABEL: cmp32_reg:
; X64: # %bb.0:
; X64-NEXT: cmpl %esi, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_reg:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: cmpl {{[0-9]+}}(%esp), %eax
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p acquire, align 4
%c = icmp eq i32 %v, %x
ret i1 %c
}
; The loaded value sits on the compare's RHS.
define i1 @cmp32_reg_rhs(ptr %p, i32 %x) {
; X64-LABEL: cmp32_reg_rhs:
; X64: # %bb.0:
; X64-NEXT: cmpl (%rdi), %esi
; X64-NEXT: setl %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_reg_rhs:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: cmpl %eax, {{[0-9]+}}(%esp)
; X86-NEXT: setl %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p acquire, align 4
%c = icmp slt i32 %x, %v
ret i1 %c
}
; Relaxed load of a level, compare, branch (the log-level-check shape).
define i32 @cmp32_sge_branch(ptr %p, i32 %lvl) {
; X64-LABEL: cmp32_sge_branch:
; X64: # %bb.0:
; X64-NEXT: cmpl %esi, (%rdi)
; X64-NEXT: jl .LBB10_2
; X64-NEXT: # %bb.1: # %log
; X64-NEXT: movl $1, %eax
; X64-NEXT: retq
; X64-NEXT: .LBB10_2: # %skip
; X64-NEXT: xorl %eax, %eax
; X64-NEXT: retq
;
; X86-LABEL: cmp32_sge_branch:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: cmpl {{[0-9]+}}(%esp), %eax
; X86-NEXT: jl .LBB10_2
; X86-NEXT: # %bb.1: # %log
; X86-NEXT: movl $1, %eax
; X86-NEXT: retl
; X86-NEXT: .LBB10_2: # %skip
; X86-NEXT: xorl %eax, %eax
; X86-NEXT: retl
%v = load atomic i32, ptr %p monotonic, align 4
%c = icmp sge i32 %v, %lvl
br i1 %c, label %log, label %skip
log:
ret i32 1
skip:
ret i32 0
}
define i1 @test32_mask_bit(ptr %p) {
; X64-LABEL: test32_mask_bit:
; X64: # %bb.0:
; X64-NEXT: movl (%rdi), %eax
; X64-NEXT: andl $8, %eax
; X64-NEXT: shrl $3, %eax
; X64-NEXT: # kill: def $al killed $al killed $eax
; X64-NEXT: retq
;
; X86-LABEL: test32_mask_bit:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: andl $8, %eax
; X86-NEXT: shrl $3, %eax
; X86-NEXT: # kill: def $al killed $al killed $eax
; X86-NEXT: retl
%v = load atomic i32, ptr %p monotonic, align 4
%a = and i32 %v, 8
%c = icmp ne i32 %a, 0
ret i1 %c
}
; The mask fits neither i8 nor i16 and is not a shifted mask, so the
; masked compare cannot be narrowed and keeps its full width.
define i1 @test32_mask_wide(ptr %p) {
; X64-LABEL: test32_mask_wide:
; X64: # %bb.0:
; X64-NEXT: movl (%rdi), %eax
; X64-NEXT: testl $65792, %eax # imm = 0x10100
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: test32_mask_wide:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: testl $65792, %eax # imm = 0x10100
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic i32, ptr %p monotonic, align 4
%a = and i32 %v, 65792 ; 0x10100
%c = icmp eq i32 %a, 0
ret i1 %c
}
; The loaded value has a second use: the load must stay.
define i32 @no_fold_multiuse(ptr %p) {
; X64-LABEL: no_fold_multiuse:
; X64: # %bb.0:
; X64-NEXT: movl (%rdi), %ecx
; X64-NEXT: cmpl $7, %ecx
; X64-NEXT: movl $100, %eax
; X64-NEXT: cmovnel %ecx, %eax
; X64-NEXT: retq
;
; X86-LABEL: no_fold_multiuse:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl (%eax), %ecx
; X86-NEXT: cmpl $7, %ecx
; X86-NEXT: movl $100, %eax
; X86-NEXT: je .LBB13_2
; X86-NEXT: # %bb.1:
; X86-NEXT: movl %ecx, %eax
; X86-NEXT: .LBB13_2:
; X86-NEXT: retl
%v = load atomic i32, ptr %p acquire, align 4
%c = icmp eq i32 %v, 7
%r = select i1 %c, i32 100, i32 %v
ret i32 %r
}
; Two atomic loads: at most one side can fold.
define i1 @cmp_two_loads(ptr %p, ptr %q) {
; X64-LABEL: cmp_two_loads:
; X64: # %bb.0:
; X64-NEXT: movl (%rdi), %eax
; X64-NEXT: cmpl (%rsi), %eax
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp_two_loads:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl (%ecx), %ecx
; X86-NEXT: cmpl (%eax), %ecx
; X86-NEXT: sete %al
; X86-NEXT: retl
%a = load atomic i32, ptr %p acquire, align 4
%b = load atomic i32, ptr %q acquire, align 4
%c = icmp eq i32 %a, %b
ret i1 %c
}
; Volatile atomic load: folding keeps the single access, matching how
; compares of volatile non-atomic loads are handled.
define i1 @cmp32_volatile(ptr %p) {
; X64-LABEL: cmp32_volatile:
; X64: # %bb.0:
; X64-NEXT: cmpl $0, (%rdi)
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X86-LABEL: cmp32_volatile:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: cmpl $0, (%eax)
; X86-NEXT: sete %al
; X86-NEXT: retl
%v = load atomic volatile i32, ptr %p acquire, align 4
%c = icmp eq i32 %v, 0
ret i1 %c
}