📄 pa.h
字号:
during the scan of that argument list. This data type should hold all necessary information about the function itself and about the args processed so far, enough to enable macros such as FUNCTION_ARG to determine where the next arg should go. On the HP-PA, the WORDS field holds the number of words of arguments scanned so far (including the invisible argument, if any, which holds the structure-value-address). Thus, 4 or more means all following args should go on the stack. The INCOMING field tracks whether this is an "incoming" or "outgoing" argument. The INDIRECT field indicates whether this is is an indirect call or not. The NARGS_PROTOTYPE field indicates that an argument does not have a prototype when it less than or equal to 0. */struct hppa_args {int words, nargs_prototype, incoming, indirect; };#define CUMULATIVE_ARGS struct hppa_args/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ (CUM).words = 0, \ (CUM).incoming = 0, \ (CUM).indirect = (FNTYPE) && !(FNDECL), \ (CUM).nargs_prototype = (FNTYPE && TYPE_ARG_TYPES (FNTYPE) \ ? (list_length (TYPE_ARG_TYPES (FNTYPE)) - 1 \ + (TYPE_MODE (TREE_TYPE (FNTYPE)) == BLKmode \ || pa_return_in_memory (TREE_TYPE (FNTYPE), 0))) \ : 0)/* Similar, but when scanning the definition of a procedure. We always set NARGS_PROTOTYPE large so we never return a PARALLEL. */#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,IGNORE) \ (CUM).words = 0, \ (CUM).incoming = 1, \ (CUM).indirect = 0, \ (CUM).nargs_prototype = 1000/* Figure out the size in words of the function argument. The size returned by this macro should always be greater than zero because we pass variable and zero sized objects by reference. */#define FUNCTION_ARG_SIZE(MODE, TYPE) \ ((((MODE) != BLKmode \ ? (HOST_WIDE_INT) GET_MODE_SIZE (MODE) \ : int_size_in_bytes (TYPE)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \{ (CUM).nargs_prototype--; \ (CUM).words += FUNCTION_ARG_SIZE(MODE, TYPE) \ + (((CUM).words & 01) && (TYPE) != 0 \ && FUNCTION_ARG_SIZE(MODE, TYPE) > 1); \}/* Determine where to put an argument to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. MODE is the argument's machine mode. TYPE is the data type of the argument (as a tree). This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). On the HP-PA the first four words of args are normally in registers and the rest are pushed. But any arg that won't entirely fit in regs is pushed. Arguments passed in registers are either 1 or 2 words long. The caller must make a distinction between calls to explicitly named functions and calls through pointers to functions -- the conventions are different! Calls through pointers to functions only use general registers for the first four argument words. Of course all this is different for the portable runtime model HP wants everyone to use for ELF. Ugh. Here's a quick description of how it's supposed to work. 1) callee side remains unchanged. It expects integer args to be in the integer registers, float args in the float registers and unnamed args in integer registers. 2) caller side now depends on if the function being called has a prototype in scope (rather than if it's being called indirectly). 2a) If there is a prototype in scope, then arguments are passed according to their type (ints in integer registers, floats in float registers, unnamed args in integer registers. 2b) If there is no prototype in scope, then floating point arguments are passed in both integer and float registers. egad. FYI: The portable parameter passing conventions are almost exactly like the standard parameter passing conventions on the RS6000. That's why you'll see lots of similar code in rs6000.h. *//* If defined, a C expression which determines whether, and in which direction, to pad out an argument with extra space. */#define FUNCTION_ARG_PADDING(MODE, TYPE) function_arg_padding ((MODE), (TYPE))/* Specify padding for the last element of a block move between registers and memory. The 64-bit runtime specifies that objects need to be left justified (i.e., the normal justification for a big endian target). The 32-bit runtime specifies right justification for objects smaller than 64 bits. We use a DImode register in the parallel for 5 to 7 byte structures so that there is only one element. This allows the object to be correctly padded. */#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ function_arg_padding ((MODE), (TYPE))/* Do not expect to understand this without reading it several times. I'm tempted to try and simply it, but I worry about breaking something. */#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ function_arg (&CUM, MODE, TYPE, NAMED)/* If defined, a C expression that gives the alignment boundary, in bits, of an argument with the specified mode and type. If it is not defined, `PARM_BOUNDARY' is used for all arguments. *//* Arguments larger than one word are double word aligned. */#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \ (((TYPE) \ ? (integer_zerop (TYPE_SIZE (TYPE)) \ || !TREE_CONSTANT (TYPE_SIZE (TYPE)) \ || int_size_in_bytes (TYPE) <= UNITS_PER_WORD) \ : GET_MODE_SIZE(MODE) <= UNITS_PER_WORD) \ ? PARM_BOUNDARY : MAX_PARM_BOUNDARY)extern GTY(()) rtx hppa_compare_op0;extern GTY(()) rtx hppa_compare_op1;extern enum cmp_type hppa_branch_type;/* On HPPA, we emit profiling code as rtl via PROFILE_HOOK rather than as assembly via FUNCTION_PROFILER. Just output a local label. We can't use the function label because the GAS SOM target can't handle the difference of a global symbol and a local symbol. */#ifndef FUNC_BEGIN_PROLOG_LABEL#define FUNC_BEGIN_PROLOG_LABEL "LFBP"#endif#define FUNCTION_PROFILER(FILE, LABEL) \ (*targetm.asm_out.internal_label) (FILE, FUNC_BEGIN_PROLOG_LABEL, LABEL)#define PROFILE_HOOK(label_no) hppa_profile_hook (label_no)void hppa_profile_hook (int label_no);/* The profile counter if emitted must come before the prologue. */#define PROFILE_BEFORE_PROLOGUE 1/* We never want final.c to emit profile counters. When profile counters are required, we have to defer emitting them to the end of the current file. */#define NO_PROFILE_COUNTERS 1/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in functions that have frame pointers. No definition is equivalent to always zero. */extern int may_call_alloca;#define EXIT_IGNORE_STACK \ (get_frame_size () != 0 \ || current_function_calls_alloca || current_function_outgoing_args_size)/* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts.\ The trampoline sets the static chain pointer to STATIC_CHAIN_REGNUM and then branches to the specified routine. This code template is copied from text segment to stack location and then patched with INITIALIZE_TRAMPOLINE to contain valid values, and then entered as a subroutine. It is best to keep this as small as possible to avoid having to flush multiple lines in the cache. */#define TRAMPOLINE_TEMPLATE(FILE) \ { \ if (!TARGET_64BIT) \ { \ fputs ("\tldw 36(%r22),%r21\n", FILE); \ fputs ("\tbb,>=,n %r21,30,.+16\n", FILE); \ if (ASSEMBLER_DIALECT == 0) \ fputs ("\tdepi 0,31,2,%r21\n", FILE); \ else \ fputs ("\tdepwi 0,31,2,%r21\n", FILE); \ fputs ("\tldw 4(%r21),%r19\n", FILE); \ fputs ("\tldw 0(%r21),%r21\n", FILE); \ if (TARGET_PA_20) \ { \ fputs ("\tbve (%r21)\n", FILE); \ fputs ("\tldw 40(%r22),%r29\n", FILE); \ fputs ("\t.word 0\n", FILE); \ fputs ("\t.word 0\n", FILE); \ } \ else \ { \ fputs ("\tldsid (%r21),%r1\n", FILE); \ fputs ("\tmtsp %r1,%sr0\n", FILE); \ fputs ("\tbe 0(%sr0,%r21)\n", FILE); \ fputs ("\tldw 40(%r22),%r29\n", FILE); \ } \ fputs ("\t.word 0\n", FILE); \ fputs ("\t.word 0\n", FILE); \ fputs ("\t.word 0\n", FILE); \ fputs ("\t.word 0\n", FILE); \ } \ else \ { \ fputs ("\t.dword 0\n", FILE); \ fputs ("\t.dword 0\n", FILE); \ fputs ("\t.dword 0\n", FILE); \ fputs ("\t.dword 0\n", FILE); \ fputs ("\tmfia %r31\n", FILE); \ fputs ("\tldd 24(%r31),%r1\n", FILE); \ fputs ("\tldd 24(%r1),%r27\n", FILE); \ fputs ("\tldd 16(%r1),%r1\n", FILE); \ fputs ("\tbve (%r1)\n", FILE); \ fputs ("\tldd 32(%r31),%r31\n", FILE); \ fputs ("\t.dword 0 ; fptr\n", FILE); \ fputs ("\t.dword 0 ; static link\n", FILE); \ } \ }/* Length in units of the trampoline for entering a nested function. */#define TRAMPOLINE_SIZE (TARGET_64BIT ? 72 : 52)/* Length in units of the trampoline instruction code. */#define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 32 : 40))/* Minimum length of a cache line. A length of 16 will work on all PA-RISC processors. All PA 1.1 processors have a cache line of 32 bytes. Most but not all PA 2.0 processors have a cache line of 64 bytes. As cache flushes are expensive and we don't support PA 1.0, we use a minimum length of 32. */#define MIN_CACHELINE_SIZE 32/* Emit RTL insns to initialize the variable parts of a trampoline. FNADDR is an RTX for the address of the function's pure code. CXT is an RTX for the static chain value for the function. Move the function address to the trampoline template at offset 36. Move the static chain value to trampoline template at offset 40. Move the trampoline address to trampoline template at offset 44. Move r19 to trampoline template at offset 48. The latter two words create a plabel for the indirect call to the trampoline. A similar sequence is used for the 64-bit port but the plabel is at the beginning of the trampoline. Finally, the cache entries for the trampoline code are flushed. This is necessary to ensure that the trampoline instruction sequence is written to memory prior to any attempts at prefetching the code sequence. */#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \{ \ rtx start_addr = gen_reg_rtx (Pmode); \ rtx end_addr = gen_reg_rtx (Pmode); \ rtx line_length = gen_reg_rtx (Pmode); \ rtx tmp; \ \ if (!TARGET_64BIT) \ { \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 36)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), (FNADDR)); \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 40)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), (CXT)); \ \ /* Create a fat pointer for the trampoline. */ \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 44)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), (TRAMP)); \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 48)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), \ gen_rtx_REG (Pmode, 19)); \ \ /* fdc and fic only use registers for the address to flush, \ they do not accept integer displacements. We align the \ start and end addresses to the beginning of their respective \ cache lines to minimize the number of lines flushed. */ \ tmp = force_reg (Pmode, (TRAMP)); \ emit_insn (gen_andsi3 (start_addr, tmp, \ GEN_INT (-MIN_CACHELINE_SIZE))); \ tmp = force_reg (Pmode, \ plus_constant (tmp, TRAMPOLINE_CODE_SIZE - 1)); \ emit_insn (gen_andsi3 (end_addr, tmp, \ GEN_INT (-MIN_CACHELINE_SIZE))); \ emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE)); \ emit_insn (gen_dcacheflush (start_addr, end_addr, line_length)); \ emit_insn (gen_icacheflush (start_addr, end_addr, line_length, \ gen_reg_rtx (Pmode), \ gen_reg_rtx (Pmode))); \ } \ else \ { \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 56)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), (FNADDR)); \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 64)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), (CXT)); \ \ /* Create a fat pointer for the trampoline. */ \ tmp = memory_address (Pmode, plus_constant ((TRAMP), 16)); \ emit_move_insn (gen_rtx_MEM (Pmode, tmp), \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -