aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m32r/lib/memcpy.S
blob: 05987cd639ef70b9fa193ff3c0351e4f9215b4e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
 *  linux/arch/m32r/lib/memcpy.S
 *
 *  Copyright (C) 2001  Hiroyuki Kondo, and Hirokazu Takata
 *  Copyright (C) 2004  Hirokazu Takata
 *
 *  void *memcopy(void *dst, const void *src, int n);
 *
 *        dst: r0
 *        src: r1
 *        n  : r2
 */

	.text
#include <linux/linkage.h>
#include <asm/assembler.h>

#ifdef CONFIG_ISA_DUAL_ISSUE

	.text
ENTRY(memcpy)
memcopy:
	mv	r4, r0		    ||	mv	r7, r0
	or	r7, r1		    ||	cmpz	r2
	jc	r14		    ||	cmpeq	r0, r1	; return if r2=0
	jc	r14					; return if r0=r1

	and3	r7, r7, #3
	bnez	r7, byte_copy
	srl3	r3, r2, #2
	and3	r2, r2, #3
	beqz	r3, byte_copy
	addi	r4, #-4
word_copy:
	ld	r7, @r1+	    ||	addi	r3, #-1
	st	r7, @+r4	    ||	cmpz	r2
	bnez	r3, word_copy
	addi	r4, #4		    ||	jc	r14	; return if r2=0
#if defined(CONFIG_ISA_M32R2)
byte_copy:
	ldb	r7, @r1		    ||	addi	r1, #1
	addi	r2, #-1		    ||	stb	r7, @r4+
	bnez	r2, byte_copy
#elif defined(CONFIG_ISA_M32R)
byte_copy:
	ldb	r7, @r1		    ||	addi	r1, #1
	addi	r2, #-1		    ||	stb	r7, @r4
	addi	r4, #1
	bnez	r2, byte_copy
#else
#error unknown isa configuration
#endif
end_memcopy:
	jmp	r14

#else /* not CONFIG_ISA_DUAL_ISSUE */

	.text
ENTRY(memcpy)
memcopy:
	mv	r4, r0
	mv	r7, r0
	or	r7, r1
	beq	r0, r1, end_memcopy
	beqz	r2, end_memcopy

	and3	r7, r7, #3
	bnez	r7, byte_copy
	srl3	r3, r2, #2
	and3	r2, r2, #3
	beqz	r3, byte_copy
	addi	r4, #-4
word_copy:
	ld	r7, @r1+
	addi	r3, #-1
	st	r7, @+r4
	bnez	r3, word_copy
	beqz	r2, end_memcopy
	addi	r4, #4
byte_copy:
	ldb	r7, @r1
	addi	r1, #1
	addi	r2, #-1
	stb	r7, @r4
	addi	r4, #1
	bnez	r2, byte_copy
end_memcopy:
	jmp	r14

#endif /* not CONFIG_ISA_DUAL_ISSUE */

	.end
">void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); static inline void rb_insert_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { __rb_insert_augmented(node, root, augment->rotate); } #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ rbtype, rbaugmented, rbcompute) \ static inline void \ rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ { \ while (rb != stop) { \ rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ rbtype augmented = rbcompute(node); \ if (node->rbaugmented == augmented) \ break; \ node->rbaugmented = augmented; \ rb = rb_parent(&node->rbfield); \ } \ } \ static inline void \ rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ new->rbaugmented = old->rbaugmented; \ } \ static void \ rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ new->rbaugmented = old->rbaugmented; \ old->rbaugmented = rbcompute(old); \ } \ rbstatic const struct rb_augment_callbacks rbname = { \ rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ }; #define RB_RED 0 #define RB_BLACK 1 #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) #define __rb_color(pc) ((pc) & 1) #define __rb_is_black(pc) __rb_color(pc) #define __rb_is_red(pc) (!__rb_color(pc)) #define rb_color(rb) __rb_color((rb)->__rb_parent_color) #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) { rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; } static inline void rb_set_parent_color(struct rb_node *rb, struct rb_node *p, int color) { rb->__rb_parent_color = (unsigned long)p | color; } static inline void __rb_change_child(struct rb_node *old, struct rb_node *new, struct rb_node *parent, struct rb_root *root) { if (parent) { if (parent->rb_left == old) parent->rb_left = new; else parent->rb_right = new; } else root->rb_node = new; } extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); static __always_inline struct rb_node * __rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { struct rb_node *child = node->rb_right, *tmp = node->rb_left; struct rb_node *parent, *rebalance; unsigned long pc; if (!tmp) { /* * Case 1: node to erase has no more than 1 child (easy!) * * Note that if there is one child it must be red due to 5) * and node must be black due to 4). We adjust colors locally * so as to bypass __rb_erase_color() later on. */ pc = node->__rb_parent_color; parent = __rb_parent(pc); __rb_change_child(node, child, parent, root); if (child) { child->__rb_parent_color = pc; rebalance = NULL; } else rebalance = __rb_is_black(pc) ? parent : NULL; tmp = parent; } else if (!child) { /* Still case 1, but this time the child is node->rb_left */ tmp->__rb_parent_color = pc = node->__rb_parent_color; parent = __rb_parent(pc); __rb_change_child(node, tmp, parent, root); rebalance = NULL; tmp = parent; } else { struct rb_node *successor = child, *child2; tmp = child->rb_left; if (!tmp) { /* * Case 2: node's successor is its right child * * (n) (s) * / \ / \ * (x) (s) -> (x) (c) * \ * (c) */ parent = successor; child2 = successor->rb_right; augment->copy(node, successor); } else { /* * Case 3: node's successor is leftmost under * node's right child subtree * * (n) (s) * / \ / \ * (x) (y) -> (x) (y) * / / * (p) (p) * / / * (s) (c) * \ * (c) */ do { parent = successor; successor = tmp; tmp = tmp->rb_left; } while (tmp); parent->rb_left = child2 = successor->rb_right; successor->rb_right = child; rb_set_parent(child, successor); augment->copy(node, successor); augment->propagate(parent, successor); } successor->rb_left = tmp = node->rb_left; rb_set_parent(tmp, successor); pc = node->__rb_parent_color; tmp = __rb_parent(pc); __rb_change_child(node, successor, tmp, root); if (child2) { successor->__rb_parent_color = pc; rb_set_parent_color(child2, parent, RB_BLACK); rebalance = NULL; } else { unsigned long pc2 = successor->__rb_parent_color; successor->__rb_parent_color = pc; rebalance = __rb_is_black(pc2) ? parent : NULL; } tmp = successor; } augment->propagate(tmp, NULL); return rebalance; } static __always_inline void rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); if (rebalance) __rb_erase_color(rebalance, root, augment->rotate); } #endif /* _LINUX_RBTREE_AUGMENTED_H */