| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2015 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 | #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_ | 
|  | 18 | #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_ | 
|  | 19 |  | 
|  | 20 | #include "code_generator.h" | 
| David Sehr | 312f3b2 | 2018-03-19 08:39:26 -0700 | [diff] [blame] | 21 | #include "dex/type_reference.h" | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 22 | #include "driver/compiler_options.h" | 
|  | 23 | #include "nodes.h" | 
|  | 24 | #include "parallel_move_resolver.h" | 
|  | 25 | #include "utils/mips64/assembler_mips64.h" | 
|  | 26 |  | 
|  | 27 | namespace art { | 
|  | 28 | namespace mips64 { | 
|  | 29 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 30 | // InvokeDexCallingConvention registers | 
|  | 31 |  | 
|  | 32 | static constexpr GpuRegister kParameterCoreRegisters[] = | 
|  | 33 | { A1, A2, A3, A4, A5, A6, A7 }; | 
|  | 34 | static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); | 
|  | 35 |  | 
|  | 36 | static constexpr FpuRegister kParameterFpuRegisters[] = | 
|  | 37 | { F13, F14, F15, F16, F17, F18, F19 }; | 
|  | 38 | static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters); | 
|  | 39 |  | 
|  | 40 |  | 
|  | 41 | // InvokeRuntimeCallingConvention registers | 
|  | 42 |  | 
|  | 43 | static constexpr GpuRegister kRuntimeParameterCoreRegisters[] = | 
|  | 44 | { A0, A1, A2, A3, A4, A5, A6, A7 }; | 
|  | 45 | static constexpr size_t kRuntimeParameterCoreRegistersLength = | 
|  | 46 | arraysize(kRuntimeParameterCoreRegisters); | 
|  | 47 |  | 
|  | 48 | static constexpr FpuRegister kRuntimeParameterFpuRegisters[] = | 
|  | 49 | { F12, F13, F14, F15, F16, F17, F18, F19 }; | 
|  | 50 | static constexpr size_t kRuntimeParameterFpuRegistersLength = | 
|  | 51 | arraysize(kRuntimeParameterFpuRegisters); | 
|  | 52 |  | 
|  | 53 |  | 
|  | 54 | static constexpr GpuRegister kCoreCalleeSaves[] = | 
| Alexey Frunze | 627c1a0 | 2017-01-30 19:28:14 -0800 | [diff] [blame] | 55 | { S0, S1, S2, S3, S4, S5, S6, S7, GP, S8, RA }; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 56 | static constexpr FpuRegister kFpuCalleeSaves[] = | 
|  | 57 | { F24, F25, F26, F27, F28, F29, F30, F31 }; | 
|  | 58 |  | 
|  | 59 |  | 
|  | 60 | class CodeGeneratorMIPS64; | 
|  | 61 |  | 
| Lena Djokic | ca8c295 | 2017-05-29 11:31:46 +0200 | [diff] [blame] | 62 | VectorRegister VectorRegisterFrom(Location location); | 
|  | 63 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 64 | class InvokeDexCallingConvention : public CallingConvention<GpuRegister, FpuRegister> { | 
|  | 65 | public: | 
|  | 66 | InvokeDexCallingConvention() | 
|  | 67 | : CallingConvention(kParameterCoreRegisters, | 
|  | 68 | kParameterCoreRegistersLength, | 
|  | 69 | kParameterFpuRegisters, | 
|  | 70 | kParameterFpuRegistersLength, | 
|  | 71 | kMips64PointerSize) {} | 
|  | 72 |  | 
|  | 73 | private: | 
|  | 74 | DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); | 
|  | 75 | }; | 
|  | 76 |  | 
|  | 77 | class InvokeDexCallingConventionVisitorMIPS64 : public InvokeDexCallingConventionVisitor { | 
|  | 78 | public: | 
|  | 79 | InvokeDexCallingConventionVisitorMIPS64() {} | 
|  | 80 | virtual ~InvokeDexCallingConventionVisitorMIPS64() {} | 
|  | 81 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 82 | Location GetNextLocation(DataType::Type type) OVERRIDE; | 
|  | 83 | Location GetReturnLocation(DataType::Type type) const OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 84 | Location GetMethodLocation() const OVERRIDE; | 
|  | 85 |  | 
|  | 86 | private: | 
|  | 87 | InvokeDexCallingConvention calling_convention; | 
|  | 88 |  | 
|  | 89 | DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS64); | 
|  | 90 | }; | 
|  | 91 |  | 
|  | 92 | class InvokeRuntimeCallingConvention : public CallingConvention<GpuRegister, FpuRegister> { | 
|  | 93 | public: | 
|  | 94 | InvokeRuntimeCallingConvention() | 
|  | 95 | : CallingConvention(kRuntimeParameterCoreRegisters, | 
|  | 96 | kRuntimeParameterCoreRegistersLength, | 
|  | 97 | kRuntimeParameterFpuRegisters, | 
|  | 98 | kRuntimeParameterFpuRegistersLength, | 
|  | 99 | kMips64PointerSize) {} | 
|  | 100 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 101 | Location GetReturnLocation(DataType::Type return_type); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 102 |  | 
|  | 103 | private: | 
|  | 104 | DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); | 
|  | 105 | }; | 
|  | 106 |  | 
| Calin Juravle | e460d1d | 2015-09-29 04:52:17 +0100 | [diff] [blame] | 107 | class FieldAccessCallingConventionMIPS64 : public FieldAccessCallingConvention { | 
|  | 108 | public: | 
|  | 109 | FieldAccessCallingConventionMIPS64() {} | 
|  | 110 |  | 
|  | 111 | Location GetObjectLocation() const OVERRIDE { | 
|  | 112 | return Location::RegisterLocation(A1); | 
|  | 113 | } | 
|  | 114 | Location GetFieldIndexLocation() const OVERRIDE { | 
|  | 115 | return Location::RegisterLocation(A0); | 
|  | 116 | } | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 117 | Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE { | 
| Goran Jakovljevic | 8c34ec1 | 2015-10-14 11:23:48 +0200 | [diff] [blame] | 118 | return Location::RegisterLocation(V0); | 
| Calin Juravle | e460d1d | 2015-09-29 04:52:17 +0100 | [diff] [blame] | 119 | } | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 120 | Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED, | 
| Alexey Frunze | 0cb1242 | 2017-01-25 19:30:18 -0800 | [diff] [blame] | 121 | bool is_instance) const OVERRIDE { | 
|  | 122 | return is_instance | 
| Alexey Frunze | 00580bd | 2015-11-11 13:31:12 -0800 | [diff] [blame] | 123 | ? Location::RegisterLocation(A2) | 
| Alexey Frunze | 0cb1242 | 2017-01-25 19:30:18 -0800 | [diff] [blame] | 124 | : Location::RegisterLocation(A1); | 
| Calin Juravle | e460d1d | 2015-09-29 04:52:17 +0100 | [diff] [blame] | 125 | } | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 126 | Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE { | 
| Calin Juravle | e460d1d | 2015-09-29 04:52:17 +0100 | [diff] [blame] | 127 | return Location::FpuRegisterLocation(F0); | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | private: | 
|  | 131 | DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS64); | 
|  | 132 | }; | 
|  | 133 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 134 | class ParallelMoveResolverMIPS64 : public ParallelMoveResolverWithSwap { | 
|  | 135 | public: | 
|  | 136 | ParallelMoveResolverMIPS64(ArenaAllocator* allocator, CodeGeneratorMIPS64* codegen) | 
|  | 137 | : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} | 
|  | 138 |  | 
|  | 139 | void EmitMove(size_t index) OVERRIDE; | 
|  | 140 | void EmitSwap(size_t index) OVERRIDE; | 
|  | 141 | void SpillScratch(int reg) OVERRIDE; | 
|  | 142 | void RestoreScratch(int reg) OVERRIDE; | 
|  | 143 |  | 
|  | 144 | void Exchange(int index1, int index2, bool double_slot); | 
| Goran Jakovljevic | e7de5ec | 2017-12-14 10:25:20 +0100 | [diff] [blame] | 145 | void ExchangeQuadSlots(int index1, int index2); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 146 |  | 
|  | 147 | Mips64Assembler* GetAssembler() const; | 
|  | 148 |  | 
|  | 149 | private: | 
|  | 150 | CodeGeneratorMIPS64* const codegen_; | 
|  | 151 |  | 
|  | 152 | DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS64); | 
|  | 153 | }; | 
|  | 154 |  | 
|  | 155 | class SlowPathCodeMIPS64 : public SlowPathCode { | 
|  | 156 | public: | 
| David Srbecky | 9cd6d37 | 2016-02-09 15:24:47 +0000 | [diff] [blame] | 157 | explicit SlowPathCodeMIPS64(HInstruction* instruction) | 
|  | 158 | : SlowPathCode(instruction), entry_label_(), exit_label_() {} | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 159 |  | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 160 | Mips64Label* GetEntryLabel() { return &entry_label_; } | 
|  | 161 | Mips64Label* GetExitLabel() { return &exit_label_; } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 162 |  | 
|  | 163 | private: | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 164 | Mips64Label entry_label_; | 
|  | 165 | Mips64Label exit_label_; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 166 |  | 
|  | 167 | DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS64); | 
|  | 168 | }; | 
|  | 169 |  | 
|  | 170 | class LocationsBuilderMIPS64 : public HGraphVisitor { | 
|  | 171 | public: | 
|  | 172 | LocationsBuilderMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen) | 
|  | 173 | : HGraphVisitor(graph), codegen_(codegen) {} | 
|  | 174 |  | 
|  | 175 | #define DECLARE_VISIT_INSTRUCTION(name, super)     \ | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 176 | void Visit##name(H##name* instr) OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 177 |  | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 178 | FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) | 
|  | 179 | FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION) | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 180 |  | 
|  | 181 | #undef DECLARE_VISIT_INSTRUCTION | 
|  | 182 |  | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 183 | void VisitInstruction(HInstruction* instruction) OVERRIDE { | 
|  | 184 | LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() | 
|  | 185 | << " (id " << instruction->GetId() << ")"; | 
|  | 186 | } | 
|  | 187 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 188 | private: | 
|  | 189 | void HandleInvoke(HInvoke* invoke); | 
|  | 190 | void HandleBinaryOp(HBinaryOperation* operation); | 
| Vladimir Marko | 5f7b58e | 2015-11-23 19:49:34 +0000 | [diff] [blame] | 191 | void HandleCondition(HCondition* instruction); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 192 | void HandleShift(HBinaryOperation* operation); | 
|  | 193 | void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); | 
|  | 194 | void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); | 
| Tijana Jakovljevic | ba89c34 | 2017-03-10 13:36:08 +0100 | [diff] [blame] | 195 | Location RegisterOrZeroConstant(HInstruction* instruction); | 
|  | 196 | Location FpuRegisterOrConstantForStore(HInstruction* instruction); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 197 |  | 
|  | 198 | InvokeDexCallingConventionVisitorMIPS64 parameter_visitor_; | 
|  | 199 |  | 
|  | 200 | CodeGeneratorMIPS64* const codegen_; | 
|  | 201 |  | 
|  | 202 | DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS64); | 
|  | 203 | }; | 
|  | 204 |  | 
| Aart Bik | 42249c3 | 2016-01-07 15:33:50 -0800 | [diff] [blame] | 205 | class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator { | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 206 | public: | 
|  | 207 | InstructionCodeGeneratorMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen); | 
|  | 208 |  | 
|  | 209 | #define DECLARE_VISIT_INSTRUCTION(name, super)     \ | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 210 | void Visit##name(H##name* instr) OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 211 |  | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 212 | FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) | 
|  | 213 | FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION) | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 214 |  | 
|  | 215 | #undef DECLARE_VISIT_INSTRUCTION | 
|  | 216 |  | 
| Alexandre Rames | f39e064 | 2015-06-23 11:33:45 +0100 | [diff] [blame] | 217 | void VisitInstruction(HInstruction* instruction) OVERRIDE { | 
|  | 218 | LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() | 
|  | 219 | << " (id " << instruction->GetId() << ")"; | 
|  | 220 | } | 
|  | 221 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 222 | Mips64Assembler* GetAssembler() const { return assembler_; } | 
|  | 223 |  | 
| Alexey Frunze | 0960ac5 | 2016-12-20 17:24:59 -0800 | [diff] [blame] | 224 | // Compare-and-jump packed switch generates approx. 3 + 2.5 * N 32-bit | 
|  | 225 | // instructions for N cases. | 
|  | 226 | // Table-based packed switch generates approx. 11 32-bit instructions | 
|  | 227 | // and N 32-bit data words for N cases. | 
|  | 228 | // At N = 6 they come out as 18 and 17 32-bit words respectively. | 
|  | 229 | // We switch to the table-based method starting with 7 cases. | 
|  | 230 | static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6; | 
|  | 231 |  | 
| Chris Larsen | 5633ce7 | 2017-04-10 15:47:40 -0700 | [diff] [blame] | 232 | void GenerateMemoryBarrier(MemBarrierKind kind); | 
|  | 233 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 234 | private: | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 235 | void GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg); | 
| Vladimir Marko | 175e786 | 2018-03-27 09:03:13 +0000 | [diff] [blame] | 236 | void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check, GpuRegister temp); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 237 | void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); | 
|  | 238 | void HandleBinaryOp(HBinaryOperation* operation); | 
| Vladimir Marko | 5f7b58e | 2015-11-23 19:49:34 +0000 | [diff] [blame] | 239 | void HandleCondition(HCondition* instruction); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 240 | void HandleShift(HBinaryOperation* operation); | 
| Goran Jakovljevic | 8ed1826 | 2016-01-22 13:01:00 +0100 | [diff] [blame] | 241 | void HandleFieldSet(HInstruction* instruction, | 
|  | 242 | const FieldInfo& field_info, | 
|  | 243 | bool value_can_be_null); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 244 | void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 245 |  | 
| Aart Bik | 351df3e | 2018-03-07 11:54:57 -0800 | [diff] [blame] | 246 | void GenerateMinMaxInt(LocationSummary* locations, bool is_min); | 
| Aart Bik | 1f8d51b | 2018-02-15 10:42:37 -0800 | [diff] [blame] | 247 | void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); | 
| Aart Bik | 351df3e | 2018-03-07 11:54:57 -0800 | [diff] [blame] | 248 | void GenerateMinMax(HBinaryOperation* minmax, bool is_min); | 
| Aart Bik | 1f8d51b | 2018-02-15 10:42:37 -0800 | [diff] [blame] | 249 |  | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 250 | // Generate a heap reference load using one register `out`: | 
|  | 251 | // | 
|  | 252 | //   out <- *(out + offset) | 
|  | 253 | // | 
|  | 254 | // while honoring heap poisoning and/or read barriers (if any). | 
|  | 255 | // | 
|  | 256 | // Location `maybe_temp` is used when generating a read barrier and | 
|  | 257 | // shall be a register in that case; it may be an invalid location | 
|  | 258 | // otherwise. | 
|  | 259 | void GenerateReferenceLoadOneRegister(HInstruction* instruction, | 
|  | 260 | Location out, | 
|  | 261 | uint32_t offset, | 
|  | 262 | Location maybe_temp, | 
|  | 263 | ReadBarrierOption read_barrier_option); | 
|  | 264 | // Generate a heap reference load using two different registers | 
|  | 265 | // `out` and `obj`: | 
|  | 266 | // | 
|  | 267 | //   out <- *(obj + offset) | 
|  | 268 | // | 
|  | 269 | // while honoring heap poisoning and/or read barriers (if any). | 
|  | 270 | // | 
|  | 271 | // Location `maybe_temp` is used when generating a Baker's (fast | 
|  | 272 | // path) read barrier and shall be a register in that case; it may | 
|  | 273 | // be an invalid location otherwise. | 
|  | 274 | void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, | 
|  | 275 | Location out, | 
|  | 276 | Location obj, | 
|  | 277 | uint32_t offset, | 
|  | 278 | Location maybe_temp, | 
|  | 279 | ReadBarrierOption read_barrier_option); | 
|  | 280 |  | 
| Alexey Frunze | f63f569 | 2016-12-13 17:43:11 -0800 | [diff] [blame] | 281 | // Generate a GC root reference load: | 
|  | 282 | // | 
|  | 283 | //   root <- *(obj + offset) | 
|  | 284 | // | 
|  | 285 | // while honoring read barriers (if any). | 
|  | 286 | void GenerateGcRootFieldLoad(HInstruction* instruction, | 
|  | 287 | Location root, | 
|  | 288 | GpuRegister obj, | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 289 | uint32_t offset, | 
| Alexey Frunze | 4147fcc | 2017-06-17 19:57:27 -0700 | [diff] [blame] | 290 | ReadBarrierOption read_barrier_option, | 
|  | 291 | Mips64Label* label_low = nullptr); | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 292 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 293 | void GenerateTestAndBranch(HInstruction* instruction, | 
| David Brazdil | 0debae7 | 2015-11-12 18:37:00 +0000 | [diff] [blame] | 294 | size_t condition_input_index, | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 295 | Mips64Label* true_target, | 
|  | 296 | Mips64Label* false_target); | 
| Alexey Frunze | c857c74 | 2015-09-23 15:12:39 -0700 | [diff] [blame] | 297 | void DivRemOneOrMinusOne(HBinaryOperation* instruction); | 
|  | 298 | void DivRemByPowerOfTwo(HBinaryOperation* instruction); | 
|  | 299 | void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); | 
|  | 300 | void GenerateDivRemIntegral(HBinaryOperation* instruction); | 
| Alexey Frunze | 299a939 | 2015-12-08 16:08:02 -0800 | [diff] [blame] | 301 | void GenerateIntLongCompare(IfCondition cond, bool is64bit, LocationSummary* locations); | 
| Goran Jakovljevic | 2dec927 | 2017-08-02 11:41:26 +0200 | [diff] [blame] | 302 | // When the function returns `false` it means that the condition holds if `dst` is non-zero | 
|  | 303 | // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero | 
|  | 304 | // `dst` are exchanged. | 
|  | 305 | bool MaterializeIntLongCompare(IfCondition cond, | 
|  | 306 | bool is64bit, | 
|  | 307 | LocationSummary* input_locations, | 
|  | 308 | GpuRegister dst); | 
| Alexey Frunze | 299a939 | 2015-12-08 16:08:02 -0800 | [diff] [blame] | 309 | void GenerateIntLongCompareAndBranch(IfCondition cond, | 
|  | 310 | bool is64bit, | 
|  | 311 | LocationSummary* locations, | 
|  | 312 | Mips64Label* label); | 
| Tijana Jakovljevic | 4375819 | 2016-12-30 09:23:01 +0100 | [diff] [blame] | 313 | void GenerateFpCompare(IfCondition cond, | 
|  | 314 | bool gt_bias, | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 315 | DataType::Type type, | 
| Tijana Jakovljevic | 4375819 | 2016-12-30 09:23:01 +0100 | [diff] [blame] | 316 | LocationSummary* locations); | 
| Goran Jakovljevic | 2dec927 | 2017-08-02 11:41:26 +0200 | [diff] [blame] | 317 | // When the function returns `false` it means that the condition holds if `dst` is non-zero | 
|  | 318 | // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero | 
|  | 319 | // `dst` are exchanged. | 
|  | 320 | bool MaterializeFpCompare(IfCondition cond, | 
|  | 321 | bool gt_bias, | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 322 | DataType::Type type, | 
| Goran Jakovljevic | 2dec927 | 2017-08-02 11:41:26 +0200 | [diff] [blame] | 323 | LocationSummary* input_locations, | 
|  | 324 | FpuRegister dst); | 
| Alexey Frunze | 299a939 | 2015-12-08 16:08:02 -0800 | [diff] [blame] | 325 | void GenerateFpCompareAndBranch(IfCondition cond, | 
|  | 326 | bool gt_bias, | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 327 | DataType::Type type, | 
| Alexey Frunze | 299a939 | 2015-12-08 16:08:02 -0800 | [diff] [blame] | 328 | LocationSummary* locations, | 
|  | 329 | Mips64Label* label); | 
| David Brazdil | fc6a86a | 2015-06-26 10:33:45 +0000 | [diff] [blame] | 330 | void HandleGoto(HInstruction* got, HBasicBlock* successor); | 
| Alexey Frunze | 0960ac5 | 2016-12-20 17:24:59 -0800 | [diff] [blame] | 331 | void GenPackedSwitchWithCompares(GpuRegister value_reg, | 
|  | 332 | int32_t lower_bound, | 
|  | 333 | uint32_t num_entries, | 
|  | 334 | HBasicBlock* switch_block, | 
|  | 335 | HBasicBlock* default_block); | 
|  | 336 | void GenTableBasedPackedSwitch(GpuRegister value_reg, | 
|  | 337 | int32_t lower_bound, | 
|  | 338 | uint32_t num_entries, | 
|  | 339 | HBasicBlock* switch_block, | 
|  | 340 | HBasicBlock* default_block); | 
| Goran Jakovljevic | 19680d3 | 2017-05-11 10:38:36 +0200 | [diff] [blame] | 341 | int32_t VecAddress(LocationSummary* locations, | 
|  | 342 | size_t size, | 
|  | 343 | /* out */ GpuRegister* adjusted_base); | 
| Goran Jakovljevic | 2dec927 | 2017-08-02 11:41:26 +0200 | [diff] [blame] | 344 | void GenConditionalMove(HSelect* select); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 345 |  | 
|  | 346 | Mips64Assembler* const assembler_; | 
|  | 347 | CodeGeneratorMIPS64* const codegen_; | 
|  | 348 |  | 
|  | 349 | DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS64); | 
|  | 350 | }; | 
|  | 351 |  | 
|  | 352 | class CodeGeneratorMIPS64 : public CodeGenerator { | 
|  | 353 | public: | 
|  | 354 | CodeGeneratorMIPS64(HGraph* graph, | 
|  | 355 | const Mips64InstructionSetFeatures& isa_features, | 
| Serban Constantinescu | ecc4366 | 2015-08-13 13:33:12 +0100 | [diff] [blame] | 356 | const CompilerOptions& compiler_options, | 
|  | 357 | OptimizingCompilerStats* stats = nullptr); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 358 | virtual ~CodeGeneratorMIPS64() {} | 
|  | 359 |  | 
|  | 360 | void GenerateFrameEntry() OVERRIDE; | 
|  | 361 | void GenerateFrameExit() OVERRIDE; | 
|  | 362 |  | 
|  | 363 | void Bind(HBasicBlock* block) OVERRIDE; | 
|  | 364 |  | 
| Lazar Trsic | d967266 | 2015-09-03 17:33:01 +0200 | [diff] [blame] | 365 | size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 366 |  | 
| Goran Jakovljevic | d8b6a53 | 2017-04-20 11:42:30 +0200 | [diff] [blame] | 367 | size_t GetFloatingPointSpillSlotSize() const OVERRIDE { | 
|  | 368 | return GetGraph()->HasSIMD() | 
|  | 369 | ? 2 * kMips64DoublewordSize   // 16 bytes for each spill. | 
|  | 370 | : 1 * kMips64DoublewordSize;  //  8 bytes for each spill. | 
|  | 371 | } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 372 |  | 
| Alexandre Rames | c01a664 | 2016-04-15 11:54:06 +0100 | [diff] [blame] | 373 | uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE { | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 374 | return assembler_.GetLabelLocation(GetLabelOf(block)); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 375 | } | 
|  | 376 |  | 
|  | 377 | HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } | 
|  | 378 | HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } | 
|  | 379 | Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; } | 
| Alexandre Rames | eb7b739 | 2015-06-19 14:47:01 +0100 | [diff] [blame] | 380 | const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 381 |  | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 382 | // Emit linker patches. | 
| Vladimir Marko | d8dbc8d | 2017-09-20 13:37:47 +0100 | [diff] [blame] | 383 | void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE; | 
| Alexey Frunze | 627c1a0 | 2017-01-30 19:28:14 -0800 | [diff] [blame] | 384 | void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE; | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 385 |  | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 386 | // Fast path implementation of ReadBarrier::Barrier for a heap | 
|  | 387 | // reference field load when Baker's read barriers are used. | 
|  | 388 | void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, | 
|  | 389 | Location ref, | 
|  | 390 | GpuRegister obj, | 
|  | 391 | uint32_t offset, | 
|  | 392 | Location temp, | 
|  | 393 | bool needs_null_check); | 
|  | 394 | // Fast path implementation of ReadBarrier::Barrier for a heap | 
|  | 395 | // reference array load when Baker's read barriers are used. | 
|  | 396 | void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, | 
|  | 397 | Location ref, | 
|  | 398 | GpuRegister obj, | 
|  | 399 | uint32_t data_offset, | 
|  | 400 | Location index, | 
|  | 401 | Location temp, | 
|  | 402 | bool needs_null_check); | 
|  | 403 |  | 
|  | 404 | // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, | 
|  | 405 | // GenerateArrayLoadWithBakerReadBarrier and some intrinsics. | 
|  | 406 | // | 
|  | 407 | // Load the object reference located at the address | 
|  | 408 | // `obj + offset + (index << scale_factor)`, held by object `obj`, into | 
|  | 409 | // `ref`, and mark it if needed. | 
|  | 410 | // | 
|  | 411 | // If `always_update_field` is true, the value of the reference is | 
|  | 412 | // atomically updated in the holder (`obj`). | 
|  | 413 | void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, | 
|  | 414 | Location ref, | 
|  | 415 | GpuRegister obj, | 
|  | 416 | uint32_t offset, | 
|  | 417 | Location index, | 
|  | 418 | ScaleFactor scale_factor, | 
|  | 419 | Location temp, | 
|  | 420 | bool needs_null_check, | 
|  | 421 | bool always_update_field = false); | 
|  | 422 |  | 
|  | 423 | // Generate a read barrier for a heap reference within `instruction` | 
|  | 424 | // using a slow path. | 
|  | 425 | // | 
|  | 426 | // A read barrier for an object reference read from the heap is | 
|  | 427 | // implemented as a call to the artReadBarrierSlow runtime entry | 
|  | 428 | // point, which is passed the values in locations `ref`, `obj`, and | 
|  | 429 | // `offset`: | 
|  | 430 | // | 
|  | 431 | //   mirror::Object* artReadBarrierSlow(mirror::Object* ref, | 
|  | 432 | //                                      mirror::Object* obj, | 
|  | 433 | //                                      uint32_t offset); | 
|  | 434 | // | 
|  | 435 | // The `out` location contains the value returned by | 
|  | 436 | // artReadBarrierSlow. | 
|  | 437 | // | 
|  | 438 | // When `index` is provided (i.e. for array accesses), the offset | 
|  | 439 | // value passed to artReadBarrierSlow is adjusted to take `index` | 
|  | 440 | // into account. | 
|  | 441 | void GenerateReadBarrierSlow(HInstruction* instruction, | 
|  | 442 | Location out, | 
|  | 443 | Location ref, | 
|  | 444 | Location obj, | 
|  | 445 | uint32_t offset, | 
|  | 446 | Location index = Location::NoLocation()); | 
|  | 447 |  | 
|  | 448 | // If read barriers are enabled, generate a read barrier for a heap | 
|  | 449 | // reference using a slow path. If heap poisoning is enabled, also | 
|  | 450 | // unpoison the reference in `out`. | 
|  | 451 | void MaybeGenerateReadBarrierSlow(HInstruction* instruction, | 
|  | 452 | Location out, | 
|  | 453 | Location ref, | 
|  | 454 | Location obj, | 
|  | 455 | uint32_t offset, | 
|  | 456 | Location index = Location::NoLocation()); | 
|  | 457 |  | 
|  | 458 | // Generate a read barrier for a GC root within `instruction` using | 
|  | 459 | // a slow path. | 
|  | 460 | // | 
|  | 461 | // A read barrier for an object reference GC root is implemented as | 
|  | 462 | // a call to the artReadBarrierForRootSlow runtime entry point, | 
|  | 463 | // which is passed the value in location `root`: | 
|  | 464 | // | 
|  | 465 | //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); | 
|  | 466 | // | 
|  | 467 | // The `out` location contains the value returned by | 
|  | 468 | // artReadBarrierForRootSlow. | 
|  | 469 | void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); | 
|  | 470 |  | 
| Goran Jakovljevic | 8ed1826 | 2016-01-22 13:01:00 +0100 | [diff] [blame] | 471 | void MarkGCCard(GpuRegister object, GpuRegister value, bool value_can_be_null); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 472 |  | 
|  | 473 | // Register allocation. | 
|  | 474 |  | 
| David Brazdil | 58282f4 | 2016-01-14 12:45:10 +0000 | [diff] [blame] | 475 | void SetupBlockedRegisters() const OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 476 |  | 
| Roland Levillain | f41f956 | 2016-09-14 19:26:48 +0100 | [diff] [blame] | 477 | size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; | 
|  | 478 | size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; | 
|  | 479 | size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; | 
|  | 480 | size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 481 |  | 
|  | 482 | void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; | 
|  | 483 | void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; | 
|  | 484 |  | 
|  | 485 | InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; } | 
|  | 486 |  | 
|  | 487 | const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const { | 
|  | 488 | return isa_features_; | 
|  | 489 | } | 
|  | 490 |  | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 491 | Mips64Label* GetLabelOf(HBasicBlock* block) const { | 
|  | 492 | return CommonGetLabelOf<Mips64Label>(block_labels_, block); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 493 | } | 
|  | 494 |  | 
|  | 495 | void Initialize() OVERRIDE { | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 496 | block_labels_ = CommonInitializeLabels<Mips64Label>(); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 497 | } | 
|  | 498 |  | 
| Alexey Frunze | c378980 | 2016-12-22 13:54:23 -0800 | [diff] [blame] | 499 | // We prefer aligned loads and stores (less code), so spill and restore registers in slow paths | 
|  | 500 | // at aligned locations. | 
|  | 501 | uint32_t GetPreferredSlotsAlignment() const OVERRIDE { return kMips64DoublewordSize; } | 
|  | 502 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 503 | void Finalize(CodeAllocator* allocator) OVERRIDE; | 
|  | 504 |  | 
|  | 505 | // Code generation helpers. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 506 | void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 507 |  | 
| Calin Juravle | 175dc73 | 2015-08-25 15:42:32 +0100 | [diff] [blame] | 508 | void MoveConstant(Location destination, int32_t value) OVERRIDE; | 
|  | 509 |  | 
| Calin Juravle | e460d1d | 2015-09-29 04:52:17 +0100 | [diff] [blame] | 510 | void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; | 
|  | 511 |  | 
|  | 512 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 513 | void SwapLocations(Location loc1, Location loc2, DataType::Type type); | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 514 |  | 
|  | 515 | // Generate code to invoke a runtime entry point. | 
| Calin Juravle | 175dc73 | 2015-08-25 15:42:32 +0100 | [diff] [blame] | 516 | void InvokeRuntime(QuickEntrypointEnum entrypoint, | 
|  | 517 | HInstruction* instruction, | 
|  | 518 | uint32_t dex_pc, | 
| Serban Constantinescu | fc73408 | 2016-07-19 17:18:07 +0100 | [diff] [blame] | 519 | SlowPathCode* slow_path = nullptr) OVERRIDE; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 520 |  | 
| Alexey Frunze | 1595815 | 2017-02-09 19:08:30 -0800 | [diff] [blame] | 521 | // Generate code to invoke a runtime entry point, but do not record | 
|  | 522 | // PC-related information in a stack map. | 
|  | 523 | void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset, | 
|  | 524 | HInstruction* instruction, | 
|  | 525 | SlowPathCode* slow_path); | 
|  | 526 |  | 
|  | 527 | void GenerateInvokeRuntime(int32_t entry_point_offset); | 
|  | 528 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 529 | ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; } | 
|  | 530 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 531 | bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE { return false; } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 532 |  | 
| Vladimir Marko | cac5a7e | 2016-02-22 10:39:50 +0000 | [diff] [blame] | 533 | // Check if the desired_string_load_kind is supported. If it is, return it, | 
|  | 534 | // otherwise return a fall-back kind that should be used instead. | 
|  | 535 | HLoadString::LoadKind GetSupportedLoadStringKind( | 
|  | 536 | HLoadString::LoadKind desired_string_load_kind) OVERRIDE; | 
|  | 537 |  | 
| Vladimir Marko | dbb7f5b | 2016-03-30 13:23:58 +0100 | [diff] [blame] | 538 | // Check if the desired_class_load_kind is supported. If it is, return it, | 
|  | 539 | // otherwise return a fall-back kind that should be used instead. | 
|  | 540 | HLoadClass::LoadKind GetSupportedLoadClassKind( | 
|  | 541 | HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; | 
|  | 542 |  | 
| Vladimir Marko | dc151b2 | 2015-10-15 18:02:30 +0100 | [diff] [blame] | 543 | // Check if the desired_dispatch_info is supported. If it is, return it, | 
|  | 544 | // otherwise return a fall-back info that should be used instead. | 
|  | 545 | HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( | 
|  | 546 | const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, | 
| Nicolas Geoffray | 5e4e11e | 2016-09-22 13:17:41 +0100 | [diff] [blame] | 547 | HInvokeStaticOrDirect* invoke) OVERRIDE; | 
| Vladimir Marko | dc151b2 | 2015-10-15 18:02:30 +0100 | [diff] [blame] | 548 |  | 
| Vladimir Marko | e7197bf | 2017-06-02 17:00:23 +0100 | [diff] [blame] | 549 | void GenerateStaticOrDirectCall( | 
|  | 550 | HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; | 
|  | 551 | void GenerateVirtualCall( | 
|  | 552 | HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; | 
| Andreas Gampe | 85b62f2 | 2015-09-09 13:15:38 -0700 | [diff] [blame] | 553 |  | 
|  | 554 | void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED, | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 555 | DataType::Type type ATTRIBUTE_UNUSED) OVERRIDE { | 
| Chris Larsen | 3acee73 | 2015-11-18 13:31:08 -0800 | [diff] [blame] | 556 | UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64"; | 
| Andreas Gampe | 85b62f2 | 2015-09-09 13:15:38 -0700 | [diff] [blame] | 557 | } | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 558 |  | 
| Roland Levillain | f41f956 | 2016-09-14 19:26:48 +0100 | [diff] [blame] | 559 | void GenerateNop() OVERRIDE; | 
|  | 560 | void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE; | 
|  | 561 | void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE; | 
| David Srbecky | c7098ff | 2016-02-09 14:30:11 +0000 | [diff] [blame] | 562 |  | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 563 | // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types, | 
|  | 564 | // whether through .data.bimg.rel.ro, .bss, or directly in the boot image. | 
|  | 565 | // | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 566 | // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating | 
|  | 567 | // two patches/infos. There can be more than two patches/infos if the instruction supplying | 
|  | 568 | // the high half is shared with e.g. a slow path, while the low half is supplied by separate | 
|  | 569 | // instructions, e.g.: | 
|  | 570 | //     auipc r1, high       // patch | 
|  | 571 | //     lwu   r2, low(r1)    // patch | 
|  | 572 | //     beqzc r2, slow_path | 
|  | 573 | //   back: | 
|  | 574 | //     ... | 
|  | 575 | //   slow_path: | 
|  | 576 | //     ... | 
|  | 577 | //     sw    r2, low(r1)    // patch | 
|  | 578 | //     bc    back | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 579 | struct PcRelativePatchInfo : PatchInfo<Mips64Label> { | 
|  | 580 | PcRelativePatchInfo(const DexFile* dex_file, | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 581 | uint32_t off_or_idx, | 
|  | 582 | const PcRelativePatchInfo* info_high) | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 583 | : PatchInfo<Mips64Label>(dex_file, off_or_idx), | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 584 | patch_info_high(info_high) { } | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 585 |  | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 586 | // Pointer to the info for the high half patch or nullptr if this is the high half patch info. | 
|  | 587 | const PcRelativePatchInfo* patch_info_high; | 
|  | 588 |  | 
|  | 589 | private: | 
|  | 590 | PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete; | 
|  | 591 | DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 592 | }; | 
|  | 593 |  | 
| Vladimir Marko | b066d43 | 2018-01-03 13:14:37 +0000 | [diff] [blame] | 594 | PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset, | 
|  | 595 | const PcRelativePatchInfo* info_high = nullptr); | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 596 | PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method, | 
|  | 597 | const PcRelativePatchInfo* info_high = nullptr); | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 598 | PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method, | 
|  | 599 | const PcRelativePatchInfo* info_high = nullptr); | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 600 | PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, | 
|  | 601 | dex::TypeIndex type_index, | 
|  | 602 | const PcRelativePatchInfo* info_high = nullptr); | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 603 | PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, | 
|  | 604 | dex::TypeIndex type_index, | 
|  | 605 | const PcRelativePatchInfo* info_high = nullptr); | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 606 | PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file, | 
|  | 607 | dex::StringIndex string_index, | 
|  | 608 | const PcRelativePatchInfo* info_high = nullptr); | 
| Vladimir Marko | 6cfbdbc | 2017-07-25 13:26:39 +0100 | [diff] [blame] | 609 | PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file, | 
|  | 610 | dex::StringIndex string_index, | 
|  | 611 | const PcRelativePatchInfo* info_high = nullptr); | 
| Alexey Frunze | f63f569 | 2016-12-13 17:43:11 -0800 | [diff] [blame] | 612 | Literal* DeduplicateBootImageAddressLiteral(uint64_t address); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 613 |  | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 614 | void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high, | 
|  | 615 | GpuRegister out, | 
| Alexey Frunze | 4147fcc | 2017-06-17 19:57:27 -0700 | [diff] [blame] | 616 | PcRelativePatchInfo* info_low = nullptr); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 617 |  | 
| Alexey Frunze | 627c1a0 | 2017-01-30 19:28:14 -0800 | [diff] [blame] | 618 | void PatchJitRootUse(uint8_t* code, | 
|  | 619 | const uint8_t* roots_data, | 
|  | 620 | const Literal* literal, | 
|  | 621 | uint64_t index_in_table) const; | 
|  | 622 | Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, | 
|  | 623 | dex::StringIndex string_index, | 
|  | 624 | Handle<mirror::String> handle); | 
|  | 625 | Literal* DeduplicateJitClassLiteral(const DexFile& dex_file, | 
|  | 626 | dex::TypeIndex type_index, | 
|  | 627 | Handle<mirror::Class> handle); | 
|  | 628 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 629 | private: | 
| Alexey Frunze | f63f569 | 2016-12-13 17:43:11 -0800 | [diff] [blame] | 630 | using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>; | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 631 | using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, Literal*>; | 
| Alexey Frunze | 627c1a0 | 2017-01-30 19:28:14 -0800 | [diff] [blame] | 632 | using StringToLiteralMap = ArenaSafeMap<StringReference, | 
|  | 633 | Literal*, | 
|  | 634 | StringReferenceValueComparator>; | 
|  | 635 | using TypeToLiteralMap = ArenaSafeMap<TypeReference, | 
|  | 636 | Literal*, | 
|  | 637 | TypeReferenceValueComparator>; | 
| Alexey Frunze | f63f569 | 2016-12-13 17:43:11 -0800 | [diff] [blame] | 638 |  | 
|  | 639 | Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 640 | Literal* DeduplicateUint64Literal(uint64_t value); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 641 |  | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 642 | PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file, | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 643 | uint32_t offset_or_index, | 
| Alexey Frunze | 5fa5c04 | 2017-06-01 21:07:52 -0700 | [diff] [blame] | 644 | const PcRelativePatchInfo* info_high, | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 645 | ArenaDeque<PcRelativePatchInfo>* patches); | 
|  | 646 |  | 
| Vladimir Marko | d8dbc8d | 2017-09-20 13:37:47 +0100 | [diff] [blame] | 647 | template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 648 | void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos, | 
| Vladimir Marko | d8dbc8d | 2017-09-20 13:37:47 +0100 | [diff] [blame] | 649 | ArenaVector<linker::LinkerPatch>* linker_patches); | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 650 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 651 | // Labels for each block that will be compiled. | 
| Alexey Frunze | a0e87b0 | 2015-09-24 22:57:20 -0700 | [diff] [blame] | 652 | Mips64Label* block_labels_;  // Indexed by block id. | 
|  | 653 | Mips64Label frame_entry_label_; | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 654 | LocationsBuilderMIPS64 location_builder_; | 
|  | 655 | InstructionCodeGeneratorMIPS64 instruction_visitor_; | 
|  | 656 | ParallelMoveResolverMIPS64 move_resolver_; | 
|  | 657 | Mips64Assembler assembler_; | 
|  | 658 | const Mips64InstructionSetFeatures& isa_features_; | 
|  | 659 |  | 
| Alexey Frunze | f63f569 | 2016-12-13 17:43:11 -0800 | [diff] [blame] | 660 | // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. | 
|  | 661 | Uint32ToLiteralMap uint32_literals_; | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 662 | // Deduplication map for 64-bit literals, used for non-patchable method address or method code | 
|  | 663 | // address. | 
|  | 664 | Uint64ToLiteralMap uint64_literals_; | 
| Vladimir Marko | b066d43 | 2018-01-03 13:14:37 +0000 | [diff] [blame] | 665 | // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo. | 
| Vladimir Marko | e47f60c | 2018-02-21 13:43:28 +0000 | [diff] [blame] | 666 | // Also used for type/string patches for kBootImageRelRo (same linker patch as for methods). | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 667 | ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_; | 
| Vladimir Marko | 0eb882b | 2017-05-15 13:39:18 +0100 | [diff] [blame] | 668 | // PC-relative method patch info for kBssEntry. | 
|  | 669 | ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; | 
| Vladimir Marko | 1998cd0 | 2017-01-13 13:02:58 +0000 | [diff] [blame] | 670 | // PC-relative type patch info for kBootImageLinkTimePcRelative. | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 671 | ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_; | 
| Vladimir Marko | 1998cd0 | 2017-01-13 13:02:58 +0000 | [diff] [blame] | 672 | // PC-relative type patch info for kBssEntry. | 
|  | 673 | ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_; | 
| Vladimir Marko | e47f60c | 2018-02-21 13:43:28 +0000 | [diff] [blame] | 674 | // PC-relative String patch info for kBootImageLinkTimePcRelative. | 
| Vladimir Marko | 59eb30f | 2018-02-20 11:52:34 +0000 | [diff] [blame] | 675 | ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_; | 
| Vladimir Marko | 6cfbdbc | 2017-07-25 13:26:39 +0100 | [diff] [blame] | 676 | // PC-relative type patch info for kBssEntry. | 
|  | 677 | ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_; | 
| Vladimir Marko | 6597946 | 2017-05-19 17:25:12 +0100 | [diff] [blame] | 678 |  | 
| Alexey Frunze | 627c1a0 | 2017-01-30 19:28:14 -0800 | [diff] [blame] | 679 | // Patches for string root accesses in JIT compiled code. | 
|  | 680 | StringToLiteralMap jit_string_patches_; | 
|  | 681 | // Patches for class root accesses in JIT compiled code. | 
|  | 682 | TypeToLiteralMap jit_class_patches_; | 
| Alexey Frunze | 19f6c69 | 2016-11-30 19:19:55 -0800 | [diff] [blame] | 683 |  | 
| Alexey Frunze | 4dda337 | 2015-06-01 18:31:49 -0700 | [diff] [blame] | 684 | DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS64); | 
|  | 685 | }; | 
|  | 686 |  | 
|  | 687 | }  // namespace mips64 | 
|  | 688 | }  // namespace art | 
|  | 689 |  | 
|  | 690 | #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_ |