1changecom(`/*', `*/')dnl
2/*
3 * %CopyrightBegin%
4 *
5 * Copyright Ericsson AB 2002-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_X86_ASM_H
24#define HIPE_X86_ASM_H'
25
26/*
27 * Tunables.
28 */
29define(LEAF_WORDS,24)dnl number of stack words for leaf functions
30define(NR_ARG_REGS,3)dnl admissible values are 0 to 5, inclusive
31define(HP_IN_ESI,1)dnl change to 0 to not reserve a global register for HP
32define(SIMULATE_NSP,0)dnl change to 1 to simulate call/ret insns
33
34`#define X86_LEAF_WORDS	'LEAF_WORDS
35`#define LEAF_WORDS	'LEAF_WORDS
36
37`#define X86_NR_ARG_REGS	'NR_ARG_REGS
38`#define NR_ARG_REGS	'NR_ARG_REGS
39
40`#define X86_HP_IN_ESI	'HP_IN_ESI
41`#define X86_SIMULATE_NSP	'SIMULATE_NSP
42
43
44`#ifdef ASM'
45/*
46 * Only assembler stuff from here on (when included from *.S)
47 */
48
49/*
50 * Workarounds for Darwin.
51 */
52ifelse(OPSYS,darwin,``
53/* Darwin */
54#define TEXT		.text
55#define JOIN(X,Y)	X##Y
56#define CSYM(NAME)	JOIN(_,NAME)
57#define ASYM(NAME)	CSYM(NAME)
58#define GLOBAL(NAME)	.globl NAME
59#define SET_SIZE(NAME)	/*empty*/
60#define TYPE_FUNCTION(NAME)	/*empty*/
61'',``
62/* Not Darwin */
63#define TEXT		.section ".text"
64#define CSYM(NAME)	NAME
65#define ASYM(NAME)	NAME
66#define GLOBAL(NAME)	.global NAME
67#define SET_SIZE(NAME)	.size NAME,.-NAME
68#define TYPE_FUNCTION(NAME)	.type NAME,@function
69'')dnl
70
71/*
72 * Reserved registers.
73 */
74`#define P	%ebp'
75
76`#if X86_HP_IN_ESI
77#define SAVE_HP		movl %esi, P_HP(P)
78#define RESTORE_HP	movl P_HP(P), %esi
79#else
80#define SAVE_HP		/*empty*/
81#define RESTORE_HP	/*empty*/
82#endif'
83
84`#define NSP		%esp
85#define SAVE_CSP	movl %esp, P_CSP(P)
86#define RESTORE_CSP	movl P_CSP(P), %esp'
87
88
89/*
90 * Context switching macros.
91 */
92`#define SWITCH_C_TO_ERLANG_QUICK	\
93	SAVE_CSP; \
94	movl P_NSP(P), NSP'
95
96`#define SWITCH_ERLANG_TO_C_QUICK	\
97	movl NSP, P_NSP(P); \
98	RESTORE_CSP'
99
100`#define SAVE_CACHED_STATE	\
101	SAVE_HP'
102
103`#define RESTORE_CACHED_STATE	\
104	RESTORE_HP'
105
106`#define SWITCH_C_TO_ERLANG	\
107	RESTORE_CACHED_STATE;	\
108	SWITCH_C_TO_ERLANG_QUICK'
109
110`#define SWITCH_ERLANG_TO_C	\
111	SAVE_CACHED_STATE;	\
112	SWITCH_ERLANG_TO_C_QUICK'
113
114
115/*
116 * Argument (parameter) registers.
117 */
118ifelse(eval(NR_ARG_REGS >= 1),0,,
119``#define ARG0	%eax
120'')dnl
121ifelse(eval(NR_ARG_REGS >= 2),0,,
122``#define ARG1	%edx
123'')dnl
124ifelse(eval(NR_ARG_REGS >= 3),0,,
125``#define ARG2	%ecx
126'')dnl
127ifelse(eval(NR_ARG_REGS >= 4),0,,
128``#define ARG3	%ebx
129'')dnl
130ifelse(eval(NR_ARG_REGS >= 5),0,,
131``#define ARG4	%edi
132'')dnl
133
134/*
135 * TEMP_RV:
136 *	Used in nbif_stack_trap_ra to preserve the return value.
137 *	Must be a C callee-save register.
138 *	Must be otherwise unused in the return path.
139 */
140`#define TEMP_RV	%ebx'
141
142/*
143 * TEMP_NSP:
144 *	Used in BIF wrappers to permit copying stacked parameter from
145 *	the native stack to the C stack.
146 *	Set up by NBIF_COPY_NSP(arity) and used by NBIF_ARG(arity,argno).
147 *	TEMP_NSP may alias the last BIF argument register.
148 *	NBIF_COPY_NSP and NBIF_ARG currently fail if ARITY > NR_ARG_REGS!
149 */
150`#define TEMP_NSP	%edi'
151
152dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
153dnl X								X
154dnl X			hipe_x86_glue.S support			X
155dnl X								X
156dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
157
158dnl
159dnl LOAD_ARG_REGS
160dnl
161define(LAR_1,`movl P_ARG$1(P), ARG$1 ; ')dnl
162define(LAR_N,`ifelse(eval($1 >= 0),0,,`LAR_N(eval($1-1))LAR_1($1)')')dnl
163define(LOAD_ARG_REGS,`LAR_N(eval(NR_ARG_REGS-1))')dnl
164`#define LOAD_ARG_REGS	'LOAD_ARG_REGS
165
166dnl
167dnl STORE_ARG_REGS
168dnl
169define(SAR_1,`movl ARG$1, P_ARG$1(P) ; ')dnl
170define(SAR_N,`ifelse(eval($1 >= 0),0,,`SAR_N(eval($1-1))SAR_1($1)')')dnl
171define(STORE_ARG_REGS,`SAR_N(eval(NR_ARG_REGS-1))')dnl
172`#define STORE_ARG_REGS	'STORE_ARG_REGS
173
174dnl
175dnl NSP_CALL(FUN)
176dnl Emit a CALL FUN instruction, or simulate it.
177dnl FUN must not be an NSP-based memory operand.
178dnl
179ifelse(eval(SIMULATE_NSP),0,
180``#define NSP_CALL(FUN)	call FUN'',
181``#define NSP_CALL(FUN)	subl $4,NSP; movl $1f,(NSP); jmp FUN; 1:'')dnl
182
183dnl
184dnl NSP_RETN(NPOP)
185dnl Emit a RET $NPOP instruction, or simulate it.
186dnl NPOP should be non-zero.
187dnl
188ifelse(eval(SIMULATE_NSP),0,
189``#define NSP_RETN(NPOP)	ret $NPOP'',
190``#define NSP_RETN(NPOP)	movl (NSP),TEMP_RV; addl $4+NPOP,NSP; jmp *TEMP_RV'')dnl
191
192dnl
193dnl NSP_RET0
194dnl Emit a RET instruction, or simulate it.
195dnl
196ifelse(eval(SIMULATE_NSP),0,
197``#define NSP_RET0	ret'',
198``#define NSP_RET0	movl (NSP),TEMP_RV; addl $4,NSP; jmp *TEMP_RV'')dnl
199
200dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
201dnl X								X
202dnl X			hipe_x86_bifs.m4 support		X
203dnl X								X
204dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
205
206dnl
207dnl NBIF_COPY_NSP(ARITY)
208dnl if ARITY > NR_ARG_REGS then TEMP_NSP := %esp.
209dnl Allows the stacked formals to be referenced via TEMP_NSP after the stack switch.
210dnl
211define(NBIF_COPY_NSP,`ifelse(eval($1 > NR_ARG_REGS),0,,`movl	%esp, TEMP_NSP')')dnl
212`/* #define NBIF_COPY_NSP_0	'NBIF_COPY_NSP(0)` */'
213`/* #define NBIF_COPY_NSP_1	'NBIF_COPY_NSP(1)` */'
214`/* #define NBIF_COPY_NSP_2	'NBIF_COPY_NSP(2)` */'
215`/* #define NBIF_COPY_NSP_3	'NBIF_COPY_NSP(3)` */'
216`/* #define NBIF_COPY_NSP_4	'NBIF_COPY_NSP(4)` */'
217`/* #define NBIF_COPY_NSP_5	'NBIF_COPY_NSP(5)` */'
218
219dnl
220dnl BASE_OFFSET(N)
221dnl Generates a base-register offset operand for the value N.
222dnl When N is zero the offset becomes the empty string, as this
223dnl may allow the assembler to choose a more compat encoding.
224dnl
225define(BASE_OFFSET,`ifelse(eval($1),0,`',`$1')')dnl
226
227dnl
228dnl NBIF_ARG_OPND(ARITY,ARGNO)
229dnl Generates an operand for this formal parameter.
230dnl It will be a register operand when 0 <= ARGNO < NR_ARG_REGS.
231dnl It will be a memory operand via TEMP_NSP when ARGNO >= NR_ARG_REGS.
232dnl
233define(NBIF_ARG_OPND,`ifelse(eval($2 >= NR_ARG_REGS),0,`ARG'$2,BASE_OFFSET(eval(($1-NR_ARG_REGS)*4-($2-NR_ARG_REGS)*4))`(TEMP_NSP)')')dnl
234`/* #define NBIF_ARG_OPND_1_0	'NBIF_ARG_OPND(1,0)` */'
235`/* #define NBIF_ARG_OPND_2_0	'NBIF_ARG_OPND(2,0)` */'
236`/* #define NBIF_ARG_OPND_2_1	'NBIF_ARG_OPND(2,1)` */'
237`/* #define NBIF_ARG_OPND_3_0	'NBIF_ARG_OPND(3,0)` */'
238`/* #define NBIF_ARG_OPND_3_1	'NBIF_ARG_OPND(3,1)` */'
239`/* #define NBIF_ARG_OPND_3_2	'NBIF_ARG_OPND(3,2)` */'
240`/* #define NBIF_ARG_OPND_4_0	'NBIF_ARG_OPND(4,0)` */'
241`/* #define NBIF_ARG_OPND_4_1	'NBIF_ARG_OPND(4,1)` */'
242`/* #define NBIF_ARG_OPND_4_2	'NBIF_ARG_OPND(4,2)` */'
243`/* #define NBIF_ARG_OPND_4_3	'NBIF_ARG_OPND(4,3)` */'
244`/* #define NBIF_ARG_OPND_5_0	'NBIF_ARG_OPND(5,0)` */'
245`/* #define NBIF_ARG_OPND_5_1	'NBIF_ARG_OPND(5,1)` */'
246`/* #define NBIF_ARG_OPND_5_2	'NBIF_ARG_OPND(5,2)` */'
247`/* #define NBIF_ARG_OPND_5_3	'NBIF_ARG_OPND(5,3)` */'
248`/* #define NBIF_ARG_OPND_5_4	'NBIF_ARG_OPND(5,4)` */'
249
250dnl
251dnl NBIF_ARG_REG(CARGNO,REG)
252dnl Generates code to move REG to C argument number CARGNO.
253dnl
254define(NBIF_ARG_REG,`movl $2,BASE_OFFSET(eval(4*$1))(%esp)')dnl
255`/* #define NBIF_ARG_REG_0_P	'NBIF_ARG_REG(0,P)` */'
256
257dnl
258dnl NBIF_ARG(CARGNO,ARITY,ARGNO)
259dnl Generates code to move Erlang parameter number ARGNO
260dnl in a BIF of arity ARITY to C parameter number CARGNO.
261dnl
262dnl This must be called after NBIF_COPY_NSP(ARITY).
263dnl
264dnl NBIF_ARG(_,_,ARGNO2) must be called after NBIF_ARG(_,_,ARGNO1)
265dnl if ARGNO2 > ARGNO1. (ARG0 may be reused as a temporary register
266dnl for Erlang parameters passed on the stack.)
267dnl
268define(NBIF_ARG_MEM,`movl NBIF_ARG_OPND($2,$3),%eax; NBIF_ARG_REG($1,%eax)')dnl
269define(NBIF_ARG,`ifelse(eval($3 >= NR_ARG_REGS),0,`NBIF_ARG_REG($1,`ARG'$3)',`NBIF_ARG_MEM($1,$2,$3)')')dnl
270
271dnl
272dnl NBIF_RET(ARITY)
273dnl Generates a return from a native BIF, taking care to pop
274dnl any stacked formal parameters.
275dnl
276define(RET_POP,`ifelse(eval($1 > NR_ARG_REGS),0,0,eval(4*($1 - NR_ARG_REGS)))')dnl
277define(NBIF_RET_N,`ifelse(eval($1),0,`NSP_RET0',`NSP_RETN($1)')')dnl
278define(NBIF_RET,`NBIF_RET_N(eval(RET_POP($1)))')dnl
279`/* #define NBIF_RET_0	'NBIF_RET(0)` */'
280`/* #define NBIF_RET_1	'NBIF_RET(1)` */'
281`/* #define NBIF_RET_2	'NBIF_RET(2)` */'
282`/* #define NBIF_RET_3	'NBIF_RET(3)` */'
283`/* #define NBIF_RET_4	'NBIF_RET(4)` */'
284`/* #define NBIF_RET_5	'NBIF_RET(5)` */'
285
286dnl
287dnl STORE_CALLER_SAVE
288dnl LOAD_CALLER_SAVE
289dnl Used to save and restore C caller-save argument registers around
290dnl calls to hipe_inc_nstack. The first 3 arguments registers are C
291dnl caller-save, remaining ones are C callee-save.
292dnl
293define(NBIF_MIN,`ifelse(eval($1 > $2),0,$1,$2)')dnl
294define(NR_CALLER_SAVE,NBIF_MIN(NR_ARG_REGS,3))dnl
295define(STORE_CALLER_SAVE,`SAR_N(eval(NR_CALLER_SAVE-1))')dnl
296define(LOAD_CALLER_SAVE,`LAR_N(eval(NR_CALLER_SAVE-1))')dnl
297`#define STORE_CALLER_SAVE	'STORE_CALLER_SAVE
298`#define LOAD_CALLER_SAVE	'LOAD_CALLER_SAVE
299
300`#endif /* ASM */'
301
302`#endif /* HIPE_X86_ASM_H */'
303