aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/hipe/hipe_ppc_asm.m4
blob: 343402f9f0578e9c6ec1124c8f7b95e5db4e8c21 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11

                        

                                                        



                                                                      
  


                                                                         
  
                 
 










                       





                                             




                     


                                     























                                                                 
                                 


                     




                                                                             
                                    






                                                 

                            
                                 


















































































































































































































                                                                                                      
changecom(`/*', `*/')dnl
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2004-2011. All Rights Reserved.
 *
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * %CopyrightEnd%
 */


`#ifndef HIPE_PPC_ASM_H
#define HIPE_PPC_ASM_H'

/*
 * Handle 32 vs 64-bit.
 */
ifelse(ARCH,ppc64,`
/* 64-bit PowerPC */
define(LOAD,ld)dnl
define(STORE,std)dnl
define(CMPI,cmpdi)dnl
define(WSIZE,8)dnl
`#define STORE_IA(ADDR, DST, TMP)  \
	addis TMP, 0, ADDR@highest 	SEMI\
	ori TMP, TMP, ADDR@higher  	SEMI\
	rldicr TMP, TMP, 32, 31 	SEMI\
	oris TMP, TMP, ADDR@h 		SEMI\
	ori TMP, TMP, ADDR@l		SEMI\
	std TMP, DST'
',`
/* 32-bit PowerPC */
define(LOAD,lwz)dnl
define(STORE,stw)dnl
define(CMPI,cmpwi)dnl
define(WSIZE,4)dnl
`#define STORE_IA(ADDR, DST, TMP)   \
	lis TMP, ADDR@ha 	SEMI\
	addi TMP, TMP, ADDR@l	SEMI\
	stw TMP, DST'
')dnl
`#define LOAD	'LOAD
`#define STORE	'STORE
`#define CMPI	'CMPI

/*
 * Tunables.
 */
define(LEAF_WORDS,16)dnl number of stack words for leaf functions
define(NR_ARG_REGS,4)dnl admissible values are 0 to 6, inclusive

`#define PPC_LEAF_WORDS	'LEAF_WORDS

/*
 * Workarounds for Darwin.
 */
ifelse(OPSYS,darwin,``
/* Darwin */
#define JOIN(X,Y)	X##Y
#define CSYM(NAME)	JOIN(_,NAME)
#define ASYM(NAME)	CSYM(NAME)
#define GLOBAL(NAME)	.globl NAME
#define SEMI		@
#define SET_SIZE(NAME)	/*empty*/
#define TYPE_FUNCTION(NAME)	/*empty*/
#define OPD(NAME)	/*empty*/
'',``
/* Not Darwin */''
`ifelse(ARCH,ppc64,``
/* 64-bit */
/*
 * The 64-bit PowerPC ABI requires us to setup Official Procedure Descriptors
 * for functions called from C. These are exported as "func", while the entry
 * point should is exported as ".func". A function pointer in C points to the
 * function descriptor in the opd rather than to the function entry point.
 */
#define JOIN(X,Y)	X##Y
#define CSYM(NAME)	JOIN(.,NAME)
#define OPD(NAME)       			\
	.pushsection .opd, "aw";		\
	.align 3;				\
	.global NAME;				\
NAME:						\
	.quad CSYM(NAME), .TOC.@tocbase, 0;	\
	.type NAME, @function;			\
	.popsection
'',``
/* 32-bit */
#define CSYM(NAME)	NAME
#define OPD(NAME)	/*empty*/
'')'
``#define ASYM(NAME)	NAME
#define GLOBAL(NAME)	.global NAME
#define SEMI		;
#define SET_SIZE(NAME)	.size NAME,.-NAME
#define TYPE_FUNCTION(NAME)	.type NAME,@function
#define lo16(X)		X@l
#define ha16(X)		X@ha

/*
 * Standard register names.
 */
#define r0	0
#define r1	1
#define r2	2
#define r3	3
#define r4	4
#define r5	5
#define r6	6
#define r7	7
#define r8	8
#define r9	9
#define r10	10
#define r11	11
#define r12	12
#define r13	13
#define r14	14
#define r15	15
#define r16	16
#define r17	17
#define r18	18
#define r19	19
#define r20	20
#define r21	21
#define r22	22
#define r23	23
#define r24	24
#define r25	25
#define r26	26
#define r27	27
#define r28	28
#define r29	29
#define r30	30
#define r31	31
'')dnl

/*
 * Reserved registers.
 */
`#define P	r31'
`#define NSP	r30'
`#define HP	r29'
`#define TEMP_LR	r28'

/*
 * Context switching macros.
 *
 * RESTORE_CONTEXT and RESTORE_CONTEXT_QUICK do not affect
 * the condition register.
 */
`#define SAVE_CONTEXT_QUICK	\
	mflr	TEMP_LR'

`#define RESTORE_CONTEXT_QUICK	\
	mtlr	TEMP_LR'

`#define SAVE_CACHED_STATE	\
	STORE	HP, P_HP(P) SEMI\
	STORE	NSP, P_NSP(P)'

`#define RESTORE_CACHED_STATE	\
	LOAD	HP, P_HP(P) SEMI\
	LOAD	NSP, P_NSP(P)'

`#define SAVE_CONTEXT_BIF	\
	mflr	TEMP_LR SEMI	\
	STORE	HP, P_HP(P)'

`#define RESTORE_CONTEXT_BIF	\
	mtlr	TEMP_LR SEMI	\
	LOAD	HP, P_HP(P)'

`#define SAVE_CONTEXT_GC	\
	mflr	TEMP_LR SEMI	\
	STORE	TEMP_LR, P_NRA(P) SEMI	\
	STORE	NSP, P_NSP(P) SEMI	\
	STORE	HP, P_HP(P)'

`#define RESTORE_CONTEXT_GC	\
	mtlr	TEMP_LR SEMI	\
	LOAD	HP, P_HP(P)'

/*
 * Argument (parameter) registers.
 */
`#define PPC_NR_ARG_REGS	'NR_ARG_REGS
`#define NR_ARG_REGS	'NR_ARG_REGS

define(defarg,`define(ARG$1,`$2')dnl
#`define ARG'$1	$2'
)dnl

ifelse(eval(NR_ARG_REGS >= 1),0,,
`defarg(0,`r4')')dnl
ifelse(eval(NR_ARG_REGS >= 2),0,,
`defarg(1,`r5')')dnl
ifelse(eval(NR_ARG_REGS >= 3),0,,
`defarg(2,`r6')')dnl
ifelse(eval(NR_ARG_REGS >= 4),0,,
`defarg(3,`r7')')dnl
ifelse(eval(NR_ARG_REGS >= 5),0,,
`defarg(4,`r8')')dnl
ifelse(eval(NR_ARG_REGS >= 6),0,,
`defarg(5,`r9')')dnl

/*
 * TEMP_ARG0:
 *	Used in nbif_stack_trap_ra to preserve the return value.
 *	Must be a C callee-save register.
 *	Must be otherwise unused in the return path.
 *
 * TEMP_ARG0:
 *	Used in hipe_ppc_inc_stack to preserve the return address
 *	(TEMP_LR contains the caller's saved return address).
 *	Must be a C callee-save register.
 *	Must be otherwise unused in the call path.
 */
`#define TEMP_ARG0	r27'

dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
dnl X								X
dnl X			hipe_ppc_glue.S support			X
dnl X								X
dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

dnl
dnl LOAD_ARG_REGS
dnl
define(LAR_1,`LOAD ARG$1, P_ARG$1(P) SEMI ')dnl
define(LAR_N,`ifelse(eval($1 >= 0),0,,`LAR_N(eval($1-1))LAR_1($1)')')dnl
define(LOAD_ARG_REGS,`LAR_N(eval(NR_ARG_REGS-1))')dnl
`#define LOAD_ARG_REGS	'LOAD_ARG_REGS

dnl
dnl STORE_ARG_REGS
dnl
define(SAR_1,`STORE ARG$1, P_ARG$1(P) SEMI ')dnl
define(SAR_N,`ifelse(eval($1 >= 0),0,,`SAR_N(eval($1-1))SAR_1($1)')')dnl
define(STORE_ARG_REGS,`SAR_N(eval(NR_ARG_REGS-1))')dnl
`#define STORE_ARG_REGS	'STORE_ARG_REGS

dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
dnl X								X
dnl X			hipe_ppc_bifs.m4 support		X
dnl X								X
dnl XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

dnl
dnl NBIF_ARG(DST,ARITY,ARGNO)
dnl Access a formal parameter.
dnl It will be a memory load via NSP when ARGNO >= NR_ARG_REGS.
dnl It will be a register move when 0 <= ARGNO < NR_ARG_REGS; if
dnl the source and destination are the same, the move is suppressed.
dnl
define(NBIF_MOVE_REG,`ifelse($1,$2,`# mr $1, $2',`mr	$1, $2')')dnl
define(NBIF_REG_ARG,`NBIF_MOVE_REG($1,ARG$2)')dnl
define(NBIF_STK_LOAD,`LOAD	$1, $2(NSP)')dnl
define(NBIF_STK_ARG,`NBIF_STK_LOAD($1,eval(WSIZE*(($2-$3)-1)))')dnl
define(NBIF_ARG,`ifelse(eval($3 >= NR_ARG_REGS),0,`NBIF_REG_ARG($1,$3)',`NBIF_STK_ARG($1,$2,$3)')')dnl
`/* #define NBIF_ARG_1_0	'NBIF_ARG(r3,1,0)` */'
`/* #define NBIF_ARG_2_0	'NBIF_ARG(r3,2,0)` */'
`/* #define NBIF_ARG_2_1	'NBIF_ARG(r3,2,1)` */'
`/* #define NBIF_ARG_3_0	'NBIF_ARG(r3,3,0)` */'
`/* #define NBIF_ARG_3_1	'NBIF_ARG(r3,3,1)` */'
`/* #define NBIF_ARG_3_2	'NBIF_ARG(r3,3,2)` */'
`/* #define NBIF_ARG_5_0	'NBIF_ARG(r3,5,0)` */'
`/* #define NBIF_ARG_5_1	'NBIF_ARG(r3,5,1)` */'
`/* #define NBIF_ARG_5_2	'NBIF_ARG(r3,5,2)` */'
`/* #define NBIF_ARG_5_3	'NBIF_ARG(r3,5,3)` */'
`/* #define NBIF_ARG_5_4	'NBIF_ARG(r3,5,4)` */'

dnl
dnl NBIF_RET(ARITY)
dnl Generates a return from a native BIF, taking care to pop
dnl any stacked formal parameters.
dnl
define(NSP_RETN,`addi	NSP, NSP, $1
	blr')dnl
define(NSP_RET0,`blr')dnl
define(RET_POP,`ifelse(eval($1 > NR_ARG_REGS),0,0,eval(WSIZE*($1 - NR_ARG_REGS)))')dnl
define(NBIF_RET_N,`ifelse(eval($1),0,`NSP_RET0',`NSP_RETN($1)')')dnl
define(NBIF_RET,`NBIF_RET_N(eval(RET_POP($1)))')dnl
`/* #define NBIF_RET_0	'NBIF_RET(0)` */'
`/* #define NBIF_RET_1	'NBIF_RET(1)` */'
`/* #define NBIF_RET_2	'NBIF_RET(2)` */'
`/* #define NBIF_RET_3	'NBIF_RET(3)` */'
`/* #define NBIF_RET_5	'NBIF_RET(5)` */'

dnl
dnl QUICK_CALL_RET(CFUN,ARITY)
dnl Used in nocons_nofail and noproc primop interfaces to optimise
dnl SAVE_CONTEXT_QUICK; bl CFUN; RESTORE_CONTEXT_QUICK; NBIF_RET(ARITY).
dnl
define(NBIF_POP_N,`ifelse(eval($1),0,`',`addi NSP, NSP, $1 SEMI ')')dnl
define(QUICK_CALL_RET,`NBIF_POP_N(eval(RET_POP($2)))b $1')dnl
`/* #define QUICK_CALL_RET_F_0 'QUICK_CALL_RET(F,0)` */'
`/* #define QUICK_CALL_RET_F_1 'QUICK_CALL_RET(F,1)` */'
`/* #define QUICK_CALL_RET_F_2 'QUICK_CALL_RET(F,2)` */'
`/* #define QUICK_CALL_RET_F_3 'QUICK_CALL_RET(F,3)` */'
`/* #define QUICK_CALL_RET_F_5 'QUICK_CALL_RET(F,5)` */'

`#endif /* HIPE_PPC_ASM_H */'