/* Copyright (C) 2005-2009 Clozure Associates */ /* This file is part of Clozure CL. */ /* Clozure CL is licensed under the terms of the Lisp Lesser GNU Public */ /* License , known as the LLGPL and distributed with Clozure CL as the */ /* file "LICENSE". The LLGPL consists of a preamble and the LGPL, */ /* which is distributed with Clozure CL as the file "LGPL". Where these */ /* conflict, the preamble takes precedence. */ /* Clozure CL is referenced in the preamble as the "LIBRARY." */ /* The LLGPL is also available online at */ /* http://opensource.franz.com/preamble.html */ /* Register usage. This is certainly a little short of */ /* immediate registers; we can maybe use the low bits */ /* of mmx or xmm registers to hold immediate values and */ /* do some unboxed arithmetic. */ /* Register usage in C calling conventions differ between Darwin/Linux/FreeBSD (which use the AMD-defined ABI) and Windows64 (which uses something else). The good news is that Win64 did away with the cdecl/stdcall/fastcall madness, there is only one ABI left. Here's a rundown. AMD64^Wx86-64 ABI: * Integer and pointer function arguments passed (from left to right) in RDI, RSI, RDX, RCX, R8 and R9 * FP arguments are passed in XMM0..XMM7 * rest is passed on stack * return value in RAX * Callee must preserve RBP, RBX, R12..R15, MXCSR control bits * On function entry, x87 mode and DF clear is assumed * `RSP'..`RSP-128' must not be touched by signal handlers Win64 ABI: * Integer and pointers passed in RCX, RDX, R8, R9 * FP passed in XMM0..XMM3 * rest is passed on stack * Return value in RAX or XMM0 * Caller (!) responsible for creating and cleaning stack space for spilling integer registers * Callee must preserve RBP, RBX, RSI, RDI, R12..R15, XMM6..XMM15 Both want their stack pointers to be 16 byte aligned on call, equivalent to 8 byte offset after call due to pushed return address. http://msdn2.microsoft.com/en-us/library/zthk2dkh(VS.80).aspx http://www.tortall.net/projects/yasm/manual/html/objfmt-win64-exception.html http://www.x86-64.org/documentation/abi.pdf Lisp register usage: Clozure CL renames the physical registers, giving them names based on their usage. An overview: imm0..imm2 temp0..temp2 save0..save3 arg_x, arg_y, arg_z fn On top of that, further mappings are defined: fname, next_method_context: temp0 nargs: imm2 ra0: temp2 xfn: temp1 allocptr: temp0 stack_temp: mm7 x86-64 ABI mapping: imm0..imm2: RAX, RDX, RCX temp0..temp2: RBX, R9, R10 save0..save3: R15, R14, R12, R11 arg_x, arg_y, arg_z: R8, RDI, RSI fn: R13 rcontext_reg: GS Win64 specifics: rcontext_reg: R11 */ /* Redefining these standard register names - with the same _l, _w, _b suffixes */ /* used in lispy symbolic names - allows us to play Stupid M4 Tricks in macros */ define(`rax_l',`eax') define(`rax_w',`ax') define(`rax_b',`al') define(`rbx_l',`ebx') define(`rbx_w',`bx') define(`rbx_b',`bl') define(`rcx_l',`ecx') define(`rcx_w',`cx') define(`rdx_l',`edx') define(`rdx_w',`dx') define(`rdx_b',`dl') define(`rsi_l',`esi') define(`rsi_w',`si') define(`rsi_b',`sil') define(`rdi_l',`edo') define(`rdi_w',`di') define(`rdi_b',`dil') define(`r8_l',`r8d') define(`r8_w',`r8w') define(`r8_b',`r8b') define(`r9_l',`r9d') define(`r9_w',`r9w') define(`r9_b',`r9b') define(`r10_l',`r10d') define(`r10_w',`r10w') define(`r10_b',`r10b') define(`r10_l',`r11d') define(`r11_w',`r11w') define(`r11_b',`r11b') define(`r12_l',`r12d') define(`r12_w',`r12w') define(`r12_b',`r12b') define(`r13_l',`r13d') define(`r13_w',`r13w') define(`r13_b',`r13b') define(`r14_l',`r14d') define(`r14_w',`r14w') define(`r14_b',`r14b') define(`r15_l',`r15d') define(`r15_w',`r15w') define(`r15_b',`r15b') /* Registers when using Lisp calling conventions */ define(`imm0',`rax') define(`imm0_l',`eax') define(`imm0_w',`ax') define(`imm0_b',`al') define(`Rimm0',`0') define(`temp0',`rbx') define(`temp0_l',`ebx') define(`temp0_w',`bx') define(`temp0_b',`bl') define(`Rtemp0',`3') define(`imm2',`rcx') define(`imm2_l',`ecx') define(`imm2_w',`cx') define(`imm2_b',`cl') define(`Rimm2',`1') define(`imm1',`rdx') define(`imm1_l',`edx') define(`imm1_w',`dx') define(`imm1_b',`dl') define(`Rimm1',`2') define(`arg_z',`rsi') define(`arg_z_l',`esi') define(`arg_z_w',`si') define(`arg_z_b',`sil') define(`Rarg_z',`6') define(`arg_y',`rdi') define(`arg_y_l',`edi') define(`arg_y_w',`di') define(`arg_y_b',`dil') define(`Rarg_y',`7') define(`arg_x',`r8') define(`arg_x_l',`r8d') define(`arg_x_w',`r8w') define(`arg_x_b',`r8b') define(`Rarg_x',`8') define(`temp1',`r9') define(`temp1_l',`r9d') define(`temp1_w',`r9w') define(`temp1_b',`r9b') define(`Rtemp1',`9') define(`temp2',`r10') define(`temp2_l',`r10d') define(`temp2_w',`r10w') define(`temp2_x_b',`r10b') define(`Rtemp2',`10') define(`save3',`r11') define(`save3_l',`r11d') define(`save3_w',`r11w') define(`save3_b',`r11b') define(`Rsave3',`11') define(`save2',`r12') define(`save2_l',`r12d') define(`save2_w',`r12w') define(`save2_b',`r12b') define(`Rsave2',`12') define(`fn',`r13') /* some addressing restrictions */ define(`fn_l',`r13d') define(`fn_w',`r13w') define(`fn_b',`r13b') define(`Rfn',`13') define(`save1',`r14') define(`save1_l',`r14d') define(`save1_w',`r14w') define(`save1_b',`r14b') define(`Rsave1',`14') define(`save0',`r15') define(`save0_l',`r15d') define(`save0_w',`r15w') define(`save0_b',`r15b') define(`Rsave0',`15') ifdef(`TCR_IN_GPR',` /* We keep the TCR pointer in r11 */ define(`rcontext_reg', r11) define(`rcontext',`$1(%rcontext_reg)') ',` /* The TCR can be accessed relative to %gs */ define(`rcontext_reg',`gs') define(`rcontext',`%rcontext_reg:$1') ') define(`fname',`temp0') define(`next_method_context',`temp0') define(`nargs_b',`imm2_b') define(`nargs_w',`imm2_w') define(`nargs_q',`imm2') define(`nargs',`imm2_l') define(`ra0',`temp2') define(`xfn',`temp1') define(`allocptr',`temp0') define(`stack_temp',`mm7') define(`fp0',`xmm0') define(`fp1',`xmm1') define(`fp2',`xmm2') define(`fp3',`xmm3') define(`fp4',`xmm4') define(`fp5',`xmm5') define(`fp6',`xmm6') define(`fp7',`xmm7') define(`fp8',`xmm8') define(`fp9',`xmm9') define(`fp10',`xmm10') define(`fp11',`xmm11') define(`fp12',`xmm12') define(`fp13',`xmm13') define(`fp14',`xmm14') define(`fp15',`xmm15') define(`fpzero',`fp15') /* Registers when running with native C calling conventions */ define(`cret',`rax') define(`cret_l',`eax') define(`cret_w',`ax') define(`cret_b',`al') define(`Rcret',`0') define(`ctemp0',`r10') define(`ctemp0_l',`r10d') define(`ctemp0_w',`r10w') define(`ctemp0_b',`r10b') define(`Rctemp0',`10') define(`ctemp1',`r11') define(`ctemp1_l',`r11d') define(`ctemp1_w',`r11w') define(`ctemp1_b',`r11b') define(`Rctemp1',`11') define(`csave0',`rbx') define(`csave0_l',`ebx') define(`csave0_w',`bx') define(`csave0_b',`bl') define(`Rcsave0',`3') define(`csave1',`r12') define(`csave1_l',`r12d') define(`csave1_w',`r12w') define(`csave1_b',`r12b') define(`Rcsave1',`12') define(`csave2',`r13') define(`csave2_l',`r13d') define(`csave2_w',`r13w') define(`csave2_b',`r13b') define(`Rcsave2',`13') define(`csave3',`r14') define(`csave3_l',`r14d') define(`csave3_w',`r14w') define(`csave3_b',`r14b') define(`Rcsave3',`14') define(`csave4',`r15') define(`csave4_l',`r15d') define(`csave4_w',`r15w') define(`csave4_b',`r15b') define(`Rcsave4',`15') ifdef(`WINDOWS',` define(`carg0',`rcx') define(`carg0_l',`ecx') define(`carg0_w',`cx') define(`carg0_b',`cl') define(`Rcarg0',`1') define(`carg1',`rdx') define(`carg1_l',`edx') define(`carg1_w',`dx') define(`carg1_b',`dl') define(`Rcarg1',`2') define(`carg2',`r8') define(`carg2_l',`r8d') define(`carg2_w',`r8w') define(`carg2_b',`r8b') define(`Rcarg2',`8') define(`carg3',`r9') define(`carg3_l',`r9d') define(`carg3_w',`r9w') define(`carg3_b',`r9b') define(`Rcarg3',`9') define(`csave5',`rsi') define(`csave5_l',`esi') define(`csave5_w',`si') define(`csave5_b',`sil') define(`csave5_z',`6') define(`csave6',`rdi') define(`csave6_l',`edi') define(`csave6_w',`di') define(`csave6_b',`dil') define(`Rcsave6',`7') ',` define(`carg0',`rdi') define(`carg0_l',`edi') define(`carg0_w',`di') define(`carg0_b',`dil') define(`Rcarg0',`7') define(`carg1',`rsi') define(`carg1_l',`esi') define(`carg1_w',`si') define(`carg1_b',`sil') define(`carg1_z',`6') define(`carg2',`rdx') define(`carg2_l',`edx') define(`carg2_w',`dx') define(`carg2_b',`dl') define(`Rcarg2',`2') define(`carg3',`rcx') define(`carg3_l',`ecx') define(`carg3_w',`cx') define(`carg3_b',`cl') define(`Rcarg3',`1') define(`carg4',`r8') define(`carg4_l',`r8d') define(`carg4_w',`r8w') define(`carg4_b',`r8b') define(`Rcarg4',`8') define(`carg5',`r9') define(`carg5_l',`r9d') define(`carg5_w',`r9w') define(`carg5_b',`r9b') define(`Rcarg5',`9') ') nbits_in_word = 64 nbits_in_byte = 8 ntagbits = 4 nlisptagbits = 3 nfixnumtagbits = 3 nlowtagbits = 2 num_subtag_bits = 8 subtag_shift = num_subtag_bits fixnumshift = 3 fixnum_shift = 3 fulltagmask = 15 tagmask = 7 fixnummask = 7 ncharcodebits = 8 charcode_shift = 8 word_shift = 3 node_size = 8 dnode_size = 16 dnode_align_bits = 4 dnode_shift = dnode_align_bits bitmap_shift = 6 fixnumone = (1< -> unwind-protect, else catch */ _node(link) /* backpointer to previous catch frame */ _node(mvflag) /* 0 if single-valued catch, fixnum 1 otherwise */ _node(rsp) /* saved lisp sp */ _node(rbp) /* saved lisp rbp */ _node(foreign_sp) /* necessary ? */ _node(db_link) /* head of special-binding chain */ _node(_save3) _node(_save2) _node(_save1) _node(_save0) _node(xframe) /* exception frame chain */ _node(pc) /* TRA of catch exit or cleanup form */ _endstructf _structf(vectorH) _node(logsize) _node(physsize) _node(data_vector) _node(displacement) _node(flags) _endstructf _structf(arrayH) _node(rank) _node(physsize) _node(data_vector) _node(displacement) _node(flags) _struct_label(dim0) _endstructf _struct(lisp_frame,0) _node(backlink) _node(savera0) _ends _struct(vector,-fulltag_misc) _node(header) _struct_label(data) _ends _struct(binding,0) _node(link) _node(sym) _node(val) _ends nrs_origin = 0x13020 nrs_symbol_fulltag = fulltag_symbol lisp_globals_limit = 0x13000 include(lisp_globals.s) define(`def_header',` $1 = ($2<