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 ::testing::Test { 29 public: 30 void SetUp() OVERRIDE { 31 allocator_.reset(new ArenaAllocator(&pool_)); 32 graph_ = CreateGraph(allocator_.get()); 33 isa_features_ = MipsInstructionSetFeatures::FromCppDefines(); 34 codegen_ = new (graph_->GetArena()) mips::CodeGeneratorMIPS(graph_, 35 *isa_features_.get(), 36 CompilerOptions()); 37 moves_ = new (allocator_.get()) HParallelMove(allocator_.get()); 38 test_helper_.reset( 39 new AssemblerTestInfrastructure(GetArchitectureString(), 40 GetAssemblerCmdName(), 41 GetAssemblerParameters(), 42 GetObjdumpCmdName(), 43 GetObjdumpParameters(), 44 GetDisassembleCmdName(), 45 GetDisassembleParameters(), 46 GetAssemblyHeader())); 47 } 48 49 void TearDown() OVERRIDE { 50 allocator_.reset(); 51 test_helper_.reset(); 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, std::string assembly_text, std::string test_name) { 95 codegen_->GetMoveResolver()->EmitNativeCode(move); 96 assembler_ = codegen_->GetAssembler(); 97 assembler_->FinalizeCode(); 98 std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(assembler_->CodeSize())); 99 MemoryRegion code(&(*data)[0], data->size()); 100 assembler_->FinalizeInstructions(code); 101 test_helper_->Driver(*data, assembly_text, test_name); 102 } 103 104 protected: 105 ArenaPool pool_; 106 HGraph* graph_; 107 HParallelMove* moves_; 108 mips::CodeGeneratorMIPS* codegen_; 109 mips::MipsAssembler* assembler_; 110 std::unique_ptr<ArenaAllocator> allocator_; 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 Primitive::kPrimInt, 120 nullptr); 121 moves_->AddMove( 122 Location::RegisterLocation(5), 123 Location::RegisterLocation(4), 124 Primitive::kPrimInt, 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 Primitive::kPrimLong, 138 nullptr); 139 moves_->AddMove( 140 Location::RegisterPairLocation(6, 7), 141 Location::RegisterPairLocation(4, 5), 142 Primitive::kPrimLong, 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 Primitive::kPrimFloat, 159 nullptr); 160 moves_->AddMove( 161 Location::FpuRegisterLocation(2), 162 Location::FpuRegisterLocation(4), 163 Primitive::kPrimFloat, 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 Primitive::kPrimDouble, 177 nullptr); 178 moves_->AddMove( 179 Location::FpuRegisterLocation(2), 180 Location::FpuRegisterLocation(4), 181 Primitive::kPrimDouble, 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 Primitive::kPrimFloat, 195 nullptr); 196 moves_->AddMove( 197 Location::FpuRegisterLocation(2), 198 Location::RegisterLocation(4), 199 Primitive::kPrimFloat, 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 Primitive::kPrimDouble, 213 nullptr); 214 moves_->AddMove( 215 Location::FpuRegisterLocation(4), 216 Location::RegisterPairLocation(4, 5), 217 Primitive::kPrimDouble, 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 Primitive::kPrimInt, 234 nullptr); 235 moves_->AddMove( 236 Location::StackSlot(48), 237 Location::StackSlot(52), 238 Primitive::kPrimInt, 239 nullptr); 240 const char* expected = 241 "addiu $sp, $sp, -4\n" 242 "sw $v0, 0($sp)\n" 243 "lw $v0, 56($sp)\n" 244 "lw $t8, 52($sp)\n" 245 "sw $v0, 52($sp)\n" 246 "sw $t8, 56($sp)\n" 247 "lw $v0, 0($sp)\n" 248 "addiu $sp, $sp, 4\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 Primitive::kPrimLong, 257 nullptr); 258 moves_->AddMove( 259 Location::DoubleStackSlot(48), 260 Location::DoubleStackSlot(56), 261 Primitive::kPrimLong, 262 nullptr); 263 const char* expected = 264 "addiu $sp, $sp, -4\n" 265 "sw $v0, 0($sp)\n" 266 "lw $v0, 60($sp)\n" 267 "lw $t8, 52($sp)\n" 268 "sw $v0, 52($sp)\n" 269 "sw $t8, 60($sp)\n" 270 "lw $v0, 64($sp)\n" 271 "lw $t8, 56($sp)\n" 272 "sw $v0, 56($sp)\n" 273 "sw $t8, 64($sp)\n" 274 "lw $v0, 0($sp)\n" 275 "addiu $sp, $sp, 4\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 Primitive::kPrimInt, 284 nullptr); 285 moves_->AddMove( 286 Location::StackSlot(48), 287 Location::RegisterLocation(4), 288 Primitive::kPrimInt, 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 Primitive::kPrimLong, 302 nullptr); 303 moves_->AddMove( 304 Location::DoubleStackSlot(32), 305 Location::RegisterPairLocation(4, 5), 306 Primitive::kPrimLong, 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 Primitive::kPrimFloat, 323 nullptr); 324 moves_->AddMove( 325 Location::StackSlot(48), 326 Location::FpuRegisterLocation(4), 327 Primitive::kPrimFloat, 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 Primitive::kPrimDouble, 341 nullptr); 342 moves_->AddMove( 343 Location::DoubleStackSlot(48), 344 Location::FpuRegisterLocation(4), 345 Primitive::kPrimDouble, 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