"Register allocation"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // AAPCS64 (procedure call standard) stuff | |
| uint32_t ngrn = 0; // "Next General-Purpose Register Number (NGRN)" | |
| uint32_t reg_avail = ~((1u << 18) | (1u << 29) | (1u << 30) | (1u << 31)); // available regs | |
| bool regs_assigned = false; | |
| Var *new_arg(const std::string &name) | |
| { | |
| assert(ngrn < 8); // not handling stack args for now | |
| assert(reg_avail & (1u << ngrn)); // reg must be free | |
| Var *v = new_var(name); | |
| v->reg = Reg(ngrn); | |
| reg_avail &= ~(1u << ngrn); | |
| ++ngrn; | |
| return v; | |
| } | |
| // Args get assigned regs immediately; we delay assigning regs to temps until | |
| // we've seen all args. | |
| void assign_temp_regs() | |
| { | |
| Var *spills[32]; | |
| int spill_count = 0; | |
| for (auto &v : vars) | |
| { | |
| if (v->reg.valid) | |
| continue; | |
| if (!reg_avail) | |
| errorf("%s: No register left to assign to variable '%s'.\n", name.c_str(), v->name.c_str()); | |
| // assign first free reg | |
| uint32_t i = 0; | |
| while ((reg_avail & (1u << i)) == 0) | |
| ++i; | |
| v->reg = Reg(i); | |
| reg_avail &= ~(1u << i); | |
| // If it's a callee-save register, we need to generate prologue/epilogue code for it! | |
| if (i >= 19) | |
| spills[spill_count++] = v.get(); | |
| } | |
| // Generate prologue/epilogue code | |
| if (spill_count) | |
| { | |
| int frame_size = (spill_count*8 + 15) & ~15; // SP must stay 16-byte aligned | |
| for (uint32_t i = 0; i < spill_count; ) | |
| { | |
| Addr store_addr = (i == 0) ? Addr::pre_idx(SP, -frame_size) : Addr::base(SP, i*8); | |
| Addr load_addr = (i == 0) ? Addr::post_idx(SP, frame_size) : Addr::base(SP, i*8); | |
| if (i + 1 < spill_count) // use a pair! | |
| { | |
| bb_entry->append(STP(spills[i+0], spills[i+1], store_addr)); | |
| bb_exit->prepend(LDP(spills[i+0], spills[i+1], load_addr)); | |
| i += 2; | |
| } | |
| else | |
| { | |
| bb_entry->append(STR(spills[i], store_addr)); | |
| bb_exit->prepend(LDR(spills[i], load_addr)); | |
| i += 1; | |
| } | |
| } | |
| } | |
| regs_assigned = true; | |
| } | |
| void validate() | |
| { | |
| // Verify that all vars have been assigned registers | |
| for (auto &v : vars) | |
| { | |
| if (!v->reg.valid) | |
| errorf("%s: Variable '%s' has no assigned register.\n", name.c_str(), v->name.c_str()); | |
| } | |
| // Validate all basic blocks | |
| for (auto &bb : blocks) | |
| bb->validate(name.c_str()); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment