/*
 * Copyright 2011 Tilera Corporation. All Rights Reserved.
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation, version 2.
 *
 *   This program is distributed in the hope that it will be useful, but
 *   WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 *   NON INFRINGEMENT.  See the GNU General Public License for
 *   more details.
 *
 * Runtime support for the compiler's feedback-based optimization.
 */

#ifndef __FEEDBACK_H__
#define __FEEDBACK_H__

#ifdef __ASSEMBLER__

/* FEEDBACK_ENTER is a macro to be called at the very start of any
 * hand-written assembly function that wants to be instrumented for
 * cache packing purposes.
 *
 * It clobbers r10-r29, as any subroutine call would. This should be OK
 * since it is being called on entry to an asm procedure, so presumably
 * those registers are not in use anyway (they are not part of the standard
 * calling convention).
 *
 * A sample call would look like this, and assumes that function
 * "myfunc" is in section ".text.myfunc", and has a label at the end
 * of the function called ".Lend_myfunc":
 *
 * FEEDBACK_ENTER(myfunc)
 *
 * If your function does not have a standard section or end-label
 * naming, you can use
 *
 * FEEDBACK_ENTER_EXPLICIT(myfunc, mysection, mysize)
 *
 * If your function calls another function internally, you should place
 * a macro immediately after return, as follows:
 *
 * FEEDBACK_REENTER(myfunc)
 *
 * Note that this also clobbers r10-r29, but they should be dead at
 * this point anyway due to the function call.
 *
 * If your function has multiple entry points, you should make one of
 * them be FEEDBACK_ENTER, and the remainder use FEEDBACK_REENTER.
 * The distinction is that FEEDBACK_ENTER defines the static data
 * structures used by both macros.
 *
 */
#ifdef __COLLECT_LINKER_FEEDBACK__

#ifndef __tilegx__
#define __FEEDBACK_CODE(feedbackfunc)                           \
        {                                                       \
        move r10, lr;                                           \
        moveli r11, lo16(feedbackfunc - 3f);                    \
        };                                                      \
        {                                                       \
        auli r11, r11, ha16(feedbackfunc - 3f);                 \
        jal plt(__feedback_asm_function_entered);               \
        };                                                      \
3:
#define __FEEDBACK_CODE_SIZE 16
#else
#define __FEEDBACK_CODE(feedbackfunc)                           \
        {                                                       \
        move r10, lr;                                           \
        moveli r11, hw2_last(feedbackfunc - 3f);                \
        };                                                      \
        shl16insli r11, r11, hw1(feedbackfunc - 3f);            \
        {                                                       \
        shl16insli r11, r11, hw0(feedbackfunc - 3f);            \
        jal plt(__feedback_asm_function_entered);               \
        };                                                      \
3:
#define __FEEDBACK_CODE_SIZE 24
#endif

#define FEEDBACK_ENTER_EXPLICIT(FUNCNAME, SECNAME, SIZE)        \
        .pushsection .feedback.strings, "aMS",@progbits,1;      \
0:      .asciz #FUNCNAME;                                       \
1:      .asciz #SECNAME;                                        \
2:      .asciz __FILE__;                                        \
        .popsection;                                            \
                                                                \
        .pushsection .feedback.functions, "aw";                 \
        .align 4;                                               \
        /* Define a FeedbackFunction struct. */                 \
.Lfeedback_function_##FUNCNAME:;                                \
        .word 0;                                                \
        .word (SIZE) - 16; /* Subtract code overhead below. */  \
        .word 0b - .Lfeedback_function_##FUNCNAME;              \
        .word 1b - .Lfeedback_function_##FUNCNAME;              \
        .word 2b - .Lfeedback_function_##FUNCNAME;              \
        .word 0;                                                \
        .word 0;                                                \
        .zero 32;                                               \
        .zero 32;                                               \
        .popsection;                                            \
        __FEEDBACK_CODE(.Lfeedback_function_##FUNCNAME)

#define FEEDBACK_ENTER(FUNCNAME) \
  FEEDBACK_ENTER_EXPLICIT(FUNCNAME, .text.##FUNCNAME, \
    .Lend_##FUNCNAME - FUNCNAME)

#define FEEDBACK_REENTER(FUNCNAME) \
  __FEEDBACK_CODE(.Lfeedback_function_##FUNCNAME)

/*
 * DEPRECATED: Backwards compatible for code from 2.0 and earlier.
 * Note that you can't use FEEDBACK_REENTER with FEEDBACK_ENTRY.
 */
#define FEEDBACK_ENTRY(FUNCNAME, SECNAME, SIZE)                 \
        .pushsection .feedback.strings, "aMS",@progbits,1;      \
0:      .asciz FUNCNAME;                                        \
1:      .asciz SECNAME;                                         \
2:      .asciz __FILE__;                                        \
        .popsection;                                            \
                                                                \
        .pushsection .feedback.functions, "aw";                 \
        .align 4;                                               \
        /* Define a FeedbackFunction struct. */                 \
99:     .word 0;                                                \
        .word (SIZE) - 16; /* Subtract code overhead below. */  \
        .word 0b - 99b;                                         \
        .word 1b - 99b;                                         \
        .word 2b - 99b;                                         \
        .word 0;                                                \
        .word 0;                                                \
        .zero 32;                                               \
        .zero 32;                                               \
        .popsection;                                            \
        __FEEDBACK_CODE(99b)

#else  /* !__COLLECT_LINKER_FEEDBACK__ */

/* Not collecting linker feedback, so these are no-ops. */
#define FEEDBACK_ENTER_EXPLICIT(FUNCNAME, SECNAME, SIZE)
#define FEEDBACK_ENTER(FUNCNAME)
#define FEEDBACK_REENTER(FUNCNAME)
#define FEEDBACK_ENTRY(FUNCNAME, SECNAME, SIZE)

#endif  /* !__COLLECT_LINKER_FEEDBACK__ */

#endif  /* __ASSEMBLER__ */


#endif  /* !__FEEDBACK_H__ */
