kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

attrs.c (13394B)


      1 #include <string.h>
      2 
      3 #include "internal.h"
      4 
      5 static void toy_attr_set_init(ToyAttrSet* attrs, KitSymBind default_bind) {
      6   memset(attrs, 0, sizeof *attrs);
      7   attrs->sym.bind = default_bind;
      8   attrs->sym.visibility = KIT_CG_VIS_DEFAULT;
      9   attrs->object.tls_model = KIT_CG_TLS_AUTO;
     10   attrs->call_conv = KIT_CG_CC_TARGET_C;
     11 }
     12 
     13 int toy_parse_attr_dot_name(ToyParser* p, KitSym* out) {
     14   if (!toy_parser_expect(p, TOK_DOT) ||
     15       !(p->cur.kind == TOK_IDENT ||
     16         (p->cur.kind >= TOK_FN && p->cur.kind <= TOK_INT))) {
     17     toy_error(p, p->cur.loc, "expected attribute name");
     18     return 0;
     19   }
     20   *out = toy_tok_sym(p, p->cur);
     21   toy_parser_advance(p);
     22   return 1;
     23 }
     24 
     25 static int toy_parse_attr_dot_arg(ToyParser* p, KitSym* out) {
     26   if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_attr_dot_name(p, out) ||
     27       !toy_parser_expect(p, TOK_RPAREN)) {
     28     toy_error(p, p->cur.loc, "expected dot attribute argument");
     29     return 0;
     30   }
     31   return 1;
     32 }
     33 
     34 int toy_parse_attr_int_arg(ToyParser* p, int64_t* out) {
     35   if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_number_arg(p, out) ||
     36       !toy_parser_expect(p, TOK_RPAREN)) {
     37     toy_error(p, p->cur.loc, "expected integer attribute argument");
     38     return 0;
     39   }
     40   return 1;
     41 }
     42 
     43 static int toy_parse_attr_string_arg(ToyParser* p, KitSym* out) {
     44   if (!toy_parser_expect(p, TOK_LPAREN) ||
     45       !toy_parse_string_sym(p, out, NULL) ||
     46       !toy_parser_expect(p, TOK_RPAREN)) {
     47     toy_error(p, p->cur.loc, "expected string attribute argument");
     48     return 0;
     49   }
     50   return 1;
     51 }
     52 
     53 int toy_parse_callconv_const(ToyParser* p, KitCgCallConv* out) {
     54   static const ToyConstRow rows[] = {
     55       {"target_c", KIT_CG_CC_TARGET_C}, {"sysv", KIT_CG_CC_SYSV},
     56       {"win64", KIT_CG_CC_WIN64},       {"aapcs", KIT_CG_CC_AAPCS},
     57       {"wasm", KIT_CG_CC_WASM},         {"interrupt", KIT_CG_CC_INTERRUPT},
     58   };
     59   uint64_t v;
     60   if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1,
     61                            "call convention", "call convention", &v))
     62     return 0;
     63   *out = (KitCgCallConv)v;
     64   return 1;
     65 }
     66 
     67 static int toy_parse_attr_one(ToyParser* p, ToyAttrSet* attrs) {
     68   KitSym name;
     69   KitSym arg;
     70   int64_t int_arg;
     71   if (!toy_parse_attr_dot_name(p, &name)) return 0;
     72 
     73   if (toy_sym_is(p, name, "bind")) {
     74     attrs->attr_kinds |= TOY_ATTR_SYMBOL;
     75     if (!toy_parse_attr_dot_arg(p, &arg)) return 0;
     76     if (toy_sym_is(p, arg, "local"))
     77       attrs->sym.bind = KIT_SB_LOCAL;
     78     else if (toy_sym_is(p, arg, "global"))
     79       attrs->sym.bind = KIT_SB_GLOBAL;
     80     else if (toy_sym_is(p, arg, "weak"))
     81       attrs->sym.bind = KIT_SB_WEAK;
     82     else {
     83       toy_error(p, p->cur.loc, "unknown bind attribute");
     84       return 0;
     85     }
     86     return 1;
     87   }
     88   if (toy_sym_is(p, name, "visibility")) {
     89     attrs->attr_kinds |= TOY_ATTR_SYMBOL;
     90     if (!toy_parse_attr_dot_arg(p, &arg)) return 0;
     91     if (toy_sym_is(p, arg, "default"))
     92       attrs->sym.visibility = KIT_CG_VIS_DEFAULT;
     93     else if (toy_sym_is(p, arg, "hidden"))
     94       attrs->sym.visibility = KIT_CG_VIS_HIDDEN;
     95     else if (toy_sym_is(p, arg, "protected"))
     96       attrs->sym.visibility = KIT_CG_VIS_PROTECTED;
     97     else {
     98       toy_error(p, p->cur.loc, "unknown visibility attribute");
     99       return 0;
    100     }
    101     return 1;
    102   }
    103   if (toy_sym_is(p, name, "used")) {
    104     attrs->attr_kinds |= TOY_ATTR_SYMBOL;
    105     attrs->sym.flags |= KIT_CG_SYM_USED;
    106     return 1;
    107   }
    108   if (toy_sym_is(p, name, "dllimport")) {
    109     attrs->attr_kinds |= TOY_ATTR_SYMBOL;
    110     attrs->sym.flags |= KIT_CG_SYM_DLLIMPORT;
    111     return 1;
    112   }
    113   if (toy_sym_is(p, name, "dllexport")) {
    114     attrs->attr_kinds |= TOY_ATTR_SYMBOL;
    115     attrs->sym.flags |= KIT_CG_SYM_DLLEXPORT;
    116     return 1;
    117   }
    118   if (toy_sym_is(p, name, "section")) {
    119     KitSym section;
    120     attrs->attr_kinds |= TOY_ATTR_SECTION;
    121     if (!toy_parse_attr_string_arg(p, &section)) return 0;
    122     attrs->func.section = section;
    123     attrs->object.section = section;
    124     attrs->data.section = section;
    125     return 1;
    126   }
    127   if (toy_sym_is(p, name, "noreturn")) {
    128     attrs->attr_kinds |= TOY_ATTR_FUNC;
    129     attrs->func.flags |= KIT_CG_FUNC_NORETURN;
    130     return 1;
    131   }
    132   if (toy_sym_is(p, name, "ifunc")) {
    133     attrs->attr_kinds |= TOY_ATTR_FUNC;
    134     attrs->func.flags |= KIT_CG_FUNC_IFUNC;
    135     return 1;
    136   }
    137   if (toy_sym_is(p, name, "cold")) {
    138     attrs->attr_kinds |= TOY_ATTR_FUNC;
    139     attrs->func.flags |= KIT_CG_FUNC_COLD;
    140     return 1;
    141   }
    142   if (toy_sym_is(p, name, "hot")) {
    143     attrs->attr_kinds |= TOY_ATTR_FUNC;
    144     attrs->func.flags |= KIT_CG_FUNC_HOT;
    145     return 1;
    146   }
    147   if (toy_sym_is(p, name, "naked")) {
    148     attrs->attr_kinds |= TOY_ATTR_FUNC;
    149     attrs->func.flags |= KIT_CG_FUNC_NAKED;
    150     return 1;
    151   }
    152   if (toy_sym_is(p, name, "interrupt")) {
    153     attrs->attr_kinds |= TOY_ATTR_FUNC;
    154     attrs->func.flags |= KIT_CG_FUNC_INTERRUPT;
    155     return 1;
    156   }
    157   if (toy_sym_is(p, name, "no_red_zone")) {
    158     attrs->attr_kinds |= TOY_ATTR_FUNC;
    159     attrs->func.flags |= KIT_CG_FUNC_NO_RED_ZONE;
    160     return 1;
    161   }
    162   if (toy_sym_is(p, name, "inline")) {
    163     attrs->attr_kinds |= TOY_ATTR_FUNC;
    164     attrs->func.inline_policy = KIT_CG_INLINE_HINT;
    165     return 1;
    166   }
    167   if (toy_sym_is(p, name, "always_inline")) {
    168     attrs->attr_kinds |= TOY_ATTR_FUNC;
    169     attrs->func.inline_policy = KIT_CG_INLINE_ALWAYS;
    170     return 1;
    171   }
    172   if (toy_sym_is(p, name, "noinline")) {
    173     attrs->attr_kinds |= TOY_ATTR_FUNC;
    174     attrs->func.inline_policy = KIT_CG_INLINE_NEVER;
    175     return 1;
    176   }
    177   if (toy_sym_is(p, name, "stack_align")) {
    178     attrs->attr_kinds |= TOY_ATTR_FUNC;
    179     if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    180     attrs->func.stack_align = (uint32_t)int_arg;
    181     return 1;
    182   }
    183   if (toy_sym_is(p, name, "target_features")) {
    184     attrs->attr_kinds |= TOY_ATTR_FUNC;
    185     if (!toy_parse_attr_string_arg(p, &attrs->func.target_features)) return 0;
    186     return 1;
    187   }
    188   if (toy_sym_is(p, name, "callconv")) {
    189     attrs->attr_kinds |= TOY_ATTR_FUNC;
    190     if (!toy_parser_expect(p, TOK_LPAREN) ||
    191         !toy_parse_callconv_const(p, &attrs->call_conv) ||
    192         !toy_parser_expect(p, TOK_RPAREN)) {
    193       toy_error(p, p->cur.loc, "expected callconv attribute argument");
    194       return 0;
    195     }
    196     attrs->has_call_conv = 1;
    197     return 1;
    198   }
    199   if (toy_sym_is(p, name, "align")) {
    200     attrs->attr_kinds |= TOY_ATTR_OBJECT_DATA;
    201     if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    202     attrs->object.align = (uint32_t)int_arg;
    203     attrs->data.align = (uint32_t)int_arg;
    204     return 1;
    205   }
    206   if (toy_sym_is(p, name, "readonly")) {
    207     attrs->attr_kinds |= TOY_ATTR_OBJECT_DATA;
    208     attrs->object.flags |= KIT_CG_OBJ_READONLY;
    209     attrs->data.flags |= KIT_CG_DATADEF_READONLY;
    210     return 1;
    211   }
    212   if (toy_sym_is(p, name, "threadlocal")) {
    213     attrs->attr_kinds |= TOY_ATTR_OBJECT;
    214     attrs->object.flags |= KIT_CG_OBJ_TLS;
    215     return 1;
    216   }
    217   if (toy_sym_is(p, name, "tls_model")) {
    218     attrs->attr_kinds |= TOY_ATTR_OBJECT;
    219     if (!toy_parse_attr_dot_arg(p, &arg)) return 0;
    220     if (toy_sym_is(p, arg, "auto"))
    221       attrs->object.tls_model = KIT_CG_TLS_AUTO;
    222     else if (toy_sym_is(p, arg, "local_exec"))
    223       attrs->object.tls_model = KIT_CG_TLS_LOCAL_EXEC;
    224     else if (toy_sym_is(p, arg, "initial_exec"))
    225       attrs->object.tls_model = KIT_CG_TLS_INITIAL_EXEC;
    226     else if (toy_sym_is(p, arg, "local_dynamic"))
    227       attrs->object.tls_model = KIT_CG_TLS_LOCAL_DYNAMIC;
    228     else if (toy_sym_is(p, arg, "general_dynamic"))
    229       attrs->object.tls_model = KIT_CG_TLS_GENERAL_DYNAMIC;
    230     else {
    231       toy_error(p, p->cur.loc, "unknown tls_model attribute");
    232       return 0;
    233     }
    234     return 1;
    235   }
    236   if (toy_sym_is(p, name, "static")) {
    237     attrs->attr_kinds |= TOY_ATTR_OBJECT;
    238     attrs->has_static = 1;
    239     return 1;
    240   }
    241   if (toy_sym_is(p, name, "common")) {
    242     attrs->attr_kinds |= TOY_ATTR_OBJECT;
    243     attrs->is_common = 1;
    244     return 1;
    245   }
    246   if (toy_sym_is(p, name, "retain")) {
    247     attrs->attr_kinds |= TOY_ATTR_DATA;
    248     attrs->data.flags |= KIT_CG_DATADEF_RETAIN;
    249     return 1;
    250   }
    251   if (toy_sym_is(p, name, "merge")) {
    252     attrs->attr_kinds |= TOY_ATTR_DATA;
    253     attrs->data.flags |= KIT_CG_DATADEF_MERGE;
    254     return 1;
    255   }
    256   if (toy_sym_is(p, name, "strings")) {
    257     attrs->attr_kinds |= TOY_ATTR_DATA;
    258     attrs->data.flags |= KIT_CG_DATADEF_STRINGS;
    259     return 1;
    260   }
    261   if (toy_sym_is(p, name, "entsize")) {
    262     attrs->attr_kinds |= TOY_ATTR_DATA;
    263     if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    264     attrs->data.entsize = (uint32_t)int_arg;
    265     return 1;
    266   }
    267 
    268   toy_error(p, p->cur.loc, "unknown attribute");
    269   return 0;
    270 }
    271 
    272 int toy_parse_attr_list(ToyParser* p, ToyAttrSet* attrs,
    273                         KitSymBind default_bind) {
    274   toy_attr_set_init(attrs, default_bind);
    275   if (!toy_parser_match(p, TOK_AT)) return 1;
    276   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    277     toy_error(p, p->cur.loc, "expected '[' after '@'");
    278     return 0;
    279   }
    280   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    281     if (!toy_parse_attr_one(p, attrs)) return 0;
    282     if (!toy_parser_match(p, TOK_COMMA)) break;
    283   }
    284   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    285     toy_error(p, p->cur.loc, "expected ']' after attribute list");
    286     return 0;
    287   }
    288   return 1;
    289 }
    290 
    291 int toy_validate_attr_placement(ToyParser* p, const ToyAttrSet* attrs,
    292                                 uint32_t allowed, const char* message) {
    293   if (attrs->attr_kinds & ~allowed) {
    294     toy_error(p, p->cur.loc, message);
    295     return 0;
    296   }
    297   return 1;
    298 }
    299 
    300 static int toy_parse_abi_attr_one(ToyParser* p, KitCgAbiAttrs* attrs) {
    301   KitSym name;
    302   int64_t int_arg;
    303   if (!toy_parse_attr_dot_name(p, &name)) return 0;
    304   if (toy_sym_is(p, name, "signext"))
    305     attrs->flags |= KIT_CG_ABI_SIGNEXT;
    306   else if (toy_sym_is(p, name, "zeroext"))
    307     attrs->flags |= KIT_CG_ABI_ZEROEXT;
    308   else if (toy_sym_is(p, name, "sret"))
    309     attrs->flags |= KIT_CG_ABI_SRET;
    310   else if (toy_sym_is(p, name, "byval"))
    311     attrs->flags |= KIT_CG_ABI_BYVAL;
    312   else if (toy_sym_is(p, name, "byref"))
    313     attrs->flags |= KIT_CG_ABI_BYREF;
    314   else if (toy_sym_is(p, name, "inreg"))
    315     attrs->flags |= KIT_CG_ABI_INREG;
    316   else if (toy_sym_is(p, name, "noalias"))
    317     attrs->flags |= KIT_CG_ABI_NOALIAS;
    318   else if (toy_sym_is(p, name, "readonly"))
    319     attrs->flags |= KIT_CG_ABI_READONLY;
    320   else if (toy_sym_is(p, name, "writeonly"))
    321     attrs->flags |= KIT_CG_ABI_WRITEONLY;
    322   else if (toy_sym_is(p, name, "nonnull"))
    323     attrs->flags |= KIT_CG_ABI_NONNULL;
    324   else if (toy_sym_is(p, name, "nest"))
    325     attrs->flags |= KIT_CG_ABI_NEST;
    326   else if (toy_sym_is(p, name, "align")) {
    327     if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    328     attrs->align = (uint32_t)int_arg;
    329   } else if (toy_sym_is(p, name, "dereferenceable")) {
    330     if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    331     attrs->dereferenceable_size = (uint64_t)int_arg;
    332   } else {
    333     toy_error(p, p->cur.loc, "unknown ABI attribute");
    334     return 0;
    335   }
    336   return 1;
    337 }
    338 
    339 int toy_parse_abi_attr_list(ToyParser* p, KitCgAbiAttrs* attrs) {
    340   memset(attrs, 0, sizeof *attrs);
    341   if (!toy_parser_match(p, TOK_AT)) return 1;
    342   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    343     toy_error(p, p->cur.loc, "expected '[' after '@'");
    344     return 0;
    345   }
    346   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    347     if (!toy_parse_abi_attr_one(p, attrs)) return 0;
    348     if (!toy_parser_match(p, TOK_COMMA)) break;
    349   }
    350   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    351     toy_error(p, p->cur.loc, "expected ']' after ABI attribute list");
    352     return 0;
    353   }
    354   return 1;
    355 }
    356 
    357 int toy_parse_field_attr_list(ToyParser* p, KitCgField* field) {
    358   if (!toy_parser_match(p, TOK_AT)) return 1;
    359   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    360     toy_error(p, p->cur.loc, "expected '[' after '@'");
    361     return 0;
    362   }
    363   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    364     KitSym name;
    365     int64_t int_arg;
    366     if (!toy_parse_attr_dot_name(p, &name)) return 0;
    367     if (toy_sym_is(p, name, "align")) {
    368       if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    369       field->align_override = (uint32_t)int_arg;
    370     } else if (toy_sym_is(p, name, "packed")) {
    371       field->align_override = 1;
    372     } else {
    373       toy_error(p, p->cur.loc, "unknown field attribute");
    374       return 0;
    375     }
    376     if (!toy_parser_match(p, TOK_COMMA)) break;
    377   }
    378   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    379     toy_error(p, p->cur.loc, "expected ']' after field attribute list");
    380     return 0;
    381   }
    382   return 1;
    383 }
    384 
    385 int toy_parse_record_attr_list(ToyParser* p, int* packed_out,
    386                                uint32_t* align_out) {
    387   *packed_out = 0;
    388   *align_out = 0;
    389   if (!toy_parser_match(p, TOK_AT)) return 1;
    390   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    391     toy_error(p, p->cur.loc, "expected '[' after '@'");
    392     return 0;
    393   }
    394   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    395     KitSym name;
    396     int64_t int_arg;
    397     if (!toy_parse_attr_dot_name(p, &name)) return 0;
    398     if (toy_sym_is(p, name, "packed")) {
    399       *packed_out = 1;
    400     } else if (toy_sym_is(p, name, "align")) {
    401       if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0;
    402       *align_out = (uint32_t)int_arg;
    403     } else {
    404       toy_error(p, p->cur.loc, "unknown record attribute");
    405       return 0;
    406     }
    407     if (!toy_parser_match(p, TOK_COMMA)) break;
    408   }
    409   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    410     toy_error(p, p->cur.loc, "expected ']' after record attribute list");
    411     return 0;
    412   }
    413   return 1;
    414 }