美文网首页
GCC与平台关联关系 - 学习笔记

GCC与平台关联关系 - 学习笔记

作者: 走在成长的道路上 | 来源:发表于2018-11-02 09:47 被阅读0次

    本文以 riscv-tools 为基础进行分析 gcc 与平台之间的关系,及porting基础描述。

    GCC 平台描述

    GCC 使用 RTL 和 C 宏的结合来描述平台,后缀为 "md" 的文件(gcc/config/*/.md)定义了 Machine description 。它是 RTL 的子集,描述目标机模型的指令集和用于代码优化的指令属性、指令延迟特性及窥孔优化策略等辅助信息。编译后转换为 C 的结构、数组或函数,作为共用算法的参数。

    其他平台特性信息用C的宏定义来表示,也作为共用算法的参数。宏定义的内容有存储器的定义、源语言数据类型的宽度、栈定义、函数调用参数/返回方式、寻址模式、汇编输出的符号定义、GCC命令参数,以及调试信息格式等。

    GCC的抽象机是一套标准名(包括宏), 它定义了一套标准指令集,各个不同平台对标准指令名提供语义模板或库函数实现。当语法树节点被分析为某一标准指令名所表示的操作时,代入平台对此标准指令的解释。GCC各平台的目标机模型实现抽象机时所表现的功能特性,即GCC使用参数代入的方法将目标机的具体参数代入抽象机,然后操作抽象机。

    编译系统的平台移植时,首先确定新平台将要实现的系统抽象机子集。并书写新平台的描述文件,然后交叉编译生成新平台的编译程序。

    GCC 定义抽象机的指令集,它以操作类型来划分指令并建立标准操作表。标准操作表由一组子表组成,每个子表代表一类操作。

    GCC 标准指令与平台指令的连接

    gcc/gensupport.h 文件中定义了 optab 结构体,并通过 OPTAB_CL 等宏将 optabs.def 文件中定义的操作函数定义到 optab 枚举中,如下所示:

    #define OPTAB_CL(name, pat, c, b, l)        name,
    #define OPTAB_CX(name, pat)
    #define OPTAB_CD(name, pat)         name,
    #define OPTAB_NL(name, pat, c, b, s, l)     name,
    #define OPTAB_NC(name, pat, c)          name,
    #define OPTAB_NX(name, pat)
    #define OPTAB_VL(name, pat, c, b, s, l)     name,
    #define OPTAB_VC(name, pat, c)          name,
    #define OPTAB_VX(name, pat)
    #define OPTAB_DC(name, pat, c)          name,
    #define OPTAB_D(name, pat)          name,
    
    /* Enumerates all optabs.  */
    typedef enum optab_tag {
      unknown_optab,
    #include "optabs.def"
      NUM_OPTABS
    } optab;
    

    而在 gcc/gensupport.c 文件中将所有 optabs.def 中的函数定义到 optabs 数组内,如下:

    
    #define NS "NULL"
    #define ZS "'\\0'"
    #define OPTAB_CL(o, p, c, b, l)    { #o, p, #b, ZS, #l, o, c, UNKNOWN, 1 },
    #define OPTAB_CX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 1 },
    #define OPTAB_CD(o, p) { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 2 },
    #define OPTAB_NL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, c, 3 },
    #define OPTAB_NC(o, p, c)          { #o, p, NS, ZS, NS, o, c, c, 3 },
    #define OPTAB_NX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 },
    #define OPTAB_VL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, UNKNOWN, 3 },
    #define OPTAB_VC(o, p, c)          { #o, p, NS, ZS, NS, o, c, UNKNOWN, 3 },
    #define OPTAB_VX(o, p) { #o, p, NULL, NULL, NULL, o, UNKNOWN, UNKNOWN, 3 },
    #define OPTAB_DC(o, p, c)          { #o, p, NS, ZS, NS, o, c, c, 4 },
    #define OPTAB_D(o, p)  { #o, p, NS, ZS, NS, o, UNKNOWN, UNKNOWN, 4 },
    
    /* An array of all optabs.  Note that the same optab can appear more
       than once, with a different pattern.  */
    optab_def optabs[] = {
      { "unknown_optab", NULL, NS, ZS, NS, unknown_optab, UNKNOWN, UNKNOWN, 0 },
    #include "optabs.def"
    };
    
    /* The number of entries in optabs[].  */
    unsigned int num_optabs = ARRAY_SIZE (optabs);
    
    /** 省略中间代码 */
    
    /* Describes one entry in optabs.def.  */
    struct optab_def
    {
      /* The name of the optab (e.g. "add_optab").  */
      const char *name;
    
      /* The pattern that matching define_expands and define_insns have.
         See the comment at the head of optabs.def for details.  */
      const char *pattern;
    
      /* The initializers (in the form of C code) for the libcall_basename,
         libcall_suffix and libcall_gen fields of (convert_)optab_libcall_d.  */
      const char *base;
      const char *suffix;
      const char *libcall;
    
      /* The optab's enum value.  */
      unsigned int op;
    
      /* The value returned by optab_to_code (OP).  */
      enum rtx_code fcode;
    
      /* CODE if code_to_optab (CODE) should return OP, otherwise UNKNOWN.  */
      enum rtx_code rcode;
    
      /* 1: conversion optabs with libcall data,
         2: conversion optabs without libcall data,
         3: non-conversion optabs with libcall data ("normal" and "overflow"
            optabs in the optabs.def comment)
         4: non-conversion optabs without libcall data ("direct" optabs).  */
      unsigned int kind;
    };
    
    

    gcc/optabs.def 文件中定义了 add_optabsub_optab 等基础的标准表操作如下:

    OPTAB_NL(add_optab, "add$P$a3", PLUS, "add", '3', gen_int_fp_fixed_libfunc)
    OPTAB_NX(add_optab, "add$F$a3")
    OPTAB_NX(add_optab, "add$Q$a3")
    OPTAB_VL(addv_optab, "addv$I$a3", PLUS, "add", '3', gen_intv_fp_libfunc)
    OPTAB_VX(addv_optab, "add$F$a3")
    OPTAB_NL(ssadd_optab, "ssadd$Q$a3", SS_PLUS, "ssadd", '3', gen_signed_fixed_libfunc)
    OPTAB_NL(usadd_optab, "usadd$Q$a3", US_PLUS, "usadd", '3', gen_unsigned_fixed_libfunc)
    OPTAB_NL(sub_optab, "sub$P$a3", MINUS, "sub", '3', gen_int_fp_fixed_libfunc)
    OPTAB_NX(sub_optab, "sub$F$a3")
    OPTAB_NX(sub_optab, "sub$Q$a3")
    OPTAB_VL(subv_optab, "subv$I$a3", MINUS, "sub", '3', gen_intv_fp_libfunc)
    OPTAB_VX(subv_optab, "sub$F$a3")
    OPTAB_NL(sssub_optab, "sssub$Q$a3", SS_MINUS, "sssub", '3', gen_signed_fixed_libfunc)
    OPTAB_NL(ussub_optab, "ussub$Q$a3", US_MINUS, "ussub", '3', gen_unsigned_fixed_libfunc)
    

    对于 add_optab 实际定义为

    #define OPTAB_NL(o, p, c, b, s, l) { #o, p, #b, #s, #l, o, c, c, 3 },
    
    
    OPTAB_NL(add_optab, "add$P$a3", PLUS, "add", '3', gen_int_fp_fixed_libfunc)
    
    # 而 optab_def 定义如下:
    # {name,         pattern,     base,  suffix,  libcall,                  op,        fcode,    rcode,   kind}
      {"add_optab",  "add$P$a3",  "add", "3",     gen_int_fp_fixed_libfunc, add_optab, PLUS,     PLUS,    3   }
    
    

    因此,对于 add_optab 来说,主要实现 add 指令操作,其对应与 gcc/config/riscv/riscv.md 文件中的如下定义:

    (define_insn "add<mode>3"
      [(set (match_operand:ANYF            0 "register_operand" "=f")
        (plus:ANYF (match_operand:ANYF 1 "register_operand" " f")
               (match_operand:ANYF 2 "register_operand" " f")))]
      "TARGET_HARD_FLOAT"
      "fadd.<fmt>\t%0,%1,%2"
      [(set_attr "type" "fadd")
       (set_attr "mode" "<UNITMODE>")])
    
    (define_insn "addsi3"
      [(set (match_operand:SI          0 "register_operand" "=r,r")
        (plus:SI (match_operand:SI 1 "register_operand" " r,r")
             (match_operand:SI 2 "arith_operand"    " r,I")))]
      ""
      { return TARGET_64BIT ? "add%i2w\t%0,%1,%2" : "add%i2\t%0,%1,%2"; }
      [(set_attr "type" "arith")
       (set_attr "mode" "SI")])
    
    (define_insn "adddi3"
      [(set (match_operand:DI          0 "register_operand" "=r,r")
        (plus:DI (match_operand:DI 1 "register_operand" " r,r")
             (match_operand:DI 2 "arith_operand"    " r,I")))]
      "TARGET_64BIT"
      "add%i2\t%0,%1,%2"
      [(set_attr "type" "arith")
       (set_attr "mode" "DI")])
    
    

    相关文章

      网友评论

          本文标题:GCC与平台关联关系 - 学习笔记

          本文链接:https://www.haomeiwen.com/subject/lzdqxqtx.html