linux-headers/arch/e2k/include/asm/alternative-asm.h

194 lines
4.5 KiB
C

#ifndef _ASM_E2K_ALTERNATIVE_ASM_H
#define _ASM_E2K_ALTERNATIVE_ASM_H
#ifdef __ASSEMBLY__
/*
* Check the length of an instruction sequence, must be a multiple of 8.
*/
.macro alt_len_check start,end
.if ( \end - \start ) % 8
.error "cpu alternatives instructions length is not divisible by 8\n"
.endif
.endm
/*
* Issue one struct alt_instr descriptor entry (need to put it into
* the section .altinstructions, see below). This entry contains
* enough information for the alternatives patching code to patch an
* instruction. See apply_alternatives().
*/
.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
.align 4
.word \orig_start - .
.word \alt_start - .
.short \orig_end - \orig_start
.short \alt_end - \alt_start
.short \feature
.endm
.macro alt_pad_64bytes bytes, check
.if ( \bytes >= \check )
.fill 1, 4, 0x00000070
.fill 15, 4, 0
.endif
.endm
/*
* Fill up @bytes with nops.
*/
.macro alt_pad bytes
.if ( \bytes >= 576 )
ibranch . + \bytes
alt_pad_fill \bytes - 16
.else
alt_pad_64bytes \bytes, 512
alt_pad_64bytes \bytes, 448
alt_pad_64bytes \bytes, 384
alt_pad_64bytes \bytes, 320
alt_pad_64bytes \bytes, 256
alt_pad_64bytes \bytes, 192
alt_pad_64bytes \bytes, 128
alt_pad_64bytes \bytes, 64
.if ( \bytes % 64 ) == 56
.fill 1, 4, 0x00000060
.fill 13, 4, 0
.endif
.if ( \bytes % 64 ) == 48
.fill 1, 4, 0x00000050
.fill 11, 4, 0
.endif
.if ( \bytes % 64 ) == 40
.fill 1, 4, 0x00000040
.fill 9, 4, 0
.endif
.if ( \bytes % 64 ) == 32
.fill 1, 4, 0x00000030
.fill 7, 4, 0
.endif
.if ( \bytes % 64 ) == 24
.fill 1, 4, 0x00000020
.fill 5, 4, 0
.endif
.if ( \bytes % 64 ) == 16
.fill 1, 4, 0x00000010
.fill 3, 4, 0
.endif
.if ( \bytes % 64 ) == 8
.fill 2, 4, 0
.endif
.endif
.endm
/*
* Define an alternative between two instructions. If @feature is
* present, early code in apply_alternatives() replaces @oldinstr with
* @newinstr.
*/
.macro ALTERNATIVE oldinstr, newinstr, feature
.pushsection .altinstr_replacement,"ax"
770: \newinstr
771: .popsection
772: \oldinstr
773: alt_len_check 770b, 771b
alt_len_check 772b, 773b
alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) )
774: .pushsection .altinstructions,"a"
alt_entry 772b, 774b, 770b, 771b, \feature
.popsection
.endm
/*
* Define an alternative between three instructions.
*/
.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
.pushsection .altinstr_replacement,"ax"
770: \newinstr1
771: \newinstr2
772: .popsection
773: \oldinstr
774: alt_len_check 770b, 771b
alt_len_check 771b, 772b
alt_len_check 773b, 774b
.if ( 771b - 770b > 772b - 771b )
alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) )
.else
alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) )
.endif
775: .pushsection .altinstructions,"a"
alt_entry 773b, 775b, 770b, 771b,\feature1
alt_entry 773b, 775b, 771b, 772b,\feature2
.popsection
.endm
/*
* bug 110687: we cannot pass e2k wide instructions to GNU assembler .macro
* as a parameter in a sane way so use the following in complex cases.
* How to use:
*
* 1) There is one alternative
*
* ALTERNATIVE_1_ALTINSTR
* < alt. instruction >
* ALTERNATIVE_2_OLDINSTR
* < initial instruction >
* ALTERNATIVE_3_FEATURE
*
* 2) There are two alternatives
*
* ALTERNATIVE_1_ALTINSTR
* "< first alt. instruction >"
* ALTERNATIVE_2_ALTINSTR2
* "< second alt. instruction >"
* ALTERNATIVE_3_OLDINSTR2
* "< initial instruction >"
* ALTERNATIVE_4_FEATURE2(feature1, feature2)
*/
#define ALTERNATIVE_1_ALTINSTR \
.pushsection .altinstr_replacement,"ax" ; \
770:
#define ALTERNATIVE_2_OLDINSTR \
771: ; \
.popsection ; \
772:
#define ALTERNATIVE_3_FEATURE(feature) \
773: ; \
alt_len_check 770b, 771b ; \
alt_len_check 772b, 773b ; \
alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) ) ; \
774: ; \
.pushsection .altinstructions,"a" ; \
alt_entry 772b, 774b, 770b, 771b, feature ; \
.popsection
#define ALTERNATIVE_2_ALTINSTR2 \
771:
#define ALTERNATIVE_3_OLDINSTR2 \
772: ; \
.popsection ; \
773:
#define ALTERNATIVE_4_FEATURE2(feature1, feature2) \
774: ; \
alt_len_check 770b, 771b ; \
alt_len_check 771b, 772b ; \
alt_len_check 773b, 774b ; \
.if ( 771b - 770b > 772b - 771b ) ; \
alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) ) ; \
.else ; \
alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) ) ; \
.endif ; \
775: ; \
.pushsection .altinstructions,"a" ; \
alt_entry 773b, 775b, 770b, 771b, feature1 ; \
alt_entry 773b, 775b, 771b, 772b, feature2 ; \
.popsection
#endif /* __ASSEMBLY__ */
#endif /* _ASM_E2K_ALTERNATIVE_ASM_H */