kit

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

attrs.c (13228B)


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