; RUN: llc < %s -march=sparc -mcpu=v9 -verify-machineinstrs | FileCheck %s --check-prefixes=SPARC
; RUN: llc < %s -march=sparcv9 -verify-machineinstrs | FileCheck %s --check-prefixes=SPARC64
; SPARC-LABEL: test_atomic_i8
; SPARC: ldub [%o0]
; SPARC: membar
; SPARC: ldub [%o1]
; SPARC: membar
; SPARC: membar
; SPARC: stb {{.+}}, [%o2]
; SPARC64-LABEL: test_atomic_i8
; SPARC64: ldub [%o0]
; SPARC64: membar
; SPARC64: ldub [%o1]
; SPARC64: membar
; SPARC64: membar
; SPARC64: stb {{.+}}, [%o2]
define i8 @test_atomic_i8(ptr %ptr1, ptr %ptr2, ptr %ptr3) {
entry:
%0 = load atomic i8, ptr %ptr1 acquire, align 1
%1 = load atomic i8, ptr %ptr2 acquire, align 1
%2 = add i8 %0, %1
store atomic i8 %2, ptr %ptr3 release, align 1
ret i8 %2
}
; SPARC-LABEL: test_atomic_i16
; SPARC: lduh [%o0]
; SPARC: membar
; SPARC: lduh [%o1]
; SPARC: membar
; SPARC: membar
; SPARC: sth {{.+}}, [%o2]
; SPARC64-LABEL: test_atomic_i16
; SPARC64: lduh [%o0]
; SPARC64: membar
; SPARC64: lduh [%o1]
; SPARC64: membar
; SPARC64: membar
; SPARC64: sth {{.+}}, [%o2]
define i16 @test_atomic_i16(ptr %ptr1, ptr %ptr2, ptr %ptr3) {
entry:
%0 = load atomic i16, ptr %ptr1 acquire, align 2
%1 = load atomic i16, ptr %ptr2 acquire, align 2
%2 = add i16 %0, %1
store atomic i16 %2, ptr %ptr3 release, align 2
ret i16 %2
}
; SPARC-LABEL: test_atomic_i32
; SPARC: ld [%o0]
; SPARC: membar
; SPARC: ld [%o1]
; SPARC: membar
; SPARC: membar
; SPARC: st {{.+}}, [%o2]
; SPARC64-LABEL: test_atomic_i32
; SPARC64: ld [%o0]
; SPARC64: membar
; SPARC64: ld [%o1]
; SPARC64: membar
; SPARC64: membar
; SPARC64: st {{.+}}, [%o2]
define i32 @test_atomic_i32(ptr %ptr1, ptr %ptr2, ptr %ptr3) {
entry:
%0 = load atomic i32, ptr %ptr1 acquire, align 4
%1 = load atomic i32, ptr %ptr2 acquire, align 4
%2 = add i32 %0, %1
store atomic i32 %2, ptr %ptr3 release, align 4
ret i32 %2
}
;; TODO: the "move %icc" and related instructions are totally
;; redundant here. There's something weird happening in optimization
;; of the success value of cmpxchg.
; SPARC-LABEL: test_cmpxchg_i8
; SPARC: and %o1, -4, %o2
; SPARC: mov 3, %o3
; SPARC: andn %o3, %o1, %o1
; SPARC: sll %o1, 3, %o1
; SPARC: mov 255, %o3
; SPARC: sll %o3, %o1, %o5
; SPARC: xor %o5, -1, %o3
; SPARC: mov 123, %o4
; SPARC: ld [%o2], %g2
; SPARC: sll %o4, %o1, %o4
; SPARC: and %o0, 255, %o0
; SPARC: sll %o0, %o1, %o0
; SPARC: andn %g2, %o5, %o5
; SPARC: [[LABEL1:\.L.*]]:
; SPARC: or %o5, %o4, %g2
; SPARC: or %o5, %o0, %g3
; SPARC: cas [%o2], %g3, %g2
; SPARC: mov %g0, %g4
; SPARC: cmp %g2, %g3
; SPARC: move %icc, 1, %g4
; SPARC: cmp %g4, 0
; SPARC: bne %icc, [[LABEL2:\.L.*]]
; SPARC: nop
; SPARC: and %g2, %o3, %g3
; SPARC: cmp %o5, %g3
; SPARC: bne %icc, [[LABEL1]]
; SPARC: mov %g3, %o5
; SPARC: [[LABEL2]]:
; SPARC: retl
; SPARC: srl %g2, %o1, %o0
; SPARC64-LABEL: test_cmpxchg_i8
; SPARC64: and %o1, -4, %o2
; SPARC64: mov 3, %o3
; SPARC64: andn %o3, %o1, %o1
; SPARC64: sll %o1, 3, %o1
; SPARC64: mov 255, %o3
; SPARC64: sll %o3, %o1, %o5
; SPARC64: xor %o5, -1, %o3
; SPARC64: mov 123, %o4
; SPARC64: ld [%o2], %g2
; SPARC64: sll %o4, %o1, %o4
; SPARC64: and %o0, 255, %o0
; SPARC64: sll %o0, %o1, %o0
; SPARC64: andn %g2, %o5, %o5
; SPARC64: [[LABEL1:\.L.*]]:
; SPARC64: or %o5, %o4, %g2
; SPARC64: or %o5, %o0, %g3
; SPARC64: cas [%o2], %g3, %g2
; SPARC64: mov %g0, %g4
; SPARC64: cmp %g2, %g3
; SPARC64: move %icc, 1, %g4
; SPARC64: cmp %g4, 0
; SPARC64: bne %icc, [[LABEL2:\.L.*]]
; SPARC64: nop
; SPARC64: and %g2, %o3, %g3
; SPARC64: cmp %o5, %g3
; SPARC64: bne %icc, [[LABEL1]]
; SPARC64: mov %g3, %o5
; SPARC64: [[LABEL2]]:
; SPARC64: retl
; SPARC64: srl %g2, %o1, %o0
define i8 @test_cmpxchg_i8(i8 %a, ptr %ptr) {
entry:
%pair = cmpxchg ptr %ptr, i8 %a, i8 123 monotonic monotonic
%b = extractvalue { i8, i1 } %pair, 0
ret i8 %b
}
; SPARC-LABEL: test_cmpxchg_i16
; SPARC: and %o1, -4, %o2
; SPARC: and %o1, 3, %o1
; SPARC: xor %o1, 2, %o1
; SPARC: sll %o1, 3, %o1
; SPARC: sethi 63, %o3
; SPARC: or %o3, 1023, %o4
; SPARC: sll %o4, %o1, %o5
; SPARC: xor %o5, -1, %o3
; SPARC: and %o0, %o4, %o4
; SPARC: ld [%o2], %g2
; SPARC: mov 123, %o0
; SPARC: sll %o0, %o1, %o0
; SPARC: sll %o4, %o1, %o4
; SPARC: andn %g2, %o5, %o5
; SPARC: [[LABEL1:\.L.*]]:
; SPARC: or %o5, %o0, %g2
; SPARC: or %o5, %o4, %g3
; SPARC: cas [%o2], %g3, %g2
; SPARC: mov %g0, %g4
; SPARC: cmp %g2, %g3
; SPARC: move %icc, 1, %g4
; SPARC: cmp %g4, 0
; SPARC: bne %icc, [[LABEL2:\.L.*]]
; SPARC: nop
; SPARC: and %g2, %o3, %g3
; SPARC: cmp %o5, %g3
; SPARC: bne %icc, [[LABEL1]]
; SPARC: mov %g3, %o5
; SPARC: [[LABEL2]]:
; SPARC: retl
; SPARC: srl %g2, %o1, %o0
; SPARC64-LABEL: test_cmpxchg_i16
; SPARC64: and %o1, -4, %o2
; SPARC64: and %o1, 3, %o1
; SPARC64: xor %o1, 2, %o1
; SPARC64: sll %o1, 3, %o1
; SPARC64: sethi 63, %o3
; SPARC64: or %o3, 1023, %o4
; SPARC64: sll %o4, %o1, %o5
; SPARC64: xor %o5, -1, %o3
; SPARC64: and %o0, %o4, %o4
; SPARC64: ld [%o2], %g2
; SPARC64: mov 123, %o0
; SPARC64: sll %o0, %o1, %o0
; SPARC64: sll %o4, %o1, %o4
; SPARC64: andn %g2, %o5, %o5
; SPARC64: [[LABEL1:\.L.*]]:
; SPARC64: or %o5, %o0, %g2
; SPARC64: or %o5, %o4, %g3
; SPARC64: cas [%o2], %g3, %g2
; SPARC64: mov %g0, %g4
; SPARC64: cmp %g2, %g3
; SPARC64: move %icc, 1, %g4
; SPARC64: cmp %g4, 0
; SPARC64: bne %icc, [[LABEL2:\.L.*]]
; SPARC64: nop
; SPARC64: and %g2, %o3, %g3
; SPARC64: cmp %o5, %g3
; SPARC64: bne %icc, [[LABEL1]]
; SPARC64: mov %g3, %o5
; SPARC64: [[LABEL2]]:
; SPARC64: retl
; SPARC64: srl %g2, %o1, %o0
define i16 @test_cmpxchg_i16(i16 %a, ptr %ptr) {
entry:
%pair = cmpxchg ptr %ptr, i16 %a, i16 123 monotonic monotonic
%b = extractvalue { i16, i1 } %pair, 0
ret i16 %b
}
; SPARC-LABEL: test_cmpxchg_i32
; SPARC: mov 123, [[R:%[gilo][0-7]]]
; SPARC: cas [%o1], %o0, [[R]]
; SPARC64-LABEL: test_cmpxchg_i32
; SPARC64: mov 123, [[R:%[gilo][0-7]]]
; SPARC64: cas [%o1], %o0, [[R]]
define i32 @test_cmpxchg_i32(i32 %a, ptr %ptr) {
entry:
%pair = cmpxchg ptr %ptr, i32 %a, i32 123 monotonic monotonic
%b = extractvalue { i32, i1 } %pair, 0
ret i32 %b
}
; SPARC-LABEL: test_swap_i8
; SPARC: mov 42, [[R:%[gilo][0-7]]]
; SPARC: cas
; SPARC64-LABEL: test_swap_i8
; SPARC64: mov 42, [[R:%[gilo][0-7]]]
; SPARC64: cas
define i8 @test_swap_i8(i8 %a, ptr %ptr) {
entry:
%b = atomicrmw xchg ptr %ptr, i8 42 monotonic
ret i8 %b
}
; SPARC-LABEL: test_swap_i16
; SPARC: mov 42, [[R:%[gilo][0-7]]]
; SPARC: cas
; SPARC64-LABEL: test_swap_i16
; SPARC64: mov 42, [[R:%[gilo][0-7]]]
; SPARC64: cas
define i16 @test_swap_i16(i16 %a, ptr %ptr) {
entry:
%b = atomicrmw xchg ptr %ptr, i16 42 monotonic
ret i16 %b
}
; SPARC-LABEL: test_swap_i32
; SPARC: mov 42, [[R:%[gilo][0-7]]]
; SPARC: swap [%o1], [[R]]
; SPARC64-LABEL: test_swap_i32
; SPARC64: mov 42, [[R:%[gilo][0-7]]]
; SPARC64: swap [%o1], [[R]]
define i32 @test_swap_i32(i32 %a, ptr %ptr) {
entry:
%b = atomicrmw xchg ptr %ptr, i32 42 monotonic
ret i32 %b
}
; SPARC-LABEL: test_load_sub_i8
; SPARC: membar
; SPARC: .L{{.*}}:
; SPARC: sub
; SPARC: cas [{{%[gilo][0-7]}}]
; SPARC: membar
; SPARC64-LABEL: test_load_sub_i8
; SPARC64: membar
; SPARC64: .L{{.*}}:
; SPARC64: sub
; SPARC64: cas [{{%[gilo][0-7]}}]
; SPARC64: membar
define zeroext i8 @test_load_sub_i8(ptr %p, i8 zeroext %v) {
entry:
%0 = atomicrmw sub ptr %p, i8 %v seq_cst
ret i8 %0
}
; SPARC-LABEL: test_load_sub_i16
; SPARC: membar
; SPARC: .L{{.*}}:
; SPARC: sub
; SPARC: cas [{{%[gilo][0-7]}}]
; SPARC: membar
; SPARC64-LABEL: test_load_sub_i16
; SPARC64: membar
; SPARC64: .L{{.*}}:
; SPARC64: sub
; SPARC64: cas [{{%[gilo][0-7]}}]
; SPARC64: membar
define zeroext i16 @test_load_sub_i16(ptr %p, i16 zeroext %v) {
entry:
%0 = atomicrmw sub ptr %p, i16 %v seq_cst
ret i16 %0
}
; SPARC-LABEL: test_load_add_i32
; SPARC: membar
; SPARC: mov [[U:%[gilo][0-7]]], [[V:%[gilo][0-7]]]
; SPARC: add [[U:%[gilo][0-7]]], %o1, [[V2:%[gilo][0-7]]]
; SPARC: cas [%o0], [[V]], [[V2]]
; SPARC: membar
; SPARC64-LABEL: test_load_add_i32
; SPARC64: membar
; SPARC64: mov [[U:%[gilo][0-7]]], [[V:%[gilo][0-7]]]
; SPARC64: add [[U:%[gilo][0-7]]], %o1, [[V2:%[gilo][0-7]]]
; SPARC64: cas [%o0], [[V]], [[V2]]
; SPARC64: membar
define zeroext i32 @test_load_add_i32(ptr %p, i32 zeroext %v) {
entry:
%0 = atomicrmw add ptr %p, i32 %v seq_cst
ret i32 %0
}
; SPARC-LABEL: test_load_xor_32
; SPARC: membar
; SPARC: xor
; SPARC: cas [%o0]
; SPARC: membar
; SPARC64-LABEL: test_load_xor_32
; SPARC64: membar
; SPARC64: xor
; SPARC64: cas [%o0]
; SPARC64: membar
define zeroext i32 @test_load_xor_32(ptr %p, i32 zeroext %v) {
entry:
%0 = atomicrmw xor ptr %p, i32 %v seq_cst
ret i32 %0
}
; SPARC-LABEL: test_load_and_32
; SPARC: membar
; SPARC: and
; SPARC-NOT: xor
; SPARC: cas [%o0]
; SPARC: membar
; SPARC64-LABEL: test_load_and_32
; SPARC64: membar
; SPARC64: and
; SPARC64-NOT: xor
; SPARC64: cas [%o0]
; SPARC64: membar
define zeroext i32 @test_load_and_32(ptr %p, i32 zeroext %v) {
entry:
%0 = atomicrmw and ptr %p, i32 %v seq_cst
ret i32 %0
}
; SPARC-LABEL: test_load_nand_32
; SPARC: membar
; SPARC: and
; SPARC: xor
; SPARC: cas [%o0]
; SPARC: membar
; SPARC64-LABEL: test_load_nand_32
; SPARC64: membar
; SPARC64: and
; SPARC64: xor
; SPARC64: cas [%o0]
; SPARC64: membar
define zeroext i32 @test_load_nand_32(ptr %p, i32 zeroext %v) {
entry:
%0 = atomicrmw nand ptr %p, i32 %v seq_cst
ret i32 %0
}
; SPARC-LABEL: test_load_umin_32
; SPARC: membar
; SPARC: cmp
; SPARC: movleu %icc
; SPARC: cas [%o0]
; SPARC: membar
; SPARC64-LABEL: test_load_umin_32
; SPARC64: membar
; SPARC64: cmp
; SPARC64: movleu %icc
; SPARC64: cas [%o0]
; SPARC64: membar
define zeroext i32 @test_load_umin_32(ptr %p, i32 zeroext %v) {
entry:
%0 = atomicrmw umin ptr %p, i32 %v seq_cst
ret i32 %0
}