this repo has no description
at trunk 114 lines 3.6 kB view raw
1/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */ 2#pragma once 3 4#include "assembler-x64.h" 5#include "view.h" 6 7namespace py { 8namespace x64 { 9 10class WARN_UNUSED VirtualRegister { 11 public: 12 VirtualRegister(const char* name); 13 14 operator Register(); 15 16 void assign(Register reg); 17 void free(); 18 bool isAssigned(); 19 const char* name(); 20 21 private: 22 Register assigned_ = kNoRegister; 23 const char* name_; 24}; 25 26struct RegisterAssignment { 27 VirtualRegister* vreg; 28 Register reg; 29}; 30 31static constexpr View<RegisterAssignment> kNoRegisterAssignment = 32 View<RegisterAssignment>(nullptr, 0); 33 34/// Register state tracker. 35/// Tracks assignment of registers to instances of the `VirtualRegister` class. 36/// This helps catching problems in code generating machine code. 37/// 38/// Straight line code example: 39/// VirtualRegister r_value; 40/// reg_state->assign(&r_value, RAX); 41/// __ movl(r_value, Immediate(42)); 42/// __ pushq(r_value); 43/// reg_state->clobber({..., RAX, ...}); 44/// __ pushq(r_value); // Fails because r_value is no longer assigned. 45/// 46/// Re-use example 47/// VirtualRegister r_value; 48/// reg_state->assign(&r_value, RAX); 49/// __ popq(r_value) 50/// // ... 51/// VirtualRegister r_other; 52/// reg_state->assign(&r_other, RAX); // this resets `r_value` kNoRegister 53/// __ movl(r_other, Immediate(5)); 54/// // .. 55/// __ movl(..., r_value); // Fails because `r_value` is no longer assigned 56/// 57/// Control Flow 58/// When there are multiple jumps to a common label then there is usually also 59/// an expectation to what registers values are available/unavailable in a 60/// particular register at that label. Use `RegisterAssignment` lists for that. 61/// 62/// // In env struct: 63/// VirtualRegister arg0; 64/// VirtualRegister arg1; 65/// View<RegisterAssignment> function_begin_assignment; 66/// Label function_begin; 67/// 68/// RegisterAssignment function_begin_assignment[] = { 69/// {&env->arg0, RDI}, 70/// {&env->arg1, RSI}, 71/// }; 72/// env->function_begin_assignment = function_begin_assignment; 73/// 74/// // Reset state to expected assignment at common label. 75/// // Revert all register assignment; then assign RDI to arg0, RSI to arg1. 76/// reg_state->resetTo(env->function_begin_assignment); 77/// __ bind(&env->function_begin); 78/// __ pushq(env->arg0); 79/// ... 80/// // Check assignment before jumping to label. Fail if arg0 is not 81/// // assigned to RDI or arg1 not assigned to RSI. 82/// reg_state->check(&env->function_begin_assignment); 83/// __ jmp(&env->function_begin); 84class RegisterState { 85 public: 86 RegisterState(); 87 88 void assign(VirtualRegister* vreg, Register reg); 89 void free(VirtualRegister* vreg); 90 void allocate(VirtualRegister* vreg, View<Register> candidates); 91 void clobber(View<Register> registers); 92 93 void reset(); 94 void resetTo(View<RegisterAssignment> assignment); 95 void check(View<RegisterAssignment> assignment); 96 97 private: 98 VirtualRegister* assignment_[kNumRegisters]; 99}; 100 101inline VirtualRegister::VirtualRegister(const char* name) : name_(name) {} 102 103inline VirtualRegister::operator Register() { 104 CHECK(isAssigned(), "no register assigned to '%s'", name_); 105 return assigned_; 106} 107 108inline void VirtualRegister::assign(Register reg) { assigned_ = reg; } 109inline void VirtualRegister::free() { assigned_ = kNoRegister; } 110inline bool VirtualRegister::isAssigned() { return assigned_ != kNoRegister; } 111inline const char* VirtualRegister::name() { return name_; } 112 113} // namespace x64 114} // namespace py