| 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 | |