diff options
author | Richard Kenner <kenner@gcc.gnu.org> | 1995-12-24 17:43:00 -0500 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 1995-12-24 17:43:00 -0500 |
commit | 88c956eb52a65d895b23052655fa25497af3d843 (patch) | |
tree | 384b1c0d1188583c384e4e61ccc93fa020a87cb1 /gcc | |
parent | 90b4a764701e87a51dcb2a04d932f1454d24b157 (diff) | |
download | gcc-88c956eb52a65d895b23052655fa25497af3d843.zip gcc-88c956eb52a65d895b23052655fa25497af3d843.tar.gz gcc-88c956eb52a65d895b23052655fa25497af3d843.tar.bz2 |
(FUNCTION_BLOCK_PROFILER, BLOCK_PROFILER): Extension for -ax option (profile_block_flag == 2).
(FUNCTION_BLOCK_PROFILER, BLOCK_PROFILER): Extension for -ax
option (profile_block_flag == 2).
(MACHINE_STATE_SAVE,MACHINE_STATE_RESTORE): New macros.
(FUNCTION_BLOCK_PROFILER_EXIT): New macro.
From-SVN: r10851
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/sparc/sparc.h | 362 |
1 files changed, 337 insertions, 25 deletions
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 5edf530..08a8d23 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -1548,33 +1548,345 @@ extern int leaf_function; fputs ("),%o0,%o0\n", (FILE)); \ } while (0) -/* Output assembler code to FILE to initialize this source file's - basic block profiling info, if that has not already been done. */ - -#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ - do { \ - if (TARGET_MEDANY) \ - fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tor %%0,%%lo(LPBX0),%%o0\n\tld [%s+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%s,%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n", \ - MEDANY_BASE_REG, (LABELNO), MEDANY_BASE_REG, (LABELNO)); \ - else \ - fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tld [%%lo(LPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%%lo(LPBX0),%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n", \ - (LABELNO), (LABELNO)); \ - } while (0) -/* Output assembler code to FILE to increment the entry-count for - the BLOCKNO'th basic block in this source file. */ - -#define BLOCK_PROFILER(FILE, BLOCKNO) \ -{ \ - int blockn = (BLOCKNO); \ - if (TARGET_MEDANY) \ - fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tor %%g1,%%lo(LPBX2+%d),%%g1\n\tld [%%g1+%s],%%g2\n\tadd %%g2,1,%%g2\n\tst %%g2,[%%g1+%s]\n", \ - 4 * blockn, 4 * blockn, MEDANY_BASE_REG, MEDANY_BASE_REG); \ - else \ - fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tld [%%lo(LPBX2+%d)+%%g1],%%g2\n\ +/* There are three profiling modes for basic blocks available. + The modes are selected at compile time by using the options + -a or -ax of the gnu compiler. + The variable `profile_block_flag' will be set according to the + selected option. + + profile_block_flag == 0, no option used: + + No profiling done. + + profile_block_flag == 1, -a option used. + + Count frequency of execution of every basic block. + + profile_block_flag == 2, -ax option used. + + Generate code to allow several different profiling modes at run time. + Available modes are: + Produce a trace of all basic blocks. + Count frequency of jump instructions executed. + In every mode it is possible to start profiling upon entering + certain functions and to disable profiling of some other functions. + + The result of basic-block profiling will be written to a file `bb.out'. + If the -ax option is used parameters for the profiling will be read + from file `bb.in'. + +*/ + +/* The following macro shall output assembler code to FILE + to initialize basic-block profiling. + + If profile_block_flag == 2 + + Output code to call the subroutine `__bb_init_trace_func' + and pass two parameters to it. The first parameter is + the address of a block allocated in the object module. + The second parameter is the number of the first basic block + of the function. + + The name of the block is a local symbol made with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + The number of the first basic block of the function is + passed to the macro in BLOCK_OR_LABEL. + + If described in a virtual assembler language the code to be + output looks like: + + parameter1 <- LPBX0 + parameter2 <- BLOCK_OR_LABEL + call __bb_init_trace_func + + else if profile_block_flag != 0 + + Output code to call the subroutine `__bb_init_func' + and pass one single parameter to it, which is the same + as the first parameter to `__bb_init_trace_func'. + + The first word of this parameter is a flag which will be nonzero if + the object module has already been initialized. So test this word + first, and do not call `__bb_init_func' if the flag is nonzero. + Note: When profile_block_flag == 2 the test need not be done + but `__bb_init_trace_func' *must* be called. + + BLOCK_OR_LABEL may be used to generate a label number as a + branch destination in case `__bb_init_func' will not be called. + + If described in a virtual assembler language the code to be + output looks like: + + cmp (LPBX0),0 + jne local_label + parameter1 <- LPBX0 + call __bb_init_func +local_label: + +*/ + +#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \ +do \ + { \ + int bol = (BLOCK_OR_LABEL); \ + switch (profile_block_flag) \ + { \ + case 2: \ + if (TARGET_MEDANY) \ + fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tor %%0,%%lo(LPBX0),%%o0\n\tadd %%o0,%s,%%o0\n\tsethi %%hi(%d),%%o1\n\tcall ___bb_init_trace_func\n\tadd %g0,%%lo(%d),%%o1\n",\ + MEDANY_BASE_REG, bol, bol); \ + else \ + fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tor %%o0,%%lo(LPBX0),%%o0\n\tsethi %%hi(%d),%%o1\n\tcall ___bb_init_trace_func\n\tor %%o1,%%lo(%d),%%o1\n",\ + bol, bol); \ + break; \ + default: \ + if (TARGET_MEDANY) \ + fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tor %%0,%%lo(LPBX0),%%o0\n\tld [%s+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%s,%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n",\ + MEDANY_BASE_REG, bol, MEDANY_BASE_REG, bol);\ + else \ + fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tld [%%lo(LPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%%lo(LPBX0),%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n",\ + bol, bol); \ + break; \ + } \ + } \ +while (0) + +/* The following macro shall output assembler code to FILE + to increment a counter associated with basic block number BLOCKNO. + + If profile_block_flag == 2 + + Output code to initialize the global structure `__bb' and + call the function `__bb_trace_func' which will increment the + counter. + + `__bb' consists of two words. In the first word the number + of the basic block has to be stored. In the second word + the address of a block allocated in the object module + has to be stored. + + The basic block number is given by BLOCKNO. + + The address of the block is given by the label created with + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); + + by FUNCTION_BLOCK_PROFILER. + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + If described in a virtual assembler language the code to be + output looks like: + + move BLOCKNO -> (__bb) + move LPBX0 -> (__bb+4) + call __bb_trace_func + + Note that function `__bb_trace_func' must not change the + machine state, especially the flag register. To grant + this, you must output code to save and restore registers + either in this macro or in the macros MACHINE_STATE_SAVE + and MACHINE_STATE_RESTORE. The last two macros will be + used in the function `__bb_trace_func', so you must make + sure that the function prologue does not change any + register prior to saving it with MACHINE_STATE_SAVE. + + else if profile_block_flag != 0 + + Output code to increment the counter directly. + Basic blocks are numbered separately from zero within each + compiled object module. The count associated with block number + BLOCKNO is at index BLOCKNO in an array of words; the name of + this array is a local symbol made with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + If described in a virtual assembler language, the code to be + output looks like: + + inc (LPBX2+4*BLOCKNO) + +*/ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ +do \ + { \ + int blockn = (BLOCKNO); \ + switch (profile_block_flag) \ + { \ + case 2: \ + if (TARGET_MEDANY) \ + fprintf (FILE, "\tsethi %%hi(___bb),%%g1\n\tor %%0,%%lo(___bb),%%g1\n\tsethi %%hi(%d),%%g2\n\tor %%g2,%%lo(%d),%%g2\n\tst %%g2,[%s+%%g1]\n\tsethi %%hi(LPBX0),%%g2\n\tor %%0,%%lo(LPBX0),%%g2\n\tadd %%g2,%s,%%g2\n\tadd 4,%%g1,%%g1\n\tst %%g2,[%%g1+%%lo(___bb)]\n\tmov %%o7,%%g2\n\tcall ___bb_trace_func\n\tnop\n\tmov %%g2,%%o7\n",\ + blockn, blockn, MEDANY_BASE_REG, MEDANY_BASE_REG); \ + else \ + fprintf (FILE, "\tsethi %%hi(___bb),%%g1\n\tsethi %%hi(%d),%%g2\n\tor %%g2,%%lo(%d),%%g2\n\tst %%g2,[%%lo(___bb)+%%g1]\n\tsethi %%hi(LPBX0),%%g2\n\tor %%g2,%%lo(LPBX0),%%g2\n\tadd 4,%%g1,%%g1\n\tst %%g2,[%%lo(___bb)+%%g1]\n\tmov %%o7,%%g2\n\tcall ___bb_trace_func\n\tnop\n\tmov %%g2,%%o7\n",\ + blockn, blockn); \ + break; \ + default: \ + if (TARGET_MEDANY) \ + fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tor %%g1,%%lo(LPBX2+%d),%%g1\n\tld [%%g1+%s],%%g2\n\tadd %%g2,1,%%g2\n\tst %%g2,[%%g1+%s]\n", \ + 4 * blockn, 4 * blockn, MEDANY_BASE_REG, MEDANY_BASE_REG); \ + else \ + fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tld [%%lo(LPBX2+%d)+%%g1],%%g2\n\ \tadd %%g2,1,%%g2\n\tst %%g2,[%%lo(LPBX2+%d)+%%g1]\n", \ - 4 * blockn, 4 * blockn, 4 * blockn); \ -} + 4 * blockn, 4 * blockn, 4 * blockn); \ + break; \ + } \ + } \ +while(0) + +/* The following macro shall output assembler code to FILE + to indicate a return from function during basic-block profiling. + + If profiling_block_flag == 2: + + Output assembler code to call function `__bb_trace_ret'. + + Note that function `__bb_trace_ret' must not change the + machine state, especially the flag register. To grant + this, you must output code to save and restore registers + either in this macro or in the macros MACHINE_STATE_SAVE_RET + and MACHINE_STATE_RESTORE_RET. The last two macros will be + used in the function `__bb_trace_ret', so you must make + sure that the function prologue does not change any + register prior to saving it with MACHINE_STATE_SAVE_RET. + + else if profiling_block_flag != 0: + + The macro will not be used, so it need not distinguish + these cases. +*/ + +#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \ + fprintf (FILE, "\tcall ___bb_trace_ret\n\tnop\n" ); + +/* The function `__bb_trace_func' is called in every basic block + and is not allowed to change the machine state. Saving (restoring) + the state can either be done in the BLOCK_PROFILER macro, + before calling function (rsp. after returning from function) + `__bb_trace_func', or it can be done inside the function by + defining the macros: + + MACHINE_STATE_SAVE(ID) + MACHINE_STATE_RESTORE(ID) + + In the latter case care must be taken, that the prologue code + of function `__bb_trace_func' does not already change the + state prior to saving it with MACHINE_STATE_SAVE. + + The parameter `ID' is a string identifying a unique macro use. + + On sparc it is sufficient to save the psw register to memory. + Unfortunately the psw register can be read in supervisor mode only, + so we read only the condition codes by using branch instructions + and hope that this is enough. */ + +#define MACHINE_STATE_SAVE(ID) \ + asm (" mov %g0,%l0");\ + asm (" be,a LFLGNZ" ID);\ + asm (" or %l0,4,%l0");\ + asm ("LFLGNZ" ID ": bcs,a LFLGNC" ID);\ + asm (" or %l0,1,%l0");\ + asm ("LFLGNC" ID ": bvs,a LFLGNV" ID);\ + asm (" or %l0,2,%l0");\ + asm ("LFLGNV" ID ": bneg,a LFLGNN" ID);\ + asm (" or %l0,8,%l0");\ + asm ("LFLGNN" ID ": sethi %hi(LFLAGS" ID "),%l1");\ + asm (" st %l0,[%l1+%lo(LFLAGS" ID ")]"); \ + asm (" st %g2,[%l1+%lo(LSAVRET" ID ")]"); + +/* On sparc MACHINE_STATE_RESTORE restores the psw register from memory. + The psw register can be written in supervisor mode only, + which is true even for simple condition codes. + We use some combination of instructions to produce the + proper condition codes, but some flag combinations can not + be generated in this way. If this happens an unimplemented + instruction will be executed to abort the program. */ + +#define MACHINE_STATE_RESTORE(ID) \ + asm (" sethi %hi(LFLGTAB" ID "),%l1");\ + asm (" ld [%l1+%lo(LFLGTAB" ID "-(LFLGTAB" ID "-LFLAGS" ID "))],%l0");\ + asm (" ld [%l1+%lo(LFLGTAB" ID "-(LFLGTAB" ID "-LSAVRET" ID "))],%g2");\ + asm (" sll %l0,2,%l0");\ + asm (" add %l0,%l1,%l0");\ + asm (" ld [%l0+%lo(LFLGTAB" ID ")],%l1");\ + asm (" jmp %l1");\ + asm (" nop");\ + asm (".data");\ + asm ("LFLAGS" ID ":");\ + asm (" .word 0");\ + asm ("LSAVRET" ID ":");\ + asm (" .word 0");\ + asm ("LFLGTAB" ID ": ");\ + asm (" .word LSFLG0" ID);\ + asm (" .word LSFLGC" ID);\ + asm (" .word LSFLGV" ID);\ + asm (" .word LSFLGVC" ID);\ + asm (" .word LSFLGZ" ID);\ + asm (" .word LSFLGZC" ID);\ + asm (" .word LSFLGZV" ID);\ + asm (" .word LSFLGZVC" ID);\ + asm (" .word LSFLGN" ID);\ + asm (" .word LSFLGNC" ID);\ + asm (" .word LSFLGNV" ID);\ + asm (" .word LSFLGNVC" ID);\ + asm (" .word LSFLGNZ" ID);\ + asm (" .word LSFLGNZC" ID);\ + asm (" .word LSFLGNZV" ID);\ + asm (" .word LSFLGNZVC" ID);\ + asm (".text");\ + asm ("LSFLGVC" ID ": mov -1,%l0");\ + asm (" addcc 2,%l0,%g0");\ + asm (" sethi %hi(0x80000000),%l0");\ + asm (" mov %l0,%l1");\ + asm (" ba LFLGRET" ID);\ + asm (" addxcc %l0,%l1,%l0");\ + asm ("LSFLGC" ID ": mov -1,%l0");\ + asm (" ba LFLGRET" ID);\ + asm (" addcc 2,%l0,%g0");\ + asm ("LSFLGZC" ID ": mov -1,%l0");\ + asm (" ba LFLGRET" ID);\ + asm (" addcc 1,%l0,%l0");\ + asm ("LSFLGZVC" ID ": sethi %hi(0x80000000),%l0");\ + asm (" mov %l0,%l1");\ + asm (" ba LFLGRET" ID);\ + asm (" addcc %l0,%l1,%l0");\ + asm ("LSFLGZ" ID ": ba LFLGRET" ID);\ + asm (" subcc %g0,%g0,%g0");\ + asm ("LSFLGNC" ID ": add %g0,1,%l0");\ + asm (" ba LFLGRET" ID);\ + asm (" subcc %g0,%l0,%g0");\ + asm ("LSFLG0" ID ": ba LFLGRET" ID);\ + asm (" orcc 1,%g0,%g0");\ + asm ("LSFLGN" ID ": ba LFLGRET" ID);\ + asm (" orcc -1,%g0,%g0");\ + asm ("LSFLGV" ID ":");\ + asm ("LSFLGZV" ID ":");\ + asm ("LSFLGNV" ID ":");\ + asm ("LSFLGNVC" ID ":");\ + asm ("LSFLGNZ" ID ":");\ + asm ("LSFLGNZC" ID ":");\ + asm ("LSFLGNZV" ID ":");\ + asm ("LSFLGNZVC" ID ":");\ + asm (" unimp");\ + asm ("LFLGRET" ID ":"); /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in |