kit

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

opt_12_small_aggregate_arg_spill.c (7513B)


      1 /* Non-power-of-two ABI aggregate parts must move only their semantic bytes.
      2  * A widened register spill may overlap an adjacent frame slot; a narrowed
      3  * transfer silently drops the tail. Three, five, six, and seven bytes cover
      4  * every non-power-of-two integer-carrier width and the 32-bit lane boundary. */
      5 typedef struct TinyOptions {
      6   unsigned char packed;
      7   unsigned short max_align;
      8   unsigned short align_override;
      9 } TinyOptions;
     10 
     11 typedef struct TinyThree {
     12   unsigned char first;
     13   unsigned char second;
     14   unsigned char third;
     15 } TinyThree;
     16 
     17 typedef struct TinyFive {
     18   unsigned char first;
     19   unsigned char second;
     20   unsigned char third;
     21   unsigned char fourth;
     22   unsigned char fifth;
     23 } TinyFive;
     24 
     25 typedef struct TinySeven {
     26   unsigned char first;
     27   unsigned char second;
     28   unsigned char third;
     29   unsigned char fourth;
     30   unsigned char fifth;
     31   unsigned char sixth;
     32   unsigned char seventh;
     33 } TinySeven;
     34 
     35 typedef struct Builder {
     36   void* pool;
     37   unsigned kind;
     38   unsigned tag;
     39   unsigned symbol;
     40   TinyOptions opts;
     41   TinyThree three;
     42   TinyFive five;
     43   TinySeven seven;
     44 } Builder;
     45 
     46 __attribute__((noinline)) static void barrier(Builder* b) {
     47   volatile unsigned* p = &b->kind;
     48   *p = *p;
     49 }
     50 
     51 __attribute__((noinline)) static Builder* begin(Builder* b, unsigned kind,
     52                                                 unsigned tag, unsigned symbol,
     53                                                 TinyOptions opts) {
     54   barrier(b);
     55   b->pool = b;
     56   b->kind = kind;
     57   b->tag = tag;
     58   b->symbol = symbol;
     59   b->opts = opts;
     60   return b;
     61 }
     62 
     63 __attribute__((noinline)) static Builder* begin_three(Builder* b,
     64                                                       unsigned kind,
     65                                                       unsigned tag,
     66                                                       unsigned symbol,
     67                                                       TinyThree three) {
     68   barrier(b);
     69   b->pool = b;
     70   b->kind = kind;
     71   b->tag = tag;
     72   b->symbol = symbol;
     73   b->three = three;
     74   return b;
     75 }
     76 
     77 __attribute__((noinline)) static Builder* begin_five(Builder* b, unsigned kind,
     78                                                      unsigned tag,
     79                                                      unsigned symbol,
     80                                                      TinyFive five) {
     81   barrier(b);
     82   b->pool = b;
     83   b->kind = kind;
     84   b->tag = tag;
     85   b->symbol = symbol;
     86   b->five = five;
     87   return b;
     88 }
     89 
     90 __attribute__((noinline)) static Builder* begin_seven(Builder* b,
     91                                                       unsigned kind,
     92                                                       unsigned tag,
     93                                                       unsigned symbol,
     94                                                       TinySeven seven) {
     95   barrier(b);
     96   b->pool = b;
     97   b->kind = kind;
     98   b->tag = tag;
     99   b->symbol = symbol;
    100   b->seven = seven;
    101   return b;
    102 }
    103 
    104 /* Returning a short aggregate exercises the call-plan write phase as well as
    105  * its incoming argument bind. On 64-bit targets the pointer input and integer
    106  * return carrier can alias; on ARM32 a three-byte tail has an I32 carrier. Both
    107  * cases must retain the semantic width through the complete return move. */
    108 __attribute__((noinline)) static TinyOptions load_options(
    109     const TinyOptions* opts) {
    110   return *opts;
    111 }
    112 
    113 __attribute__((noinline)) static TinyThree load_three(const TinyThree* three) {
    114   return *three;
    115 }
    116 
    117 __attribute__((noinline)) static TinyFive load_five(const TinyFive* five) {
    118   return *five;
    119 }
    120 
    121 __attribute__((noinline)) static TinySeven load_seven(const TinySeven* seven) {
    122   return *seven;
    123 }
    124 
    125 __attribute__((noinline)) static int exercise(Builder* b, unsigned kind,
    126                                                unsigned tag, unsigned symbol,
    127                                                int* sentinel) {
    128   TinyOptions opts = {1, 0x2345, 0x6789};
    129   TinyOptions returned = load_options(&opts);
    130   Builder* out = begin(b, kind, tag, symbol, opts);
    131   return out == b && out->kind == kind && out->tag == tag &&
    132          out->symbol == symbol && out->opts.packed == opts.packed &&
    133          out->opts.max_align == opts.max_align &&
    134          out->opts.align_override == opts.align_override &&
    135          returned.packed == opts.packed &&
    136          returned.max_align == opts.max_align &&
    137          returned.align_override == opts.align_override && *sentinel == 42;
    138 }
    139 
    140 __attribute__((noinline)) static int exercise_three(Builder* b, unsigned kind,
    141                                                      unsigned tag,
    142                                                      unsigned symbol,
    143                                                      int* sentinel) {
    144   TinyThree three = {0x12, 0x34, 0x56};
    145   TinyThree returned = load_three(&three);
    146   Builder* out = begin_three(b, kind, tag, symbol, three);
    147   return out == b && out->kind == kind && out->tag == tag &&
    148          out->symbol == symbol && out->three.first == three.first &&
    149          out->three.second == three.second && out->three.third == three.third &&
    150          returned.first == three.first && returned.second == three.second &&
    151          returned.third == three.third &&
    152          *sentinel == 42;
    153 }
    154 
    155 __attribute__((noinline)) static int exercise_five(Builder* b, unsigned kind,
    156                                                     unsigned tag,
    157                                                     unsigned symbol,
    158                                                     int* sentinel) {
    159   TinyFive five = {0x10, 0x20, 0x30, 0x40, 0x50};
    160   TinyFive returned = load_five(&five);
    161   Builder* out = begin_five(b, kind, tag, symbol, five);
    162   return out == b && out->kind == kind && out->tag == tag &&
    163          out->symbol == symbol && out->five.first == five.first &&
    164          out->five.second == five.second && out->five.third == five.third &&
    165          out->five.fourth == five.fourth && out->five.fifth == five.fifth &&
    166          returned.first == five.first && returned.second == five.second &&
    167          returned.third == five.third && returned.fourth == five.fourth &&
    168          returned.fifth == five.fifth && *sentinel == 42;
    169 }
    170 
    171 __attribute__((noinline)) static int exercise_seven(Builder* b, unsigned kind,
    172                                                      unsigned tag,
    173                                                      unsigned symbol,
    174                                                      int* sentinel) {
    175   TinySeven seven = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
    176   TinySeven returned = load_seven(&seven);
    177   Builder* out = begin_seven(b, kind, tag, symbol, seven);
    178   return out == b && out->kind == kind && out->tag == tag &&
    179          out->symbol == symbol && out->seven.first == seven.first &&
    180          out->seven.second == seven.second &&
    181          out->seven.third == seven.third &&
    182          out->seven.fourth == seven.fourth &&
    183          out->seven.fifth == seven.fifth && out->seven.sixth == seven.sixth &&
    184          out->seven.seventh == seven.seventh &&
    185          returned.first == seven.first && returned.second == seven.second &&
    186          returned.third == seven.third && returned.fourth == seven.fourth &&
    187          returned.fifth == seven.fifth && returned.sixth == seven.sixth &&
    188          returned.seventh == seven.seventh && *sentinel == 42;
    189 }
    190 
    191 int test_main(void) {
    192   Builder b = {0};
    193   int sentinel = 42;
    194   if (!exercise(&b, 11, 22, 33, &sentinel)) return 1;
    195   if (!exercise_three(&b, 44, 55, 66, &sentinel)) return 2;
    196   if (!exercise_five(&b, 77, 88, 99, &sentinel)) return 3;
    197   return exercise_seven(&b, 111, 122, 133, &sentinel) ? 0 : 4;
    198 }