OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/compiler/instruction.h" | |
6 #include "src/compiler/register-allocator-verifier.h" | |
7 | |
8 namespace v8 { | |
9 namespace internal { | |
10 namespace compiler { | |
11 | |
12 static size_t OperandCount(const Instruction* instr) { | |
13 return instr->InputCount() + instr->OutputCount() + instr->TempCount(); | |
14 } | |
15 | |
16 | |
17 RegisterAllocatorVerifier::RegisterAllocatorVerifier( | |
18 Zone* zone, const InstructionSequence* sequence) | |
19 : sequence_(sequence), constraints_(zone) { | |
20 constraints_.reserve(sequence->instructions().size()); | |
21 for (const auto* instr : sequence->instructions()) { | |
22 const size_t operand_count = OperandCount(instr); | |
23 auto* op_constraints = | |
24 zone->NewArray<OperandConstraint>(static_cast<int>(operand_count)); | |
25 // Construct OperandConstraints for all InstructionOperands, eliminating | |
26 // kSameAsFirst along the way. | |
27 size_t count = 0; | |
28 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { | |
29 BuildConstraint(instr->InputAt(i), &op_constraints[count]); | |
30 CHECK_NE(kSameAsFirst, op_constraints[count].type_); | |
31 } | |
32 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { | |
33 BuildConstraint(instr->OutputAt(i), &op_constraints[count]); | |
34 if (op_constraints[count].type_ == kSameAsFirst) { | |
35 CHECK(instr->InputCount() > 0); | |
36 op_constraints[count] = op_constraints[0]; | |
37 } | |
38 } | |
39 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { | |
40 BuildConstraint(instr->TempAt(i), &op_constraints[count]); | |
41 CHECK_NE(kSameAsFirst, op_constraints[count].type_); | |
42 } | |
43 // All gaps should be totally unallocated at this point. | |
44 if (instr->IsGapMoves()) { | |
45 const auto* gap = GapInstruction::cast(instr); | |
46 for (int i = GapInstruction::FIRST_INNER_POSITION; | |
47 i <= GapInstruction::LAST_INNER_POSITION; i++) { | |
48 GapInstruction::InnerPosition inner_pos = | |
49 static_cast<GapInstruction::InnerPosition>(i); | |
50 CHECK_EQ(NULL, gap->GetParallelMove(inner_pos)); | |
51 } | |
52 } | |
53 InstructionConstraint instr_constraint = {instr, operand_count, | |
54 op_constraints}; | |
55 constraints()->push_back(instr_constraint); | |
56 } | |
57 } | |
58 | |
59 | |
60 void RegisterAllocatorVerifier::VerifyAssignment() { | |
61 CHECK(sequence()->instructions().size() == constraints()->size()); | |
62 auto instr_it = sequence()->begin(); | |
63 for (const auto& instr_constraint : *constraints()) { | |
64 const auto* instr = instr_constraint.instruction_; | |
65 const size_t operand_count = instr_constraint.operand_constaints_size_; | |
66 const auto* op_constraints = instr_constraint.operand_constraints_; | |
67 CHECK_EQ(instr, *instr_it); | |
68 CHECK(operand_count == OperandCount(instr)); | |
69 size_t count = 0; | |
70 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) { | |
71 CheckConstraint(instr->InputAt(i), &op_constraints[count]); | |
72 } | |
73 for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) { | |
74 CheckConstraint(instr->OutputAt(i), &op_constraints[count]); | |
75 } | |
76 for (size_t i = 0; i < instr->TempCount(); ++i, ++count) { | |
77 CheckConstraint(instr->TempAt(i), &op_constraints[count]); | |
78 } | |
79 ++instr_it; | |
80 } | |
81 } | |
82 | |
83 | |
84 void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op, | |
85 OperandConstraint* constraint) { | |
86 constraint->value_ = kMinInt; | |
87 if (op->IsConstant()) { | |
88 constraint->type_ = kConstant; | |
89 constraint->value_ = ConstantOperand::cast(op)->index(); | |
90 } else if (op->IsImmediate()) { | |
91 constraint->type_ = kImmediate; | |
92 constraint->value_ = ImmediateOperand::cast(op)->index(); | |
93 } else { | |
94 CHECK(op->IsUnallocated()); | |
95 const auto* unallocated = UnallocatedOperand::cast(op); | |
96 int vreg = unallocated->virtual_register(); | |
97 if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) { | |
98 constraint->type_ = kFixedSlot; | |
99 constraint->value_ = unallocated->fixed_slot_index(); | |
100 } else { | |
101 switch (unallocated->extended_policy()) { | |
102 case UnallocatedOperand::ANY: | |
103 CHECK(false); | |
Jarin
2014/11/10 11:24:59
What is wrong with the ANY constraint?
dcarney
2014/11/10 11:27:17
it's only used for phi gap moves, not as an instru
| |
104 break; | |
105 case UnallocatedOperand::NONE: | |
106 if (sequence()->IsDouble(vreg)) { | |
107 constraint->type_ = kNoneDouble; | |
108 } else { | |
109 constraint->type_ = kNone; | |
110 } | |
111 break; | |
112 case UnallocatedOperand::FIXED_REGISTER: | |
113 constraint->type_ = kFixedRegister; | |
114 constraint->value_ = unallocated->fixed_register_index(); | |
115 break; | |
116 case UnallocatedOperand::FIXED_DOUBLE_REGISTER: | |
117 constraint->type_ = kFixedDoubleRegister; | |
118 constraint->value_ = unallocated->fixed_register_index(); | |
119 break; | |
120 case UnallocatedOperand::MUST_HAVE_REGISTER: | |
121 if (sequence()->IsDouble(vreg)) { | |
122 constraint->type_ = kDoubleRegister; | |
123 } else { | |
124 constraint->type_ = kRegister; | |
125 } | |
126 break; | |
127 case UnallocatedOperand::SAME_AS_FIRST_INPUT: | |
128 constraint->type_ = kSameAsFirst; | |
129 break; | |
130 } | |
131 } | |
132 } | |
133 } | |
134 | |
135 | |
136 void RegisterAllocatorVerifier::CheckConstraint( | |
137 const InstructionOperand* op, const OperandConstraint* constraint) { | |
138 switch (constraint->type_) { | |
139 case kConstant: | |
140 CHECK(op->IsConstant()); | |
141 CHECK_EQ(op->index(), constraint->value_); | |
142 return; | |
143 case kImmediate: | |
144 CHECK(op->IsImmediate()); | |
145 CHECK_EQ(op->index(), constraint->value_); | |
146 return; | |
147 case kRegister: | |
148 CHECK(op->IsRegister()); | |
149 return; | |
150 case kFixedRegister: | |
151 CHECK(op->IsRegister()); | |
152 CHECK_EQ(op->index(), constraint->value_); | |
153 return; | |
154 case kDoubleRegister: | |
155 CHECK(op->IsDoubleRegister()); | |
156 return; | |
157 case kFixedDoubleRegister: | |
158 CHECK(op->IsDoubleRegister()); | |
159 CHECK_EQ(op->index(), constraint->value_); | |
160 return; | |
161 case kFixedSlot: | |
162 CHECK(op->IsStackSlot()); | |
163 CHECK_EQ(op->index(), constraint->value_); | |
164 return; | |
165 case kNone: | |
166 CHECK(op->IsRegister() || op->IsStackSlot()); | |
167 return; | |
168 case kNoneDouble: | |
169 CHECK(op->IsDoubleRegister() || op->IsDoubleStackSlot()); | |
170 return; | |
171 case kSameAsFirst: | |
172 CHECK(false); | |
173 return; | |
174 } | |
175 } | |
176 | |
177 } // namespace compiler | |
178 } // namespace internal | |
179 } // namespace v8 | |
OLD | NEW |