aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <jhogan@kernel.org>2017-11-22 06:30:27 -0500
committerJames Hogan <jhogan@kernel.org>2018-01-22 15:51:13 -0500
commitfc62f53bb2f1a436fa69c42c82e207a7c7062efc (patch)
tree9cb98a526bf35f7f646d7ef12285c64da99da8e2
parentf2d0b0d5c1718487f8a27d3ca3ec0f05ca3adedd (diff)
MIPS: Add helpers for assembler macro instructions
Implement a parse_r assembler macro in asm/mipsregs.h to parse a register in $n form, and a few C macros for defining assembler macro instructions. These can be used to more transparently support older binutils versions which don't support for example the msa, virt, xpa, or crc instructions. In particular they overcome the difficulty of turning a register name in $n form into an instruction encoding suitable for giving to .word / .hword, which is particularly problematic when needed from inline assembly where the compiler is responsible for register allocation. Traditionally this had required the use of $at and an extra MOV instruction, but for CRC instructions with multiple GP register operands that approach becomes more difficult. Three assembler macro creation helpers are added: - _ASM_MACRO_0(OP, ENC) This is to define an assembler macro for an instruction which has no operands, for example the VZ TLBGR instruction. - _ASM_MACRO_2R(OP, R1, R2, ENC) This is to define an assembler macro for an instruction which has 2 register operands, for example the CFCMSA instruction. - _ASM_MACRO_3R(OP, R1, R2, R3, ENC) This is to define an assembler macro for an instruction which has 3 register operands, for example the crc32 instructions. - _ASM_MACRO_2R_1S(OP, R1, R2, SEL3, ENC) This is to define an assembler macro for a Cop0 move instruction, with 2 register operands and an optional register select operand which defaults to 0, for example the VZ MFGC0 instruction. Suggested-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: James Hogan <jhogan@kernel.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Marcin Nowakowski <marcin.nowakowski@mips.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/17770/
-rw-r--r--arch/mips/include/asm/mipsregs.h83
1 files changed, 83 insertions, 0 deletions
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 7a59ad6e7f7d..ac70613fd3b8 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -1181,6 +1181,89 @@ static inline int mm_insn_16bit(u16 insn)
1181#endif 1181#endif
1182 1182
1183/* 1183/*
1184 * parse_r var, r - Helper assembler macro for parsing register names.
1185 *
1186 * This converts the register name in $n form provided in \r to the
1187 * corresponding register number, which is assigned to the variable \var. It is
1188 * needed to allow explicit encoding of instructions in inline assembly where
1189 * registers are chosen by the compiler in $n form, allowing us to avoid using
1190 * fixed register numbers.
1191 *
1192 * It also allows newer instructions (not implemented by the assembler) to be
1193 * transparently implemented using assembler macros, instead of needing separate
1194 * cases depending on toolchain support.
1195 *
1196 * Simple usage example:
1197 * __asm__ __volatile__("parse_r __rt, %0\n\t"
1198 * ".insn\n\t"
1199 * "# di %0\n\t"
1200 * ".word (0x41606000 | (__rt << 16))"
1201 * : "=r" (status);
1202 */
1203
1204/* Match an individual register number and assign to \var */
1205#define _IFC_REG(n) \
1206 ".ifc \\r, $" #n "\n\t" \
1207 "\\var = " #n "\n\t" \
1208 ".endif\n\t"
1209
1210__asm__(".macro parse_r var r\n\t"
1211 "\\var = -1\n\t"
1212 _IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3)
1213 _IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7)
1214 _IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11)
1215 _IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15)
1216 _IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19)
1217 _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23)
1218 _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27)
1219 _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31)
1220 ".iflt \\var\n\t"
1221 ".error \"Unable to parse register name \\r\"\n\t"
1222 ".endif\n\t"
1223 ".endm");
1224
1225#undef _IFC_REG
1226
1227/*
1228 * C macros for generating assembler macros for common instruction formats.
1229 *
1230 * The names of the operands can be chosen by the caller, and the encoding of
1231 * register operand \<Rn> is assigned to __<Rn> where it can be accessed from
1232 * the ENC encodings.
1233 */
1234
1235/* Instructions with no operands */
1236#define _ASM_MACRO_0(OP, ENC) \
1237 __asm__(".macro " #OP "\n\t" \
1238 ENC \
1239 ".endm")
1240
1241/* Instructions with 2 register operands */
1242#define _ASM_MACRO_2R(OP, R1, R2, ENC) \
1243 __asm__(".macro " #OP " " #R1 ", " #R2 "\n\t" \
1244 "parse_r __" #R1 ", \\" #R1 "\n\t" \
1245 "parse_r __" #R2 ", \\" #R2 "\n\t" \
1246 ENC \
1247 ".endm")
1248
1249/* Instructions with 3 register operands */
1250#define _ASM_MACRO_3R(OP, R1, R2, R3, ENC) \
1251 __asm__(".macro " #OP " " #R1 ", " #R2 ", " #R3 "\n\t" \
1252 "parse_r __" #R1 ", \\" #R1 "\n\t" \
1253 "parse_r __" #R2 ", \\" #R2 "\n\t" \
1254 "parse_r __" #R3 ", \\" #R3 "\n\t" \
1255 ENC \
1256 ".endm")
1257
1258/* Instructions with 2 register operands and 1 optional select operand */
1259#define _ASM_MACRO_2R_1S(OP, R1, R2, SEL3, ENC) \
1260 __asm__(".macro " #OP " " #R1 ", " #R2 ", " #SEL3 " = 0\n\t" \
1261 "parse_r __" #R1 ", \\" #R1 "\n\t" \
1262 "parse_r __" #R2 ", \\" #R2 "\n\t" \
1263 ENC \
1264 ".endm")
1265
1266/*
1184 * TLB Invalidate Flush 1267 * TLB Invalidate Flush
1185 */ 1268 */
1186static inline void tlbinvf(void) 1269static inline void tlbinvf(void)