Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: src/compiler/register-allocator-verifier.h

Issue 1855023002: [turbofan] New Register Allocator Validator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/compiler/register-allocator-verifier.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_REGISTER_ALLOCATOR_VERIFIER_H_ 5 #ifndef V8_REGISTER_ALLOCATOR_VERIFIER_H_
6 #define V8_REGISTER_ALLOCATOR_VERIFIER_H_ 6 #define V8_REGISTER_ALLOCATOR_VERIFIER_H_
7 7
8 #include "src/zone-containers.h" 8 #include "src/zone-containers.h"
9 9
10 namespace v8 { 10 namespace v8 {
11 namespace internal { 11 namespace internal {
12 namespace compiler { 12 namespace compiler {
13 13
14 class InstructionOperand; 14 class InstructionOperand;
15 class InstructionSequence; 15 class InstructionSequence;
16 16
17 // The register allocator validator traverses instructions in the instruction
18 // sequence, and verifies the correctness of machine operand substitutions of
19 // virtual registers. It collects the virtual register instruction signatures
20 // before register allocation. Then, after the register allocation pipeline
21 // completes, it compares the operand substitutions against the pre-allocation
22 // data.
23 // At a high level, validation works as follows: we iterate through each block,
24 // and, in a block, through each instruction; then:
25 // - when an operand is the output of an instruction, we associate it to the
26 // virtual register that the instruction sequence declares as its output. We
27 // use the concept of "FinalAssessment" to model this.
28 // - when an operand is used in an instruction, we check that the assessment
29 // matches the expectation of the instruction
30 // - moves simply copy the assessment over to the new operand
31 // - blocks with more than one predecessor associate to each operand a "Pending"
32 // assessment. The pending assessment remembers the operand and block where it
33 // was created. Then, when the value is used (which may be as a different
34 // operand, because of moves), we check that the virtual register at the use
35 // site matches the definition of this pending operand: either the phi inputs
36 // match, or, if it's not a phi, all the predecessors at the point the pending
37 // assessment was defined have that operand assigned to the given virtual
38 // register.
39 // If a block is a loop header - so one or more of its predecessors are it or
40 // below - we still treat uses of operands as above, but we record which operand
41 // assessments haven't been made yet, and what virtual register they must
42 // correspond to, and verify that when we are done with the respective
43 // predecessor blocks.
44 // This way, the algorithm always makes a final decision about the operands
45 // in an instruction, ensuring convergence.
46 // Operand assessments are recorded per block, as the result at the exit from
47 // the block. When moving to a new block, we copy assessments from its single
48 // predecessor, or, if the block has multiple predecessors, the mechanism was
49 // described already.
50
51 enum AssessmentKind { Final, Pending };
52
53 class Assessment : public ZoneObject {
54 public:
55 AssessmentKind kind() const { return kind_; }
56
57 protected:
58 explicit Assessment(AssessmentKind kind) : kind_(kind) {}
59 AssessmentKind kind_;
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(Assessment);
63 };
64
65 // FinalAssessmens are associated to operands that we know to be a certain
66 // virtual register.
67 class FinalAssessment final : public Assessment {
68 public:
69 explicit FinalAssessment(int virtual_register)
70 : Assessment(Final), virtual_register_(virtual_register) {}
71
72 int virtual_register() const { return virtual_register_; }
73 static const FinalAssessment* cast(const Assessment* assessment) {
74 CHECK(assessment->kind() == Final);
75 return static_cast<const FinalAssessment*>(assessment);
76 }
77
78 private:
79 int virtual_register_;
80
81 DISALLOW_COPY_AND_ASSIGN(FinalAssessment);
82 };
83
84 // PendingAssessments are associated to operands coming from the multiple
85 // predecessors of a block. We only record the operand and the block, and
86 // will determine if the way the operand is defined (from the predecessors)
87 // matches a particular use. This handles scenarios where multiple phis are
88 // defined with identical operands, and the move optimizer moved down the moves
89 // separating the 2 phis in the block defining them.
90 class PendingAssessment final : public Assessment {
91 public:
92 explicit PendingAssessment(const InstructionBlock* origin,
93 InstructionOperand operand)
94 : Assessment(Pending), origin_(origin), operand_(operand) {}
95
96 static PendingAssessment* cast(Assessment* assessment) {
97 CHECK(assessment->kind() == Pending);
98 return static_cast<PendingAssessment*>(assessment);
99 }
100
101 const InstructionBlock* origin() const { return origin_; }
102 InstructionOperand operand() const { return operand_; }
103
104 private:
105 const InstructionBlock* const origin_;
106 InstructionOperand operand_;
107
108 DISALLOW_COPY_AND_ASSIGN(PendingAssessment);
109 };
110
111 struct OperandAsKeyLess {
112 bool operator()(const InstructionOperand& a,
113 const InstructionOperand& b) const {
114 return a.CompareCanonicalized(b);
115 }
116 };
117
118 // Assessments associated with a basic block.
119 class BlockAssessments : public ZoneObject {
120 public:
121 typedef ZoneMap<InstructionOperand, Assessment*, OperandAsKeyLess> OperandMap;
122 explicit BlockAssessments(Zone* zone)
123 : map_(zone), map_for_moves_(zone), zone_(zone) {}
124 void Drop(InstructionOperand operand) { map_.erase(operand); }
125 void DropRegisters();
126 void AddDefinition(InstructionOperand operand, int virtual_register) {
127 auto existent = map_.find(operand);
128 if (existent != map_.end()) {
129 // Drop the assignment
130 map_.erase(existent);
131 }
132 map_.insert(
133 std::make_pair(operand, new (zone_) FinalAssessment(virtual_register)));
134 }
135
136 void PerformMoves(const Instruction* instruction);
137 void PerformParallelMoves(const ParallelMove* moves);
138 void CopyFrom(const BlockAssessments* other) {
139 CHECK(map_.empty());
140 CHECK_NOT_NULL(other);
141 map_.insert(other->map_.begin(), other->map_.end());
142 }
143
144 OperandMap& map() { return map_; }
145 const OperandMap& map() const { return map_; }
146 void Print() const;
147
148 private:
149 OperandMap map_;
150 OperandMap map_for_moves_;
151 Zone* zone_;
152
153 DISALLOW_COPY_AND_ASSIGN(BlockAssessments);
154 };
155
17 class RegisterAllocatorVerifier final : public ZoneObject { 156 class RegisterAllocatorVerifier final : public ZoneObject {
18 public: 157 public:
19 RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config, 158 RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config,
20 const InstructionSequence* sequence); 159 const InstructionSequence* sequence);
21 160
22 void VerifyAssignment(); 161 void VerifyAssignment();
23 void VerifyGapMoves(); 162 void VerifyGapMoves();
24 163
25 private: 164 private:
26 enum ConstraintType { 165 enum ConstraintType {
(...skipping 19 matching lines...) Expand all
46 int spilled_slot_; 185 int spilled_slot_;
47 int virtual_register_; 186 int virtual_register_;
48 }; 187 };
49 188
50 struct InstructionConstraint { 189 struct InstructionConstraint {
51 const Instruction* instruction_; 190 const Instruction* instruction_;
52 size_t operand_constaints_size_; 191 size_t operand_constaints_size_;
53 OperandConstraint* operand_constraints_; 192 OperandConstraint* operand_constraints_;
54 }; 193 };
55 194
56 class BlockMaps; 195 typedef ZoneVector<InstructionConstraint> Constraints;
57 196
58 typedef ZoneVector<InstructionConstraint> Constraints; 197 class DelayedAssessments : public ZoneObject {
198 public:
199 explicit DelayedAssessments(Zone* zone) : map_(zone) {}
200
201 const ZoneMap<InstructionOperand, int, OperandAsKeyLess>& map() const {
202 return map_;
203 }
204
205 void AddDelayedAssessment(InstructionOperand op, int vreg) {
206 auto it = map_.find(op);
207 if (it == map_.end()) {
208 map_.insert(std::make_pair(op, vreg));
209 } else {
210 CHECK_EQ(it->second, vreg);
211 }
212 }
213
214 private:
215 ZoneMap<InstructionOperand, int, OperandAsKeyLess> map_;
216 };
59 217
60 Zone* zone() const { return zone_; } 218 Zone* zone() const { return zone_; }
61 const RegisterConfiguration* config() { return config_; } 219 const RegisterConfiguration* config() { return config_; }
62 const InstructionSequence* sequence() const { return sequence_; } 220 const InstructionSequence* sequence() const { return sequence_; }
63 Constraints* constraints() { return &constraints_; } 221 Constraints* constraints() { return &constraints_; }
64 222
65 static void VerifyInput(const OperandConstraint& constraint); 223 static void VerifyInput(const OperandConstraint& constraint);
66 static void VerifyTemp(const OperandConstraint& constraint); 224 static void VerifyTemp(const OperandConstraint& constraint);
67 static void VerifyOutput(const OperandConstraint& constraint); 225 static void VerifyOutput(const OperandConstraint& constraint);
68 226
69 void BuildConstraint(const InstructionOperand* op, 227 void BuildConstraint(const InstructionOperand* op,
70 OperandConstraint* constraint); 228 OperandConstraint* constraint);
71 void CheckConstraint(const InstructionOperand* op, 229 void CheckConstraint(const InstructionOperand* op,
72 const OperandConstraint* constraint); 230 const OperandConstraint* constraint);
231 BlockAssessments* CreateForBlock(const InstructionBlock* block);
73 232
74 void VerifyGapMoves(BlockMaps* outgoing_mappings, bool initial_pass); 233 void ValidatePendingAssessment(RpoNumber block_id, InstructionOperand op,
234 PendingAssessment* assessment,
235 int virtual_register);
236 void ValidateUse(RpoNumber block_id, BlockAssessments* current_assessments,
237 InstructionOperand op, int virtual_register);
75 238
76 Zone* const zone_; 239 Zone* const zone_;
77 const RegisterConfiguration* config_; 240 const RegisterConfiguration* config_;
78 const InstructionSequence* const sequence_; 241 const InstructionSequence* const sequence_;
79 Constraints constraints_; 242 Constraints constraints_;
243 ZoneMap<RpoNumber, BlockAssessments*> assessments_;
244 ZoneMap<RpoNumber, DelayedAssessments*> outstanding_assessments_;
245
246 // Cached structures, to avoid memory churn. Needed solely in
247 // ValidatePendingAssessment.
248 ZoneQueue<std::pair<PendingAssessment*, int>> worklist_;
249 ZoneSet<RpoNumber> seen_;
80 250
81 DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorVerifier); 251 DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorVerifier);
82 }; 252 };
83 253
84 } // namespace compiler 254 } // namespace compiler
85 } // namespace internal 255 } // namespace internal
86 } // namespace v8 256 } // namespace v8
87 257
88 #endif 258 #endif
OLDNEW
« no previous file with comments | « no previous file | src/compiler/register-allocator-verifier.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698