【博文精选】如何向riscv-gcc中增加编译器内置宏
riscv-gcc工具,有内置的一些宏参数。我们可以根据这些内置的宏参数,判断编译器的行为。
一、查看gcc内置宏参数
这里以芯来科技发布的riscv-nuclei-elf-gcc工具链为例。
使用以下命令,可以得到该工具的内置宏参数:
riscv-nuclei-elf-gcc -E -dM a.h | grep 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_flen 64 #define __riscv_compressed 1 #define __riscv_mul 1 #define __riscv_muldiv 1 #define __riscv_xlen 32 #define __riscv_fsqrt 1 #define __riscv_div 1 |
从内置宏参数,可以看出编译器,默认支持RV64IMAFDC指令集架构。
如果使用以下命令:
riscv-nuclei-elf-gcc -march=rv32gc -mabi=ilp32 -E -dM a.h | grep riscv |
得到如下结果:
#define __riscv 1 #define __riscv_atomic 1 #define __riscv_cmodel_medlow 1 #define __riscv_float_abi_soft 1 #define __riscv_fdiv 1 #define __riscv_flen 64 #define __riscv_compressed 1 #define __riscv_mul 1 #define __riscv_muldiv 1 #define __riscv_xlen 32 #define __riscv_fsqrt 1 #define __riscv_div 1 |
从内置宏参数,可以看出编译器,支持RV32IMAFDC指令集架构。
二、增加内置宏参数
对于riscv,支持p扩展,该扩展,是针对于dsp应用。
如果我们想,当gcc的-march选项中,有指定p扩展指令集,那么编译器就内置__riscv_dsp宏。如果没有指定p扩展指令集,就不内置该__riscv_dsp宏。
这样的话,编写的dsp程序,就可以使用该宏判断,是否支持p扩展指令。
下面简述一下,如何实现该功能,也就是如何根据所传参指令集架构参数,增加内置宏参数。
这里,主要是参考riscv-gcc的如下commit:
https://github.com/riscv/riscv-gcc/commit/06ab742f982d23488ec2d8c0266cb720fe775f7c
该commit,是往riscv-gcc中增加RV32E的支持。
三、修改riscv.opt
首先是修改 gcc/config/riscv/riscv.opt文件,在其中,增加DSP宏。
gcc的脚本工具,会处理该文件,通过Mask展开,定义新的宏参数。
MASK_DSP
TARGET_DSP
在编译目录下的 gcc/options.h 文件中,有该宏参数定义。
TARGET和MASK宏的定义
#define MASK_DIV (1U << 0) #define MASK_EXPLICIT_RELOCS (1U << 1) #define MASK_FDIV (1U << 2) #define MASK_SAVE_RESTORE (1U << 3) #define MASK_STRICT_ALIGN (1U << 4) #define MASK_64BIT (1U << 5) #define MASK_ATOMIC (1U << 6) #define MASK_DOUBLE_FLOAT (1U << 7) #define MASK_DSP (1U << 8) #define MASK_HARD_FLOAT (1U << 9) #define MASK_MUL (1U << 10) #define MASK_RVC (1U << 11) #define MASK_RVE (1U << 12) #define TARGET_DIV ((target_flags & MASK_DIV) != 0) #define TARGET_DIV_P(target_flags) (((target_flags) & MASK_DIV) != 0) #define TARGET_EXPLICIT_RELOCS ((target_flags & MASK_EXPLICIT_RELOCS) != 0) #define TARGET_EXPLICIT_RELOCS_P(target_flags) (((target_flags) & MASK_EXPLICIT_RELOCS) != 0) #define TARGET_FDIV ((target_flags & MASK_FDIV) != 0) #define TARGET_FDIV_P(target_flags) (((target_flags) & MASK_FDIV) != 0) #define TARGET_SAVE_RESTORE ((target_flags & MASK_SAVE_RESTORE) != 0) #define TARGET_SAVE_RESTORE_P(target_flags) (((target_flags) & MASK_SAVE_RESTORE) != 0) #define TARGET_STRICT_ALIGN ((target_flags & MASK_STRICT_ALIGN) != 0) #define TARGET_STRICT_ALIGN_P(target_flags) (((target_flags) & MASK_STRICT_ALIGN) != 0) #define TARGET_64BIT ((target_flags & MASK_64BIT) != 0) #define TARGET_ATOMIC ((target_flags & MASK_ATOMIC) != 0) #define TARGET_DOUBLE_FLOAT ((target_flags & MASK_DOUBLE_FLOAT) != 0) #define TARGET_DSP ((target_flags & MASK_DSP) != 0) #define TARGET_HARD_FLOAT ((target_flags & MASK_HARD_FLOAT) != 0) #define TARGET_MUL ((target_flags & MASK_MUL) != 0) #define TARGET_RVC ((target_flags & MASK_RVC) != 0) #define TARGET_RVE ((target_flags & MASK_RVE) != 0) |
这里的options.h文件,是gcc的内置脚本生成的,目前我还没有研究清楚该脚本是如何工作生成的。
四、修改riscv-common.c
得到上述的宏之后,需要修改gcc/common/config/riscv/riscv-common.c文件。
在riscv_parse_arch_string函数中,就会分析传入的--march参数,然后设置flags,给flags加上对应的TARGET支持。
模仿c扩展的支持,增加p扩展的支持。
static void riscv_parse_arch_string (const char *isa, int *flags, location_t loc) { riscv_subset_list *subset_list; subset_list = riscv_subset_list::parse (isa, loc); if (!subset_list) return; if (subset_list->xlen () == 32) *flags &= ~MASK_64BIT; else if (subset_list->xlen () == 64) *flags |= MASK_64BIT; *flags &= ~MASK_RVE; if (subset_list->lookup ("e")) *flags |= MASK_RVE; *flags &= ~MASK_MUL; if (subset_list->lookup ("m")) *flags |= MASK_MUL; *flags &= ~MASK_ATOMIC; if (subset_list->lookup ("a")) *flags |= MASK_ATOMIC; *flags &= ~(MASK_HARD_FLOAT | MASK_DOUBLE_FLOAT); if (subset_list->lookup ("f")) *flags |= MASK_HARD_FLOAT; if (subset_list->lookup ("d")) *flags |= MASK_DOUBLE_FLOAT; *flags &= ~MASK_RVC; if (subset_list->lookup ("c")) *flags |= MASK_RVC; *flags &= ~MASK_DSP; if (subset_list->lookup ("p")) *flags |= MASK_DSP; if (current_subset_list) delete current_subset_list; current_subset_list = subset_list; } |
通过调用subset_list的lookup函数,查看是否有传入对应的指令集架构。如果有的话,在flags中,将对应的MASK给设置上。
五、修改riscv-c.c
修改 gcc/config/riscv/riscv-c.c 文件。增加内置宏。
该文件中的riscv_cpu_cpp_builtins函数,就是增加内置宏参数的函数。
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"); if (TARGET_DSP) builtin_define ("__riscv_dsp"); 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; } switch (riscv_cmodel) { case CM_MEDLOW: builtin_define ("__riscv_cmodel_medlow"); break; case CM_MEDANY: builtin_define ("__riscv_cmodel_medany"); break; case CM_PIC: builtin_define ("__riscv_cmodel_pic"); break; } } |
在其中加上我们要加的代码:
if (TARGET_DSP) builtin_define ("__riscv_dsp"); |
因为之前flags,已经设置了MASK_DSP,而TARGET_DSP宏定义如下:
#define TARGET_DSP ((target_flags & MASK_DSP) != 0) |
如果该宏的返回值不为0,表示-march有传入p扩展指令集,因此就会调用builtin_define函数,定义__riscv_dsp宏。
如果该宏的返回值为0,表示-march没有传入p扩展指令集,因此就不会调用builtin_define函数,定义__riscv_dsp宏。
六、测试
重新编译riscv-gcc工具链。然后进行测试:
使用如下命令:
riscv-nuclei-elf-gcc -march=rv64gcp -mabi=lp64 -E -dM a.h | grep riscv |
得到:
#define __riscv 1 #define __riscv_atomic 1 #define __riscv_cmodel_medlow 1 #define __riscv_float_abi_soft 1 #define __riscv_fdiv 1 #define __riscv_flen 64 #define __riscv_compressed 1 #define __riscv_mul 1 #define __riscv_muldiv 1 #define __riscv_xlen 64 #define __riscv_fsqrt 1 #define __riscv_div 1 #define __riscv_dsp 1 |
从结果可以看出,有__riscv_dsp宏
使用如下命令:
riscv-nuclei-elf-gcc -march=rv64gc -mabi=lp64 -E -dM a.h | grep riscv |
得到:
#define __riscv 1 #define __riscv_atomic 1 #define __riscv_cmodel_medlow 1 #define __riscv_float_abi_soft 1 #define __riscv_fdiv 1 #define __riscv_flen 64 #define __riscv_compressed 1 #define __riscv_mul 1 #define __riscv_muldiv 1 #define __riscv_xlen 64 #define __riscv_fsqrt 1 #define __riscv_div 1 |
从结果可以看出,没有__riscv_dsp宏
七、总结
以上就完成了向riscv-gcc中增加编译器自带宏。
如果单纯加一个宏,和任何参数没有关系,那么直接修改riscv-common.c文件,在riscv_cpu_cpp_builtins函数中,直接调用builtin_define函数,定义内置宏。
如果加的宏,和-march参数有关系,那么可以按照上述的流程,进行修改,增加内置宏。