1changecom(`/*', `*/')dnl
2/*
3 * %CopyrightBegin%
4 *
5 * Copyright Ericsson AB 2004-2016. All Rights Reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * %CopyrightEnd%
20 */
21
22
23`#ifndef HIPE_AMD64_ASM_H
24#define HIPE_AMD64_ASM_H'
25
26dnl
27dnl Tunables.
28dnl
29define(LEAF_WORDS,24)dnl number of stack words for leaf functions
30define(NR_ARG_REGS,4)dnl admissible values are 0 to 6, inclusive
31define(HP_IN_REGISTER,1)dnl 1 to reserve a global register for HP
32define(FCALLS_IN_REGISTER,0)dnl 1 to reserve global register for FCALLS
33define(HEAP_LIMIT_IN_REGISTER,0)dnl global for HL
34define(SIMULATE_NSP,0)dnl change to 1 to simulate call/ret insns
35
36`#define AMD64_LEAF_WORDS	'LEAF_WORDS
37`#define LEAF_WORDS		'LEAF_WORDS
38`#define AMD64_NR_ARG_REGS	'NR_ARG_REGS
39`#define NR_ARG_REGS		'NR_ARG_REGS
40
41`#define AMD64_HP_IN_REGISTER	'HP_IN_REGISTER
42`#if AMD64_HP_IN_REGISTER'
43`#define AMD64_HEAP_POINTER 15'
44define(HP,%r15)dnl Only change this together with above
45`#endif'
46
47`#define AMD64_FCALLS_IN_REGISTER 'FCALLS_IN_REGISTER
48`#if AMD64_FCALLS_IN_REGISTER'
49`#define AMD64_FCALLS_REGISTER 11'
50define(FCALLS,%r11)dnl This goes together with line above
51`#endif'
52
53`#define AMD64_HEAP_LIMIT_IN_REGISTER 'HEAP_LIMIT_IN_REGISTER
54`#if AMD64_HEAP_LIMIT_IN_REGISTER'
55`#define AMD64_HEAP_LIMIT_REGISTER 12'
56define(HEAP_LIMIT,%r12)dnl Change this together with line above
57`#endif'
58
59`#define AMD64_SIMULATE_NSP	'SIMULATE_NSP
60
61
62`#ifdef ASM'
63/*
64 * Only assembler stuff from here on (when included from *.S)
65 */
66
67/*
68 * Workarounds for Darwin.
69 */
70ifelse(OPSYS,darwin,``
71/* Darwin */
72#define TEXT		.text
73#define JOIN(X,Y)	X##Y
74#define CSYM(NAME)	JOIN(_,NAME)
75#define ASYM(NAME)	CSYM(NAME)
76#define GLOBAL(NAME)	.globl NAME
77#define SET_SIZE(NAME)	/*empty*/
78#define TYPE_FUNCTION(NAME)	/*empty*/
79'',``
80/* Not Darwin */
81#define TEXT		.section ".text"
82#define CSYM(NAME)	NAME
83#define ASYM(NAME)	NAME
84#define GLOBAL(NAME)	.global NAME
85#define SET_SIZE(NAME)	.size NAME,.-NAME
86#define TYPE_FUNCTION(NAME)	.type NAME,@function
87'')dnl
88
89
90/*
91 * Reserved registers.
92 */
93`#define P		%rbp'
94
95`#if AMD64_HP_IN_REGISTER
96#define SAVE_HP	        movq 'HP`, P_HP(P)
97#define RESTORE_HP	movq P_HP(P), 'HP`
98#else
99#define SAVE_HP		/*empty*/
100#define RESTORE_HP	/*empty*/
101#endif'
102
103`#if AMD64_FCALLS_IN_REGISTER
104#define SAVE_FCALLS	movq 'FCALLS`, P_FCALLS(P)
105#define RESTORE_FCALLS	movq P_FCALLS(P), 'FCALLS`
106#else
107#define SAVE_FCALLS	/*empty*/
108#define RESTORE_FCALLS	/*empty*/
109#endif'
110
111`#if AMD64_HEAP_LIMIT_IN_REGISTER
112#define RESTORE_HEAP_LIMIT	movq P_HP_LIMIT(P), 'HEAP_LIMIT`
113#else
114#define RESTORE_HEAP_LIMIT	/*empty*/
115#endif'
116
117define(NSP,%rsp)dnl
118`#define NSP		'NSP
119`#define SAVE_CSP	movq	%rsp, P_CSP(P)
120#define RESTORE_CSP	movq	P_CSP(P), %rsp'
121
122
123/*
124 * Debugging macros
125 *
126 * Keeps track of whether context has been saved in the debug build, allowing us
127 * to detect when the garbage collector is called when it shouldn't.
128 */
129`#ifdef DEBUG
130#  define SET_GC_UNSAFE			\
131	movq	$1, P_GCUNSAFE(P)
132#  define SET_GC_SAFE			\
133	movq	$0, P_GCUNSAFE(P)
134#else
135#  define SET_GC_UNSAFE
136#  define SET_GC_SAFE
137#endif'
138
139/*
140 * Context switching macros.
141 */
142`#define SWITCH_C_TO_ERLANG_QUICK	\
143	SAVE_CSP; \
144	movq P_NSP(P), NSP'
145
146`#define SWITCH_ERLANG_TO_C_QUICK	\
147	movq NSP, P_NSP(P); \
148	RESTORE_CSP'
149
150`#define SAVE_CACHED_STATE	\
151	SAVE_HP;		\
152	SAVE_FCALLS;		\
153	SET_GC_SAFE'
154
155`#define RESTORE_CACHED_STATE	\
156	RESTORE_HP;		\
157	RESTORE_HEAP_LIMIT;	\
158	RESTORE_FCALLS;		\
159	SET_GC_UNSAFE'
160
161`#define SWITCH_C_TO_ERLANG	\
162	RESTORE_CACHED_STATE;	\
163	SWITCH_C_TO_ERLANG_QUICK'
164
165`#define SWITCH_ERLANG_TO_C	\
166	SAVE_CACHED_STATE;	\
167	SWITCH_ERLANG_TO_C_QUICK'
168
169/*
170 * Argument (parameter) registers.
171 */
172
173define(defarg,`define(ARG$1,`$2')dnl
174#`define ARG'$1	$2'
175)dnl
176
177ifelse(eval(NR_ARG_REGS >= 1),0,,
178`defarg(0,`%rsi')')dnl
179ifelse(eval(NR_ARG_REGS >= 2),0,,
180`defarg(1,`%rdx')')dnl
181ifelse(eval(NR_ARG_REGS >= 3),0,,
182`defarg(2,`%rcx')')dnl
183ifelse(eval(NR_ARG_REGS >= 4),0,,
184`defarg(3,`%r8')')dnl
185ifelse(eval(NR_ARG_REGS >= 5),0,,
186`defarg(4,`%r9')')dnl
187ifelse(eval(NR_ARG_REGS >= 6),0,,
188`defarg(5,`%rdi')')dnl
189
190/*
191 * TEMP_RV:
192 *	Used in nbif_stack_trap_ra to preserve the return value.
193 *	Must be a C callee-save register.
194 *	Must be otherwise unused in the return path.
195 */
196`#define TEMP_RV		%rbx'
197
198dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
199dnl X								X
200dnl X			hipe_amd64_glue.S support		X
201dnl X								X
202dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
203
204dnl
205dnl LOAD_ARG_REGS
206dnl (identical to x86 version except for movq)
207dnl
208define(LAR_1,`movq P_ARG$1(P), ARG$1 ; ')dnl
209define(LAR_N,`ifelse(eval($1 >= 0),0,,`LAR_N(eval($1-1))LAR_1($1)')')dnl
210define(LOAD_ARG_REGS,`LAR_N(eval(NR_ARG_REGS-1))')dnl
211`#define LOAD_ARG_REGS	'LOAD_ARG_REGS
212
213dnl
214dnl STORE_ARG_REGS
215dnl (identical to x86 version except for movq)
216dnl
217define(SAR_1,`movq ARG$1, P_ARG$1(P) ; ')dnl
218define(SAR_N,`ifelse(eval($1 >= 0),0,,`SAR_N(eval($1-1))SAR_1($1)')')dnl
219define(STORE_ARG_REGS,`SAR_N(eval(NR_ARG_REGS-1))')dnl
220`#define STORE_ARG_REGS	'STORE_ARG_REGS
221
222dnl
223dnl NSP_CALL(FUN)
224dnl Emit a CALL FUN instruction, or simulate it.
225dnl FUN must not be an NSP-based memory operand.
226dnl
227ifelse(eval(SIMULATE_NSP),0,
228``#define NSP_CALL(FUN)	call FUN'',
229``#define NSP_CALL(FUN)	subq $8,NSP; leaq 1f(%rip),%rax; movq %rax,(NSP); jmp FUN; 1:'')dnl
230
231dnl
232dnl NSP_RETN(NPOP)
233dnl Emit a RET $NPOP instruction, or simulate it.
234dnl NPOP should be non-zero.
235dnl
236ifelse(eval(SIMULATE_NSP),0,
237``#define NSP_RETN(NPOP)	ret $NPOP'',
238``#define NSP_RETN(NPOP)	movq (NSP),TEMP_RV; addq $8+NPOP,NSP; jmp *TEMP_RV'')dnl
239
240dnl
241dnl NSP_RET0
242dnl Emit a RET instruction, or simulate it.
243dnl
244ifelse(eval(SIMULATE_NSP),0,
245``#define NSP_RET0	ret'',
246``#define NSP_RET0	movq (NSP),TEMP_RV; addq $8,NSP; jmp *TEMP_RV'')dnl
247
248dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
249dnl X								X
250dnl X			hipe_amd64_bifs.m4 support		X
251dnl X								X
252dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
253
254dnl
255dnl NBIF_ARG(DST,ARITY,ARGNO)
256dnl Access a formal parameter.
257dnl It will be a memory load via NSP when ARGNO >= NR_ARG_REGS.
258dnl It will be a register move when 0 <= ARGNO < NR_ARG_REGS; if
259dnl the source and destination are the same, the move is suppressed.
260dnl
261dnl This must be called before SWITCH_ERLANG_TO_C{,QUICK}.
262dnl This must not be called if the C BIF's arity > 6.
263dnl
264define(NBIF_MOVE_REG,`ifelse($1,$2,`# movq	$2, $1',`movq	$2, $1')')dnl
265define(NBIF_REG_ARG,`NBIF_MOVE_REG($1,ARG$2)')dnl
266define(NBIF_STK_LOAD,`movq	$2(NSP), $1')dnl
267define(NBIF_STK_ARG,`NBIF_STK_LOAD($1,eval(8*($2-$3)))')dnl
268define(NBIF_ARG,`ifelse(eval($3 >= NR_ARG_REGS),0,`NBIF_REG_ARG($1,$3)',`NBIF_STK_ARG($1,$2,$3)')')dnl
269`/* #define NBIF_ARG_1_0	'NBIF_ARG(%rsi,1,0)` */'
270`/* #define NBIF_ARG_2_0	'NBIF_ARG(%rsi,2,0)` */'
271`/* #define NBIF_ARG_2_1	'NBIF_ARG(%rdx,2,1)` */'
272`/* #define NBIF_ARG_3_0	'NBIF_ARG(%rsi,3,0)` */'
273`/* #define NBIF_ARG_3_1	'NBIF_ARG(%rdx,3,1)` */'
274`/* #define NBIF_ARG_3_2	'NBIF_ARG(%rcx,3,2)` */'
275`/* #define NBIF_ARG_4_0	'NBIF_ARG(%rsi,4,0)` */'
276`/* #define NBIF_ARG_4_1	'NBIF_ARG(%rdx,4,1)` */'
277`/* #define NBIF_ARG_4_2	'NBIF_ARG(%rcx,4,2)` */'
278`/* #define NBIF_ARG_4_3	'NBIF_ARG(%r8,4,3)` */'
279`/* #define NBIF_ARG_5_0	'NBIF_ARG(%rsi,5,0)` */'
280`/* #define NBIF_ARG_5_1	'NBIF_ARG(%rdx,5,1)` */'
281`/* #define NBIF_ARG_5_2	'NBIF_ARG(%rcx,5,2)` */'
282`/* #define NBIF_ARG_5_3	'NBIF_ARG(%r8,5,3)` */'
283`/* #define NBIF_ARG_5_4	'NBIF_ARG(%r9,5,4)` */'
284
285dnl XXX: For >6 arity C BIFs, we need:
286dnl	NBIF_COPY_NSP(ARITY)
287dnl	SWITCH_ERLANG_TO_C
288dnl	NBIF_GE6_ARG_MOVE(DSTREG,ARITY,ARGNO)
289dnl	pushq NBIF_GE6_ARG_OPND(ARITY,ARGNO) <-- uses NSP copied above
290
291dnl
292dnl NBIF_RET(ARITY)
293dnl Generates a return from a native BIF, taking care to pop
294dnl any stacked formal parameters.
295dnl
296define(RET_POP,`ifelse(eval($1 > NR_ARG_REGS),0,0,eval(8*($1 - NR_ARG_REGS)))')dnl
297define(NBIF_RET_N,`ifelse(eval($1),0,`NSP_RET0',`NSP_RETN($1)')')dnl
298define(NBIF_RET,`NBIF_RET_N(eval(RET_POP($1)))')dnl
299`/* #define NBIF_RET_0	'NBIF_RET(0)` */'
300`/* #define NBIF_RET_1	'NBIF_RET(1)` */'
301`/* #define NBIF_RET_2	'NBIF_RET(2)` */'
302`/* #define NBIF_RET_3	'NBIF_RET(3)` */'
303`/* #define NBIF_RET_4	'NBIF_RET(4)` */'
304`/* #define NBIF_RET_5	'NBIF_RET(5)` */'
305
306`#endif /* ASM */'
307
308`#endif /* HIPE_AMD64_ASM_H */'
309