OSDN Git Service

(FUNCTION_BLOCK_PROFILER, BLOCK_PROFILER): Extension for -ax
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 24 Dec 1995 22:43:00 +0000 (22:43 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 24 Dec 1995 22:43:00 +0000 (22:43 +0000)
option (profile_block_flag == 2).
(MACHINE_STATE_SAVE,MACHINE_STATE_RESTORE): New macros.
(FUNCTION_BLOCK_PROFILER_EXIT): New macro.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@10851 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/sparc/sparc.h

index 5edf530..08a8d23 100644 (file)
@@ -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