this repo has no description
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