1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/compiler/backend/locations_helpers.h" |
6 | #include "vm/dart_api_impl.h" |
7 | #include "vm/dart_entry.h" |
8 | #include "vm/unit_test.h" |
9 | |
10 | namespace dart { |
11 | |
12 | #define Reg(index) (static_cast<Register>(index)) |
13 | #define Fpu(index) (static_cast<FpuRegister>(index)) |
14 | |
15 | #define ReqReg Location::RequiresRegister() |
16 | #define ReqFpu Location::RequiresFpuRegister() |
17 | #define RegLoc(index) Location::RegisterLocation(Reg(index)) |
18 | #define FpuLoc(index) Location::FpuRegisterLocation(Fpu(index)) |
19 | |
20 | typedef ZoneGrowableArray<Location> LocationArray; |
21 | |
22 | static LocationArray* MakeLocationArray() { |
23 | LocationArray* arr = new LocationArray(); |
24 | return arr; |
25 | } |
26 | |
27 | static LocationArray* MakeLocationArray(Location loc0) { |
28 | LocationArray* arr = new LocationArray(); |
29 | arr->Add(loc0); |
30 | return arr; |
31 | } |
32 | |
33 | static LocationArray* MakeLocationArray(Location loc0, Location loc1) { |
34 | LocationArray* arr = new LocationArray(); |
35 | arr->Add(loc0); |
36 | arr->Add(loc1); |
37 | return arr; |
38 | } |
39 | |
40 | static void ValidateSummary(LocationSummary* locs, |
41 | Location expected_output, |
42 | const LocationArray* expected_inputs, |
43 | const LocationArray* expected_temps) { |
44 | EXPECT(locs->out(0).Equals(expected_output)); |
45 | EXPECT_EQ(expected_inputs->length(), locs->input_count()); |
46 | for (intptr_t i = 0; i < expected_inputs->length(); i++) { |
47 | EXPECT(locs->in(i).Equals(expected_inputs->At(i))); |
48 | } |
49 | EXPECT_EQ(expected_temps->length(), locs->temp_count()); |
50 | for (intptr_t i = 0; i < expected_temps->length(); i++) { |
51 | EXPECT(locs->temp(i).Equals(expected_temps->At(i))); |
52 | } |
53 | } |
54 | |
55 | static void FillSummary(LocationSummary* locs, |
56 | Location expected_output, |
57 | const LocationArray* expected_inputs, |
58 | const LocationArray* expected_temps) { |
59 | locs->set_out(0, expected_output); |
60 | for (intptr_t i = 0; i < expected_inputs->length(); i++) { |
61 | locs->set_in(i, expected_inputs->At(i)); |
62 | } |
63 | for (intptr_t i = 0; i < expected_temps->length(); i++) { |
64 | locs->set_temp(i, expected_temps->At(i)); |
65 | } |
66 | } |
67 | |
68 | class MockInstruction : public ZoneAllocated { |
69 | public: |
70 | virtual ~MockInstruction() {} |
71 | |
72 | LocationSummary* locs() { |
73 | if (locs_ == NULL) { |
74 | locs_ = MakeLocationSummary(Thread::Current()->zone(), false); |
75 | } |
76 | return locs_; |
77 | } |
78 | |
79 | virtual LocationSummary* MakeLocationSummary(Zone* zone, bool opt) const = 0; |
80 | virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0; |
81 | |
82 | private: |
83 | LocationSummary* locs_; |
84 | }; |
85 | |
86 | #define INSTRUCTION_TEST(Name, Arity, Signature, ExpectedOut, ExpectedIn, \ |
87 | ExpectedTemp, AllocatedOut, AllocatedIn, \ |
88 | AllocatedTemp) \ |
89 | class Name##Instr : public MockInstruction { \ |
90 | public: \ |
91 | LocationSummary* MakeLocationSummary(Zone* zone, bool opt) const; \ |
92 | void EmitNativeCode(FlowGraphCompiler* compiler); \ |
93 | virtual intptr_t InputCount() const { return Arity; } \ |
94 | }; \ |
95 | TEST_CASE(LocationsHelpers_##Name) { \ |
96 | const Location expected_out = ExpectedOut; \ |
97 | const LocationArray* expected_inputs = MakeLocationArray ExpectedIn; \ |
98 | const LocationArray* expected_temps = MakeLocationArray ExpectedTemp; \ |
99 | \ |
100 | const Location allocated_out = AllocatedOut; \ |
101 | const LocationArray* allocated_inputs = MakeLocationArray AllocatedIn; \ |
102 | const LocationArray* allocated_temps = MakeLocationArray AllocatedTemp; \ |
103 | \ |
104 | Name##Instr* instr = new Name##Instr(); \ |
105 | LocationSummary* locs = instr->locs(); \ |
106 | \ |
107 | ValidateSummary(locs, expected_out, expected_inputs, expected_temps); \ |
108 | FillSummary(locs, allocated_out, allocated_inputs, allocated_temps); \ |
109 | \ |
110 | instr->EmitNativeCode(NULL); \ |
111 | } \ |
112 | DEFINE_BACKEND(Name, Signature) |
113 | |
114 | // Reg -> Reg |
115 | INSTRUCTION_TEST(Unary, |
116 | 1, |
117 | (Register out, Register in), |
118 | ReqReg, |
119 | (ReqReg), |
120 | (), |
121 | RegLoc(0), |
122 | (RegLoc(1)), |
123 | ()) { |
124 | EXPECT_EQ(Reg(0), out); |
125 | EXPECT_EQ(Reg(1), in); |
126 | } |
127 | |
128 | // (Reg, Fpu) -> Reg |
129 | INSTRUCTION_TEST(Binary1, |
130 | 2, |
131 | (Register out, Register in0, FpuRegister in1), |
132 | ReqReg, |
133 | (ReqReg, Location::RequiresFpuRegister()), |
134 | (), |
135 | RegLoc(0), |
136 | (RegLoc(1), FpuLoc(2)), |
137 | ()) { |
138 | EXPECT_EQ(Reg(0), out); |
139 | EXPECT_EQ(Reg(1), in0); |
140 | EXPECT_EQ(Fpu(2), in1); |
141 | } |
142 | |
143 | // (Fpu, Reg) -> Reg |
144 | INSTRUCTION_TEST(Binary2, |
145 | 2, |
146 | (Register out, FpuRegister in0, Register in1), |
147 | ReqReg, |
148 | (ReqFpu, ReqReg), |
149 | (), |
150 | RegLoc(0), |
151 | (FpuLoc(1), RegLoc(2)), |
152 | ()) { |
153 | EXPECT_EQ(Reg(0), out); |
154 | EXPECT_EQ(Fpu(1), in0); |
155 | EXPECT_EQ(Reg(2), in1); |
156 | } |
157 | |
158 | // -> Reg(3) |
159 | INSTRUCTION_TEST(FixedOutput, |
160 | 0, |
161 | (Fixed<Register, Reg(3)> out), |
162 | RegLoc(3), |
163 | (), |
164 | (), |
165 | RegLoc(3), |
166 | (), |
167 | ()) { |
168 | EXPECT_EQ(Reg(3), Reg(out)); |
169 | } |
170 | |
171 | // Fpu(3) -> Fpu |
172 | INSTRUCTION_TEST(FixedInput, |
173 | 1, |
174 | (FpuRegister out, Fixed<FpuRegister, Fpu(3)> in), |
175 | ReqFpu, |
176 | (FpuLoc(3)), |
177 | (), |
178 | FpuLoc(0), |
179 | (FpuLoc(3)), |
180 | ()) { |
181 | EXPECT_EQ(Fpu(0), out); |
182 | EXPECT_EQ(Fpu(3), Fpu(in)); |
183 | } |
184 | |
185 | // Reg -> SameAsFirstInput |
186 | INSTRUCTION_TEST(SameAsFirstInput, |
187 | 2, |
188 | (SameAsFirstInput, Register in0, Register in1), |
189 | Location::SameAsFirstInput(), |
190 | (ReqReg, ReqReg), |
191 | (), |
192 | RegLoc(0), |
193 | (RegLoc(0), RegLoc(1)), |
194 | ()) { |
195 | EXPECT_EQ(Reg(0), in0); |
196 | EXPECT_EQ(Reg(1), in1); |
197 | } |
198 | |
199 | // {Temps: Fpu, Reg} (Reg, Fpu) -> Reg |
200 | INSTRUCTION_TEST(Temps, |
201 | 2, |
202 | (Register out, |
203 | Register in0, |
204 | FpuRegister in1, |
205 | Temp<FpuRegister> temp0, |
206 | Temp<Register> temp1), |
207 | ReqReg, |
208 | (ReqReg, ReqFpu), |
209 | (ReqFpu, ReqReg), |
210 | RegLoc(0), |
211 | (RegLoc(1), FpuLoc(2)), |
212 | (FpuLoc(3), RegLoc(4))) { |
213 | EXPECT_EQ(Reg(0), out); |
214 | EXPECT_EQ(Reg(1), in0); |
215 | EXPECT_EQ(Fpu(2), in1); |
216 | EXPECT_EQ(Fpu(3), Fpu(temp0)); |
217 | EXPECT_EQ(Reg(4), Reg(temp1)); |
218 | } |
219 | |
220 | // {Temps: Fpu(3)} -> Fpu |
221 | INSTRUCTION_TEST(FixedTemp, |
222 | 0, |
223 | (FpuRegister out, Temp<Fixed<FpuRegister, Fpu(3)> > temp), |
224 | ReqFpu, |
225 | (), |
226 | (FpuLoc(3)), |
227 | FpuLoc(4), |
228 | (), |
229 | (FpuLoc(3))) { |
230 | EXPECT_EQ(Fpu(4), out); |
231 | EXPECT_EQ(Fpu(3), Fpu(temp)); |
232 | } |
233 | |
234 | } // namespace dart |
235 | |