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 }