1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Example of how to write a compiler with sparse 3f08c3bdfSopenharmony_ci */ 4f08c3bdfSopenharmony_ci#include <stdio.h> 5f08c3bdfSopenharmony_ci#include <stdlib.h> 6f08c3bdfSopenharmony_ci#include <stdarg.h> 7f08c3bdfSopenharmony_ci#include <string.h> 8f08c3bdfSopenharmony_ci#include <assert.h> 9f08c3bdfSopenharmony_ci 10f08c3bdfSopenharmony_ci#include "symbol.h" 11f08c3bdfSopenharmony_ci#include "expression.h" 12f08c3bdfSopenharmony_ci#include "linearize.h" 13f08c3bdfSopenharmony_ci#include "flow.h" 14f08c3bdfSopenharmony_ci#include "storage.h" 15f08c3bdfSopenharmony_ci#include "target.h" 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_cistatic const char *opcodes[] = { 18f08c3bdfSopenharmony_ci [OP_BADOP] = "bad_op", 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci /* Fn entrypoint */ 21f08c3bdfSopenharmony_ci [OP_ENTRY] = "<entry-point>", 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci /* Terminator */ 24f08c3bdfSopenharmony_ci [OP_RET] = "ret", 25f08c3bdfSopenharmony_ci [OP_BR] = "br", 26f08c3bdfSopenharmony_ci [OP_CBR] = "cbr", 27f08c3bdfSopenharmony_ci [OP_SWITCH] = "switch", 28f08c3bdfSopenharmony_ci [OP_COMPUTEDGOTO] = "jmp *", 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci /* Binary */ 31f08c3bdfSopenharmony_ci [OP_ADD] = "add", 32f08c3bdfSopenharmony_ci [OP_SUB] = "sub", 33f08c3bdfSopenharmony_ci [OP_MUL] = "mul", 34f08c3bdfSopenharmony_ci [OP_DIVU] = "divu", 35f08c3bdfSopenharmony_ci [OP_DIVS] = "divs", 36f08c3bdfSopenharmony_ci [OP_MODU] = "modu", 37f08c3bdfSopenharmony_ci [OP_MODS] = "mods", 38f08c3bdfSopenharmony_ci [OP_SHL] = "shl", 39f08c3bdfSopenharmony_ci [OP_LSR] = "lsr", 40f08c3bdfSopenharmony_ci [OP_ASR] = "asr", 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci /* Logical */ 43f08c3bdfSopenharmony_ci [OP_AND] = "and", 44f08c3bdfSopenharmony_ci [OP_OR] = "or", 45f08c3bdfSopenharmony_ci [OP_XOR] = "xor", 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci /* Binary comparison */ 48f08c3bdfSopenharmony_ci [OP_SET_EQ] = "seteq", 49f08c3bdfSopenharmony_ci [OP_SET_NE] = "setne", 50f08c3bdfSopenharmony_ci [OP_SET_LE] = "setle", 51f08c3bdfSopenharmony_ci [OP_SET_GE] = "setge", 52f08c3bdfSopenharmony_ci [OP_SET_LT] = "setlt", 53f08c3bdfSopenharmony_ci [OP_SET_GT] = "setgt", 54f08c3bdfSopenharmony_ci [OP_SET_B] = "setb", 55f08c3bdfSopenharmony_ci [OP_SET_A] = "seta", 56f08c3bdfSopenharmony_ci [OP_SET_BE] = "setbe", 57f08c3bdfSopenharmony_ci [OP_SET_AE] = "setae", 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci /* Uni */ 60f08c3bdfSopenharmony_ci [OP_NOT] = "not", 61f08c3bdfSopenharmony_ci [OP_NEG] = "neg", 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci /* Special three-input */ 64f08c3bdfSopenharmony_ci [OP_SEL] = "select", 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci /* Memory */ 67f08c3bdfSopenharmony_ci [OP_LOAD] = "load", 68f08c3bdfSopenharmony_ci [OP_STORE] = "store", 69f08c3bdfSopenharmony_ci [OP_LABEL] = "label", 70f08c3bdfSopenharmony_ci [OP_SETVAL] = "set", 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci /* Other */ 73f08c3bdfSopenharmony_ci [OP_PHI] = "phi", 74f08c3bdfSopenharmony_ci [OP_PHISOURCE] = "phisrc", 75f08c3bdfSopenharmony_ci [OP_COPY] = "copy", 76f08c3bdfSopenharmony_ci [OP_SEXT] = "sext", 77f08c3bdfSopenharmony_ci [OP_ZEXT] = "zext", 78f08c3bdfSopenharmony_ci [OP_TRUNC] = "trunc", 79f08c3bdfSopenharmony_ci [OP_FCVTU] = "fcvtu", 80f08c3bdfSopenharmony_ci [OP_FCVTS] = "fcvts", 81f08c3bdfSopenharmony_ci [OP_UCVTF] = "ucvtf", 82f08c3bdfSopenharmony_ci [OP_SCVTF] = "scvtf", 83f08c3bdfSopenharmony_ci [OP_FCVTF] = "fcvtf", 84f08c3bdfSopenharmony_ci [OP_UTPTR] = "utptr", 85f08c3bdfSopenharmony_ci [OP_PTRTU] = "utptr", 86f08c3bdfSopenharmony_ci [OP_PTRCAST] = "ptrcast", 87f08c3bdfSopenharmony_ci [OP_CALL] = "call", 88f08c3bdfSopenharmony_ci [OP_SLICE] = "slice", 89f08c3bdfSopenharmony_ci [OP_NOP] = "nop", 90f08c3bdfSopenharmony_ci [OP_DEATHNOTE] = "dead", 91f08c3bdfSopenharmony_ci [OP_ASM] = "asm", 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci /* Sparse tagging (line numbers, context, whatever) */ 94f08c3bdfSopenharmony_ci [OP_CONTEXT] = "context", 95f08c3bdfSopenharmony_ci}; 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_cistatic int last_reg, stack_offset; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistruct hardreg { 100f08c3bdfSopenharmony_ci const char *name; 101f08c3bdfSopenharmony_ci struct pseudo_list *contains; 102f08c3bdfSopenharmony_ci unsigned busy:16, 103f08c3bdfSopenharmony_ci dead:8, 104f08c3bdfSopenharmony_ci used:1; 105f08c3bdfSopenharmony_ci}; 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci#define TAG_DEAD 1 108f08c3bdfSopenharmony_ci#define TAG_DIRTY 2 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci/* Our "switch" generation is very very stupid. */ 111f08c3bdfSopenharmony_ci#define SWITCH_REG (1) 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_cistatic void output_bb(struct basic_block *bb, unsigned long generation); 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci/* 116f08c3bdfSopenharmony_ci * We only know about the caller-clobbered registers 117f08c3bdfSopenharmony_ci * right now. 118f08c3bdfSopenharmony_ci */ 119f08c3bdfSopenharmony_cistatic struct hardreg hardregs[] = { 120f08c3bdfSopenharmony_ci { .name = "%eax" }, 121f08c3bdfSopenharmony_ci { .name = "%edx" }, 122f08c3bdfSopenharmony_ci { .name = "%ecx" }, 123f08c3bdfSopenharmony_ci { .name = "%ebx" }, 124f08c3bdfSopenharmony_ci { .name = "%esi" }, 125f08c3bdfSopenharmony_ci { .name = "%edi" }, 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci { .name = "%ebp" }, 128f08c3bdfSopenharmony_ci { .name = "%esp" }, 129f08c3bdfSopenharmony_ci}; 130f08c3bdfSopenharmony_ci#define REGNO 6 131f08c3bdfSopenharmony_ci#define REG_EBP 6 132f08c3bdfSopenharmony_ci#define REG_ESP 7 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_cistruct bb_state { 135f08c3bdfSopenharmony_ci struct position pos; 136f08c3bdfSopenharmony_ci struct storage_hash_list *inputs; 137f08c3bdfSopenharmony_ci struct storage_hash_list *outputs; 138f08c3bdfSopenharmony_ci struct storage_hash_list *internal; 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci /* CC cache.. */ 141f08c3bdfSopenharmony_ci int cc_opcode, cc_dead; 142f08c3bdfSopenharmony_ci pseudo_t cc_target; 143f08c3bdfSopenharmony_ci}; 144f08c3bdfSopenharmony_ci 145f08c3bdfSopenharmony_cienum optype { 146f08c3bdfSopenharmony_ci OP_UNDEF, 147f08c3bdfSopenharmony_ci OP_REG, 148f08c3bdfSopenharmony_ci OP_VAL, 149f08c3bdfSopenharmony_ci OP_MEM, 150f08c3bdfSopenharmony_ci OP_ADDR, 151f08c3bdfSopenharmony_ci}; 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_cistruct operand { 154f08c3bdfSopenharmony_ci enum optype type; 155f08c3bdfSopenharmony_ci int size; 156f08c3bdfSopenharmony_ci union { 157f08c3bdfSopenharmony_ci struct hardreg *reg; 158f08c3bdfSopenharmony_ci long long value; 159f08c3bdfSopenharmony_ci struct /* OP_MEM and OP_ADDR */ { 160f08c3bdfSopenharmony_ci unsigned int offset; 161f08c3bdfSopenharmony_ci unsigned int scale; 162f08c3bdfSopenharmony_ci struct symbol *sym; 163f08c3bdfSopenharmony_ci struct hardreg *base; 164f08c3bdfSopenharmony_ci struct hardreg *index; 165f08c3bdfSopenharmony_ci }; 166f08c3bdfSopenharmony_ci }; 167f08c3bdfSopenharmony_ci}; 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_cistatic const char *show_op(struct bb_state *state, struct operand *op) 170f08c3bdfSopenharmony_ci{ 171f08c3bdfSopenharmony_ci static char buf[256][4]; 172f08c3bdfSopenharmony_ci static int bufnr; 173f08c3bdfSopenharmony_ci char *p, *ret; 174f08c3bdfSopenharmony_ci int nr; 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci nr = (bufnr + 1) & 3; 177f08c3bdfSopenharmony_ci bufnr = nr; 178f08c3bdfSopenharmony_ci ret = p = buf[nr]; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci switch (op->type) { 181f08c3bdfSopenharmony_ci case OP_UNDEF: 182f08c3bdfSopenharmony_ci return "undef"; 183f08c3bdfSopenharmony_ci case OP_REG: 184f08c3bdfSopenharmony_ci return op->reg->name; 185f08c3bdfSopenharmony_ci case OP_VAL: 186f08c3bdfSopenharmony_ci sprintf(p, "$%lld", op->value); 187f08c3bdfSopenharmony_ci break; 188f08c3bdfSopenharmony_ci case OP_MEM: 189f08c3bdfSopenharmony_ci case OP_ADDR: 190f08c3bdfSopenharmony_ci if (op->offset) 191f08c3bdfSopenharmony_ci p += sprintf(p, "%d", op->offset); 192f08c3bdfSopenharmony_ci if (op->sym) 193f08c3bdfSopenharmony_ci p += sprintf(p, "%s%s", 194f08c3bdfSopenharmony_ci op->offset ? "+" : "", 195f08c3bdfSopenharmony_ci show_ident(op->sym->ident)); 196f08c3bdfSopenharmony_ci if (op->base || op->index) { 197f08c3bdfSopenharmony_ci p += sprintf(p, "(%s%s%s", 198f08c3bdfSopenharmony_ci op->base ? op->base->name : "", 199f08c3bdfSopenharmony_ci (op->base && op->index) ? "," : "", 200f08c3bdfSopenharmony_ci op->index ? op->index->name : ""); 201f08c3bdfSopenharmony_ci if (op->scale > 1) 202f08c3bdfSopenharmony_ci p += sprintf(p, ",%d", op->scale); 203f08c3bdfSopenharmony_ci *p++ = ')'; 204f08c3bdfSopenharmony_ci *p = '\0'; 205f08c3bdfSopenharmony_ci } 206f08c3bdfSopenharmony_ci break; 207f08c3bdfSopenharmony_ci } 208f08c3bdfSopenharmony_ci return ret; 209f08c3bdfSopenharmony_ci} 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_cistatic struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list) 212f08c3bdfSopenharmony_ci{ 213f08c3bdfSopenharmony_ci struct storage_hash *entry; 214f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, entry) { 215f08c3bdfSopenharmony_ci if (entry->pseudo == pseudo) 216f08c3bdfSopenharmony_ci return entry; 217f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 218f08c3bdfSopenharmony_ci return NULL; 219f08c3bdfSopenharmony_ci} 220f08c3bdfSopenharmony_ci 221f08c3bdfSopenharmony_cistatic struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp) 222f08c3bdfSopenharmony_ci{ 223f08c3bdfSopenharmony_ci struct storage_hash *entry; 224f08c3bdfSopenharmony_ci 225f08c3bdfSopenharmony_ci entry = find_storage_hash(pseudo, *listp); 226f08c3bdfSopenharmony_ci if (!entry) { 227f08c3bdfSopenharmony_ci entry = alloc_storage_hash(alloc_storage()); 228f08c3bdfSopenharmony_ci entry->pseudo = pseudo; 229f08c3bdfSopenharmony_ci add_ptr_list(listp, entry); 230f08c3bdfSopenharmony_ci } 231f08c3bdfSopenharmony_ci return entry; 232f08c3bdfSopenharmony_ci} 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci/* Eventually we should just build it up in memory */ 235f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_line(struct bb_state *state, const char *fmt, ...) 236f08c3bdfSopenharmony_ci{ 237f08c3bdfSopenharmony_ci va_list args; 238f08c3bdfSopenharmony_ci 239f08c3bdfSopenharmony_ci va_start(args, fmt); 240f08c3bdfSopenharmony_ci vprintf(fmt, args); 241f08c3bdfSopenharmony_ci va_end(args); 242f08c3bdfSopenharmony_ci} 243f08c3bdfSopenharmony_ci 244f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_label(struct bb_state *state, const char *fmt, ...) 245f08c3bdfSopenharmony_ci{ 246f08c3bdfSopenharmony_ci static char buffer[512]; 247f08c3bdfSopenharmony_ci va_list args; 248f08c3bdfSopenharmony_ci 249f08c3bdfSopenharmony_ci va_start(args, fmt); 250f08c3bdfSopenharmony_ci vsnprintf(buffer, sizeof(buffer), fmt, args); 251f08c3bdfSopenharmony_ci va_end(args); 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci output_line(state, "%s:\n", buffer); 254f08c3bdfSopenharmony_ci} 255f08c3bdfSopenharmony_ci 256f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_insn(struct bb_state *state, const char *fmt, ...) 257f08c3bdfSopenharmony_ci{ 258f08c3bdfSopenharmony_ci static char buffer[512]; 259f08c3bdfSopenharmony_ci va_list args; 260f08c3bdfSopenharmony_ci 261f08c3bdfSopenharmony_ci va_start(args, fmt); 262f08c3bdfSopenharmony_ci vsnprintf(buffer, sizeof(buffer), fmt, args); 263f08c3bdfSopenharmony_ci va_end(args); 264f08c3bdfSopenharmony_ci 265f08c3bdfSopenharmony_ci output_line(state, "\t%s\n", buffer); 266f08c3bdfSopenharmony_ci} 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci#define output_insn(state, fmt, arg...) \ 269f08c3bdfSopenharmony_ci output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__) 270f08c3bdfSopenharmony_ci 271f08c3bdfSopenharmony_cistatic void FORMAT_ATTR(2) output_comment(struct bb_state *state, const char *fmt, ...) 272f08c3bdfSopenharmony_ci{ 273f08c3bdfSopenharmony_ci static char buffer[512]; 274f08c3bdfSopenharmony_ci va_list args; 275f08c3bdfSopenharmony_ci 276f08c3bdfSopenharmony_ci if (!verbose) 277f08c3bdfSopenharmony_ci return; 278f08c3bdfSopenharmony_ci va_start(args, fmt); 279f08c3bdfSopenharmony_ci vsnprintf(buffer, sizeof(buffer), fmt, args); 280f08c3bdfSopenharmony_ci va_end(args); 281f08c3bdfSopenharmony_ci 282f08c3bdfSopenharmony_ci output_line(state, "\t# %s\n", buffer); 283f08c3bdfSopenharmony_ci} 284f08c3bdfSopenharmony_ci 285f08c3bdfSopenharmony_cistatic const char *show_memop(struct storage *storage) 286f08c3bdfSopenharmony_ci{ 287f08c3bdfSopenharmony_ci static char buffer[1000]; 288f08c3bdfSopenharmony_ci 289f08c3bdfSopenharmony_ci if (!storage) 290f08c3bdfSopenharmony_ci return "undef"; 291f08c3bdfSopenharmony_ci switch (storage->type) { 292f08c3bdfSopenharmony_ci case REG_FRAME: 293f08c3bdfSopenharmony_ci sprintf(buffer, "%d(FP)", storage->offset); 294f08c3bdfSopenharmony_ci break; 295f08c3bdfSopenharmony_ci case REG_STACK: 296f08c3bdfSopenharmony_ci sprintf(buffer, "%d(SP)", storage->offset); 297f08c3bdfSopenharmony_ci break; 298f08c3bdfSopenharmony_ci case REG_REG: 299f08c3bdfSopenharmony_ci return hardregs[storage->regno].name; 300f08c3bdfSopenharmony_ci default: 301f08c3bdfSopenharmony_ci return show_storage(storage); 302f08c3bdfSopenharmony_ci } 303f08c3bdfSopenharmony_ci return buffer; 304f08c3bdfSopenharmony_ci} 305f08c3bdfSopenharmony_ci 306f08c3bdfSopenharmony_cistatic int alloc_stack_offset(int size) 307f08c3bdfSopenharmony_ci{ 308f08c3bdfSopenharmony_ci int ret = stack_offset; 309f08c3bdfSopenharmony_ci stack_offset = ret + size; 310f08c3bdfSopenharmony_ci return ret; 311f08c3bdfSopenharmony_ci} 312f08c3bdfSopenharmony_ci 313f08c3bdfSopenharmony_cistatic void alloc_stack(struct bb_state *state, struct storage *storage) 314f08c3bdfSopenharmony_ci{ 315f08c3bdfSopenharmony_ci storage->type = REG_STACK; 316f08c3bdfSopenharmony_ci storage->offset = alloc_stack_offset(4); 317f08c3bdfSopenharmony_ci} 318f08c3bdfSopenharmony_ci 319f08c3bdfSopenharmony_ci/* 320f08c3bdfSopenharmony_ci * Can we re-generate the pseudo, so that we don't need to 321f08c3bdfSopenharmony_ci * flush it to memory? We can regenerate: 322f08c3bdfSopenharmony_ci * - immediates and symbol addresses 323f08c3bdfSopenharmony_ci * - pseudos we got as input in non-registers 324f08c3bdfSopenharmony_ci * - pseudos we've already saved off earlier.. 325f08c3bdfSopenharmony_ci */ 326f08c3bdfSopenharmony_cistatic int can_regenerate(struct bb_state *state, pseudo_t pseudo) 327f08c3bdfSopenharmony_ci{ 328f08c3bdfSopenharmony_ci struct storage_hash *in; 329f08c3bdfSopenharmony_ci 330f08c3bdfSopenharmony_ci switch (pseudo->type) { 331f08c3bdfSopenharmony_ci case PSEUDO_VAL: 332f08c3bdfSopenharmony_ci case PSEUDO_SYM: 333f08c3bdfSopenharmony_ci return 1; 334f08c3bdfSopenharmony_ci 335f08c3bdfSopenharmony_ci default: 336f08c3bdfSopenharmony_ci in = find_storage_hash(pseudo, state->inputs); 337f08c3bdfSopenharmony_ci if (in && in->storage->type != REG_REG) 338f08c3bdfSopenharmony_ci return 1; 339f08c3bdfSopenharmony_ci in = find_storage_hash(pseudo, state->internal); 340f08c3bdfSopenharmony_ci if (in) 341f08c3bdfSopenharmony_ci return 1; 342f08c3bdfSopenharmony_ci } 343f08c3bdfSopenharmony_ci return 0; 344f08c3bdfSopenharmony_ci} 345f08c3bdfSopenharmony_ci 346f08c3bdfSopenharmony_cistatic void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo) 347f08c3bdfSopenharmony_ci{ 348f08c3bdfSopenharmony_ci struct storage_hash *out; 349f08c3bdfSopenharmony_ci struct storage *storage; 350f08c3bdfSopenharmony_ci 351f08c3bdfSopenharmony_ci if (can_regenerate(state, pseudo)) 352f08c3bdfSopenharmony_ci return; 353f08c3bdfSopenharmony_ci 354f08c3bdfSopenharmony_ci output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name); 355f08c3bdfSopenharmony_ci out = find_storage_hash(pseudo, state->internal); 356f08c3bdfSopenharmony_ci if (!out) { 357f08c3bdfSopenharmony_ci out = find_storage_hash(pseudo, state->outputs); 358f08c3bdfSopenharmony_ci if (!out) 359f08c3bdfSopenharmony_ci out = find_or_create_hash(pseudo, &state->internal); 360f08c3bdfSopenharmony_ci } 361f08c3bdfSopenharmony_ci storage = out->storage; 362f08c3bdfSopenharmony_ci switch (storage->type) { 363f08c3bdfSopenharmony_ci default: 364f08c3bdfSopenharmony_ci /* 365f08c3bdfSopenharmony_ci * Aieee - the next user wants it in a register, but we 366f08c3bdfSopenharmony_ci * need to flush it to memory in between. Which means that 367f08c3bdfSopenharmony_ci * we need to allocate an internal one, dammit.. 368f08c3bdfSopenharmony_ci */ 369f08c3bdfSopenharmony_ci out = find_or_create_hash(pseudo, &state->internal); 370f08c3bdfSopenharmony_ci storage = out->storage; 371f08c3bdfSopenharmony_ci /* Fall through */ 372f08c3bdfSopenharmony_ci case REG_UDEF: 373f08c3bdfSopenharmony_ci alloc_stack(state, storage); 374f08c3bdfSopenharmony_ci /* Fall through */ 375f08c3bdfSopenharmony_ci case REG_STACK: 376f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage)); 377f08c3bdfSopenharmony_ci break; 378f08c3bdfSopenharmony_ci } 379f08c3bdfSopenharmony_ci} 380f08c3bdfSopenharmony_ci 381f08c3bdfSopenharmony_ci/* Flush a hardreg out to the storage it has.. */ 382f08c3bdfSopenharmony_cistatic void flush_reg(struct bb_state *state, struct hardreg *reg) 383f08c3bdfSopenharmony_ci{ 384f08c3bdfSopenharmony_ci pseudo_t pseudo; 385f08c3bdfSopenharmony_ci 386f08c3bdfSopenharmony_ci if (reg->busy) 387f08c3bdfSopenharmony_ci output_comment(state, "reg %s flushed while busy is %d!", reg->name, reg->busy); 388f08c3bdfSopenharmony_ci if (!reg->contains) 389f08c3bdfSopenharmony_ci return; 390f08c3bdfSopenharmony_ci reg->dead = 0; 391f08c3bdfSopenharmony_ci reg->used = 1; 392f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, pseudo) { 393f08c3bdfSopenharmony_ci if (CURRENT_TAG(pseudo) & TAG_DEAD) 394f08c3bdfSopenharmony_ci continue; 395f08c3bdfSopenharmony_ci if (!(CURRENT_TAG(pseudo) & TAG_DIRTY)) 396f08c3bdfSopenharmony_ci continue; 397f08c3bdfSopenharmony_ci flush_one_pseudo(state, reg, pseudo); 398f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(pseudo); 399f08c3bdfSopenharmony_ci free_ptr_list(®->contains); 400f08c3bdfSopenharmony_ci} 401f08c3bdfSopenharmony_ci 402f08c3bdfSopenharmony_cistatic struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 403f08c3bdfSopenharmony_ci{ 404f08c3bdfSopenharmony_ci struct storage_hash *src; 405f08c3bdfSopenharmony_ci 406f08c3bdfSopenharmony_ci src = find_storage_hash(pseudo, state->internal); 407f08c3bdfSopenharmony_ci if (!src) { 408f08c3bdfSopenharmony_ci src = find_storage_hash(pseudo, state->inputs); 409f08c3bdfSopenharmony_ci if (!src) { 410f08c3bdfSopenharmony_ci src = find_storage_hash(pseudo, state->outputs); 411f08c3bdfSopenharmony_ci /* Undefined? Screw it! */ 412f08c3bdfSopenharmony_ci if (!src) 413f08c3bdfSopenharmony_ci return NULL; 414f08c3bdfSopenharmony_ci 415f08c3bdfSopenharmony_ci /* 416f08c3bdfSopenharmony_ci * If we found output storage, it had better be local stack 417f08c3bdfSopenharmony_ci * that we flushed to earlier.. 418f08c3bdfSopenharmony_ci */ 419f08c3bdfSopenharmony_ci if (src->storage->type != REG_STACK) 420f08c3bdfSopenharmony_ci return NULL; 421f08c3bdfSopenharmony_ci } 422f08c3bdfSopenharmony_ci } 423f08c3bdfSopenharmony_ci 424f08c3bdfSopenharmony_ci /* 425f08c3bdfSopenharmony_ci * Incoming pseudo with out any pre-set storage allocation? 426f08c3bdfSopenharmony_ci * We can make up our own, and obviously prefer to get it 427f08c3bdfSopenharmony_ci * in the register we already selected (if it hasn't been 428f08c3bdfSopenharmony_ci * used yet). 429f08c3bdfSopenharmony_ci */ 430f08c3bdfSopenharmony_ci if (src->storage->type == REG_UDEF) { 431f08c3bdfSopenharmony_ci if (reg && !reg->used) { 432f08c3bdfSopenharmony_ci src->storage->type = REG_REG; 433f08c3bdfSopenharmony_ci src->storage->regno = reg - hardregs; 434f08c3bdfSopenharmony_ci return NULL; 435f08c3bdfSopenharmony_ci } 436f08c3bdfSopenharmony_ci alloc_stack(state, src->storage); 437f08c3bdfSopenharmony_ci } 438f08c3bdfSopenharmony_ci return src; 439f08c3bdfSopenharmony_ci} 440f08c3bdfSopenharmony_ci 441f08c3bdfSopenharmony_cistatic void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 442f08c3bdfSopenharmony_ci{ 443f08c3bdfSopenharmony_ci pseudo_t p; 444f08c3bdfSopenharmony_ci 445f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 446f08c3bdfSopenharmony_ci if (p != pseudo) 447f08c3bdfSopenharmony_ci continue; 448f08c3bdfSopenharmony_ci if (CURRENT_TAG(p) & TAG_DEAD) 449f08c3bdfSopenharmony_ci continue; 450f08c3bdfSopenharmony_ci output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name); 451f08c3bdfSopenharmony_ci TAG_CURRENT(p, TAG_DEAD); 452f08c3bdfSopenharmony_ci reg->dead++; 453f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 454f08c3bdfSopenharmony_ci} 455f08c3bdfSopenharmony_ci 456f08c3bdfSopenharmony_cistatic void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 457f08c3bdfSopenharmony_ci{ 458f08c3bdfSopenharmony_ci output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name); 459f08c3bdfSopenharmony_ci add_ptr_list_tag(®->contains, pseudo, TAG_DIRTY); 460f08c3bdfSopenharmony_ci} 461f08c3bdfSopenharmony_ci 462f08c3bdfSopenharmony_cistatic struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target) 463f08c3bdfSopenharmony_ci{ 464f08c3bdfSopenharmony_ci struct storage_hash *dst; 465f08c3bdfSopenharmony_ci 466f08c3bdfSopenharmony_ci dst = find_storage_hash(target, state->outputs); 467f08c3bdfSopenharmony_ci if (dst) { 468f08c3bdfSopenharmony_ci struct storage *storage = dst->storage; 469f08c3bdfSopenharmony_ci if (storage->type == REG_REG) 470f08c3bdfSopenharmony_ci return hardregs + storage->regno; 471f08c3bdfSopenharmony_ci } 472f08c3bdfSopenharmony_ci return NULL; 473f08c3bdfSopenharmony_ci} 474f08c3bdfSopenharmony_ci 475f08c3bdfSopenharmony_cistatic struct hardreg *empty_reg(struct bb_state *state) 476f08c3bdfSopenharmony_ci{ 477f08c3bdfSopenharmony_ci int i; 478f08c3bdfSopenharmony_ci struct hardreg *reg = hardregs; 479f08c3bdfSopenharmony_ci 480f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++, reg++) { 481f08c3bdfSopenharmony_ci if (!reg->contains) 482f08c3bdfSopenharmony_ci return reg; 483f08c3bdfSopenharmony_ci } 484f08c3bdfSopenharmony_ci return NULL; 485f08c3bdfSopenharmony_ci} 486f08c3bdfSopenharmony_ci 487f08c3bdfSopenharmony_cistatic struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target) 488f08c3bdfSopenharmony_ci{ 489f08c3bdfSopenharmony_ci int i; 490f08c3bdfSopenharmony_ci int unable_to_find_reg = 0; 491f08c3bdfSopenharmony_ci struct hardreg *reg; 492f08c3bdfSopenharmony_ci 493f08c3bdfSopenharmony_ci /* First, see if we have a preferred target register.. */ 494f08c3bdfSopenharmony_ci reg = preferred_reg(state, target); 495f08c3bdfSopenharmony_ci if (reg && !reg->contains) 496f08c3bdfSopenharmony_ci goto found; 497f08c3bdfSopenharmony_ci 498f08c3bdfSopenharmony_ci reg = empty_reg(state); 499f08c3bdfSopenharmony_ci if (reg) 500f08c3bdfSopenharmony_ci goto found; 501f08c3bdfSopenharmony_ci 502f08c3bdfSopenharmony_ci i = last_reg; 503f08c3bdfSopenharmony_ci do { 504f08c3bdfSopenharmony_ci i++; 505f08c3bdfSopenharmony_ci if (i >= REGNO) 506f08c3bdfSopenharmony_ci i = 0; 507f08c3bdfSopenharmony_ci reg = hardregs + i; 508f08c3bdfSopenharmony_ci if (!reg->busy) { 509f08c3bdfSopenharmony_ci flush_reg(state, reg); 510f08c3bdfSopenharmony_ci last_reg = i; 511f08c3bdfSopenharmony_ci goto found; 512f08c3bdfSopenharmony_ci } 513f08c3bdfSopenharmony_ci } while (i != last_reg); 514f08c3bdfSopenharmony_ci assert(unable_to_find_reg); 515f08c3bdfSopenharmony_ci 516f08c3bdfSopenharmony_cifound: 517f08c3bdfSopenharmony_ci add_pseudo_reg(state, pseudo, reg); 518f08c3bdfSopenharmony_ci return reg; 519f08c3bdfSopenharmony_ci} 520f08c3bdfSopenharmony_ci 521f08c3bdfSopenharmony_cistatic struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo) 522f08c3bdfSopenharmony_ci{ 523f08c3bdfSopenharmony_ci int i; 524f08c3bdfSopenharmony_ci struct hardreg *reg; 525f08c3bdfSopenharmony_ci 526f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 527f08c3bdfSopenharmony_ci pseudo_t p; 528f08c3bdfSopenharmony_ci 529f08c3bdfSopenharmony_ci reg = hardregs + i; 530f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 531f08c3bdfSopenharmony_ci if (p == pseudo) { 532f08c3bdfSopenharmony_ci last_reg = i; 533f08c3bdfSopenharmony_ci output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy); 534f08c3bdfSopenharmony_ci return reg; 535f08c3bdfSopenharmony_ci } 536f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 537f08c3bdfSopenharmony_ci } 538f08c3bdfSopenharmony_ci return NULL; 539f08c3bdfSopenharmony_ci} 540f08c3bdfSopenharmony_ci 541f08c3bdfSopenharmony_cistatic void flush_pseudo(struct bb_state *state, pseudo_t pseudo, struct storage *storage) 542f08c3bdfSopenharmony_ci{ 543f08c3bdfSopenharmony_ci struct hardreg *reg = find_in_reg(state, pseudo); 544f08c3bdfSopenharmony_ci 545f08c3bdfSopenharmony_ci if (reg) 546f08c3bdfSopenharmony_ci flush_reg(state, reg); 547f08c3bdfSopenharmony_ci} 548f08c3bdfSopenharmony_ci 549f08c3bdfSopenharmony_cistatic void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 550f08c3bdfSopenharmony_ci{ 551f08c3bdfSopenharmony_ci int opcode = state->cc_opcode; 552f08c3bdfSopenharmony_ci 553f08c3bdfSopenharmony_ci state->cc_opcode = 0; 554f08c3bdfSopenharmony_ci state->cc_target = NULL; 555f08c3bdfSopenharmony_ci output_insn(state, "%s %s", opcodes[opcode], reg->name); 556f08c3bdfSopenharmony_ci} 557f08c3bdfSopenharmony_ci 558f08c3bdfSopenharmony_cistatic void flush_cc_cache(struct bb_state *state) 559f08c3bdfSopenharmony_ci{ 560f08c3bdfSopenharmony_ci pseudo_t pseudo = state->cc_target; 561f08c3bdfSopenharmony_ci 562f08c3bdfSopenharmony_ci if (pseudo) { 563f08c3bdfSopenharmony_ci struct hardreg *dst; 564f08c3bdfSopenharmony_ci 565f08c3bdfSopenharmony_ci state->cc_target = NULL; 566f08c3bdfSopenharmony_ci 567f08c3bdfSopenharmony_ci if (!state->cc_dead) { 568f08c3bdfSopenharmony_ci dst = target_reg(state, pseudo, pseudo); 569f08c3bdfSopenharmony_ci flush_cc_cache_to_reg(state, pseudo, dst); 570f08c3bdfSopenharmony_ci } 571f08c3bdfSopenharmony_ci } 572f08c3bdfSopenharmony_ci} 573f08c3bdfSopenharmony_ci 574f08c3bdfSopenharmony_cistatic void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo) 575f08c3bdfSopenharmony_ci{ 576f08c3bdfSopenharmony_ci assert(!state->cc_target); 577f08c3bdfSopenharmony_ci state->cc_target = pseudo; 578f08c3bdfSopenharmony_ci state->cc_opcode = opcode; 579f08c3bdfSopenharmony_ci state->cc_dead = 0; 580f08c3bdfSopenharmony_ci output_comment(state, "caching %s", opcodes[opcode]); 581f08c3bdfSopenharmony_ci} 582f08c3bdfSopenharmony_ci 583f08c3bdfSopenharmony_ci/* Fill a hardreg with the pseudo it has */ 584f08c3bdfSopenharmony_cistatic struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo) 585f08c3bdfSopenharmony_ci{ 586f08c3bdfSopenharmony_ci struct storage_hash *src; 587f08c3bdfSopenharmony_ci struct instruction *def; 588f08c3bdfSopenharmony_ci 589f08c3bdfSopenharmony_ci if (state->cc_target == pseudo) { 590f08c3bdfSopenharmony_ci flush_cc_cache_to_reg(state, pseudo, hardreg); 591f08c3bdfSopenharmony_ci return hardreg; 592f08c3bdfSopenharmony_ci } 593f08c3bdfSopenharmony_ci 594f08c3bdfSopenharmony_ci switch (pseudo->type) { 595f08c3bdfSopenharmony_ci case PSEUDO_VAL: 596f08c3bdfSopenharmony_ci output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name); 597f08c3bdfSopenharmony_ci break; 598f08c3bdfSopenharmony_ci case PSEUDO_SYM: 599f08c3bdfSopenharmony_ci src = find_pseudo_storage(state, pseudo, NULL); 600f08c3bdfSopenharmony_ci /* Static thing? */ 601f08c3bdfSopenharmony_ci if (!src) { 602f08c3bdfSopenharmony_ci output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name); 603f08c3bdfSopenharmony_ci break; 604f08c3bdfSopenharmony_ci } 605f08c3bdfSopenharmony_ci switch (src->storage->type) { 606f08c3bdfSopenharmony_ci case REG_REG: 607f08c3bdfSopenharmony_ci /* Aiaiaiaiaii! Need to flush it to temporary memory */ 608f08c3bdfSopenharmony_ci src = find_or_create_hash(pseudo, &state->internal); 609f08c3bdfSopenharmony_ci /* Fall through */ 610f08c3bdfSopenharmony_ci default: 611f08c3bdfSopenharmony_ci alloc_stack(state, src->storage); 612f08c3bdfSopenharmony_ci /* Fall through */ 613f08c3bdfSopenharmony_ci case REG_STACK: 614f08c3bdfSopenharmony_ci case REG_FRAME: 615f08c3bdfSopenharmony_ci flush_pseudo(state, pseudo, src->storage); 616f08c3bdfSopenharmony_ci output_insn(state, "leal %s,%s", show_memop(src->storage), hardreg->name); 617f08c3bdfSopenharmony_ci break; 618f08c3bdfSopenharmony_ci } 619f08c3bdfSopenharmony_ci break; 620f08c3bdfSopenharmony_ci case PSEUDO_ARG: 621f08c3bdfSopenharmony_ci case PSEUDO_REG: 622f08c3bdfSopenharmony_ci def = pseudo->def; 623f08c3bdfSopenharmony_ci if (def && (def->opcode == OP_SETVAL || def->opcode == OP_LABEL)) { 624f08c3bdfSopenharmony_ci output_insn(state, "movl $<%s>,%s", show_pseudo(def->target), hardreg->name); 625f08c3bdfSopenharmony_ci break; 626f08c3bdfSopenharmony_ci } 627f08c3bdfSopenharmony_ci src = find_pseudo_storage(state, pseudo, hardreg); 628f08c3bdfSopenharmony_ci if (!src) 629f08c3bdfSopenharmony_ci break; 630f08c3bdfSopenharmony_ci if (src->flags & TAG_DEAD) 631f08c3bdfSopenharmony_ci mark_reg_dead(state, pseudo, hardreg); 632f08c3bdfSopenharmony_ci output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name); 633f08c3bdfSopenharmony_ci break; 634f08c3bdfSopenharmony_ci default: 635f08c3bdfSopenharmony_ci output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo)); 636f08c3bdfSopenharmony_ci break; 637f08c3bdfSopenharmony_ci } 638f08c3bdfSopenharmony_ci return hardreg; 639f08c3bdfSopenharmony_ci} 640f08c3bdfSopenharmony_ci 641f08c3bdfSopenharmony_cistatic struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target) 642f08c3bdfSopenharmony_ci{ 643f08c3bdfSopenharmony_ci struct hardreg *reg; 644f08c3bdfSopenharmony_ci 645f08c3bdfSopenharmony_ci reg = find_in_reg(state, pseudo); 646f08c3bdfSopenharmony_ci if (reg) 647f08c3bdfSopenharmony_ci return reg; 648f08c3bdfSopenharmony_ci reg = target_reg(state, pseudo, target); 649f08c3bdfSopenharmony_ci return fill_reg(state, reg, pseudo); 650f08c3bdfSopenharmony_ci} 651f08c3bdfSopenharmony_ci 652f08c3bdfSopenharmony_cistatic void move_reg(struct bb_state *state, struct hardreg *src, struct hardreg *dst) 653f08c3bdfSopenharmony_ci{ 654f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", src->name, dst->name); 655f08c3bdfSopenharmony_ci} 656f08c3bdfSopenharmony_ci 657f08c3bdfSopenharmony_cistatic struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target) 658f08c3bdfSopenharmony_ci{ 659f08c3bdfSopenharmony_ci int i; 660f08c3bdfSopenharmony_ci struct hardreg *reg; 661f08c3bdfSopenharmony_ci 662f08c3bdfSopenharmony_ci /* If the container has been killed off, just re-use it */ 663f08c3bdfSopenharmony_ci if (!src->contains) 664f08c3bdfSopenharmony_ci return src; 665f08c3bdfSopenharmony_ci 666f08c3bdfSopenharmony_ci /* If "src" only has one user, and the contents are dead, we can re-use it */ 667f08c3bdfSopenharmony_ci if (src->busy == 1 && src->dead == 1) 668f08c3bdfSopenharmony_ci return src; 669f08c3bdfSopenharmony_ci 670f08c3bdfSopenharmony_ci reg = preferred_reg(state, target); 671f08c3bdfSopenharmony_ci if (reg && !reg->contains) { 672f08c3bdfSopenharmony_ci output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name); 673f08c3bdfSopenharmony_ci move_reg(state, src, reg); 674f08c3bdfSopenharmony_ci return reg; 675f08c3bdfSopenharmony_ci } 676f08c3bdfSopenharmony_ci 677f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 678f08c3bdfSopenharmony_ci reg = hardregs + i; 679f08c3bdfSopenharmony_ci if (!reg->contains) { 680f08c3bdfSopenharmony_ci output_comment(state, "copying %s to %s", show_pseudo(target), reg->name); 681f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", src->name, reg->name); 682f08c3bdfSopenharmony_ci return reg; 683f08c3bdfSopenharmony_ci } 684f08c3bdfSopenharmony_ci } 685f08c3bdfSopenharmony_ci 686f08c3bdfSopenharmony_ci flush_reg(state, src); 687f08c3bdfSopenharmony_ci return src; 688f08c3bdfSopenharmony_ci} 689f08c3bdfSopenharmony_ci 690f08c3bdfSopenharmony_cistatic void put_operand(struct bb_state *state, struct operand *op) 691f08c3bdfSopenharmony_ci{ 692f08c3bdfSopenharmony_ci switch (op->type) { 693f08c3bdfSopenharmony_ci case OP_REG: 694f08c3bdfSopenharmony_ci op->reg->busy--; 695f08c3bdfSopenharmony_ci break; 696f08c3bdfSopenharmony_ci case OP_ADDR: 697f08c3bdfSopenharmony_ci case OP_MEM: 698f08c3bdfSopenharmony_ci if (op->base) 699f08c3bdfSopenharmony_ci op->base->busy--; 700f08c3bdfSopenharmony_ci if (op->index) 701f08c3bdfSopenharmony_ci op->index->busy--; 702f08c3bdfSopenharmony_ci break; 703f08c3bdfSopenharmony_ci default: 704f08c3bdfSopenharmony_ci break; 705f08c3bdfSopenharmony_ci } 706f08c3bdfSopenharmony_ci} 707f08c3bdfSopenharmony_ci 708f08c3bdfSopenharmony_cistatic struct operand *alloc_op(void) 709f08c3bdfSopenharmony_ci{ 710f08c3bdfSopenharmony_ci struct operand *op = malloc(sizeof(*op)); 711f08c3bdfSopenharmony_ci memset(op, 0, sizeof(*op)); 712f08c3bdfSopenharmony_ci return op; 713f08c3bdfSopenharmony_ci} 714f08c3bdfSopenharmony_ci 715f08c3bdfSopenharmony_cistatic struct operand *get_register_operand(struct bb_state *state, pseudo_t pseudo, pseudo_t target) 716f08c3bdfSopenharmony_ci{ 717f08c3bdfSopenharmony_ci struct operand *op = alloc_op(); 718f08c3bdfSopenharmony_ci op->type = OP_REG; 719f08c3bdfSopenharmony_ci op->reg = getreg(state, pseudo, target); 720f08c3bdfSopenharmony_ci op->reg->busy++; 721f08c3bdfSopenharmony_ci return op; 722f08c3bdfSopenharmony_ci} 723f08c3bdfSopenharmony_ci 724f08c3bdfSopenharmony_cistatic int get_sym_frame_offset(struct bb_state *state, pseudo_t pseudo) 725f08c3bdfSopenharmony_ci{ 726f08c3bdfSopenharmony_ci int offset = pseudo->nr; 727f08c3bdfSopenharmony_ci if (offset < 0) { 728f08c3bdfSopenharmony_ci offset = alloc_stack_offset(4); 729f08c3bdfSopenharmony_ci pseudo->nr = offset; 730f08c3bdfSopenharmony_ci } 731f08c3bdfSopenharmony_ci return offset; 732f08c3bdfSopenharmony_ci} 733f08c3bdfSopenharmony_ci 734f08c3bdfSopenharmony_cistatic struct operand *get_generic_operand(struct bb_state *state, pseudo_t pseudo) 735f08c3bdfSopenharmony_ci{ 736f08c3bdfSopenharmony_ci struct hardreg *reg; 737f08c3bdfSopenharmony_ci struct storage *src; 738f08c3bdfSopenharmony_ci struct storage_hash *hash; 739f08c3bdfSopenharmony_ci struct operand *op = malloc(sizeof(*op)); 740f08c3bdfSopenharmony_ci 741f08c3bdfSopenharmony_ci memset(op, 0, sizeof(*op)); 742f08c3bdfSopenharmony_ci switch (pseudo->type) { 743f08c3bdfSopenharmony_ci case PSEUDO_VAL: 744f08c3bdfSopenharmony_ci op->type = OP_VAL; 745f08c3bdfSopenharmony_ci op->value = pseudo->value; 746f08c3bdfSopenharmony_ci break; 747f08c3bdfSopenharmony_ci 748f08c3bdfSopenharmony_ci case PSEUDO_SYM: { 749f08c3bdfSopenharmony_ci struct symbol *sym = pseudo->sym; 750f08c3bdfSopenharmony_ci op->type = OP_ADDR; 751f08c3bdfSopenharmony_ci if (sym->ctype.modifiers & MOD_NONLOCAL) { 752f08c3bdfSopenharmony_ci op->sym = sym; 753f08c3bdfSopenharmony_ci break; 754f08c3bdfSopenharmony_ci } 755f08c3bdfSopenharmony_ci op->base = hardregs + REG_EBP; 756f08c3bdfSopenharmony_ci op->offset = get_sym_frame_offset(state, pseudo); 757f08c3bdfSopenharmony_ci break; 758f08c3bdfSopenharmony_ci } 759f08c3bdfSopenharmony_ci 760f08c3bdfSopenharmony_ci default: 761f08c3bdfSopenharmony_ci reg = find_in_reg(state, pseudo); 762f08c3bdfSopenharmony_ci if (reg) { 763f08c3bdfSopenharmony_ci op->type = OP_REG; 764f08c3bdfSopenharmony_ci op->reg = reg; 765f08c3bdfSopenharmony_ci reg->busy++; 766f08c3bdfSopenharmony_ci break; 767f08c3bdfSopenharmony_ci } 768f08c3bdfSopenharmony_ci hash = find_pseudo_storage(state, pseudo, NULL); 769f08c3bdfSopenharmony_ci if (!hash) 770f08c3bdfSopenharmony_ci break; 771f08c3bdfSopenharmony_ci src = hash->storage; 772f08c3bdfSopenharmony_ci switch (src->type) { 773f08c3bdfSopenharmony_ci case REG_REG: 774f08c3bdfSopenharmony_ci op->type = OP_REG; 775f08c3bdfSopenharmony_ci op->reg = hardregs + src->regno; 776f08c3bdfSopenharmony_ci op->reg->busy++; 777f08c3bdfSopenharmony_ci break; 778f08c3bdfSopenharmony_ci case REG_FRAME: 779f08c3bdfSopenharmony_ci op->type = OP_MEM; 780f08c3bdfSopenharmony_ci op->offset = src->offset; 781f08c3bdfSopenharmony_ci op->base = hardregs + REG_EBP; 782f08c3bdfSopenharmony_ci break; 783f08c3bdfSopenharmony_ci case REG_STACK: 784f08c3bdfSopenharmony_ci op->type = OP_MEM; 785f08c3bdfSopenharmony_ci op->offset = src->offset; 786f08c3bdfSopenharmony_ci op->base = hardregs + REG_ESP; 787f08c3bdfSopenharmony_ci break; 788f08c3bdfSopenharmony_ci default: 789f08c3bdfSopenharmony_ci break; 790f08c3bdfSopenharmony_ci } 791f08c3bdfSopenharmony_ci } 792f08c3bdfSopenharmony_ci return op; 793f08c3bdfSopenharmony_ci} 794f08c3bdfSopenharmony_ci 795f08c3bdfSopenharmony_ci/* Callers should be made to use the proper "operand" formats */ 796f08c3bdfSopenharmony_cistatic const char *generic(struct bb_state *state, pseudo_t pseudo) 797f08c3bdfSopenharmony_ci{ 798f08c3bdfSopenharmony_ci struct hardreg *reg; 799f08c3bdfSopenharmony_ci struct operand *op = get_generic_operand(state, pseudo); 800f08c3bdfSopenharmony_ci static char buf[100]; 801f08c3bdfSopenharmony_ci const char *str; 802f08c3bdfSopenharmony_ci 803f08c3bdfSopenharmony_ci switch (op->type) { 804f08c3bdfSopenharmony_ci case OP_ADDR: 805f08c3bdfSopenharmony_ci if (!op->offset && op->base && !op->sym) 806f08c3bdfSopenharmony_ci return op->base->name; 807f08c3bdfSopenharmony_ci if (op->sym && !op->base) { 808f08c3bdfSopenharmony_ci int len = sprintf(buf, "$ %s", show_op(state, op)); 809f08c3bdfSopenharmony_ci if (op->offset) 810f08c3bdfSopenharmony_ci sprintf(buf + len, " + %d", op->offset); 811f08c3bdfSopenharmony_ci return buf; 812f08c3bdfSopenharmony_ci } 813f08c3bdfSopenharmony_ci str = show_op(state, op); 814f08c3bdfSopenharmony_ci put_operand(state, op); 815f08c3bdfSopenharmony_ci reg = target_reg(state, pseudo, NULL); 816f08c3bdfSopenharmony_ci output_insn(state, "lea %s,%s", show_op(state, op), reg->name); 817f08c3bdfSopenharmony_ci return reg->name; 818f08c3bdfSopenharmony_ci 819f08c3bdfSopenharmony_ci default: 820f08c3bdfSopenharmony_ci str = show_op(state, op); 821f08c3bdfSopenharmony_ci } 822f08c3bdfSopenharmony_ci put_operand(state, op); 823f08c3bdfSopenharmony_ci return str; 824f08c3bdfSopenharmony_ci} 825f08c3bdfSopenharmony_ci 826f08c3bdfSopenharmony_cistatic struct operand *get_address_operand(struct bb_state *state, struct instruction *memop) 827f08c3bdfSopenharmony_ci{ 828f08c3bdfSopenharmony_ci struct hardreg *base; 829f08c3bdfSopenharmony_ci struct operand *op = get_generic_operand(state, memop->src); 830f08c3bdfSopenharmony_ci 831f08c3bdfSopenharmony_ci switch (op->type) { 832f08c3bdfSopenharmony_ci case OP_ADDR: 833f08c3bdfSopenharmony_ci op->offset += memop->offset; 834f08c3bdfSopenharmony_ci break; 835f08c3bdfSopenharmony_ci default: 836f08c3bdfSopenharmony_ci put_operand(state, op); 837f08c3bdfSopenharmony_ci base = getreg(state, memop->src, NULL); 838f08c3bdfSopenharmony_ci op->type = OP_ADDR; 839f08c3bdfSopenharmony_ci op->base = base; 840f08c3bdfSopenharmony_ci base->busy++; 841f08c3bdfSopenharmony_ci op->offset = memop->offset; 842f08c3bdfSopenharmony_ci op->sym = NULL; 843f08c3bdfSopenharmony_ci } 844f08c3bdfSopenharmony_ci return op; 845f08c3bdfSopenharmony_ci} 846f08c3bdfSopenharmony_ci 847f08c3bdfSopenharmony_cistatic const char *address(struct bb_state *state, struct instruction *memop) 848f08c3bdfSopenharmony_ci{ 849f08c3bdfSopenharmony_ci struct operand *op = get_address_operand(state, memop); 850f08c3bdfSopenharmony_ci const char *str = show_op(state, op); 851f08c3bdfSopenharmony_ci put_operand(state, op); 852f08c3bdfSopenharmony_ci return str; 853f08c3bdfSopenharmony_ci} 854f08c3bdfSopenharmony_ci 855f08c3bdfSopenharmony_cistatic const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo) 856f08c3bdfSopenharmony_ci{ 857f08c3bdfSopenharmony_ci switch(pseudo->type) { 858f08c3bdfSopenharmony_ci case PSEUDO_VAL: 859f08c3bdfSopenharmony_ci return show_pseudo(pseudo); 860f08c3bdfSopenharmony_ci default: 861f08c3bdfSopenharmony_ci return getreg(state, pseudo, NULL)->name; 862f08c3bdfSopenharmony_ci } 863f08c3bdfSopenharmony_ci} 864f08c3bdfSopenharmony_ci 865f08c3bdfSopenharmony_cistatic void kill_dead_reg(struct hardreg *reg) 866f08c3bdfSopenharmony_ci{ 867f08c3bdfSopenharmony_ci if (reg->dead) { 868f08c3bdfSopenharmony_ci pseudo_t p; 869f08c3bdfSopenharmony_ci 870f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 871f08c3bdfSopenharmony_ci if (CURRENT_TAG(p) & TAG_DEAD) { 872f08c3bdfSopenharmony_ci DELETE_CURRENT_PTR(p); 873f08c3bdfSopenharmony_ci reg->dead--; 874f08c3bdfSopenharmony_ci } 875f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 876f08c3bdfSopenharmony_ci PACK_PTR_LIST(®->contains); 877f08c3bdfSopenharmony_ci assert(!reg->dead); 878f08c3bdfSopenharmony_ci } 879f08c3bdfSopenharmony_ci} 880f08c3bdfSopenharmony_ci 881f08c3bdfSopenharmony_cistatic struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target) 882f08c3bdfSopenharmony_ci{ 883f08c3bdfSopenharmony_ci kill_dead_reg(src); 884f08c3bdfSopenharmony_ci return copy_reg(state, src, target); 885f08c3bdfSopenharmony_ci} 886f08c3bdfSopenharmony_ci 887f08c3bdfSopenharmony_cistatic void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2) 888f08c3bdfSopenharmony_ci{ 889f08c3bdfSopenharmony_ci const char *op = opcodes[insn->opcode]; 890f08c3bdfSopenharmony_ci struct operand *src = get_register_operand(state, val1, insn->target); 891f08c3bdfSopenharmony_ci struct operand *src2 = get_generic_operand(state, val2); 892f08c3bdfSopenharmony_ci struct hardreg *dst; 893f08c3bdfSopenharmony_ci 894f08c3bdfSopenharmony_ci dst = target_copy_reg(state, src->reg, insn->target); 895f08c3bdfSopenharmony_ci output_insn(state, "%s.%d %s,%s", op, insn->size, show_op(state, src2), dst->name); 896f08c3bdfSopenharmony_ci put_operand(state, src); 897f08c3bdfSopenharmony_ci put_operand(state, src2); 898f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, dst); 899f08c3bdfSopenharmony_ci} 900f08c3bdfSopenharmony_ci 901f08c3bdfSopenharmony_cistatic void generate_binop(struct bb_state *state, struct instruction *insn) 902f08c3bdfSopenharmony_ci{ 903f08c3bdfSopenharmony_ci flush_cc_cache(state); 904f08c3bdfSopenharmony_ci do_binop(state, insn, insn->src1, insn->src2); 905f08c3bdfSopenharmony_ci} 906f08c3bdfSopenharmony_ci 907f08c3bdfSopenharmony_cistatic int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 908f08c3bdfSopenharmony_ci{ 909f08c3bdfSopenharmony_ci pseudo_t p; 910f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 911f08c3bdfSopenharmony_ci if (p == pseudo) 912f08c3bdfSopenharmony_ci return CURRENT_TAG(p) & TAG_DEAD; 913f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 914f08c3bdfSopenharmony_ci return 0; 915f08c3bdfSopenharmony_ci} 916f08c3bdfSopenharmony_ci 917f08c3bdfSopenharmony_ci/* 918f08c3bdfSopenharmony_ci * Commutative binops are much more flexible, since we can switch the 919f08c3bdfSopenharmony_ci * sources around to satisfy the target register, or to avoid having 920f08c3bdfSopenharmony_ci * to load one of them into a register.. 921f08c3bdfSopenharmony_ci */ 922f08c3bdfSopenharmony_cistatic void generate_commutative_binop(struct bb_state *state, struct instruction *insn) 923f08c3bdfSopenharmony_ci{ 924f08c3bdfSopenharmony_ci pseudo_t src1, src2; 925f08c3bdfSopenharmony_ci struct hardreg *reg1, *reg2; 926f08c3bdfSopenharmony_ci 927f08c3bdfSopenharmony_ci flush_cc_cache(state); 928f08c3bdfSopenharmony_ci src1 = insn->src1; 929f08c3bdfSopenharmony_ci src2 = insn->src2; 930f08c3bdfSopenharmony_ci reg2 = find_in_reg(state, src2); 931f08c3bdfSopenharmony_ci if (!reg2) 932f08c3bdfSopenharmony_ci goto dont_switch; 933f08c3bdfSopenharmony_ci reg1 = find_in_reg(state, src1); 934f08c3bdfSopenharmony_ci if (!reg1) 935f08c3bdfSopenharmony_ci goto do_switch; 936f08c3bdfSopenharmony_ci if (!is_dead_reg(state, src2, reg2)) 937f08c3bdfSopenharmony_ci goto dont_switch; 938f08c3bdfSopenharmony_ci if (!is_dead_reg(state, src1, reg1)) 939f08c3bdfSopenharmony_ci goto do_switch; 940f08c3bdfSopenharmony_ci 941f08c3bdfSopenharmony_ci /* Both are dead. Is one preferable? */ 942f08c3bdfSopenharmony_ci if (reg2 != preferred_reg(state, insn->target)) 943f08c3bdfSopenharmony_ci goto dont_switch; 944f08c3bdfSopenharmony_ci 945f08c3bdfSopenharmony_cido_switch: 946f08c3bdfSopenharmony_ci src1 = src2; 947f08c3bdfSopenharmony_ci src2 = insn->src1; 948f08c3bdfSopenharmony_cidont_switch: 949f08c3bdfSopenharmony_ci do_binop(state, insn, src1, src2); 950f08c3bdfSopenharmony_ci} 951f08c3bdfSopenharmony_ci 952f08c3bdfSopenharmony_ci/* 953f08c3bdfSopenharmony_ci * This marks a pseudo dead. It still stays on the hardreg list (the hardreg 954f08c3bdfSopenharmony_ci * still has its value), but it's scheduled to be killed after the next 955f08c3bdfSopenharmony_ci * "sequence point" when we call "kill_read_pseudos()" 956f08c3bdfSopenharmony_ci */ 957f08c3bdfSopenharmony_cistatic void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo) 958f08c3bdfSopenharmony_ci{ 959f08c3bdfSopenharmony_ci int i; 960f08c3bdfSopenharmony_ci struct storage_hash *src; 961f08c3bdfSopenharmony_ci 962f08c3bdfSopenharmony_ci if (state->cc_target == pseudo) 963f08c3bdfSopenharmony_ci state->cc_dead = 1; 964f08c3bdfSopenharmony_ci src = find_pseudo_storage(state, pseudo, NULL); 965f08c3bdfSopenharmony_ci if (src) 966f08c3bdfSopenharmony_ci src->flags |= TAG_DEAD; 967f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) 968f08c3bdfSopenharmony_ci mark_reg_dead(state, pseudo, hardregs + i); 969f08c3bdfSopenharmony_ci} 970f08c3bdfSopenharmony_ci 971f08c3bdfSopenharmony_cistatic void kill_dead_pseudos(struct bb_state *state) 972f08c3bdfSopenharmony_ci{ 973f08c3bdfSopenharmony_ci int i; 974f08c3bdfSopenharmony_ci 975f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 976f08c3bdfSopenharmony_ci kill_dead_reg(hardregs + i); 977f08c3bdfSopenharmony_ci } 978f08c3bdfSopenharmony_ci} 979f08c3bdfSopenharmony_ci 980f08c3bdfSopenharmony_cistatic void generate_store(struct instruction *insn, struct bb_state *state) 981f08c3bdfSopenharmony_ci{ 982f08c3bdfSopenharmony_ci output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn)); 983f08c3bdfSopenharmony_ci} 984f08c3bdfSopenharmony_ci 985f08c3bdfSopenharmony_cistatic void generate_load(struct instruction *insn, struct bb_state *state) 986f08c3bdfSopenharmony_ci{ 987f08c3bdfSopenharmony_ci const char *input = address(state, insn); 988f08c3bdfSopenharmony_ci struct hardreg *dst; 989f08c3bdfSopenharmony_ci 990f08c3bdfSopenharmony_ci kill_dead_pseudos(state); 991f08c3bdfSopenharmony_ci dst = target_reg(state, insn->target, NULL); 992f08c3bdfSopenharmony_ci output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name); 993f08c3bdfSopenharmony_ci} 994f08c3bdfSopenharmony_ci 995f08c3bdfSopenharmony_cistatic void kill_pseudo(struct bb_state *state, pseudo_t pseudo) 996f08c3bdfSopenharmony_ci{ 997f08c3bdfSopenharmony_ci int i; 998f08c3bdfSopenharmony_ci struct hardreg *reg; 999f08c3bdfSopenharmony_ci 1000f08c3bdfSopenharmony_ci output_comment(state, "killing pseudo %s", show_pseudo(pseudo)); 1001f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 1002f08c3bdfSopenharmony_ci pseudo_t p; 1003f08c3bdfSopenharmony_ci 1004f08c3bdfSopenharmony_ci reg = hardregs + i; 1005f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 1006f08c3bdfSopenharmony_ci if (p != pseudo) 1007f08c3bdfSopenharmony_ci continue; 1008f08c3bdfSopenharmony_ci if (CURRENT_TAG(p) & TAG_DEAD) 1009f08c3bdfSopenharmony_ci reg->dead--; 1010f08c3bdfSopenharmony_ci output_comment(state, "removing pseudo %s from reg %s", 1011f08c3bdfSopenharmony_ci show_pseudo(pseudo), reg->name); 1012f08c3bdfSopenharmony_ci DELETE_CURRENT_PTR(p); 1013f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 1014f08c3bdfSopenharmony_ci PACK_PTR_LIST(®->contains); 1015f08c3bdfSopenharmony_ci } 1016f08c3bdfSopenharmony_ci} 1017f08c3bdfSopenharmony_ci 1018f08c3bdfSopenharmony_cistatic void generate_copy(struct bb_state *state, struct instruction *insn) 1019f08c3bdfSopenharmony_ci{ 1020f08c3bdfSopenharmony_ci struct hardreg *src = getreg(state, insn->src, insn->target); 1021f08c3bdfSopenharmony_ci kill_pseudo(state, insn->target); 1022f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, src); 1023f08c3bdfSopenharmony_ci} 1024f08c3bdfSopenharmony_ci 1025f08c3bdfSopenharmony_cistatic void generate_cast(struct bb_state *state, struct instruction *insn) 1026f08c3bdfSopenharmony_ci{ 1027f08c3bdfSopenharmony_ci struct hardreg *src = getreg(state, insn->src, insn->target); 1028f08c3bdfSopenharmony_ci struct hardreg *dst; 1029f08c3bdfSopenharmony_ci unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0; 1030f08c3bdfSopenharmony_ci unsigned int new = insn->size; 1031f08c3bdfSopenharmony_ci 1032f08c3bdfSopenharmony_ci /* 1033f08c3bdfSopenharmony_ci * Cast to smaller type? Ignore the high bits, we 1034f08c3bdfSopenharmony_ci * just keep both pseudos in the same register. 1035f08c3bdfSopenharmony_ci */ 1036f08c3bdfSopenharmony_ci if (old >= new) { 1037f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, src); 1038f08c3bdfSopenharmony_ci return; 1039f08c3bdfSopenharmony_ci } 1040f08c3bdfSopenharmony_ci 1041f08c3bdfSopenharmony_ci dst = target_copy_reg(state, src, insn->target); 1042f08c3bdfSopenharmony_ci 1043f08c3bdfSopenharmony_ci if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) { 1044f08c3bdfSopenharmony_ci output_insn(state, "sext.%d.%d %s", old, new, dst->name); 1045f08c3bdfSopenharmony_ci } else { 1046f08c3bdfSopenharmony_ci unsigned long long mask; 1047f08c3bdfSopenharmony_ci mask = ~(~0ULL << old); 1048f08c3bdfSopenharmony_ci mask &= ~(~0ULL << new); 1049f08c3bdfSopenharmony_ci output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name); 1050f08c3bdfSopenharmony_ci } 1051f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, dst); 1052f08c3bdfSopenharmony_ci} 1053f08c3bdfSopenharmony_ci 1054f08c3bdfSopenharmony_cistatic void generate_output_storage(struct bb_state *state); 1055f08c3bdfSopenharmony_ci 1056f08c3bdfSopenharmony_cistatic const char *conditional[] = { 1057f08c3bdfSopenharmony_ci [OP_SET_EQ] = "e", 1058f08c3bdfSopenharmony_ci [OP_SET_NE] = "ne", 1059f08c3bdfSopenharmony_ci [OP_SET_LE] = "le", 1060f08c3bdfSopenharmony_ci [OP_SET_GE] = "ge", 1061f08c3bdfSopenharmony_ci [OP_SET_LT] = "lt", 1062f08c3bdfSopenharmony_ci [OP_SET_GT] = "gt", 1063f08c3bdfSopenharmony_ci [OP_SET_B] = "b", 1064f08c3bdfSopenharmony_ci [OP_SET_A] = "a", 1065f08c3bdfSopenharmony_ci [OP_SET_BE] = "be", 1066f08c3bdfSopenharmony_ci [OP_SET_AE] = "ae" 1067f08c3bdfSopenharmony_ci}; 1068f08c3bdfSopenharmony_ci 1069f08c3bdfSopenharmony_ci 1070f08c3bdfSopenharmony_cistatic void generate_branch(struct bb_state *state, struct instruction *br) 1071f08c3bdfSopenharmony_ci{ 1072f08c3bdfSopenharmony_ci const char *cond = "XXX"; 1073f08c3bdfSopenharmony_ci struct basic_block *target; 1074f08c3bdfSopenharmony_ci 1075f08c3bdfSopenharmony_ci if (br->cond) { 1076f08c3bdfSopenharmony_ci if (state->cc_target == br->cond) { 1077f08c3bdfSopenharmony_ci cond = conditional[state->cc_opcode]; 1078f08c3bdfSopenharmony_ci } else { 1079f08c3bdfSopenharmony_ci struct hardreg *reg = getreg(state, br->cond, NULL); 1080f08c3bdfSopenharmony_ci output_insn(state, "testl %s,%s", reg->name, reg->name); 1081f08c3bdfSopenharmony_ci cond = "ne"; 1082f08c3bdfSopenharmony_ci } 1083f08c3bdfSopenharmony_ci } 1084f08c3bdfSopenharmony_ci generate_output_storage(state); 1085f08c3bdfSopenharmony_ci target = br->bb_true; 1086f08c3bdfSopenharmony_ci if (br->cond) { 1087f08c3bdfSopenharmony_ci output_insn(state, "j%s .L%p", cond, target); 1088f08c3bdfSopenharmony_ci target = br->bb_false; 1089f08c3bdfSopenharmony_ci } 1090f08c3bdfSopenharmony_ci output_insn(state, "jmp .L%p", target); 1091f08c3bdfSopenharmony_ci} 1092f08c3bdfSopenharmony_ci 1093f08c3bdfSopenharmony_ci/* We've made sure that there is a dummy reg live for the output */ 1094f08c3bdfSopenharmony_cistatic void generate_switch(struct bb_state *state, struct instruction *insn) 1095f08c3bdfSopenharmony_ci{ 1096f08c3bdfSopenharmony_ci struct hardreg *reg = hardregs + SWITCH_REG; 1097f08c3bdfSopenharmony_ci 1098f08c3bdfSopenharmony_ci generate_output_storage(state); 1099f08c3bdfSopenharmony_ci output_insn(state, "switch on %s", reg->name); 1100f08c3bdfSopenharmony_ci output_insn(state, "unimplemented: %s", show_instruction(insn)); 1101f08c3bdfSopenharmony_ci} 1102f08c3bdfSopenharmony_ci 1103f08c3bdfSopenharmony_cistatic void generate_ret(struct bb_state *state, struct instruction *ret) 1104f08c3bdfSopenharmony_ci{ 1105f08c3bdfSopenharmony_ci if (ret->src && ret->src != VOID) { 1106f08c3bdfSopenharmony_ci struct hardreg *wants = hardregs+0; 1107f08c3bdfSopenharmony_ci struct hardreg *reg = getreg(state, ret->src, NULL); 1108f08c3bdfSopenharmony_ci if (reg != wants) 1109f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, wants->name); 1110f08c3bdfSopenharmony_ci } 1111f08c3bdfSopenharmony_ci output_insn(state, "ret"); 1112f08c3bdfSopenharmony_ci} 1113f08c3bdfSopenharmony_ci 1114f08c3bdfSopenharmony_ci/* 1115f08c3bdfSopenharmony_ci * Fake "call" linearization just as a taster.. 1116f08c3bdfSopenharmony_ci */ 1117f08c3bdfSopenharmony_cistatic void generate_call(struct bb_state *state, struct instruction *insn) 1118f08c3bdfSopenharmony_ci{ 1119f08c3bdfSopenharmony_ci int offset = 0; 1120f08c3bdfSopenharmony_ci pseudo_t arg; 1121f08c3bdfSopenharmony_ci 1122f08c3bdfSopenharmony_ci FOR_EACH_PTR(insn->arguments, arg) { 1123f08c3bdfSopenharmony_ci output_insn(state, "pushl %s", generic(state, arg)); 1124f08c3bdfSopenharmony_ci offset += 4; 1125f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(arg); 1126f08c3bdfSopenharmony_ci flush_reg(state, hardregs+0); 1127f08c3bdfSopenharmony_ci flush_reg(state, hardregs+1); 1128f08c3bdfSopenharmony_ci flush_reg(state, hardregs+2); 1129f08c3bdfSopenharmony_ci output_insn(state, "call %s", show_pseudo(insn->func)); 1130f08c3bdfSopenharmony_ci if (offset) 1131f08c3bdfSopenharmony_ci output_insn(state, "addl $%d,%%esp", offset); 1132f08c3bdfSopenharmony_ci if (insn->target && insn->target != VOID) 1133f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, hardregs+0); 1134f08c3bdfSopenharmony_ci} 1135f08c3bdfSopenharmony_ci 1136f08c3bdfSopenharmony_cistatic void generate_select(struct bb_state *state, struct instruction *insn) 1137f08c3bdfSopenharmony_ci{ 1138f08c3bdfSopenharmony_ci const char *cond; 1139f08c3bdfSopenharmony_ci struct hardreg *src1, *src2, *dst; 1140f08c3bdfSopenharmony_ci 1141f08c3bdfSopenharmony_ci src1 = getreg(state, insn->src2, NULL); 1142f08c3bdfSopenharmony_ci dst = copy_reg(state, src1, insn->target); 1143f08c3bdfSopenharmony_ci add_pseudo_reg(state, insn->target, dst); 1144f08c3bdfSopenharmony_ci src2 = getreg(state, insn->src3, insn->target); 1145f08c3bdfSopenharmony_ci 1146f08c3bdfSopenharmony_ci if (state->cc_target == insn->src1) { 1147f08c3bdfSopenharmony_ci cond = conditional[state->cc_opcode]; 1148f08c3bdfSopenharmony_ci } else { 1149f08c3bdfSopenharmony_ci struct hardreg *reg = getreg(state, insn->src1, NULL); 1150f08c3bdfSopenharmony_ci output_insn(state, "testl %s,%s", reg->name, reg->name); 1151f08c3bdfSopenharmony_ci cond = "ne"; 1152f08c3bdfSopenharmony_ci } 1153f08c3bdfSopenharmony_ci 1154f08c3bdfSopenharmony_ci output_insn(state, "sel%s %s,%s", cond, src2->name, dst->name); 1155f08c3bdfSopenharmony_ci} 1156f08c3bdfSopenharmony_ci 1157f08c3bdfSopenharmony_cistruct asm_arg { 1158f08c3bdfSopenharmony_ci const struct ident *name; 1159f08c3bdfSopenharmony_ci const char *value; 1160f08c3bdfSopenharmony_ci pseudo_t pseudo; 1161f08c3bdfSopenharmony_ci struct hardreg *reg; 1162f08c3bdfSopenharmony_ci}; 1163f08c3bdfSopenharmony_ci 1164f08c3bdfSopenharmony_cistatic void replace_asm_arg(char **dst_p, struct asm_arg *arg) 1165f08c3bdfSopenharmony_ci{ 1166f08c3bdfSopenharmony_ci char *dst = *dst_p; 1167f08c3bdfSopenharmony_ci int len = strlen(arg->value); 1168f08c3bdfSopenharmony_ci 1169f08c3bdfSopenharmony_ci memcpy(dst, arg->value, len); 1170f08c3bdfSopenharmony_ci *dst_p = dst + len; 1171f08c3bdfSopenharmony_ci} 1172f08c3bdfSopenharmony_ci 1173f08c3bdfSopenharmony_cistatic void replace_asm_percent(const char **src_p, char **dst_p, struct asm_arg *args, int nr) 1174f08c3bdfSopenharmony_ci{ 1175f08c3bdfSopenharmony_ci const char *src = *src_p; 1176f08c3bdfSopenharmony_ci char c; 1177f08c3bdfSopenharmony_ci int index; 1178f08c3bdfSopenharmony_ci 1179f08c3bdfSopenharmony_ci c = *src++; 1180f08c3bdfSopenharmony_ci switch (c) { 1181f08c3bdfSopenharmony_ci case '0' ... '9': 1182f08c3bdfSopenharmony_ci index = c - '0'; 1183f08c3bdfSopenharmony_ci if (index < nr) 1184f08c3bdfSopenharmony_ci replace_asm_arg(dst_p, args+index); 1185f08c3bdfSopenharmony_ci break; 1186f08c3bdfSopenharmony_ci } 1187f08c3bdfSopenharmony_ci *src_p = src; 1188f08c3bdfSopenharmony_ci return; 1189f08c3bdfSopenharmony_ci} 1190f08c3bdfSopenharmony_ci 1191f08c3bdfSopenharmony_cistatic void replace_asm_named(const char **src_p, char **dst_p, struct asm_arg *args, int nr) 1192f08c3bdfSopenharmony_ci{ 1193f08c3bdfSopenharmony_ci const char *src = *src_p; 1194f08c3bdfSopenharmony_ci const char *end = src; 1195f08c3bdfSopenharmony_ci 1196f08c3bdfSopenharmony_ci for(;;) { 1197f08c3bdfSopenharmony_ci char c = *end++; 1198f08c3bdfSopenharmony_ci if (!c) 1199f08c3bdfSopenharmony_ci return; 1200f08c3bdfSopenharmony_ci if (c == ']') { 1201f08c3bdfSopenharmony_ci int i; 1202f08c3bdfSopenharmony_ci 1203f08c3bdfSopenharmony_ci *src_p = end; 1204f08c3bdfSopenharmony_ci for (i = 0; i < nr; i++) { 1205f08c3bdfSopenharmony_ci const struct ident *ident = args[i].name; 1206f08c3bdfSopenharmony_ci int len; 1207f08c3bdfSopenharmony_ci if (!ident) 1208f08c3bdfSopenharmony_ci continue; 1209f08c3bdfSopenharmony_ci len = ident->len; 1210f08c3bdfSopenharmony_ci if (memcmp(src, ident->name, len)) 1211f08c3bdfSopenharmony_ci continue; 1212f08c3bdfSopenharmony_ci replace_asm_arg(dst_p, args+i); 1213f08c3bdfSopenharmony_ci return; 1214f08c3bdfSopenharmony_ci } 1215f08c3bdfSopenharmony_ci } 1216f08c3bdfSopenharmony_ci } 1217f08c3bdfSopenharmony_ci} 1218f08c3bdfSopenharmony_ci 1219f08c3bdfSopenharmony_cistatic const char *replace_asm_args(const char *str, struct asm_arg *args, int nr) 1220f08c3bdfSopenharmony_ci{ 1221f08c3bdfSopenharmony_ci static char buffer[1000]; 1222f08c3bdfSopenharmony_ci char *p = buffer; 1223f08c3bdfSopenharmony_ci 1224f08c3bdfSopenharmony_ci for (;;) { 1225f08c3bdfSopenharmony_ci char c = *str; 1226f08c3bdfSopenharmony_ci *p = c; 1227f08c3bdfSopenharmony_ci if (!c) 1228f08c3bdfSopenharmony_ci return buffer; 1229f08c3bdfSopenharmony_ci str++; 1230f08c3bdfSopenharmony_ci switch (c) { 1231f08c3bdfSopenharmony_ci case '%': 1232f08c3bdfSopenharmony_ci if (*str == '%') { 1233f08c3bdfSopenharmony_ci str++; 1234f08c3bdfSopenharmony_ci p++; 1235f08c3bdfSopenharmony_ci continue; 1236f08c3bdfSopenharmony_ci } 1237f08c3bdfSopenharmony_ci replace_asm_percent(&str, &p, args, nr); 1238f08c3bdfSopenharmony_ci continue; 1239f08c3bdfSopenharmony_ci case '[': 1240f08c3bdfSopenharmony_ci replace_asm_named(&str, &p, args, nr); 1241f08c3bdfSopenharmony_ci continue; 1242f08c3bdfSopenharmony_ci default: 1243f08c3bdfSopenharmony_ci break; 1244f08c3bdfSopenharmony_ci } 1245f08c3bdfSopenharmony_ci p++; 1246f08c3bdfSopenharmony_ci } 1247f08c3bdfSopenharmony_ci} 1248f08c3bdfSopenharmony_ci 1249f08c3bdfSopenharmony_ci#define MAX_ASM_ARG (50) 1250f08c3bdfSopenharmony_cistatic struct asm_arg asm_arguments[MAX_ASM_ARG]; 1251f08c3bdfSopenharmony_ci 1252f08c3bdfSopenharmony_cistatic struct asm_arg *generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg) 1253f08c3bdfSopenharmony_ci{ 1254f08c3bdfSopenharmony_ci struct asm_constraint *entry; 1255f08c3bdfSopenharmony_ci 1256f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, entry) { 1257f08c3bdfSopenharmony_ci const char *constraint = entry->constraint; 1258f08c3bdfSopenharmony_ci pseudo_t pseudo = entry->pseudo; 1259f08c3bdfSopenharmony_ci struct hardreg *reg, *orig; 1260f08c3bdfSopenharmony_ci const char *string; 1261f08c3bdfSopenharmony_ci int index; 1262f08c3bdfSopenharmony_ci 1263f08c3bdfSopenharmony_ci string = "undef"; 1264f08c3bdfSopenharmony_ci switch (*constraint) { 1265f08c3bdfSopenharmony_ci case 'r': 1266f08c3bdfSopenharmony_ci string = getreg(state, pseudo, NULL)->name; 1267f08c3bdfSopenharmony_ci break; 1268f08c3bdfSopenharmony_ci case '0' ... '9': 1269f08c3bdfSopenharmony_ci index = *constraint - '0'; 1270f08c3bdfSopenharmony_ci reg = asm_arguments[index].reg; 1271f08c3bdfSopenharmony_ci orig = find_in_reg(state, pseudo); 1272f08c3bdfSopenharmony_ci if (orig) 1273f08c3bdfSopenharmony_ci move_reg(state, orig, reg); 1274f08c3bdfSopenharmony_ci else 1275f08c3bdfSopenharmony_ci fill_reg(state, reg, pseudo); 1276f08c3bdfSopenharmony_ci string = reg->name; 1277f08c3bdfSopenharmony_ci break; 1278f08c3bdfSopenharmony_ci default: 1279f08c3bdfSopenharmony_ci string = generic(state, pseudo); 1280f08c3bdfSopenharmony_ci break; 1281f08c3bdfSopenharmony_ci } 1282f08c3bdfSopenharmony_ci 1283f08c3bdfSopenharmony_ci output_insn(state, "# asm input \"%s\": %s : %s", constraint, show_pseudo(pseudo), string); 1284f08c3bdfSopenharmony_ci 1285f08c3bdfSopenharmony_ci arg->name = entry->ident; 1286f08c3bdfSopenharmony_ci arg->value = string; 1287f08c3bdfSopenharmony_ci arg->pseudo = NULL; 1288f08c3bdfSopenharmony_ci arg->reg = NULL; 1289f08c3bdfSopenharmony_ci arg++; 1290f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1291f08c3bdfSopenharmony_ci return arg; 1292f08c3bdfSopenharmony_ci} 1293f08c3bdfSopenharmony_ci 1294f08c3bdfSopenharmony_cistatic struct asm_arg *generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg) 1295f08c3bdfSopenharmony_ci{ 1296f08c3bdfSopenharmony_ci struct asm_constraint *entry; 1297f08c3bdfSopenharmony_ci 1298f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, entry) { 1299f08c3bdfSopenharmony_ci const char *constraint = entry->constraint; 1300f08c3bdfSopenharmony_ci pseudo_t pseudo = entry->pseudo; 1301f08c3bdfSopenharmony_ci struct hardreg *reg; 1302f08c3bdfSopenharmony_ci const char *string; 1303f08c3bdfSopenharmony_ci 1304f08c3bdfSopenharmony_ci while (*constraint == '=' || *constraint == '+') 1305f08c3bdfSopenharmony_ci constraint++; 1306f08c3bdfSopenharmony_ci 1307f08c3bdfSopenharmony_ci string = "undef"; 1308f08c3bdfSopenharmony_ci switch (*constraint) { 1309f08c3bdfSopenharmony_ci case 'r': 1310f08c3bdfSopenharmony_ci default: 1311f08c3bdfSopenharmony_ci reg = target_reg(state, pseudo, NULL); 1312f08c3bdfSopenharmony_ci arg->pseudo = pseudo; 1313f08c3bdfSopenharmony_ci arg->reg = reg; 1314f08c3bdfSopenharmony_ci string = reg->name; 1315f08c3bdfSopenharmony_ci break; 1316f08c3bdfSopenharmony_ci } 1317f08c3bdfSopenharmony_ci 1318f08c3bdfSopenharmony_ci output_insn(state, "# asm output \"%s\": %s : %s", constraint, show_pseudo(pseudo), string); 1319f08c3bdfSopenharmony_ci 1320f08c3bdfSopenharmony_ci arg->name = entry->ident; 1321f08c3bdfSopenharmony_ci arg->value = string; 1322f08c3bdfSopenharmony_ci arg++; 1323f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1324f08c3bdfSopenharmony_ci return arg; 1325f08c3bdfSopenharmony_ci} 1326f08c3bdfSopenharmony_ci 1327f08c3bdfSopenharmony_cistatic void generate_asm(struct bb_state *state, struct instruction *insn) 1328f08c3bdfSopenharmony_ci{ 1329f08c3bdfSopenharmony_ci const char *str = insn->string; 1330f08c3bdfSopenharmony_ci 1331f08c3bdfSopenharmony_ci if (insn->asm_rules->outputs || insn->asm_rules->inputs) { 1332f08c3bdfSopenharmony_ci struct asm_arg *arg; 1333f08c3bdfSopenharmony_ci 1334f08c3bdfSopenharmony_ci arg = generate_asm_outputs(state, insn->asm_rules->outputs, asm_arguments); 1335f08c3bdfSopenharmony_ci arg = generate_asm_inputs(state, insn->asm_rules->inputs, arg); 1336f08c3bdfSopenharmony_ci str = replace_asm_args(str, asm_arguments, arg - asm_arguments); 1337f08c3bdfSopenharmony_ci } 1338f08c3bdfSopenharmony_ci output_insn(state, "%s", str); 1339f08c3bdfSopenharmony_ci} 1340f08c3bdfSopenharmony_ci 1341f08c3bdfSopenharmony_cistatic void generate_compare(struct bb_state *state, struct instruction *insn) 1342f08c3bdfSopenharmony_ci{ 1343f08c3bdfSopenharmony_ci struct hardreg *src; 1344f08c3bdfSopenharmony_ci const char *src2; 1345f08c3bdfSopenharmony_ci int opcode; 1346f08c3bdfSopenharmony_ci 1347f08c3bdfSopenharmony_ci flush_cc_cache(state); 1348f08c3bdfSopenharmony_ci opcode = insn->opcode; 1349f08c3bdfSopenharmony_ci 1350f08c3bdfSopenharmony_ci /* 1351f08c3bdfSopenharmony_ci * We should try to switch these around if necessary, 1352f08c3bdfSopenharmony_ci * and update the opcode to match.. 1353f08c3bdfSopenharmony_ci */ 1354f08c3bdfSopenharmony_ci src = getreg(state, insn->src1, insn->target); 1355f08c3bdfSopenharmony_ci src2 = generic(state, insn->src2); 1356f08c3bdfSopenharmony_ci 1357f08c3bdfSopenharmony_ci output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name); 1358f08c3bdfSopenharmony_ci 1359f08c3bdfSopenharmony_ci add_cc_cache(state, opcode, insn->target); 1360f08c3bdfSopenharmony_ci} 1361f08c3bdfSopenharmony_ci 1362f08c3bdfSopenharmony_cistatic void generate_one_insn(struct instruction *insn, struct bb_state *state) 1363f08c3bdfSopenharmony_ci{ 1364f08c3bdfSopenharmony_ci if (verbose) 1365f08c3bdfSopenharmony_ci output_comment(state, "%s", show_instruction(insn)); 1366f08c3bdfSopenharmony_ci 1367f08c3bdfSopenharmony_ci switch (insn->opcode) { 1368f08c3bdfSopenharmony_ci case OP_ENTRY: { 1369f08c3bdfSopenharmony_ci struct symbol *sym = insn->bb->ep->name; 1370f08c3bdfSopenharmony_ci const char *name = show_ident(sym->ident); 1371f08c3bdfSopenharmony_ci if (sym->ctype.modifiers & MOD_STATIC) 1372f08c3bdfSopenharmony_ci printf("\n\n%s:\n", name); 1373f08c3bdfSopenharmony_ci else 1374f08c3bdfSopenharmony_ci printf("\n\n.globl %s\n%s:\n", name, name); 1375f08c3bdfSopenharmony_ci break; 1376f08c3bdfSopenharmony_ci } 1377f08c3bdfSopenharmony_ci 1378f08c3bdfSopenharmony_ci /* 1379f08c3bdfSopenharmony_ci * OP_LABEL & OP_SETVAL likewise doesn't actually generate any 1380f08c3bdfSopenharmony_ci * code. On use, the "def" of the pseudo will be 1381f08c3bdfSopenharmony_ci * looked up. 1382f08c3bdfSopenharmony_ci */ 1383f08c3bdfSopenharmony_ci case OP_LABEL: 1384f08c3bdfSopenharmony_ci case OP_SETVAL: 1385f08c3bdfSopenharmony_ci break; 1386f08c3bdfSopenharmony_ci 1387f08c3bdfSopenharmony_ci case OP_STORE: 1388f08c3bdfSopenharmony_ci generate_store(insn, state); 1389f08c3bdfSopenharmony_ci break; 1390f08c3bdfSopenharmony_ci 1391f08c3bdfSopenharmony_ci case OP_LOAD: 1392f08c3bdfSopenharmony_ci generate_load(insn, state); 1393f08c3bdfSopenharmony_ci break; 1394f08c3bdfSopenharmony_ci 1395f08c3bdfSopenharmony_ci case OP_DEATHNOTE: 1396f08c3bdfSopenharmony_ci mark_pseudo_dead(state, insn->target); 1397f08c3bdfSopenharmony_ci return; 1398f08c3bdfSopenharmony_ci 1399f08c3bdfSopenharmony_ci case OP_COPY: 1400f08c3bdfSopenharmony_ci generate_copy(state, insn); 1401f08c3bdfSopenharmony_ci break; 1402f08c3bdfSopenharmony_ci 1403f08c3bdfSopenharmony_ci case OP_ADD: case OP_MUL: 1404f08c3bdfSopenharmony_ci case OP_AND: case OP_OR: case OP_XOR: 1405f08c3bdfSopenharmony_ci generate_commutative_binop(state, insn); 1406f08c3bdfSopenharmony_ci break; 1407f08c3bdfSopenharmony_ci 1408f08c3bdfSopenharmony_ci case OP_SUB: case OP_DIVU: case OP_DIVS: 1409f08c3bdfSopenharmony_ci case OP_MODU: case OP_MODS: 1410f08c3bdfSopenharmony_ci case OP_SHL: case OP_LSR: case OP_ASR: 1411f08c3bdfSopenharmony_ci generate_binop(state, insn); 1412f08c3bdfSopenharmony_ci break; 1413f08c3bdfSopenharmony_ci 1414f08c3bdfSopenharmony_ci case OP_BINCMP ... OP_BINCMP_END: 1415f08c3bdfSopenharmony_ci generate_compare(state, insn); 1416f08c3bdfSopenharmony_ci break; 1417f08c3bdfSopenharmony_ci 1418f08c3bdfSopenharmony_ci case OP_SEXT: case OP_ZEXT: 1419f08c3bdfSopenharmony_ci case OP_TRUNC: 1420f08c3bdfSopenharmony_ci case OP_PTRCAST: 1421f08c3bdfSopenharmony_ci case OP_UTPTR: 1422f08c3bdfSopenharmony_ci case OP_PTRTU: 1423f08c3bdfSopenharmony_ci case OP_FCVTU: case OP_FCVTS: 1424f08c3bdfSopenharmony_ci case OP_UCVTF: case OP_SCVTF: 1425f08c3bdfSopenharmony_ci case OP_FCVTF: 1426f08c3bdfSopenharmony_ci generate_cast(state, insn); 1427f08c3bdfSopenharmony_ci break; 1428f08c3bdfSopenharmony_ci 1429f08c3bdfSopenharmony_ci case OP_SEL: 1430f08c3bdfSopenharmony_ci generate_select(state, insn); 1431f08c3bdfSopenharmony_ci break; 1432f08c3bdfSopenharmony_ci 1433f08c3bdfSopenharmony_ci case OP_BR: 1434f08c3bdfSopenharmony_ci case OP_CBR: 1435f08c3bdfSopenharmony_ci generate_branch(state, insn); 1436f08c3bdfSopenharmony_ci break; 1437f08c3bdfSopenharmony_ci 1438f08c3bdfSopenharmony_ci case OP_SWITCH: 1439f08c3bdfSopenharmony_ci generate_switch(state, insn); 1440f08c3bdfSopenharmony_ci break; 1441f08c3bdfSopenharmony_ci 1442f08c3bdfSopenharmony_ci case OP_CALL: 1443f08c3bdfSopenharmony_ci generate_call(state, insn); 1444f08c3bdfSopenharmony_ci break; 1445f08c3bdfSopenharmony_ci 1446f08c3bdfSopenharmony_ci case OP_RET: 1447f08c3bdfSopenharmony_ci generate_ret(state, insn); 1448f08c3bdfSopenharmony_ci break; 1449f08c3bdfSopenharmony_ci 1450f08c3bdfSopenharmony_ci case OP_ASM: 1451f08c3bdfSopenharmony_ci generate_asm(state, insn); 1452f08c3bdfSopenharmony_ci break; 1453f08c3bdfSopenharmony_ci 1454f08c3bdfSopenharmony_ci case OP_PHI: 1455f08c3bdfSopenharmony_ci case OP_PHISOURCE: 1456f08c3bdfSopenharmony_ci default: 1457f08c3bdfSopenharmony_ci output_insn(state, "unimplemented: %s", show_instruction(insn)); 1458f08c3bdfSopenharmony_ci break; 1459f08c3bdfSopenharmony_ci } 1460f08c3bdfSopenharmony_ci kill_dead_pseudos(state); 1461f08c3bdfSopenharmony_ci} 1462f08c3bdfSopenharmony_ci 1463f08c3bdfSopenharmony_ci#define VERY_BUSY 1000 1464f08c3bdfSopenharmony_ci#define REG_FIXED 2000 1465f08c3bdfSopenharmony_ci 1466f08c3bdfSopenharmony_cistatic void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage) 1467f08c3bdfSopenharmony_ci{ 1468f08c3bdfSopenharmony_ci int i; 1469f08c3bdfSopenharmony_ci struct hardreg *out; 1470f08c3bdfSopenharmony_ci 1471f08c3bdfSopenharmony_ci switch (storage->type) { 1472f08c3bdfSopenharmony_ci case REG_REG: 1473f08c3bdfSopenharmony_ci out = hardregs + storage->regno; 1474f08c3bdfSopenharmony_ci if (reg == out) 1475f08c3bdfSopenharmony_ci return; 1476f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, out->name); 1477f08c3bdfSopenharmony_ci return; 1478f08c3bdfSopenharmony_ci case REG_UDEF: 1479f08c3bdfSopenharmony_ci if (reg->busy < VERY_BUSY) { 1480f08c3bdfSopenharmony_ci storage->type = REG_REG; 1481f08c3bdfSopenharmony_ci storage->regno = reg - hardregs; 1482f08c3bdfSopenharmony_ci reg->busy = REG_FIXED; 1483f08c3bdfSopenharmony_ci return; 1484f08c3bdfSopenharmony_ci } 1485f08c3bdfSopenharmony_ci 1486f08c3bdfSopenharmony_ci /* Try to find a non-busy register.. */ 1487f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 1488f08c3bdfSopenharmony_ci out = hardregs + i; 1489f08c3bdfSopenharmony_ci if (out->contains) 1490f08c3bdfSopenharmony_ci continue; 1491f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, out->name); 1492f08c3bdfSopenharmony_ci storage->type = REG_REG; 1493f08c3bdfSopenharmony_ci storage->regno = i; 1494f08c3bdfSopenharmony_ci out->busy = REG_FIXED; 1495f08c3bdfSopenharmony_ci return; 1496f08c3bdfSopenharmony_ci } 1497f08c3bdfSopenharmony_ci 1498f08c3bdfSopenharmony_ci /* Fall back on stack allocation ... */ 1499f08c3bdfSopenharmony_ci alloc_stack(state, storage); 1500f08c3bdfSopenharmony_ci /* Fall through */ 1501f08c3bdfSopenharmony_ci default: 1502f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, show_memop(storage)); 1503f08c3bdfSopenharmony_ci return; 1504f08c3bdfSopenharmony_ci } 1505f08c3bdfSopenharmony_ci} 1506f08c3bdfSopenharmony_ci 1507f08c3bdfSopenharmony_cistatic void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage) 1508f08c3bdfSopenharmony_ci{ 1509f08c3bdfSopenharmony_ci struct hardreg *out; 1510f08c3bdfSopenharmony_ci 1511f08c3bdfSopenharmony_ci switch (storage->type) { 1512f08c3bdfSopenharmony_ci case REG_UDEF: 1513f08c3bdfSopenharmony_ci alloc_stack(state, storage); 1514f08c3bdfSopenharmony_ci default: 1515f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage)); 1516f08c3bdfSopenharmony_ci break; 1517f08c3bdfSopenharmony_ci case REG_REG: 1518f08c3bdfSopenharmony_ci out = hardregs + storage->regno; 1519f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", show_pseudo(src), out->name); 1520f08c3bdfSopenharmony_ci } 1521f08c3bdfSopenharmony_ci} 1522f08c3bdfSopenharmony_ci 1523f08c3bdfSopenharmony_cistatic void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out) 1524f08c3bdfSopenharmony_ci{ 1525f08c3bdfSopenharmony_ci int i; 1526f08c3bdfSopenharmony_ci struct storage_hash *in; 1527f08c3bdfSopenharmony_ci struct instruction *def; 1528f08c3bdfSopenharmony_ci 1529f08c3bdfSopenharmony_ci /* Is that pseudo a constant value? */ 1530f08c3bdfSopenharmony_ci switch (pseudo->type) { 1531f08c3bdfSopenharmony_ci case PSEUDO_VAL: 1532f08c3bdfSopenharmony_ci write_val_to_storage(state, pseudo, out); 1533f08c3bdfSopenharmony_ci return; 1534f08c3bdfSopenharmony_ci case PSEUDO_REG: 1535f08c3bdfSopenharmony_ci def = pseudo->def; 1536f08c3bdfSopenharmony_ci if (def && (def->opcode == OP_SETVAL || def->opcode == OP_LABEL)) { 1537f08c3bdfSopenharmony_ci write_val_to_storage(state, pseudo, out); 1538f08c3bdfSopenharmony_ci return; 1539f08c3bdfSopenharmony_ci } 1540f08c3bdfSopenharmony_ci default: 1541f08c3bdfSopenharmony_ci break; 1542f08c3bdfSopenharmony_ci } 1543f08c3bdfSopenharmony_ci 1544f08c3bdfSopenharmony_ci /* See if we have that pseudo in a register.. */ 1545f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 1546f08c3bdfSopenharmony_ci struct hardreg *reg = hardregs + i; 1547f08c3bdfSopenharmony_ci pseudo_t p; 1548f08c3bdfSopenharmony_ci 1549f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 1550f08c3bdfSopenharmony_ci if (p == pseudo) { 1551f08c3bdfSopenharmony_ci write_reg_to_storage(state, reg, pseudo, out); 1552f08c3bdfSopenharmony_ci return; 1553f08c3bdfSopenharmony_ci } 1554f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 1555f08c3bdfSopenharmony_ci } 1556f08c3bdfSopenharmony_ci 1557f08c3bdfSopenharmony_ci /* Do we have it in another storage? */ 1558f08c3bdfSopenharmony_ci in = find_storage_hash(pseudo, state->internal); 1559f08c3bdfSopenharmony_ci if (!in) { 1560f08c3bdfSopenharmony_ci in = find_storage_hash(pseudo, state->inputs); 1561f08c3bdfSopenharmony_ci /* Undefined? */ 1562f08c3bdfSopenharmony_ci if (!in) 1563f08c3bdfSopenharmony_ci return; 1564f08c3bdfSopenharmony_ci } 1565f08c3bdfSopenharmony_ci switch (out->type) { 1566f08c3bdfSopenharmony_ci case REG_UDEF: 1567f08c3bdfSopenharmony_ci *out = *in->storage; 1568f08c3bdfSopenharmony_ci break; 1569f08c3bdfSopenharmony_ci case REG_REG: 1570f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name); 1571f08c3bdfSopenharmony_ci break; 1572f08c3bdfSopenharmony_ci default: 1573f08c3bdfSopenharmony_ci if (out == in->storage) 1574f08c3bdfSopenharmony_ci break; 1575f08c3bdfSopenharmony_ci if ((out->type == in->storage->type) && (out->regno == in->storage->regno)) 1576f08c3bdfSopenharmony_ci break; 1577f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out)); 1578f08c3bdfSopenharmony_ci break; 1579f08c3bdfSopenharmony_ci } 1580f08c3bdfSopenharmony_ci return; 1581f08c3bdfSopenharmony_ci} 1582f08c3bdfSopenharmony_ci 1583f08c3bdfSopenharmony_cistatic int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg) 1584f08c3bdfSopenharmony_ci{ 1585f08c3bdfSopenharmony_ci struct storage_hash *hash; 1586f08c3bdfSopenharmony_ci struct storage *out; 1587f08c3bdfSopenharmony_ci struct hardreg *dst; 1588f08c3bdfSopenharmony_ci 1589f08c3bdfSopenharmony_ci /* 1590f08c3bdfSopenharmony_ci * Since this pseudo is live at exit, we'd better have output 1591f08c3bdfSopenharmony_ci * storage for it.. 1592f08c3bdfSopenharmony_ci */ 1593f08c3bdfSopenharmony_ci hash = find_storage_hash(pseudo, state->outputs); 1594f08c3bdfSopenharmony_ci if (!hash) 1595f08c3bdfSopenharmony_ci return 1; 1596f08c3bdfSopenharmony_ci out = hash->storage; 1597f08c3bdfSopenharmony_ci 1598f08c3bdfSopenharmony_ci /* If the output is in a register, try to get it there.. */ 1599f08c3bdfSopenharmony_ci if (out->type == REG_REG) { 1600f08c3bdfSopenharmony_ci dst = hardregs + out->regno; 1601f08c3bdfSopenharmony_ci /* 1602f08c3bdfSopenharmony_ci * Two good cases: nobody is using the right register, 1603f08c3bdfSopenharmony_ci * or we've already set it aside for output.. 1604f08c3bdfSopenharmony_ci */ 1605f08c3bdfSopenharmony_ci if (!dst->contains || dst->busy > VERY_BUSY) 1606f08c3bdfSopenharmony_ci goto copy_to_dst; 1607f08c3bdfSopenharmony_ci 1608f08c3bdfSopenharmony_ci /* Aiee. Try to keep it in a register.. */ 1609f08c3bdfSopenharmony_ci dst = empty_reg(state); 1610f08c3bdfSopenharmony_ci if (dst) 1611f08c3bdfSopenharmony_ci goto copy_to_dst; 1612f08c3bdfSopenharmony_ci 1613f08c3bdfSopenharmony_ci return 0; 1614f08c3bdfSopenharmony_ci } 1615f08c3bdfSopenharmony_ci 1616f08c3bdfSopenharmony_ci /* If the output is undefined, let's see if we can put it in a register.. */ 1617f08c3bdfSopenharmony_ci if (out->type == REG_UDEF) { 1618f08c3bdfSopenharmony_ci dst = empty_reg(state); 1619f08c3bdfSopenharmony_ci if (dst) { 1620f08c3bdfSopenharmony_ci out->type = REG_REG; 1621f08c3bdfSopenharmony_ci out->regno = dst - hardregs; 1622f08c3bdfSopenharmony_ci goto copy_to_dst; 1623f08c3bdfSopenharmony_ci } 1624f08c3bdfSopenharmony_ci /* Uhhuh. Not so good. No empty registers right now */ 1625f08c3bdfSopenharmony_ci return 0; 1626f08c3bdfSopenharmony_ci } 1627f08c3bdfSopenharmony_ci 1628f08c3bdfSopenharmony_ci /* If we know we need to flush it, just do so already .. */ 1629f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, show_memop(out)); 1630f08c3bdfSopenharmony_ci return 1; 1631f08c3bdfSopenharmony_ci 1632f08c3bdfSopenharmony_cicopy_to_dst: 1633f08c3bdfSopenharmony_ci if (reg == dst) 1634f08c3bdfSopenharmony_ci return 1; 1635f08c3bdfSopenharmony_ci output_insn(state, "movl %s,%s", reg->name, dst->name); 1636f08c3bdfSopenharmony_ci add_pseudo_reg(state, pseudo, dst); 1637f08c3bdfSopenharmony_ci return 1; 1638f08c3bdfSopenharmony_ci} 1639f08c3bdfSopenharmony_ci 1640f08c3bdfSopenharmony_ci/* 1641f08c3bdfSopenharmony_ci * This tries to make sure that we put all the pseudos that are 1642f08c3bdfSopenharmony_ci * live on exit into the proper storage 1643f08c3bdfSopenharmony_ci */ 1644f08c3bdfSopenharmony_cistatic void generate_output_storage(struct bb_state *state) 1645f08c3bdfSopenharmony_ci{ 1646f08c3bdfSopenharmony_ci struct storage_hash *entry; 1647f08c3bdfSopenharmony_ci 1648f08c3bdfSopenharmony_ci /* Go through the fixed outputs, making sure we have those regs free */ 1649f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->outputs, entry) { 1650f08c3bdfSopenharmony_ci struct storage *out = entry->storage; 1651f08c3bdfSopenharmony_ci if (out->type == REG_REG) { 1652f08c3bdfSopenharmony_ci struct hardreg *reg = hardregs + out->regno; 1653f08c3bdfSopenharmony_ci pseudo_t p; 1654f08c3bdfSopenharmony_ci int flushme = 0; 1655f08c3bdfSopenharmony_ci 1656f08c3bdfSopenharmony_ci reg->busy = REG_FIXED; 1657f08c3bdfSopenharmony_ci FOR_EACH_PTR_TAG(reg->contains, p) { 1658f08c3bdfSopenharmony_ci if (p == entry->pseudo) { 1659f08c3bdfSopenharmony_ci flushme = -100; 1660f08c3bdfSopenharmony_ci continue; 1661f08c3bdfSopenharmony_ci } 1662f08c3bdfSopenharmony_ci if (CURRENT_TAG(p) & TAG_DEAD) 1663f08c3bdfSopenharmony_ci continue; 1664f08c3bdfSopenharmony_ci 1665f08c3bdfSopenharmony_ci /* Try to write back the pseudo to where it should go ... */ 1666f08c3bdfSopenharmony_ci if (final_pseudo_flush(state, p, reg)) { 1667f08c3bdfSopenharmony_ci DELETE_CURRENT_PTR(p); 1668f08c3bdfSopenharmony_ci continue; 1669f08c3bdfSopenharmony_ci } 1670f08c3bdfSopenharmony_ci flushme++; 1671f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(p); 1672f08c3bdfSopenharmony_ci PACK_PTR_LIST(®->contains); 1673f08c3bdfSopenharmony_ci if (flushme > 0) 1674f08c3bdfSopenharmony_ci flush_reg(state, reg); 1675f08c3bdfSopenharmony_ci } 1676f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1677f08c3bdfSopenharmony_ci 1678f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->outputs, entry) { 1679f08c3bdfSopenharmony_ci fill_output(state, entry->pseudo, entry->storage); 1680f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1681f08c3bdfSopenharmony_ci} 1682f08c3bdfSopenharmony_ci 1683f08c3bdfSopenharmony_cistatic void generate(struct basic_block *bb, struct bb_state *state) 1684f08c3bdfSopenharmony_ci{ 1685f08c3bdfSopenharmony_ci int i; 1686f08c3bdfSopenharmony_ci struct storage_hash *entry; 1687f08c3bdfSopenharmony_ci struct instruction *insn; 1688f08c3bdfSopenharmony_ci 1689f08c3bdfSopenharmony_ci for (i = 0; i < REGNO; i++) { 1690f08c3bdfSopenharmony_ci free_ptr_list(&hardregs[i].contains); 1691f08c3bdfSopenharmony_ci hardregs[i].busy = 0; 1692f08c3bdfSopenharmony_ci hardregs[i].dead = 0; 1693f08c3bdfSopenharmony_ci hardregs[i].used = 0; 1694f08c3bdfSopenharmony_ci } 1695f08c3bdfSopenharmony_ci 1696f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->inputs, entry) { 1697f08c3bdfSopenharmony_ci struct storage *storage = entry->storage; 1698f08c3bdfSopenharmony_ci const char *name = show_storage(storage); 1699f08c3bdfSopenharmony_ci output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name); 1700f08c3bdfSopenharmony_ci if (storage->type == REG_REG) { 1701f08c3bdfSopenharmony_ci int regno = storage->regno; 1702f08c3bdfSopenharmony_ci add_pseudo_reg(state, entry->pseudo, hardregs + regno); 1703f08c3bdfSopenharmony_ci name = hardregs[regno].name; 1704f08c3bdfSopenharmony_ci } 1705f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1706f08c3bdfSopenharmony_ci 1707f08c3bdfSopenharmony_ci output_label(state, ".L%p", bb); 1708f08c3bdfSopenharmony_ci FOR_EACH_PTR(bb->insns, insn) { 1709f08c3bdfSopenharmony_ci if (!insn->bb) 1710f08c3bdfSopenharmony_ci continue; 1711f08c3bdfSopenharmony_ci generate_one_insn(insn, state); 1712f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(insn); 1713f08c3bdfSopenharmony_ci 1714f08c3bdfSopenharmony_ci if (verbose) { 1715f08c3bdfSopenharmony_ci output_comment(state, "--- in ---"); 1716f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->inputs, entry) { 1717f08c3bdfSopenharmony_ci output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage)); 1718f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1719f08c3bdfSopenharmony_ci output_comment(state, "--- spill ---"); 1720f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->internal, entry) { 1721f08c3bdfSopenharmony_ci output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage)); 1722f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1723f08c3bdfSopenharmony_ci output_comment(state, "--- out ---"); 1724f08c3bdfSopenharmony_ci FOR_EACH_PTR(state->outputs, entry) { 1725f08c3bdfSopenharmony_ci output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage)); 1726f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1727f08c3bdfSopenharmony_ci } 1728f08c3bdfSopenharmony_ci printf("\n"); 1729f08c3bdfSopenharmony_ci} 1730f08c3bdfSopenharmony_ci 1731f08c3bdfSopenharmony_cistatic void generate_list(struct basic_block_list *list, unsigned long generation) 1732f08c3bdfSopenharmony_ci{ 1733f08c3bdfSopenharmony_ci struct basic_block *bb; 1734f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, bb) { 1735f08c3bdfSopenharmony_ci if (bb->generation == generation) 1736f08c3bdfSopenharmony_ci continue; 1737f08c3bdfSopenharmony_ci output_bb(bb, generation); 1738f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 1739f08c3bdfSopenharmony_ci} 1740f08c3bdfSopenharmony_ci 1741f08c3bdfSopenharmony_ci/* 1742f08c3bdfSopenharmony_ci * Mark all the output registers of all the parents 1743f08c3bdfSopenharmony_ci * as being "used" - this does not mean that we cannot 1744f08c3bdfSopenharmony_ci * re-use them, but it means that we cannot ask the 1745f08c3bdfSopenharmony_ci * parents to pass in another pseudo in one of those 1746f08c3bdfSopenharmony_ci * registers that it already uses for another child. 1747f08c3bdfSopenharmony_ci */ 1748f08c3bdfSopenharmony_cistatic void mark_used_registers(struct basic_block *bb, struct bb_state *state) 1749f08c3bdfSopenharmony_ci{ 1750f08c3bdfSopenharmony_ci struct basic_block *parent; 1751f08c3bdfSopenharmony_ci 1752f08c3bdfSopenharmony_ci FOR_EACH_PTR(bb->parents, parent) { 1753f08c3bdfSopenharmony_ci struct storage_hash_list *outputs = gather_storage(parent, STOR_OUT); 1754f08c3bdfSopenharmony_ci struct storage_hash *entry; 1755f08c3bdfSopenharmony_ci 1756f08c3bdfSopenharmony_ci FOR_EACH_PTR(outputs, entry) { 1757f08c3bdfSopenharmony_ci struct storage *s = entry->storage; 1758f08c3bdfSopenharmony_ci if (s->type == REG_REG) { 1759f08c3bdfSopenharmony_ci struct hardreg *reg = hardregs + s->regno; 1760f08c3bdfSopenharmony_ci reg->used = 1; 1761f08c3bdfSopenharmony_ci } 1762f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(entry); 1763f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(parent); 1764f08c3bdfSopenharmony_ci} 1765f08c3bdfSopenharmony_ci 1766f08c3bdfSopenharmony_cistatic void output_bb(struct basic_block *bb, unsigned long generation) 1767f08c3bdfSopenharmony_ci{ 1768f08c3bdfSopenharmony_ci struct bb_state state; 1769f08c3bdfSopenharmony_ci 1770f08c3bdfSopenharmony_ci bb->generation = generation; 1771f08c3bdfSopenharmony_ci 1772f08c3bdfSopenharmony_ci /* Make sure all parents have been generated first */ 1773f08c3bdfSopenharmony_ci generate_list(bb->parents, generation); 1774f08c3bdfSopenharmony_ci 1775f08c3bdfSopenharmony_ci state.pos = bb->pos; 1776f08c3bdfSopenharmony_ci state.inputs = gather_storage(bb, STOR_IN); 1777f08c3bdfSopenharmony_ci state.outputs = gather_storage(bb, STOR_OUT); 1778f08c3bdfSopenharmony_ci state.internal = NULL; 1779f08c3bdfSopenharmony_ci state.cc_opcode = 0; 1780f08c3bdfSopenharmony_ci state.cc_target = NULL; 1781f08c3bdfSopenharmony_ci 1782f08c3bdfSopenharmony_ci /* Mark incoming registers used */ 1783f08c3bdfSopenharmony_ci mark_used_registers(bb, &state); 1784f08c3bdfSopenharmony_ci 1785f08c3bdfSopenharmony_ci generate(bb, &state); 1786f08c3bdfSopenharmony_ci 1787f08c3bdfSopenharmony_ci free_ptr_list(&state.inputs); 1788f08c3bdfSopenharmony_ci free_ptr_list(&state.outputs); 1789f08c3bdfSopenharmony_ci 1790f08c3bdfSopenharmony_ci /* Generate all children... */ 1791f08c3bdfSopenharmony_ci generate_list(bb->children, generation); 1792f08c3bdfSopenharmony_ci} 1793f08c3bdfSopenharmony_ci 1794f08c3bdfSopenharmony_ci/* 1795f08c3bdfSopenharmony_ci * We should set up argument sources here.. 1796f08c3bdfSopenharmony_ci * 1797f08c3bdfSopenharmony_ci * Things like "first three arguments in registers" etc 1798f08c3bdfSopenharmony_ci * are all for this place. 1799f08c3bdfSopenharmony_ci * 1800f08c3bdfSopenharmony_ci * On x86, we default to stack, unless it's a static 1801f08c3bdfSopenharmony_ci * function that doesn't have its address taken. 1802f08c3bdfSopenharmony_ci * 1803f08c3bdfSopenharmony_ci * I should implement the -mregparm=X cmd line option. 1804f08c3bdfSopenharmony_ci */ 1805f08c3bdfSopenharmony_cistatic void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry) 1806f08c3bdfSopenharmony_ci{ 1807f08c3bdfSopenharmony_ci pseudo_t arg; 1808f08c3bdfSopenharmony_ci struct symbol *sym, *argtype; 1809f08c3bdfSopenharmony_ci int i, offset, regparm; 1810f08c3bdfSopenharmony_ci 1811f08c3bdfSopenharmony_ci sym = ep->name; 1812f08c3bdfSopenharmony_ci regparm = 0; 1813f08c3bdfSopenharmony_ci if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) 1814f08c3bdfSopenharmony_ci regparm = 3; 1815f08c3bdfSopenharmony_ci sym = sym->ctype.base_type; 1816f08c3bdfSopenharmony_ci i = 0; 1817f08c3bdfSopenharmony_ci offset = 0; 1818f08c3bdfSopenharmony_ci PREPARE_PTR_LIST(sym->arguments, argtype); 1819f08c3bdfSopenharmony_ci FOR_EACH_PTR(entry->arg_list, arg) { 1820f08c3bdfSopenharmony_ci struct storage *in = lookup_storage(entry->bb, arg, STOR_IN); 1821f08c3bdfSopenharmony_ci if (!in) { 1822f08c3bdfSopenharmony_ci in = alloc_storage(); 1823f08c3bdfSopenharmony_ci add_storage(in, entry->bb, arg, STOR_IN); 1824f08c3bdfSopenharmony_ci } 1825f08c3bdfSopenharmony_ci if (i < regparm) { 1826f08c3bdfSopenharmony_ci in->type = REG_REG; 1827f08c3bdfSopenharmony_ci in->regno = i; 1828f08c3bdfSopenharmony_ci } else { 1829f08c3bdfSopenharmony_ci int bits = argtype ? argtype->bit_size : 0; 1830f08c3bdfSopenharmony_ci 1831f08c3bdfSopenharmony_ci if (bits < bits_in_int) 1832f08c3bdfSopenharmony_ci bits = bits_in_int; 1833f08c3bdfSopenharmony_ci 1834f08c3bdfSopenharmony_ci in->type = REG_FRAME; 1835f08c3bdfSopenharmony_ci in->offset = offset; 1836f08c3bdfSopenharmony_ci 1837f08c3bdfSopenharmony_ci offset += bits_to_bytes(bits); 1838f08c3bdfSopenharmony_ci } 1839f08c3bdfSopenharmony_ci i++; 1840f08c3bdfSopenharmony_ci NEXT_PTR_LIST(argtype); 1841f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(arg); 1842f08c3bdfSopenharmony_ci FINISH_PTR_LIST(argtype); 1843f08c3bdfSopenharmony_ci} 1844f08c3bdfSopenharmony_ci 1845f08c3bdfSopenharmony_ci/* 1846f08c3bdfSopenharmony_ci * Set up storage information for "return" 1847f08c3bdfSopenharmony_ci * 1848f08c3bdfSopenharmony_ci * Not strictly necessary, since the code generator will 1849f08c3bdfSopenharmony_ci * certainly move the return value to the right register, 1850f08c3bdfSopenharmony_ci * but it can help register allocation if the allocator 1851f08c3bdfSopenharmony_ci * sees that the target register is going to return in %eax. 1852f08c3bdfSopenharmony_ci */ 1853f08c3bdfSopenharmony_cistatic void set_up_arch_exit(struct basic_block *bb, struct instruction *ret) 1854f08c3bdfSopenharmony_ci{ 1855f08c3bdfSopenharmony_ci pseudo_t pseudo = ret->src; 1856f08c3bdfSopenharmony_ci 1857f08c3bdfSopenharmony_ci if (pseudo && pseudo != VOID) { 1858f08c3bdfSopenharmony_ci struct storage *out = lookup_storage(bb, pseudo, STOR_OUT); 1859f08c3bdfSopenharmony_ci if (!out) { 1860f08c3bdfSopenharmony_ci out = alloc_storage(); 1861f08c3bdfSopenharmony_ci add_storage(out, bb, pseudo, STOR_OUT); 1862f08c3bdfSopenharmony_ci } 1863f08c3bdfSopenharmony_ci out->type = REG_REG; 1864f08c3bdfSopenharmony_ci out->regno = 0; 1865f08c3bdfSopenharmony_ci } 1866f08c3bdfSopenharmony_ci} 1867f08c3bdfSopenharmony_ci 1868f08c3bdfSopenharmony_ci/* 1869f08c3bdfSopenharmony_ci * Set up dummy/silly output storage information for a switch 1870f08c3bdfSopenharmony_ci * instruction. We need to make sure that a register is available 1871f08c3bdfSopenharmony_ci * when we generate code for switch, so force that by creating 1872f08c3bdfSopenharmony_ci * a dummy output rule. 1873f08c3bdfSopenharmony_ci */ 1874f08c3bdfSopenharmony_cistatic void set_up_arch_switch(struct basic_block *bb, struct instruction *insn) 1875f08c3bdfSopenharmony_ci{ 1876f08c3bdfSopenharmony_ci pseudo_t pseudo = insn->cond; 1877f08c3bdfSopenharmony_ci struct storage *out = lookup_storage(bb, pseudo, STOR_OUT); 1878f08c3bdfSopenharmony_ci if (!out) { 1879f08c3bdfSopenharmony_ci out = alloc_storage(); 1880f08c3bdfSopenharmony_ci add_storage(out, bb, pseudo, STOR_OUT); 1881f08c3bdfSopenharmony_ci } 1882f08c3bdfSopenharmony_ci out->type = REG_REG; 1883f08c3bdfSopenharmony_ci out->regno = SWITCH_REG; 1884f08c3bdfSopenharmony_ci} 1885f08c3bdfSopenharmony_ci 1886f08c3bdfSopenharmony_cistatic void arch_set_up_storage(struct entrypoint *ep) 1887f08c3bdfSopenharmony_ci{ 1888f08c3bdfSopenharmony_ci struct basic_block *bb; 1889f08c3bdfSopenharmony_ci 1890f08c3bdfSopenharmony_ci /* Argument storage etc.. */ 1891f08c3bdfSopenharmony_ci set_up_arch_entry(ep, ep->entry); 1892f08c3bdfSopenharmony_ci 1893f08c3bdfSopenharmony_ci FOR_EACH_PTR(ep->bbs, bb) { 1894f08c3bdfSopenharmony_ci struct instruction *insn = last_instruction(bb->insns); 1895f08c3bdfSopenharmony_ci if (!insn) 1896f08c3bdfSopenharmony_ci continue; 1897f08c3bdfSopenharmony_ci switch (insn->opcode) { 1898f08c3bdfSopenharmony_ci case OP_RET: 1899f08c3bdfSopenharmony_ci set_up_arch_exit(bb, insn); 1900f08c3bdfSopenharmony_ci break; 1901f08c3bdfSopenharmony_ci case OP_SWITCH: 1902f08c3bdfSopenharmony_ci set_up_arch_switch(bb, insn); 1903f08c3bdfSopenharmony_ci break; 1904f08c3bdfSopenharmony_ci default: 1905f08c3bdfSopenharmony_ci /* nothing */; 1906f08c3bdfSopenharmony_ci } 1907f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(bb); 1908f08c3bdfSopenharmony_ci} 1909f08c3bdfSopenharmony_ci 1910f08c3bdfSopenharmony_cistatic void output(struct entrypoint *ep) 1911f08c3bdfSopenharmony_ci{ 1912f08c3bdfSopenharmony_ci unsigned long generation = ++bb_generation; 1913f08c3bdfSopenharmony_ci 1914f08c3bdfSopenharmony_ci last_reg = -1; 1915f08c3bdfSopenharmony_ci stack_offset = 0; 1916f08c3bdfSopenharmony_ci 1917f08c3bdfSopenharmony_ci /* Get rid of SSA form (phinodes etc) */ 1918f08c3bdfSopenharmony_ci unssa(ep); 1919f08c3bdfSopenharmony_ci 1920f08c3bdfSopenharmony_ci /* Set up initial inter-bb storage links */ 1921f08c3bdfSopenharmony_ci set_up_storage(ep); 1922f08c3bdfSopenharmony_ci 1923f08c3bdfSopenharmony_ci /* Architecture-specific storage rules.. */ 1924f08c3bdfSopenharmony_ci arch_set_up_storage(ep); 1925f08c3bdfSopenharmony_ci 1926f08c3bdfSopenharmony_ci /* Show the results ... */ 1927f08c3bdfSopenharmony_ci output_bb(ep->entry->bb, generation); 1928f08c3bdfSopenharmony_ci 1929f08c3bdfSopenharmony_ci /* Clear the storage hashes for the next function.. */ 1930f08c3bdfSopenharmony_ci free_storage(); 1931f08c3bdfSopenharmony_ci} 1932f08c3bdfSopenharmony_ci 1933f08c3bdfSopenharmony_cistatic int compile(struct symbol_list *list) 1934f08c3bdfSopenharmony_ci{ 1935f08c3bdfSopenharmony_ci struct symbol *sym; 1936f08c3bdfSopenharmony_ci FOR_EACH_PTR(list, sym) { 1937f08c3bdfSopenharmony_ci struct entrypoint *ep; 1938f08c3bdfSopenharmony_ci expand_symbol(sym); 1939f08c3bdfSopenharmony_ci ep = linearize_symbol(sym); 1940f08c3bdfSopenharmony_ci if (ep) 1941f08c3bdfSopenharmony_ci output(ep); 1942f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(sym); 1943f08c3bdfSopenharmony_ci 1944f08c3bdfSopenharmony_ci return 0; 1945f08c3bdfSopenharmony_ci} 1946f08c3bdfSopenharmony_ci 1947f08c3bdfSopenharmony_ciint main(int argc, char **argv) 1948f08c3bdfSopenharmony_ci{ 1949f08c3bdfSopenharmony_ci struct string_list *filelist = NULL; 1950f08c3bdfSopenharmony_ci char *file; 1951f08c3bdfSopenharmony_ci 1952f08c3bdfSopenharmony_ci compile(sparse_initialize(argc, argv, &filelist)); 1953f08c3bdfSopenharmony_ci dbg_dead = 1; 1954f08c3bdfSopenharmony_ci FOR_EACH_PTR(filelist, file) { 1955f08c3bdfSopenharmony_ci compile(sparse(file)); 1956f08c3bdfSopenharmony_ci } END_FOR_EACH_PTR(file); 1957f08c3bdfSopenharmony_ci return 0; 1958f08c3bdfSopenharmony_ci} 1959f08c3bdfSopenharmony_ci 1960