aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc/config/c6x/libunwind.S
blob: 7e649837806225fb6372afcaad55473e935b4e21 (plain)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
.text
.macro do_call fn
#ifdef _TMS320C6400_PLUS
	callp	.s2	(\fn), B3
#elif defined(_TMS320C6400)
	call	.s2	(\fn)
	addkpc	.s2	9f, B3, 0
	nop		4
9f:
#else
	call	.s2	(\fn)
	mhkl	.s2	9f, B3
	mhkh	.s2	9f, B3
	nop		3
9f:
#endif
.endm
.align 2
.global restore_core_regs
.type restore_core_regs, STT_FUNC
restore_core_regs:
	mv	.s2x	A4, B4
	ldw	.d1t1	*+A4[0], A0
	|| ldw	.d2t2	*++B4[16], B0
	ldw	.d1t1	*+A4[1], A1
	|| ldw	.d2t2	*+B4[1], B1
	ldw	.d1t1	*+A4[2], A2
	|| ldw	.d2t2	*+B4[2], B2
	ldw	.d1t1	*+A4[3], A3
	|| ldw	.d2t2	*+B4[3], B3
	;; Base registers are loaded later
	ldw	.d1t1	*+A4[5], A5
	|| ldw	.d2t2	*+B4[5], B5
	ldw	.d1t1	*+A4[6], A6
	|| ldw	.d2t2	*+B4[6], B6
	ldw	.d1t1	*+A4[7], A7
	|| ldw	.d2t2	*+B4[7], B7
	ldw	.d1t1	*+A4[8], A8
	|| ldw	.d2t2	*+B4[8], B8
	ldw	.d1t1	*+A4[9], A9
	|| ldw	.d2t2	*+B4[9], B9
	;; load PC into B10 so that it is ready for the branch
	ldw	.d2t2	*+B4[16], B10
	ldw	.d1t1	*+A4[11], A11
	|| ldw	.d2t2	*+B4[11], B11
	ldw	.d1t1	*+A4[12], A12
	|| ldw	.d2t2	*+B4[12], B12
	ldw	.d1t1	*+A4[13], A13
	|| ldw	.d2t2	*+B4[13], B13
	ldw	.d1t1	*+A4[14], A14
	|| ldw	.d2t2	*+B4[14], B14
	;; Loads have 4 delay slots.  Take advantage of this to restore the
	;; scratch registers and stack pointer before the base registers
	;; disappear.  We also need to make sure no interrupts occur,
	;; so put the whole thing in the delay slots of a dummy branch
	;; We can not move the ret earlier as that would cause it to occur
	;; before the last load completes
	b	.s1	(1f)
	ldw	.d1t1	*+A4[4], A4
	|| ldw	.d2t2	*+B4[4], B4
	ldw	.d1t1	*+A4[15], A15
	|| ldw	.d2t2	*+B4[15], B15
	ret	.s2	B10
	ldw	.d1t1	*+A4[10], A10
	|| ldw	.d2t2	*+B4[10], B10
	nop		1
1:
	nop		3
.size restore_core_regs, . - restore_core_regs

.macro UNWIND_WRAPPER name argreg argside
.global \name
.type \name, STT_FUNC
\name:
	# Create saved register state: flags,A0-A15,B0-B15,PC = 136 bytes.
	# Plus 4 (rounded to 8) for saving return.
	addk	.s2	-144, B15
	stw	.d2t1	A0, *+B15[2]
	stw	.d2t1	A1, *+B15[3]
	stw	.d2t1	A2, *+B15[4]
	stw	.d2t1	A3, *+B15[5]
	stw	.d2t1	A4, *+B15[6]
	stw	.d2t1	A5, *+B15[7]
	stw	.d2t1	A6, *+B15[8]
	stw	.d2t1	A7, *+B15[9]
	stw	.d2t1	A8, *+B15[10]
	stw	.d2t1	A9, *+B15[11]
	stw	.d2t1	A10, *+B15[12]
	stw	.d2t1	A11, *+B15[13]
	stw	.d2t1	A12, *+B15[14]
	stw	.d2t1	A13, *+B15[15]
	stw	.d2t1	A14, *+B15[16]
	stw	.d2t1	A15, *+B15[17]
	mv	.s1x	B15, A0
	addk	.s1	144, A0
	stw	.d2t2	B0, *+B15[18]
	stw	.d2t2	B1, *+B15[19]
	stw	.d2t2	B2, *+B15[20]
	stw	.d2t2	B3, *+B15[21]
	stw	.d2t2	B4, *+B15[22]
	stw	.d2t2	B5, *+B15[23]
	stw	.d2t2	B6, *+B15[24]
	stw	.d2t2	B7, *+B15[25]
	stw	.d2t2	B8, *+B15[26]
	stw	.d2t2	B9, *+B15[27]
	stw	.d2t2	B10, *+B15[28]
	stw	.d2t2	B11, *+B15[29]
	stw	.d2t2	B12, *+B15[30]
	stw	.d2t2	B13, *+B15[31]
	stw	.d2t2	B14, *+B15[32]
	stw	.d2t1	A0, *+B15[33]
	stw	.d2t1	A0, *+B15[34]
	# Zero demand saved flags
	mvk	.s1	0, A0
	stw	.d2t1	A0, *+B15[1]
	# Save return address, setup additional argument and call function
	stw	.d2t2	B3, *+B15[35]
	add	.d\argside	B15, 4, \argreg
	do_call	__gnu\name
	# Restore stack and return
	ldw	.d2t2	*+B15[35], B3
	addk	.s2	144, B15
	nop		3
	ret	.s2	B3
	nop		5
.size \name, . - \name
.endm

UNWIND_WRAPPER _Unwind_RaiseException B4 2
UNWIND_WRAPPER _Unwind_Resume B4 2
UNWIND_WRAPPER _Unwind_Resume_or_Rethrow B4 2
UNWIND_WRAPPER _Unwind_ForcedUnwind B6 2
UNWIND_WRAPPER _Unwind_Backtrace A6 1x