GCC Target Hook
Table of Contents
1. GCC Target Hook
https://gcc.gnu.org/onlinedocs/gccint/Target-Macros.html#Target-Macros
GCC Backend 的 example 里看到的
- riscv_print_operand
- riscv_print_operand_address
- riscv_conditional_register_usage
都是 target hook.
target hook 定义在 target.def 中, 以 conditional_register_usage 为例:
riscv 通过 TARGET_CONDITIONAL_REGISTER_USAGE 定义一个 hook 的实现
#define TARGET_CONDITIONAL_REGISTER_USAGE riscv_conditional_register_usage
- 代码中通过 targetm.conditional_register_usage () 调用到 target hook
gcc 通过 target hook 和 macro 的方式允许 backend 针对某些功能提供自己的实现和相关的配置
1.1. runtime target 相关
1.1.1. TARGET_CPU_CPP_BUILTINS
这个 hook 会影响 gcc preprocessor, 通过 `builtin_define` 预定义了一些 runtime macro
void riscv_cpu_cpp_builtins(cpp_reader *pfile) { builtin_define("__riscv"); if (TARGET_RVC) builtin_define("__riscv_compressed"); if (TARGET_RVE) builtin_define("__riscv_32e"); if (TARGET_ATOMIC) builtin_define("__riscv_atomic"); if (TARGET_MUL) builtin_define("__riscv_mul"); if (TARGET_DIV) builtin_define("__riscv_div"); if (TARGET_DIV && TARGET_MUL) builtin_define("__riscv_muldiv"); builtin_define_with_int_value("__riscv_xlen", UNITS_PER_WORD * 8); if (TARGET_HARD_FLOAT) builtin_define_with_int_value("__riscv_flen", UNITS_PER_FP_REG * 8); if (TARGET_HARD_FLOAT && TARGET_FDIV) { builtin_define("__riscv_fdiv"); builtin_define("__riscv_fsqrt"); } switch (riscv_abi) { case ABI_ILP32E: builtin_define("__riscv_abi_rve"); gcc_fallthrough(); case ABI_ILP32: case ABI_LP64: builtin_define("__riscv_float_abi_soft"); break; case ABI_ILP32F: case ABI_LP64F: builtin_define("__riscv_float_abi_single"); break; case ABI_ILP32D: case ABI_LP64D: builtin_define("__riscv_float_abi_double"); break; } /* ... */ }
gcc 通过 march 定义了 TARGET_MUL 等 macro, 但它们是给 gcc 使用的. 应用代码如果要得到 TARGET_MUL 类似的功能, 需要使用 TARGET_CPU_CPP_BUILTINS 通过 builtin_define 定义的 __riscv_mul
通过 `echo| /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -E -dM -` 可以看到所有的 predefined macro
$> echo| /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -E -dM -|grep -i riscv #define __riscv 1 #define __riscv_atomic 1 #define __riscv_cmodel_medlow 1 #define __riscv_fdiv 1 #define __riscv_float_abi_double 1 #define __riscv_mul 1 #define __riscv_muldiv 1 #define __riscv_xlen 64 #define __riscv_fsqrt 1 #define __riscv_m 2000000 #define __riscv_a 2000000 #define __riscv_c 2000000 #define __riscv_d 2000000 #define __riscv_f 2000000 #define __riscv_i 2000000 #define __riscv_zicsr 2000000 #define __riscv_compressed 1 #define __riscv_flen 64 #define __riscv_arch_test 1 #define __riscv_div 1 #define __riscv_zifencei 2000000
Backlinks
GCC Builtin (GCC Builtin > builtin_define): TARGET_CPU_CPP_BUILTINS 通过 builtin_define 来定义 runtime builtin macro (例如 __riscv_mul)
1.1.2. TARGET_OS_CPP_BUILTINS
用来定义 `linux`, `__linux__` 等 os 相关的 runtime macro
1.1.3. TARGET_OPTION_OVERRIDE
1.1.4. TARGET_DEFAULT_TARGET_FLAGS
指定 target_flags 的默认值
1.1.5. TARGET_OPTION_OPTIMIZATION_TABLE
针对某个 opt level 打开某个 opt
1.1.6. TARGET_OPTION_INIT_STRUCT
修改 gcc option
1.1.7. TARGET_INIT_BUILTINS
Backlinks
GCC Builtin (GCC Builtin > builtins): target 自定义的 builtin 由 TARGET_INIT_BUILTINS 和 TARGET_EXPAND_BUILTIN 定义和 实现.
1.1.8. TARGET_EXPAND_BUILTIN
Backlinks
GCC Builtin (GCC Builtin > builtins): target 自定义的 builtin 由 TARGET_INIT_BUILTINS 和 TARGET_EXPAND_BUILTIN 定义和 实现.
1.2. storage layout 相关
1.2.1. endian
- BITS_BIG_ENDIAN
- BYTES_BIG_ENDIAN
- WORDS_BIG_ENDIAN
- REG_WORDS_BIG_ENDIAN
- FLOAT_WORDS_BIG_ENDIAN
1.2.2. size
- BITS_PER_WORD
- POINTER_SIZE
1.2.3. align
- PARM_BOUNDARY
- STACK_BOUNDARY
- FUNCTION_BOUNDARY
- BIGGEST_ALIGNMENT
- MALLOC_ABI_ALIGNMENT
- ATTRIBUTE_ALIGNED_VALUE
- BIGGEST_FIELD_ALIGNMENT
- DATA_ALIGNMENT
- LOCAL_ALIGNMENT
- STRICT_ALIGNMENT
- …
1.3. register 相关
pass_ira 会使用这些 macro
1.3.1. FIRST_PSEUDO_REGISTER
1.3.2. FIXED_REGISTERS
1.3.3. CALL_USED_REGISTERS
1.3.4. REG_ALLOC_ORDER
1.4. stack 相关
1.4.1. STACK_GROWS_DOWNWARD
1.4.2. FRAME_ADDR_RTX
1.4.3. RETURN_ADDR_RTX
这个宏会生成一个返回 `return address` 的 rtx, 主要用来支持 __builtin_return_address, 在 riscv 上就是返回 x1 (ra) 的值
1.4.4. STACK_POINTER_REGNUM
1.4.5. FRAME_POINTER_REGNUM
1.4.6. TARGET_STACK_PROTECT_GUARD
和 GCC Stack Protector 有关
1.4.7. TARGET_STACK_PROTECT_FAIL
1.5. cost 相关
1.5.1. TARGET_RTX_COSTS
1.5.2. TARGET_ADDRESS_COST
1.5.3. TARGET_SLOW_UNALIGNED_ACCESS
1.5.4. MEMORY_MOVE_COST
1.5.5. REGISTER_MOVE_COST
1.5.6. BRANCH_COST
1.5.7. SLOW_BYTE_ACCESS
1.5.8. MOVE_RATIO
是否使用 memcpy?
1.5.9. CLEAR_RATIO
是否使用 bzero?
1.5.10. SET_RATIO
是否使用 memset?
1.6. schedule 相关
1.6.1. TARGET_SCHED_ISSUE_RATE
1.6.2. TARGET_SCHED_ADJUST_COST
1.6.3. TARGET_SCHED_ADJUST_PRIORITY
1.6.4. TARGET_SCHED_REORDER
1.6.5. …
1.7. assembler format
1.7.1. ASM_OUTPUT_LABEL
1.8. misc
1.8.1. TARGET_PRINT_OPERAND
1.8.2. TARGET_PRINT_OPERAND_ADDRESS
1.8.3. TARGET_CONDITIONAL_REGISTER_USAGE
1.8.4. TARGET_STRUCT_VALUE_RTX
用来设置 GCC Named Return Value 如何把 nrv 传递给 callee
例如:
#define TARGET_STRUCT_VALUE_RTX my_struct_value_rtx static rtx my_struct_value_rtx( tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED) { return gen_rtx_REG(Pmode, 13); }
表示用 reg 13 (riscv 的 a3) 传递 nrv. 若该宏没有定义, 则会把 nrv 看做 callee 的第一个参数来处理
struct X { int a; int b; int c; int d; int e; int f; }; struct X foo(int a) { struct X x = {0}; x.a = a; return x; }
$> /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc test.c -O1 -c $> /opt/riscv/bin/riscv64-unknown-linux-gnu-objdump -d ./test.o 0000000000000000 <foo>: 0: c288 sw a0,0(a3) 2: 0006a223 sw zero,4(a3) 6: 0006a423 sw zero,8(a3) a: 0006a623 sw zero,12(a3) e: 0006a823 sw zero,16(a3) 12: 0006aa23 sw zero,20(a3) 16: 8536 mv a0,a3 18: 8082 ret
1.8.5. TARGET_HAVE_PREFETCH
1.8.6. TARGET_OPTAB_SUPPORTED_P
Backlinks
GCC Backend (GCC Backend > misc > target hook): target hook