1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "base/arena_allocator.h" 18 #include "code_generator_mips.h" 19 #include "optimizing_unit_test.h" 20 #include "parallel_move_resolver.h" 21 #include "utils/assembler_test_base.h" 22 #include "utils/mips/assembler_mips.h" 23 24 #include "gtest/gtest.h" 25 26 namespace art { 27 28 class EmitSwapMipsTest : public OptimizingUnitTest { 29 public: 30 void SetUp() OVERRIDE { 31 graph_ = CreateGraph(); 32 isa_features_ = MipsInstructionSetFeatures::FromCppDefines(); 33 codegen_ = new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_, 34 *isa_features_.get(), 35 CompilerOptions()); 36 moves_ = new (GetAllocator()) HParallelMove(GetAllocator()); 37 test_helper_.reset( 38 new AssemblerTestInfrastructure(GetArchitectureString(), 39 GetAssemblerCmdName(), 40 GetAssemblerParameters(), 41 GetObjdumpCmdName(), 42 GetObjdumpParameters(), 43 GetDisassembleCmdName(), 44 GetDisassembleParameters(), 45 GetAssemblyHeader())); 46 } 47 48 void TearDown() OVERRIDE { 49 test_helper_.reset(); 50 isa_features_.reset(); 51 ResetPoolAndAllocator(); 52 } 53 54 // Get the typically used name for this architecture. 55 std::string GetArchitectureString() { 56 return "mips"; 57 } 58 59 // Get the name of the assembler. 60 std::string GetAssemblerCmdName() { 61 return "as"; 62 } 63 64 // Switches to the assembler command. 65 std::string GetAssemblerParameters() { 66 return " --no-warn -32 -march=mips32r2"; 67 } 68 69 // Get the name of the objdump. 70 std::string GetObjdumpCmdName() { 71 return "objdump"; 72 } 73 74 // Switches to the objdump command. 75 std::string GetObjdumpParameters() { 76 return " -h"; 77 } 78 79 // Get the name of the objdump. 80 std::string GetDisassembleCmdName() { 81 return "objdump"; 82 } 83 84 // Switches to the objdump command. 85 std::string GetDisassembleParameters() { 86 return " -D -bbinary -mmips:isa32r2"; 87 } 88 89 // No need for assembly header here. 90 const char* GetAssemblyHeader() { 91 return nullptr; 92 } 93 94 void DriverWrapper(HParallelMove* move, 95 const std::string& assembly_text, 96 const std::string& test_name) { 97 codegen_->GetMoveResolver()->EmitNativeCode(move); 98 assembler_ = codegen_->GetAssembler(); 99 assembler_->FinalizeCode(); 100 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(assembler_->CodeSize())); 101 MemoryRegion code(&(*data)[0], data->size()); 102 assembler_->FinalizeInstructions(code); 103 test_helper_->Driver(*data, assembly_text, test_name); 104 } 105 106 protected: 107 HGraph* graph_; 108 HParallelMove* moves_; 109 mips::CodeGeneratorMIPS* codegen_; 110 mips::MipsAssembler* assembler_; 111 std::unique_ptr<AssemblerTestInfrastructure> test_helper_; 112 std::unique_ptr<const MipsInstructionSetFeatures> isa_features_; 113 }; 114 115 TEST_F(EmitSwapMipsTest, TwoRegisters) { 116 moves_->AddMove( 117 Location::RegisterLocation(4), 118 Location::RegisterLocation(5), 119 DataType::Type::kInt32, 120 nullptr); 121 moves_->AddMove( 122 Location::RegisterLocation(5), 123 Location::RegisterLocation(4), 124 DataType::Type::kInt32, 125 nullptr); 126 const char* expected = 127 "or $t8, $a1, $zero\n" 128 "or $a1, $a0, $zero\n" 129 "or $a0, $t8, $zero\n"; 130 DriverWrapper(moves_, expected, "TwoRegisters"); 131 } 132 133 TEST_F(EmitSwapMipsTest, TwoRegisterPairs) { 134 moves_->AddMove( 135 Location::RegisterPairLocation(4, 5), 136 Location::RegisterPairLocation(6, 7), 137 DataType::Type::kInt64, 138 nullptr); 139 moves_->AddMove( 140 Location::RegisterPairLocation(6, 7), 141 Location::RegisterPairLocation(4, 5), 142 DataType::Type::kInt64, 143 nullptr); 144 const char* expected = 145 "or $t8, $a2, $zero\n" 146 "or $a2, $a0, $zero\n" 147 "or $a0, $t8, $zero\n" 148 "or $t8, $a3, $zero\n" 149 "or $a3, $a1, $zero\n" 150 "or $a1, $t8, $zero\n"; 151 DriverWrapper(moves_, expected, "TwoRegisterPairs"); 152 } 153 154 TEST_F(EmitSwapMipsTest, TwoFpuRegistersFloat) { 155 moves_->AddMove( 156 Location::FpuRegisterLocation(4), 157 Location::FpuRegisterLocation(2), 158 DataType::Type::kFloat32, 159 nullptr); 160 moves_->AddMove( 161 Location::FpuRegisterLocation(2), 162 Location::FpuRegisterLocation(4), 163 DataType::Type::kFloat32, 164 nullptr); 165 const char* expected = 166 "mov.s $f6, $f2\n" 167 "mov.s $f2, $f4\n" 168 "mov.s $f4, $f6\n"; 169 DriverWrapper(moves_, expected, "TwoFpuRegistersFloat"); 170 } 171 172 TEST_F(EmitSwapMipsTest, TwoFpuRegistersDouble) { 173 moves_->AddMove( 174 Location::FpuRegisterLocation(4), 175 Location::FpuRegisterLocation(2), 176 DataType::Type::kFloat64, 177 nullptr); 178 moves_->AddMove( 179 Location::FpuRegisterLocation(2), 180 Location::FpuRegisterLocation(4), 181 DataType::Type::kFloat64, 182 nullptr); 183 const char* expected = 184 "mov.d $f6, $f2\n" 185 "mov.d $f2, $f4\n" 186 "mov.d $f4, $f6\n"; 187 DriverWrapper(moves_, expected, "TwoFpuRegistersDouble"); 188 } 189 190 TEST_F(EmitSwapMipsTest, RegisterAndFpuRegister) { 191 moves_->AddMove( 192 Location::RegisterLocation(4), 193 Location::FpuRegisterLocation(2), 194 DataType::Type::kFloat32, 195 nullptr); 196 moves_->AddMove( 197 Location::FpuRegisterLocation(2), 198 Location::RegisterLocation(4), 199 DataType::Type::kFloat32, 200 nullptr); 201 const char* expected = 202 "or $t8, $a0, $zero\n" 203 "mfc1 $a0, $f2\n" 204 "mtc1 $t8, $f2\n"; 205 DriverWrapper(moves_, expected, "RegisterAndFpuRegister"); 206 } 207 208 TEST_F(EmitSwapMipsTest, RegisterPairAndFpuRegister) { 209 moves_->AddMove( 210 Location::RegisterPairLocation(4, 5), 211 Location::FpuRegisterLocation(4), 212 DataType::Type::kFloat64, 213 nullptr); 214 moves_->AddMove( 215 Location::FpuRegisterLocation(4), 216 Location::RegisterPairLocation(4, 5), 217 DataType::Type::kFloat64, 218 nullptr); 219 const char* expected = 220 "mfc1 $t8, $f4\n" 221 "mfc1 $at, $f5\n" 222 "mtc1 $a0, $f4\n" 223 "mtc1 $a1, $f5\n" 224 "or $a0, $t8, $zero\n" 225 "or $a1, $at, $zero\n"; 226 DriverWrapper(moves_, expected, "RegisterPairAndFpuRegister"); 227 } 228 229 TEST_F(EmitSwapMipsTest, TwoStackSlots) { 230 moves_->AddMove( 231 Location::StackSlot(52), 232 Location::StackSlot(48), 233 DataType::Type::kInt32, 234 nullptr); 235 moves_->AddMove( 236 Location::StackSlot(48), 237 Location::StackSlot(52), 238 DataType::Type::kInt32, 239 nullptr); 240 const char* expected = 241 "addiu $sp, $sp, -16\n" 242 "sw $v0, 0($sp)\n" 243 "lw $v0, 68($sp)\n" 244 "lw $t8, 64($sp)\n" 245 "sw $v0, 64($sp)\n" 246 "sw $t8, 68($sp)\n" 247 "lw $v0, 0($sp)\n" 248 "addiu $sp, $sp, 16\n"; 249 DriverWrapper(moves_, expected, "TwoStackSlots"); 250 } 251 252 TEST_F(EmitSwapMipsTest, TwoDoubleStackSlots) { 253 moves_->AddMove( 254 Location::DoubleStackSlot(56), 255 Location::DoubleStackSlot(48), 256 DataType::Type::kInt64, 257 nullptr); 258 moves_->AddMove( 259 Location::DoubleStackSlot(48), 260 Location::DoubleStackSlot(56), 261 DataType::Type::kInt64, 262 nullptr); 263 const char* expected = 264 "addiu $sp, $sp, -16\n" 265 "sw $v0, 0($sp)\n" 266 "lw $v0, 72($sp)\n" 267 "lw $t8, 64($sp)\n" 268 "sw $v0, 64($sp)\n" 269 "sw $t8, 72($sp)\n" 270 "lw $v0, 76($sp)\n" 271 "lw $t8, 68($sp)\n" 272 "sw $v0, 68($sp)\n" 273 "sw $t8, 76($sp)\n" 274 "lw $v0, 0($sp)\n" 275 "addiu $sp, $sp, 16\n"; 276 DriverWrapper(moves_, expected, "TwoDoubleStackSlots"); 277 } 278 279 TEST_F(EmitSwapMipsTest, RegisterAndStackSlot) { 280 moves_->AddMove( 281 Location::RegisterLocation(4), 282 Location::StackSlot(48), 283 DataType::Type::kInt32, 284 nullptr); 285 moves_->AddMove( 286 Location::StackSlot(48), 287 Location::RegisterLocation(4), 288 DataType::Type::kInt32, 289 nullptr); 290 const char* expected = 291 "or $t8, $a0, $zero\n" 292 "lw $a0, 48($sp)\n" 293 "sw $t8, 48($sp)\n"; 294 DriverWrapper(moves_, expected, "RegisterAndStackSlot"); 295 } 296 297 TEST_F(EmitSwapMipsTest, RegisterPairAndDoubleStackSlot) { 298 moves_->AddMove( 299 Location::RegisterPairLocation(4, 5), 300 Location::DoubleStackSlot(32), 301 DataType::Type::kInt64, 302 nullptr); 303 moves_->AddMove( 304 Location::DoubleStackSlot(32), 305 Location::RegisterPairLocation(4, 5), 306 DataType::Type::kInt64, 307 nullptr); 308 const char* expected = 309 "or $t8, $a0, $zero\n" 310 "lw $a0, 32($sp)\n" 311 "sw $t8, 32($sp)\n" 312 "or $t8, $a1, $zero\n" 313 "lw $a1, 36($sp)\n" 314 "sw $t8, 36($sp)\n"; 315 DriverWrapper(moves_, expected, "RegisterPairAndDoubleStackSlot"); 316 } 317 318 TEST_F(EmitSwapMipsTest, FpuRegisterAndStackSlot) { 319 moves_->AddMove( 320 Location::FpuRegisterLocation(4), 321 Location::StackSlot(48), 322 DataType::Type::kFloat32, 323 nullptr); 324 moves_->AddMove( 325 Location::StackSlot(48), 326 Location::FpuRegisterLocation(4), 327 DataType::Type::kFloat32, 328 nullptr); 329 const char* expected = 330 "mov.s $f6, $f4\n" 331 "lwc1 $f4, 48($sp)\n" 332 "swc1 $f6, 48($sp)\n"; 333 DriverWrapper(moves_, expected, "FpuRegisterAndStackSlot"); 334 } 335 336 TEST_F(EmitSwapMipsTest, FpuRegisterAndDoubleStackSlot) { 337 moves_->AddMove( 338 Location::FpuRegisterLocation(4), 339 Location::DoubleStackSlot(48), 340 DataType::Type::kFloat64, 341 nullptr); 342 moves_->AddMove( 343 Location::DoubleStackSlot(48), 344 Location::FpuRegisterLocation(4), 345 DataType::Type::kFloat64, 346 nullptr); 347 const char* expected = 348 "mov.d $f6, $f4\n" 349 "ldc1 $f4, 48($sp)\n" 350 "sdc1 $f6, 48($sp)\n"; 351 DriverWrapper(moves_, expected, "FpuRegisterAndDoubleStackSlot"); 352 } 353 354 } // namespace art 355