Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
| 2 // All Rights Reserved. | 2 // All Rights Reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
| 9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
| 10 // | 10 // |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 33 // Copyright 2010 the V8 project authors. All rights reserved. | 33 // Copyright 2010 the V8 project authors. All rights reserved. |
| 34 | 34 |
| 35 | 35 |
| 36 #include "v8.h" | 36 #include "v8.h" |
| 37 | 37 |
| 38 #if defined(V8_TARGET_ARCH_MIPS) | 38 #if defined(V8_TARGET_ARCH_MIPS) |
| 39 | 39 |
| 40 #include "mips/assembler-mips-inl.h" | 40 #include "mips/assembler-mips-inl.h" |
| 41 #include "serialize.h" | 41 #include "serialize.h" |
| 42 | 42 |
| 43 #ifdef _MIPS_ARCH_MIPS32R2 | |
| 44 #define mips32r2 1 | |
| 45 #else | |
| 46 #define mips32r2 0 | |
| 47 #endif | |
| 43 | 48 |
| 44 namespace v8 { | 49 namespace v8 { |
| 45 namespace internal { | 50 namespace internal { |
| 46 | 51 |
| 47 | 52 |
| 53 // Safe default is no features. | |
| 54 unsigned CpuFeatures::supported_ = 0; | |
| 55 unsigned CpuFeatures::enabled_ = 0; | |
| 56 unsigned CpuFeatures::found_by_runtime_probing_ = 0; | |
| 48 | 57 |
| 49 const Register no_reg = { -1 }; | 58 void CpuFeatures::Probe(bool portable) { |
| 59 // If the compiler is allowed to use fpu then we can use fpu too in our | |
| 60 // code generation. | |
| 61 #if !defined(__mips__) | |
| 62 // For the simulator=mips build, use FPU when FLAG_enable_fpu is enabled. | |
| 63 if (FLAG_enable_fpu) { | |
| 64 supported_ |= 1u << FPU; | |
| 65 } | |
| 66 #else | |
| 67 if (portable && Serializer::enabled()) { | |
| 68 supported_ |= OS::CpuFeaturesImpliedByPlatform(); | |
| 69 return; // No features if we might serialize. | |
| 70 } | |
| 50 | 71 |
| 51 const Register zero_reg = { 0 }; | 72 if (OS::MipsCpuHasFeature(FPU)) { |
| 52 const Register at = { 1 }; | 73 // This implementation also sets the FPU flags if |
| 53 const Register v0 = { 2 }; | 74 // runtime detection of FPU returns true. |
| 54 const Register v1 = { 3 }; | 75 supported_ |= 1u << FPU; |
| 55 const Register a0 = { 4 }; | 76 found_by_runtime_probing_ |= 1u << FPU; |
| 56 const Register a1 = { 5 }; | 77 } |
| 57 const Register a2 = { 6 }; | |
| 58 const Register a3 = { 7 }; | |
| 59 const Register t0 = { 8 }; | |
| 60 const Register t1 = { 9 }; | |
| 61 const Register t2 = { 10 }; | |
| 62 const Register t3 = { 11 }; | |
| 63 const Register t4 = { 12 }; | |
| 64 const Register t5 = { 13 }; | |
| 65 const Register t6 = { 14 }; | |
| 66 const Register t7 = { 15 }; | |
| 67 const Register s0 = { 16 }; | |
| 68 const Register s1 = { 17 }; | |
| 69 const Register s2 = { 18 }; | |
| 70 const Register s3 = { 19 }; | |
| 71 const Register s4 = { 20 }; | |
| 72 const Register s5 = { 21 }; | |
| 73 const Register s6 = { 22 }; | |
| 74 const Register s7 = { 23 }; | |
| 75 const Register t8 = { 24 }; | |
| 76 const Register t9 = { 25 }; | |
| 77 const Register k0 = { 26 }; | |
| 78 const Register k1 = { 27 }; | |
| 79 const Register gp = { 28 }; | |
| 80 const Register sp = { 29 }; | |
| 81 const Register s8_fp = { 30 }; | |
| 82 const Register ra = { 31 }; | |
| 83 | 78 |
| 79 if (!portable) found_by_runtime_probing_ = 0; | |
| 80 #endif | |
| 81 } | |
| 84 | 82 |
| 85 const FPURegister no_creg = { -1 }; | |
| 86 | |
| 87 const FPURegister f0 = { 0 }; | |
| 88 const FPURegister f1 = { 1 }; | |
| 89 const FPURegister f2 = { 2 }; | |
| 90 const FPURegister f3 = { 3 }; | |
| 91 const FPURegister f4 = { 4 }; | |
| 92 const FPURegister f5 = { 5 }; | |
| 93 const FPURegister f6 = { 6 }; | |
| 94 const FPURegister f7 = { 7 }; | |
| 95 const FPURegister f8 = { 8 }; | |
| 96 const FPURegister f9 = { 9 }; | |
| 97 const FPURegister f10 = { 10 }; | |
| 98 const FPURegister f11 = { 11 }; | |
| 99 const FPURegister f12 = { 12 }; | |
| 100 const FPURegister f13 = { 13 }; | |
| 101 const FPURegister f14 = { 14 }; | |
| 102 const FPURegister f15 = { 15 }; | |
| 103 const FPURegister f16 = { 16 }; | |
| 104 const FPURegister f17 = { 17 }; | |
| 105 const FPURegister f18 = { 18 }; | |
| 106 const FPURegister f19 = { 19 }; | |
| 107 const FPURegister f20 = { 20 }; | |
| 108 const FPURegister f21 = { 21 }; | |
| 109 const FPURegister f22 = { 22 }; | |
| 110 const FPURegister f23 = { 23 }; | |
| 111 const FPURegister f24 = { 24 }; | |
| 112 const FPURegister f25 = { 25 }; | |
| 113 const FPURegister f26 = { 26 }; | |
| 114 const FPURegister f27 = { 27 }; | |
| 115 const FPURegister f28 = { 28 }; | |
| 116 const FPURegister f29 = { 29 }; | |
| 117 const FPURegister f30 = { 30 }; | |
| 118 const FPURegister f31 = { 31 }; | |
| 119 | 83 |
| 120 int ToNumber(Register reg) { | 84 int ToNumber(Register reg) { |
| 121 ASSERT(reg.is_valid()); | 85 ASSERT(reg.is_valid()); |
| 122 const int kNumbers[] = { | 86 const int kNumbers[] = { |
| 123 0, // zero_reg | 87 0, // zero_reg |
| 124 1, // at | 88 1, // at |
| 125 2, // v0 | 89 2, // v0 |
| 126 3, // v1 | 90 3, // v1 |
| 127 4, // a0 | 91 4, // a0 |
| 128 5, // a1 | 92 5, // a1 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 149 26, // k0 | 113 26, // k0 |
| 150 27, // k1 | 114 27, // k1 |
| 151 28, // gp | 115 28, // gp |
| 152 29, // sp | 116 29, // sp |
| 153 30, // s8_fp | 117 30, // s8_fp |
| 154 31, // ra | 118 31, // ra |
| 155 }; | 119 }; |
| 156 return kNumbers[reg.code()]; | 120 return kNumbers[reg.code()]; |
| 157 } | 121 } |
| 158 | 122 |
| 123 | |
| 159 Register ToRegister(int num) { | 124 Register ToRegister(int num) { |
| 160 ASSERT(num >= 0 && num < kNumRegisters); | 125 ASSERT(num >= 0 && num < kNumRegisters); |
| 161 const Register kRegisters[] = { | 126 const Register kRegisters[] = { |
| 162 zero_reg, | 127 zero_reg, |
| 163 at, | 128 at, |
| 164 v0, v1, | 129 v0, v1, |
| 165 a0, a1, a2, a3, | 130 a0, a1, a2, a3, |
| 166 t0, t1, t2, t3, t4, t5, t6, t7, | 131 t0, t1, t2, t3, t4, t5, t6, t7, |
| 167 s0, s1, s2, s3, s4, s5, s6, s7, | 132 s0, s1, s2, s3, s4, s5, s6, s7, |
| 168 t8, t9, | 133 t8, t9, |
| 169 k0, k1, | 134 k0, k1, |
| 170 gp, | 135 gp, |
| 171 sp, | 136 sp, |
| 172 s8_fp, | 137 s8_fp, |
| 173 ra | 138 ra |
| 174 }; | 139 }; |
| 175 return kRegisters[num]; | 140 return kRegisters[num]; |
| 176 } | 141 } |
| 177 | 142 |
| 178 | 143 |
| 179 // ----------------------------------------------------------------------------- | 144 // ----------------------------------------------------------------------------- |
| 180 // Implementation of RelocInfo. | 145 // Implementation of RelocInfo. |
| 181 | 146 |
| 182 const int RelocInfo::kApplyMask = 0; | 147 const int RelocInfo::kApplyMask = 0; |
| 183 | 148 |
| 149 | |
| 150 bool RelocInfo::IsCodedSpecially() { | |
| 151 // The deserializer needs to know whether a pointer is specially coded. Being | |
| 152 // specially coded on MIPS means that it is a lui/ori instruction, and that is | |
| 153 // always the case inside code objects. | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 | |
| 184 // Patch the code at the current address with the supplied instructions. | 158 // Patch the code at the current address with the supplied instructions. |
| 185 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { | 159 void RelocInfo::PatchCode(byte* instructions, int instruction_count) { |
| 186 Instr* pc = reinterpret_cast<Instr*>(pc_); | 160 Instr* pc = reinterpret_cast<Instr*>(pc_); |
| 187 Instr* instr = reinterpret_cast<Instr*>(instructions); | 161 Instr* instr = reinterpret_cast<Instr*>(instructions); |
| 188 for (int i = 0; i < instruction_count; i++) { | 162 for (int i = 0; i < instruction_count; i++) { |
| 189 *(pc + i) = *(instr + i); | 163 *(pc + i) = *(instr + i); |
| 190 } | 164 } |
| 191 | 165 |
| 192 // Indicate that code has changed. | 166 // Indicate that code has changed. |
| 193 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize); | 167 CPU::FlushICache(pc_, instruction_count * Assembler::kInstrSize); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 214 if (obj->IsHeapObject()) { | 188 if (obj->IsHeapObject()) { |
| 215 imm32_ = reinterpret_cast<intptr_t>(handle.location()); | 189 imm32_ = reinterpret_cast<intptr_t>(handle.location()); |
| 216 rmode_ = RelocInfo::EMBEDDED_OBJECT; | 190 rmode_ = RelocInfo::EMBEDDED_OBJECT; |
| 217 } else { | 191 } else { |
| 218 // No relocation needed. | 192 // No relocation needed. |
| 219 imm32_ = reinterpret_cast<intptr_t>(obj); | 193 imm32_ = reinterpret_cast<intptr_t>(obj); |
| 220 rmode_ = RelocInfo::NONE; | 194 rmode_ = RelocInfo::NONE; |
| 221 } | 195 } |
| 222 } | 196 } |
| 223 | 197 |
| 224 MemOperand::MemOperand(Register rm, int16_t offset) : Operand(rm) { | 198 |
| 199 MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) { | |
| 225 offset_ = offset; | 200 offset_ = offset; |
| 226 } | 201 } |
| 227 | 202 |
| 228 | 203 |
| 229 // ----------------------------------------------------------------------------- | 204 // ----------------------------------------------------------------------------- |
| 230 // Implementation of Assembler. | 205 // Specific instructions, constants, and masks. |
| 231 | 206 |
| 232 static const int kMinimalBufferSize = 4*KB; | 207 static const int kMinimalBufferSize = 4*KB; |
| 233 static byte* spare_buffer_ = NULL; | 208 static byte* spare_buffer_ = NULL; |
| 209 static const int kNegOffset = 0x00008000; | |
| 210 // addiu(sp, sp, 4) aka Pop() operation or part of Pop(r) | |
| 211 // operations as post-increment of sp. | |
| 212 const Instr kPopInstruction = ADDIU | (sp.code() << kRsShift) | |
| 213 | (sp.code() << kRtShift) | (kPointerSize & kImm16Mask); | |
| 214 // addiu(sp, sp, -4) part of Push(r) operation as pre-decrement of sp. | |
| 215 const Instr kPushInstruction = ADDIU | (sp.code() << kRsShift) | |
| 216 | (sp.code() << kRtShift) | (-kPointerSize & kImm16Mask); | |
| 217 // sw(r, MemOperand(sp, 0)) | |
| 218 const Instr kPushRegPattern = SW | (sp.code() << kRsShift) | |
| 219 | (0 & kImm16Mask); | |
| 220 // lw(r, MemOperand(sp, 0)) | |
| 221 const Instr kPopRegPattern = LW | (sp.code() << kRsShift) | |
| 222 | (0 & kImm16Mask); | |
| 234 | 223 |
| 235 Assembler::Assembler(void* buffer, int buffer_size) { | 224 const Instr kLwRegFpOffsetPattern = LW | (s8_fp.code() << kRsShift) |
| 225 | (0 & kImm16Mask); | |
| 226 | |
| 227 const Instr kSwRegFpOffsetPattern = SW | (s8_fp.code() << kRsShift) | |
| 228 | (0 & kImm16Mask); | |
| 229 | |
| 230 const Instr kLwRegFpNegOffsetPattern = LW | (s8_fp.code() << kRsShift) | |
| 231 | (kNegOffset & kImm16Mask); | |
| 232 | |
| 233 const Instr kSwRegFpNegOffsetPattern = SW | (s8_fp.code() << kRsShift) | |
| 234 | (kNegOffset & kImm16Mask); | |
| 235 // A mask for the Rt register for push, pop, lw, sw instructions. | |
| 236 const Instr kRtMask = kRtFieldMask; | |
| 237 const Instr kLwSwInstrTypeMask = 0xffe00000; | |
| 238 const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask; | |
| 239 const Instr kLwSwOffsetMask = kImm16Mask; | |
| 240 | |
| 241 | |
| 242 Assembler::Assembler(void* buffer, int buffer_size) | |
| 243 : positions_recorder_(this), | |
| 244 allow_peephole_optimization_(false) { | |
| 245 // BUG(3245989): disable peephole optimization if crankshaft is enabled. | |
| 246 allow_peephole_optimization_ = FLAG_peephole_optimization; | |
| 236 if (buffer == NULL) { | 247 if (buffer == NULL) { |
| 237 // Do our own buffer management. | 248 // Do our own buffer management. |
| 238 if (buffer_size <= kMinimalBufferSize) { | 249 if (buffer_size <= kMinimalBufferSize) { |
| 239 buffer_size = kMinimalBufferSize; | 250 buffer_size = kMinimalBufferSize; |
| 240 | 251 |
| 241 if (spare_buffer_ != NULL) { | 252 if (spare_buffer_ != NULL) { |
| 242 buffer = spare_buffer_; | 253 buffer = spare_buffer_; |
| 243 spare_buffer_ = NULL; | 254 spare_buffer_ = NULL; |
| 244 } | 255 } |
| 245 } | 256 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 256 ASSERT(buffer_size > 0); | 267 ASSERT(buffer_size > 0); |
| 257 buffer_ = static_cast<byte*>(buffer); | 268 buffer_ = static_cast<byte*>(buffer); |
| 258 buffer_size_ = buffer_size; | 269 buffer_size_ = buffer_size; |
| 259 own_buffer_ = false; | 270 own_buffer_ = false; |
| 260 } | 271 } |
| 261 | 272 |
| 262 // Setup buffer pointers. | 273 // Setup buffer pointers. |
| 263 ASSERT(buffer_ != NULL); | 274 ASSERT(buffer_ != NULL); |
| 264 pc_ = buffer_; | 275 pc_ = buffer_; |
| 265 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); | 276 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); |
| 266 current_statement_position_ = RelocInfo::kNoPosition; | 277 |
| 267 current_position_ = RelocInfo::kNoPosition; | 278 last_trampoline_pool_end_ = 0; |
| 268 written_statement_position_ = current_statement_position_; | 279 no_trampoline_pool_before_ = 0; |
| 269 written_position_ = current_position_; | 280 trampoline_pool_blocked_nesting_ = 0; |
| 281 next_buffer_check_ = kMaxBranchOffset - kTrampolineSize; | |
| 270 } | 282 } |
| 271 | 283 |
| 272 | 284 |
| 273 Assembler::~Assembler() { | 285 Assembler::~Assembler() { |
| 274 if (own_buffer_) { | 286 if (own_buffer_) { |
| 275 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { | 287 if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { |
| 276 spare_buffer_ = buffer_; | 288 spare_buffer_ = buffer_; |
| 277 } else { | 289 } else { |
| 278 DeleteArray(buffer_); | 290 DeleteArray(buffer_); |
| 279 } | 291 } |
| 280 } | 292 } |
| 281 } | 293 } |
| 282 | 294 |
| 283 | 295 |
| 284 void Assembler::GetCode(CodeDesc* desc) { | 296 void Assembler::GetCode(CodeDesc* desc) { |
| 285 ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap | 297 ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap |
| 286 // Setup code descriptor. | 298 // Setup code descriptor. |
| 287 desc->buffer = buffer_; | 299 desc->buffer = buffer_; |
| 288 desc->buffer_size = buffer_size_; | 300 desc->buffer_size = buffer_size_; |
| 289 desc->instr_size = pc_offset(); | 301 desc->instr_size = pc_offset(); |
| 290 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); | 302 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); |
| 291 } | 303 } |
| 292 | 304 |
| 293 | 305 |
| 306 void Assembler::Align(int m) { | |
| 307 ASSERT(m >= 4 && IsPowerOf2(m)); | |
| 308 while ((pc_offset() & (m - 1)) != 0) { | |
| 309 nop(); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 | |
| 314 void Assembler::CodeTargetAlign() { | |
| 315 // No advantage to aligning branch/call targets to more than | |
| 316 // single instruction, that I am aware of. | |
| 317 Align(4); | |
| 318 } | |
| 319 | |
| 320 | |
| 321 Register Assembler::GetRt(Instr instr) { | |
| 322 Register rt; | |
| 323 rt.code_ = (instr & kRtMask) >> kRtShift; | |
| 324 return rt; | |
| 325 } | |
| 326 | |
| 327 | |
| 328 bool Assembler::IsPop(Instr instr) { | |
| 329 return (instr & ~kRtMask) == kPopRegPattern; | |
| 330 } | |
| 331 | |
| 332 | |
| 333 bool Assembler::IsPush(Instr instr) { | |
| 334 return (instr & ~kRtMask) == kPushRegPattern; | |
| 335 } | |
| 336 | |
| 337 | |
| 338 bool Assembler::IsSwRegFpOffset(Instr instr) { | |
| 339 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern); | |
| 340 } | |
| 341 | |
| 342 | |
| 343 bool Assembler::IsLwRegFpOffset(Instr instr) { | |
| 344 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern); | |
| 345 } | |
| 346 | |
| 347 | |
| 348 bool Assembler::IsSwRegFpNegOffset(Instr instr) { | |
| 349 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) == | |
| 350 kSwRegFpNegOffsetPattern); | |
| 351 } | |
| 352 | |
| 353 | |
| 354 bool Assembler::IsLwRegFpNegOffset(Instr instr) { | |
| 355 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) == | |
| 356 kLwRegFpNegOffsetPattern); | |
| 357 } | |
| 358 | |
| 359 | |
| 294 // Labels refer to positions in the (to be) generated code. | 360 // Labels refer to positions in the (to be) generated code. |
| 295 // There are bound, linked, and unused labels. | 361 // There are bound, linked, and unused labels. |
| 296 // | 362 // |
| 297 // Bound labels refer to known positions in the already | 363 // Bound labels refer to known positions in the already |
| 298 // generated code. pos() is the position the label refers to. | 364 // generated code. pos() is the position the label refers to. |
| 299 // | 365 // |
| 300 // Linked labels refer to unknown positions in the code | 366 // Linked labels refer to unknown positions in the code |
| 301 // to be generated; pos() is the position of the last | 367 // to be generated; pos() is the position of the last |
| 302 // instruction using the label. | 368 // instruction using the label. |
| 303 | 369 |
| 370 // The link chain is terminated by a value in the instruction of -1, | |
| 371 // which is an otherwise illegal value (branch -1 is inf loop). | |
| 372 // The instruction 16-bit offset field addresses 32-bit words, but in | |
| 373 // code is conv to an 18-bit value addressing bytes, hence the -4 value. | |
| 304 | 374 |
| 305 // The link chain is terminated by a negative code position (must be aligned). | |
| 306 const int kEndOfChain = -4; | 375 const int kEndOfChain = -4; |
| 307 | 376 |
| 308 bool Assembler::is_branch(Instr instr) { | 377 |
| 378 bool Assembler::IsBranch(Instr instr) { | |
| 309 uint32_t opcode = ((instr & kOpcodeMask)); | 379 uint32_t opcode = ((instr & kOpcodeMask)); |
| 310 uint32_t rt_field = ((instr & kRtFieldMask)); | 380 uint32_t rt_field = ((instr & kRtFieldMask)); |
| 311 uint32_t rs_field = ((instr & kRsFieldMask)); | 381 uint32_t rs_field = ((instr & kRsFieldMask)); |
| 382 uint32_t label_constant = (instr & ~kImm16Mask); | |
| 312 // Checks if the instruction is a branch. | 383 // Checks if the instruction is a branch. |
| 313 return opcode == BEQ || | 384 return opcode == BEQ || |
| 314 opcode == BNE || | 385 opcode == BNE || |
| 315 opcode == BLEZ || | 386 opcode == BLEZ || |
| 316 opcode == BGTZ || | 387 opcode == BGTZ || |
| 317 opcode == BEQL || | 388 opcode == BEQL || |
| 318 opcode == BNEL || | 389 opcode == BNEL || |
| 319 opcode == BLEZL || | 390 opcode == BLEZL || |
| 320 opcode == BGTZL|| | 391 opcode == BGTZL|| |
| 321 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ || | 392 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ || |
| 322 rt_field == BLTZAL || rt_field == BGEZAL)) || | 393 rt_field == BLTZAL || rt_field == BGEZAL)) || |
| 323 (opcode == COP1 && rs_field == BC1); // Coprocessor branch. | 394 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch. |
| 395 label_constant == 0; // Emitted label const in reg-exp engine. | |
| 324 } | 396 } |
| 325 | 397 |
| 326 | 398 |
| 399 bool Assembler::IsNop(Instr instr, unsigned int type) { | |
| 400 // See Assembler::nop(type). | |
| 401 ASSERT(type < 32); | |
| 402 uint32_t opcode = ((instr & kOpcodeMask)); | |
| 403 uint32_t rt = ((instr & kRtFieldMask) >> kRtShift); | |
| 404 uint32_t rs = ((instr & kRsFieldMask) >> kRsShift); | |
| 405 uint32_t sa = ((instr & kSaFieldMask) >> kSaShift); | |
| 406 | |
| 407 // nop(type) == sll(zero_reg, zero_reg, type); | |
| 408 // Technically all these values will be 0 but | |
| 409 // this makes more sense to the reader. | |
| 410 | |
| 411 bool ret = (opcode == SLL && | |
| 412 rt == static_cast<uint32_t>(ToNumber(zero_reg)) && | |
| 413 rs == static_cast<uint32_t>(ToNumber(zero_reg)) && | |
| 414 sa == type); | |
| 415 | |
| 416 return ret; | |
| 417 } | |
| 418 | |
| 419 | |
| 420 int32_t Assembler::GetBranchOffset(Instr instr) { | |
| 421 ASSERT(IsBranch(instr)); | |
| 422 return ((int16_t)(instr & kImm16Mask)) << 2; | |
| 423 } | |
| 424 | |
| 425 | |
| 426 bool Assembler::IsLw(Instr instr) { | |
| 427 return ((instr & kOpcodeMask) == LW); | |
| 428 } | |
| 429 | |
| 430 | |
| 431 int16_t Assembler::GetLwOffset(Instr instr) { | |
| 432 ASSERT(IsLw(instr)); | |
| 433 return ((instr & kImm16Mask)); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) { | |
| 438 ASSERT(IsLw(instr)); | |
| 439 | |
| 440 // We actually create a new lw instruction based on the original one. | |
| 441 Instr temp_instr = LW | | |
| 442 (instr & kRsFieldMask) | | |
| 443 (instr & kRtFieldMask) | | |
| 444 (offset & kImm16Mask); | |
| 445 | |
| 446 return temp_instr; | |
| 447 } | |
| 448 | |
| 449 | |
| 450 bool Assembler::IsSw(Instr instr) { | |
| 451 return ((instr & kOpcodeMask) == SW); | |
| 452 } | |
| 453 | |
| 454 | |
| 455 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) { | |
| 456 ASSERT(IsSw(instr)); | |
| 457 return ((instr & ~kImm16Mask) | (offset & kImm16Mask)); | |
| 458 } | |
| 459 | |
| 460 | |
| 461 bool Assembler::IsAddImmediate(Instr instr) { | |
| 462 return ((instr & kOpcodeMask) == ADDIU); | |
| 463 } | |
| 464 | |
| 465 | |
| 466 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) { | |
| 467 ASSERT(IsAddImmediate(instr)); | |
| 468 return ((instr & ~kImm16Mask) | (offset & kImm16Mask)); | |
| 469 } | |
| 470 | |
| 471 | |
| 327 int Assembler::target_at(int32_t pos) { | 472 int Assembler::target_at(int32_t pos) { |
| 328 Instr instr = instr_at(pos); | 473 Instr instr = instr_at(pos); |
| 329 if ((instr & ~kImm16Mask) == 0) { | 474 if ((instr & ~kImm16Mask) == 0) { |
| 330 // Emitted label constant, not part of a branch. | 475 // Emitted label constant, not part of a branch. |
| 331 return instr - (Code::kHeaderSize - kHeapObjectTag); | 476 if (instr == 0) { |
| 477 return kEndOfChain; | |
| 478 } else { | |
| 479 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14; | |
| 480 return (imm18 + pos); | |
| 481 } | |
| 332 } | 482 } |
| 333 // Check we have a branch instruction. | 483 // Check we have a branch instruction. |
| 334 ASSERT(is_branch(instr)); | 484 ASSERT(IsBranch(instr)); |
| 335 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming | 485 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming |
| 336 // the compiler uses arithmectic shifts for signed integers. | 486 // the compiler uses arithmectic shifts for signed integers. |
| 337 int32_t imm18 = ((instr & | 487 int32_t imm18 = ((instr & |
| 338 static_cast<int32_t>(kImm16Mask)) << 16) >> 14; | 488 static_cast<int32_t>(kImm16Mask)) << 16) >> 14; |
| 339 | 489 |
| 340 return pos + kBranchPCOffset + imm18; | 490 if (imm18 == kEndOfChain) { |
| 491 // EndOfChain sentinel is returned directly, not relative to pc or pos. | |
| 492 return kEndOfChain; | |
| 493 } else { | |
| 494 return pos + kBranchPCOffset + imm18; | |
| 495 } | |
| 341 } | 496 } |
| 342 | 497 |
| 343 | 498 |
| 344 void Assembler::target_at_put(int32_t pos, int32_t target_pos) { | 499 void Assembler::target_at_put(int32_t pos, int32_t target_pos) { |
| 345 Instr instr = instr_at(pos); | 500 Instr instr = instr_at(pos); |
| 346 if ((instr & ~kImm16Mask) == 0) { | 501 if ((instr & ~kImm16Mask) == 0) { |
| 347 ASSERT(target_pos == kEndOfChain || target_pos >= 0); | 502 ASSERT(target_pos == kEndOfChain || target_pos >= 0); |
| 348 // Emitted label constant, not part of a branch. | 503 // Emitted label constant, not part of a branch. |
| 349 // Make label relative to Code* of generated Code object. | 504 // Make label relative to Code* of generated Code object. |
| 350 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); | 505 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); |
| 351 return; | 506 return; |
| 352 } | 507 } |
| 353 | 508 |
| 354 ASSERT(is_branch(instr)); | 509 ASSERT(IsBranch(instr)); |
| 355 int32_t imm18 = target_pos - (pos + kBranchPCOffset); | 510 int32_t imm18 = target_pos - (pos + kBranchPCOffset); |
| 356 ASSERT((imm18 & 3) == 0); | 511 ASSERT((imm18 & 3) == 0); |
| 357 | 512 |
| 358 instr &= ~kImm16Mask; | 513 instr &= ~kImm16Mask; |
| 359 int32_t imm16 = imm18 >> 2; | 514 int32_t imm16 = imm18 >> 2; |
| 360 ASSERT(is_int16(imm16)); | 515 ASSERT(is_int16(imm16)); |
| 361 | 516 |
| 362 instr_at_put(pos, instr | (imm16 & kImm16Mask)); | 517 instr_at_put(pos, instr | (imm16 & kImm16Mask)); |
| 363 } | 518 } |
| 364 | 519 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 384 } else { | 539 } else { |
| 385 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); | 540 PrintF("label in inconsistent state (pos = %d)\n", L->pos_); |
| 386 } | 541 } |
| 387 } | 542 } |
| 388 | 543 |
| 389 | 544 |
| 390 void Assembler::bind_to(Label* L, int pos) { | 545 void Assembler::bind_to(Label* L, int pos) { |
| 391 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position | 546 ASSERT(0 <= pos && pos <= pc_offset()); // must have a valid binding position |
| 392 while (L->is_linked()) { | 547 while (L->is_linked()) { |
| 393 int32_t fixup_pos = L->pos(); | 548 int32_t fixup_pos = L->pos(); |
| 549 int32_t dist = pos - fixup_pos; | |
| 394 next(L); // call next before overwriting link with target at fixup_pos | 550 next(L); // call next before overwriting link with target at fixup_pos |
| 551 if (dist > kMaxBranchOffset) { | |
| 552 do { | |
| 553 int32_t trampoline_pos = get_trampoline_entry(fixup_pos); | |
| 554 ASSERT((trampoline_pos - fixup_pos) <= kMaxBranchOffset); | |
| 555 target_at_put(fixup_pos, trampoline_pos); | |
| 556 fixup_pos = trampoline_pos; | |
| 557 dist = pos - fixup_pos; | |
| 558 } while (dist > kMaxBranchOffset); | |
| 559 } else if (dist < -kMaxBranchOffset) { | |
| 560 do { | |
| 561 int32_t trampoline_pos = get_trampoline_entry(fixup_pos, false); | |
| 562 ASSERT((trampoline_pos - fixup_pos) >= -kMaxBranchOffset); | |
| 563 target_at_put(fixup_pos, trampoline_pos); | |
| 564 fixup_pos = trampoline_pos; | |
| 565 dist = pos - fixup_pos; | |
| 566 } while (dist < -kMaxBranchOffset); | |
| 567 }; | |
| 395 target_at_put(fixup_pos, pos); | 568 target_at_put(fixup_pos, pos); |
| 396 } | 569 } |
| 397 L->bind_to(pos); | 570 L->bind_to(pos); |
| 398 | 571 |
| 399 // Keep track of the last bound label so we don't eliminate any instructions | 572 // Keep track of the last bound label so we don't eliminate any instructions |
| 400 // before a bound label. | 573 // before a bound label. |
| 401 if (pos > last_bound_pos_) | 574 if (pos > last_bound_pos_) |
| 402 last_bound_pos_ = pos; | 575 last_bound_pos_ = pos; |
| 403 } | 576 } |
| 404 | 577 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 424 } | 597 } |
| 425 | 598 |
| 426 | 599 |
| 427 void Assembler::bind(Label* L) { | 600 void Assembler::bind(Label* L) { |
| 428 ASSERT(!L->is_bound()); // label can only be bound once | 601 ASSERT(!L->is_bound()); // label can only be bound once |
| 429 bind_to(L, pc_offset()); | 602 bind_to(L, pc_offset()); |
| 430 } | 603 } |
| 431 | 604 |
| 432 | 605 |
| 433 void Assembler::next(Label* L) { | 606 void Assembler::next(Label* L) { |
| 607 // ASSERT(L->pos() == kEndOfChain || L->is_linked()); | |
|
Søren Thygesen Gjesse
2011/03/21 16:05:19
Code in comments.
Paul Lind
2011/03/23 01:55:43
Removed.
| |
| 434 ASSERT(L->is_linked()); | 608 ASSERT(L->is_linked()); |
| 435 int link = target_at(L->pos()); | 609 int link = target_at(L->pos()); |
| 436 if (link > 0) { | 610 ASSERT(link > 0 || link == kEndOfChain); |
| 611 if (link == kEndOfChain) { | |
| 612 L->Unuse(); | |
| 613 } else if (link > 0) { | |
| 437 L->link_to(link); | 614 L->link_to(link); |
| 438 } else { | |
| 439 ASSERT(link == kEndOfChain); | |
| 440 L->Unuse(); | |
| 441 } | 615 } |
| 442 } | 616 } |
| 443 | 617 |
| 444 | 618 |
| 445 // We have to use a temporary register for things that can be relocated even | 619 // We have to use a temporary register for things that can be relocated even |
| 446 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction | 620 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction |
| 447 // space. There is no guarantee that the relocated location can be similarly | 621 // space. There is no guarantee that the relocated location can be similarly |
| 448 // encoded. | 622 // encoded. |
| 449 bool Assembler::MustUseAt(RelocInfo::Mode rmode) { | 623 bool Assembler::MustUseReg(RelocInfo::Mode rmode) { |
| 450 if (rmode == RelocInfo::EXTERNAL_REFERENCE) { | 624 if (rmode == RelocInfo::NONE) { |
|
Søren Thygesen Gjesse
2011/03/21 16:05:19
Use
return rmode != RelocInfo::NONE
instead of t
Paul Lind
2011/03/23 01:55:43
Done.
| |
| 451 return Serializer::enabled(); | |
| 452 } else if (rmode == RelocInfo::NONE) { | |
| 453 return false; | 625 return false; |
| 626 } else { | |
| 627 return true; | |
| 454 } | 628 } |
| 455 return true; | |
| 456 } | 629 } |
| 457 | 630 |
| 458 | 631 |
| 459 void Assembler::GenInstrRegister(Opcode opcode, | 632 void Assembler::GenInstrRegister(Opcode opcode, |
| 460 Register rs, | 633 Register rs, |
| 461 Register rt, | 634 Register rt, |
| 462 Register rd, | 635 Register rd, |
| 463 uint16_t sa, | 636 uint16_t sa, |
| 464 SecondaryField func) { | 637 SecondaryField func) { |
| 465 ASSERT(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa)); | 638 ASSERT(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa)); |
| 466 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) | 639 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
| 467 | (rd.code() << kRdShift) | (sa << kSaShift) | func; | 640 | (rd.code() << kRdShift) | (sa << kSaShift) | func; |
| 468 emit(instr); | 641 emit(instr); |
| 469 } | 642 } |
| 470 | 643 |
| 471 | 644 |
| 472 void Assembler::GenInstrRegister(Opcode opcode, | 645 void Assembler::GenInstrRegister(Opcode opcode, |
| 646 Register rs, | |
| 647 Register rt, | |
| 648 uint16_t msb, | |
| 649 uint16_t lsb, | |
| 650 SecondaryField func) { | |
| 651 ASSERT(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb)); | |
| 652 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) | |
| 653 | (msb << kRdShift) | (lsb << kSaShift) | func; | |
| 654 emit(instr); | |
| 655 } | |
| 656 | |
| 657 | |
| 658 void Assembler::GenInstrRegister(Opcode opcode, | |
| 473 SecondaryField fmt, | 659 SecondaryField fmt, |
| 474 FPURegister ft, | 660 FPURegister ft, |
| 475 FPURegister fs, | 661 FPURegister fs, |
| 476 FPURegister fd, | 662 FPURegister fd, |
| 477 SecondaryField func) { | 663 SecondaryField func) { |
| 478 ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid()); | 664 ASSERT(fd.is_valid() && fs.is_valid() && ft.is_valid()); |
| 479 Instr instr = opcode | fmt | (ft.code() << 16) | (fs.code() << kFsShift) | 665 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift) |
| 480 | (fd.code() << 6) | func; | 666 | (fd.code() << kFdShift) | func; |
| 481 emit(instr); | 667 emit(instr); |
| 482 } | 668 } |
| 483 | 669 |
| 484 | 670 |
| 485 void Assembler::GenInstrRegister(Opcode opcode, | 671 void Assembler::GenInstrRegister(Opcode opcode, |
| 486 SecondaryField fmt, | 672 SecondaryField fmt, |
| 487 Register rt, | 673 Register rt, |
| 488 FPURegister fs, | 674 FPURegister fs, |
| 489 FPURegister fd, | 675 FPURegister fd, |
| 490 SecondaryField func) { | 676 SecondaryField func) { |
| 491 ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid()); | 677 ASSERT(fd.is_valid() && fs.is_valid() && rt.is_valid()); |
| 492 Instr instr = opcode | fmt | (rt.code() << kRtShift) | 678 Instr instr = opcode | fmt | (rt.code() << kRtShift) |
| 493 | (fs.code() << kFsShift) | (fd.code() << 6) | func; | 679 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func; |
| 494 emit(instr); | 680 emit(instr); |
| 495 } | 681 } |
| 496 | 682 |
| 683 | |
| 684 void Assembler::GenInstrRegister(Opcode opcode, | |
| 685 SecondaryField fmt, | |
| 686 Register rt, | |
| 687 FPUControlRegister fs, | |
| 688 SecondaryField func) { | |
| 689 ASSERT(fs.is_valid() && rt.is_valid()); | |
| 690 Instr instr = opcode | fmt | (rt.code() << kRtShift) | |
| 691 | (fs.code() << kFsShift) | func; | |
| 692 emit(instr); | |
| 693 } | |
| 694 | |
| 497 | 695 |
| 498 // Instructions with immediate value. | 696 // Instructions with immediate value. |
| 499 // Registers are in the order of the instruction encoding, from left to right. | 697 // Registers are in the order of the instruction encoding, from left to right. |
| 500 void Assembler::GenInstrImmediate(Opcode opcode, | 698 void Assembler::GenInstrImmediate(Opcode opcode, |
| 501 Register rs, | 699 Register rs, |
| 502 Register rt, | 700 Register rt, |
| 503 int32_t j) { | 701 int32_t j) { |
| 504 ASSERT(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j))); | 702 ASSERT(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j))); |
| 505 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) | 703 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift) |
| 506 | (j & kImm16Mask); | 704 | (j & kImm16Mask); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 525 ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j))); | 723 ASSERT(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j))); |
| 526 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift) | 724 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift) |
| 527 | (j & kImm16Mask); | 725 | (j & kImm16Mask); |
| 528 emit(instr); | 726 emit(instr); |
| 529 } | 727 } |
| 530 | 728 |
| 531 | 729 |
| 532 // Registers are in the order of the instruction encoding, from left to right. | 730 // Registers are in the order of the instruction encoding, from left to right. |
| 533 void Assembler::GenInstrJump(Opcode opcode, | 731 void Assembler::GenInstrJump(Opcode opcode, |
| 534 uint32_t address) { | 732 uint32_t address) { |
| 733 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 535 ASSERT(is_uint26(address)); | 734 ASSERT(is_uint26(address)); |
| 536 Instr instr = opcode | address; | 735 Instr instr = opcode | address; |
| 537 emit(instr); | 736 emit(instr); |
| 737 BlockTrampolinePoolFor(1); | |
| 738 } | |
| 739 | |
| 740 | |
| 741 // Returns the next free label entry from the next trampoline pool. | |
| 742 int32_t Assembler::get_label_entry(int32_t pos, bool next_pool) { | |
| 743 int trampoline_count = trampolines_.length(); | |
| 744 int32_t label_entry = 0; | |
| 745 ASSERT(trampoline_count > 0); | |
| 746 | |
| 747 if (next_pool) { | |
| 748 for (int i = 0; i < trampoline_count; i++) { | |
| 749 if (trampolines_[i].start() > pos) { | |
| 750 label_entry = trampolines_[i].take_label(); | |
| 751 break; | |
| 752 } | |
| 753 } | |
| 754 } else { // Caller needs a label entry from the previous pool. | |
| 755 for (int i = trampoline_count-1; i >= 0; i--) { | |
| 756 if (trampolines_[i].end() < pos) { | |
| 757 label_entry = trampolines_[i].take_label(); | |
| 758 break; | |
| 759 } | |
| 760 } | |
| 761 } | |
| 762 return label_entry; | |
| 763 } | |
| 764 | |
| 765 | |
| 766 // Returns the next free trampoline entry from the next trampoline pool. | |
| 767 int32_t Assembler::get_trampoline_entry(int32_t pos, bool next_pool) { | |
| 768 int trampoline_count = trampolines_.length(); | |
| 769 int32_t trampoline_entry = 0; | |
| 770 ASSERT(trampoline_count > 0); | |
| 771 | |
| 772 if (next_pool) { | |
| 773 for (int i = 0; i < trampoline_count; i++) { | |
| 774 if (trampolines_[i].start() > pos) { | |
| 775 trampoline_entry = trampolines_[i].take_slot(); | |
| 776 break; | |
| 777 } | |
| 778 } | |
| 779 } else { // Caller needs a trampoline entry from the previous pool. | |
| 780 for (int i = trampoline_count-1; i >= 0; i--) { | |
| 781 if (trampolines_[i].end() < pos) { | |
| 782 trampoline_entry = trampolines_[i].take_slot(); | |
| 783 break; | |
| 784 } | |
| 785 } | |
| 786 } | |
| 787 return trampoline_entry; | |
| 538 } | 788 } |
| 539 | 789 |
| 540 | 790 |
| 541 int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { | 791 int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { |
| 542 int32_t target_pos; | 792 int32_t target_pos; |
| 793 int32_t pc_offset_v = pc_offset(); | |
| 794 | |
| 543 if (L->is_bound()) { | 795 if (L->is_bound()) { |
| 544 target_pos = L->pos(); | 796 target_pos = L->pos(); |
| 797 int32_t dist = pc_offset_v - target_pos; | |
| 798 if (dist > kMaxBranchOffset) { | |
| 799 do { | |
| 800 int32_t trampoline_pos = get_trampoline_entry(target_pos); | |
| 801 ASSERT((trampoline_pos - target_pos) > 0); | |
| 802 ASSERT((trampoline_pos - target_pos) <= kMaxBranchOffset); | |
| 803 target_at_put(trampoline_pos, target_pos); | |
| 804 target_pos = trampoline_pos; | |
| 805 dist = pc_offset_v - target_pos; | |
| 806 } while (dist > kMaxBranchOffset); | |
| 807 } else if (dist < -kMaxBranchOffset) { | |
| 808 do { | |
| 809 int32_t trampoline_pos = get_trampoline_entry(target_pos, false); | |
| 810 ASSERT((target_pos - trampoline_pos) > 0); | |
| 811 ASSERT((target_pos - trampoline_pos) <= kMaxBranchOffset); | |
| 812 target_at_put(trampoline_pos, target_pos); | |
| 813 target_pos = trampoline_pos; | |
| 814 dist = pc_offset_v - target_pos; | |
| 815 } while (dist < -kMaxBranchOffset); | |
| 816 } | |
| 545 } else { | 817 } else { |
| 546 if (L->is_linked()) { | 818 if (L->is_linked()) { |
| 547 target_pos = L->pos(); // L's link | 819 target_pos = L->pos(); // L's link |
| 820 int32_t dist = pc_offset_v - target_pos; | |
| 821 if (dist > kMaxBranchOffset) { | |
| 822 do { | |
| 823 int32_t label_pos = get_label_entry(target_pos); | |
| 824 ASSERT((label_pos - target_pos) < kMaxBranchOffset); | |
| 825 label_at_put(L, label_pos); | |
| 826 target_pos = label_pos; | |
| 827 dist = pc_offset_v - target_pos; | |
| 828 } while (dist > kMaxBranchOffset); | |
| 829 } else if (dist < -kMaxBranchOffset) { | |
| 830 do { | |
| 831 int32_t label_pos = get_label_entry(target_pos, false); | |
| 832 ASSERT((label_pos - target_pos) > -kMaxBranchOffset); | |
| 833 label_at_put(L, label_pos); | |
| 834 target_pos = label_pos; | |
| 835 dist = pc_offset_v - target_pos; | |
| 836 } while (dist < -kMaxBranchOffset); | |
| 837 } | |
| 838 L->link_to(pc_offset()); | |
| 548 } else { | 839 } else { |
| 549 target_pos = kEndOfChain; | 840 L->link_to(pc_offset()); |
| 841 return kEndOfChain; | |
| 550 } | 842 } |
| 551 L->link_to(pc_offset()); | |
| 552 } | 843 } |
| 553 | 844 |
| 554 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset); | 845 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset); |
| 846 ASSERT((offset & 3) == 0); | |
| 847 ASSERT(is_int16(offset >> 2)); | |
| 848 | |
| 555 return offset; | 849 return offset; |
| 556 } | 850 } |
| 557 | 851 |
| 558 | 852 |
| 559 void Assembler::label_at_put(Label* L, int at_offset) { | 853 void Assembler::label_at_put(Label* L, int at_offset) { |
| 560 int target_pos; | 854 int target_pos; |
| 561 if (L->is_bound()) { | 855 if (L->is_bound()) { |
| 562 target_pos = L->pos(); | 856 target_pos = L->pos(); |
| 857 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); | |
| 563 } else { | 858 } else { |
| 564 if (L->is_linked()) { | 859 if (L->is_linked()) { |
| 565 target_pos = L->pos(); // L's link | 860 target_pos = L->pos(); // L's link |
| 861 int32_t imm18 = target_pos - at_offset; | |
| 862 ASSERT((imm18 & 3) == 0); | |
| 863 int32_t imm16 = imm18 >> 2; | |
| 864 ASSERT(is_int16(imm16)); | |
| 865 instr_at_put(at_offset, (imm16 & kImm16Mask)); | |
| 566 } else { | 866 } else { |
| 567 target_pos = kEndOfChain; | 867 target_pos = kEndOfChain; |
| 868 instr_at_put(at_offset, 0); | |
| 568 } | 869 } |
| 569 L->link_to(at_offset); | 870 L->link_to(at_offset); |
| 570 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); | |
| 571 } | 871 } |
| 572 } | 872 } |
| 573 | 873 |
| 574 | 874 |
| 575 //------- Branch and jump instructions -------- | 875 //------- Branch and jump instructions -------- |
| 576 | 876 |
| 577 void Assembler::b(int16_t offset) { | 877 void Assembler::b(int16_t offset) { |
| 578 beq(zero_reg, zero_reg, offset); | 878 beq(zero_reg, zero_reg, offset); |
| 579 } | 879 } |
| 580 | 880 |
| 581 | 881 |
| 582 void Assembler::bal(int16_t offset) { | 882 void Assembler::bal(int16_t offset) { |
| 883 positions_recorder()->WriteRecordedPositions(); | |
| 583 bgezal(zero_reg, offset); | 884 bgezal(zero_reg, offset); |
| 584 } | 885 } |
| 585 | 886 |
| 586 | 887 |
| 587 void Assembler::beq(Register rs, Register rt, int16_t offset) { | 888 void Assembler::beq(Register rs, Register rt, int16_t offset) { |
| 889 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 588 GenInstrImmediate(BEQ, rs, rt, offset); | 890 GenInstrImmediate(BEQ, rs, rt, offset); |
| 891 BlockTrampolinePoolFor(1); | |
| 589 } | 892 } |
| 590 | 893 |
| 591 | 894 |
| 592 void Assembler::bgez(Register rs, int16_t offset) { | 895 void Assembler::bgez(Register rs, int16_t offset) { |
| 896 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 593 GenInstrImmediate(REGIMM, rs, BGEZ, offset); | 897 GenInstrImmediate(REGIMM, rs, BGEZ, offset); |
| 898 BlockTrampolinePoolFor(1); | |
| 594 } | 899 } |
| 595 | 900 |
| 596 | 901 |
| 597 void Assembler::bgezal(Register rs, int16_t offset) { | 902 void Assembler::bgezal(Register rs, int16_t offset) { |
| 903 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 904 positions_recorder()->WriteRecordedPositions(); | |
| 598 GenInstrImmediate(REGIMM, rs, BGEZAL, offset); | 905 GenInstrImmediate(REGIMM, rs, BGEZAL, offset); |
| 906 BlockTrampolinePoolFor(1); | |
| 599 } | 907 } |
| 600 | 908 |
| 601 | 909 |
| 602 void Assembler::bgtz(Register rs, int16_t offset) { | 910 void Assembler::bgtz(Register rs, int16_t offset) { |
| 911 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 603 GenInstrImmediate(BGTZ, rs, zero_reg, offset); | 912 GenInstrImmediate(BGTZ, rs, zero_reg, offset); |
| 913 BlockTrampolinePoolFor(1); | |
| 604 } | 914 } |
| 605 | 915 |
| 606 | 916 |
| 607 void Assembler::blez(Register rs, int16_t offset) { | 917 void Assembler::blez(Register rs, int16_t offset) { |
| 918 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 608 GenInstrImmediate(BLEZ, rs, zero_reg, offset); | 919 GenInstrImmediate(BLEZ, rs, zero_reg, offset); |
| 920 BlockTrampolinePoolFor(1); | |
| 609 } | 921 } |
| 610 | 922 |
| 611 | 923 |
| 612 void Assembler::bltz(Register rs, int16_t offset) { | 924 void Assembler::bltz(Register rs, int16_t offset) { |
| 925 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 613 GenInstrImmediate(REGIMM, rs, BLTZ, offset); | 926 GenInstrImmediate(REGIMM, rs, BLTZ, offset); |
| 927 BlockTrampolinePoolFor(1); | |
| 614 } | 928 } |
| 615 | 929 |
| 616 | 930 |
| 617 void Assembler::bltzal(Register rs, int16_t offset) { | 931 void Assembler::bltzal(Register rs, int16_t offset) { |
| 932 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 933 positions_recorder()->WriteRecordedPositions(); | |
| 618 GenInstrImmediate(REGIMM, rs, BLTZAL, offset); | 934 GenInstrImmediate(REGIMM, rs, BLTZAL, offset); |
| 935 BlockTrampolinePoolFor(1); | |
| 619 } | 936 } |
| 620 | 937 |
| 621 | 938 |
| 622 void Assembler::bne(Register rs, Register rt, int16_t offset) { | 939 void Assembler::bne(Register rs, Register rt, int16_t offset) { |
| 940 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 623 GenInstrImmediate(BNE, rs, rt, offset); | 941 GenInstrImmediate(BNE, rs, rt, offset); |
| 942 BlockTrampolinePoolFor(1); | |
| 624 } | 943 } |
| 625 | 944 |
| 626 | 945 |
| 627 void Assembler::j(int32_t target) { | 946 void Assembler::j(int32_t target) { |
| 628 ASSERT(is_uint28(target) && ((target & 3) == 0)); | 947 ASSERT(is_uint28(target) && ((target & 3) == 0)); |
| 629 GenInstrJump(J, target >> 2); | 948 GenInstrJump(J, target >> 2); |
| 630 } | 949 } |
| 631 | 950 |
| 632 | 951 |
| 633 void Assembler::jr(Register rs) { | 952 void Assembler::jr(Register rs) { |
| 953 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 954 if (rs.is(ra)) { | |
| 955 positions_recorder()->WriteRecordedPositions(); | |
| 956 } | |
| 634 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR); | 957 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR); |
| 958 BlockTrampolinePoolFor(1); | |
| 635 } | 959 } |
| 636 | 960 |
| 637 | 961 |
| 638 void Assembler::jal(int32_t target) { | 962 void Assembler::jal(int32_t target) { |
| 963 positions_recorder()->WriteRecordedPositions(); | |
| 639 ASSERT(is_uint28(target) && ((target & 3) == 0)); | 964 ASSERT(is_uint28(target) && ((target & 3) == 0)); |
| 640 GenInstrJump(JAL, target >> 2); | 965 GenInstrJump(JAL, target >> 2); |
| 641 } | 966 } |
| 642 | 967 |
| 643 | 968 |
| 644 void Assembler::jalr(Register rs, Register rd) { | 969 void Assembler::jalr(Register rs, Register rd) { |
| 970 BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 971 positions_recorder()->WriteRecordedPositions(); | |
| 645 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR); | 972 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR); |
| 973 BlockTrampolinePoolFor(1); | |
| 646 } | 974 } |
| 647 | 975 |
| 648 | 976 |
| 649 //-------Data-processing-instructions--------- | 977 //-------Data-processing-instructions--------- |
| 650 | 978 |
| 651 // Arithmetic. | 979 // Arithmetic. |
| 652 | 980 |
| 653 void Assembler::add(Register rd, Register rs, Register rt) { | |
| 654 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADD); | |
| 655 } | |
| 656 | |
| 657 | |
| 658 void Assembler::addu(Register rd, Register rs, Register rt) { | 981 void Assembler::addu(Register rd, Register rs, Register rt) { |
| 659 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU); | 982 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU); |
| 660 } | 983 } |
| 661 | 984 |
| 662 | 985 |
| 663 void Assembler::addi(Register rd, Register rs, int32_t j) { | 986 void Assembler::addiu(Register rd, Register rs, int32_t j) { |
| 664 GenInstrImmediate(ADDI, rs, rd, j); | 987 GenInstrImmediate(ADDIU, rs, rd, j); |
| 988 | |
|
Søren Thygesen Gjesse
2011/03/21 16:05:19
You should probably consider getting rid of ppep-h
Paul Lind
2011/03/23 01:55:43
I've filed an issue to remove this. I see that it
| |
| 989 // Eliminate pattern: push(r), pop() | |
| 990 // addiu(sp, sp, Operand(-kPointerSize)); | |
| 991 // sw(src, MemOperand(sp, 0); | |
| 992 // addiu(sp, sp, Operand(kPointerSize)); | |
| 993 // Both instructions can be eliminated. | |
| 994 if (can_peephole_optimize(3) && | |
| 995 // Pattern. | |
| 996 instr_at(pc_ - 1 * kInstrSize) == kPopInstruction && | |
| 997 (instr_at(pc_ - 2 * kInstrSize) & ~kRtMask) == kPushRegPattern && | |
| 998 (instr_at(pc_ - 3 * kInstrSize)) == kPushInstruction) { | |
| 999 pc_ -= 3 * kInstrSize; | |
| 1000 if (FLAG_print_peephole_optimization) { | |
| 1001 PrintF("%x push(reg)/pop() eliminated\n", pc_offset()); | |
| 1002 } | |
| 1003 } | |
| 1004 | |
| 1005 // Eliminate pattern: push(ry), pop(rx) | |
| 1006 // addiu(sp, sp, -kPointerSize) | |
| 1007 // sw(ry, MemOperand(sp, 0) | |
| 1008 // lw(rx, MemOperand(sp, 0) | |
| 1009 // addiu(sp, sp, kPointerSize); | |
| 1010 // Both instructions can be eliminated if ry = rx. | |
| 1011 // If ry != rx, a register copy from ry to rx is inserted | |
| 1012 // after eliminating the push and the pop instructions. | |
| 1013 if (can_peephole_optimize(4)) { | |
| 1014 Instr pre_push_sp_set = instr_at(pc_ - 4 * kInstrSize); | |
| 1015 Instr push_instr = instr_at(pc_ - 3 * kInstrSize); | |
| 1016 Instr pop_instr = instr_at(pc_ - 2 * kInstrSize); | |
| 1017 Instr post_pop_sp_set = instr_at(pc_ - 1 * kInstrSize); | |
| 1018 | |
| 1019 if (IsPush(push_instr) && | |
| 1020 IsPop(pop_instr) && pre_push_sp_set == kPushInstruction && | |
| 1021 post_pop_sp_set == kPopInstruction) { | |
| 1022 if ((pop_instr & kRtMask) != (push_instr & kRtMask)) { | |
| 1023 // For consecutive push and pop on different registers, | |
| 1024 // we delete both the push & pop and insert a register move. | |
| 1025 // push ry, pop rx --> mov rx, ry | |
| 1026 Register reg_pushed, reg_popped; | |
| 1027 reg_pushed = GetRt(push_instr); | |
| 1028 reg_popped = GetRt(pop_instr); | |
| 1029 pc_ -= 4 * kInstrSize; | |
| 1030 // Insert a mov instruction, which is better than a pair of push & pop | |
| 1031 or_(reg_popped, reg_pushed, zero_reg); | |
| 1032 if (FLAG_print_peephole_optimization) { | |
| 1033 PrintF("%x push/pop (diff reg) replaced by a reg move\n", | |
| 1034 pc_offset()); | |
| 1035 } | |
| 1036 } else { | |
| 1037 // For consecutive push and pop on the same register, | |
| 1038 // both the push and the pop can be deleted. | |
| 1039 pc_ -= 4 * kInstrSize; | |
| 1040 if (FLAG_print_peephole_optimization) { | |
| 1041 PrintF("%x push/pop (same reg) eliminated\n", pc_offset()); | |
| 1042 } | |
| 1043 } | |
| 1044 } | |
| 1045 } | |
| 1046 | |
| 1047 if (can_peephole_optimize(5)) { | |
| 1048 Instr pre_push_sp_set = instr_at(pc_ - 5 * kInstrSize); | |
| 1049 Instr mem_write_instr = instr_at(pc_ - 4 * kInstrSize); | |
| 1050 Instr lw_instr = instr_at(pc_ - 3 * kInstrSize); | |
| 1051 Instr mem_read_instr = instr_at(pc_ - 2 * kInstrSize); | |
| 1052 Instr post_pop_sp_set = instr_at(pc_ - 1 * kInstrSize); | |
| 1053 | |
| 1054 if (IsPush(mem_write_instr) && | |
| 1055 pre_push_sp_set == kPushInstruction && | |
| 1056 IsPop(mem_read_instr) && | |
| 1057 post_pop_sp_set == kPopInstruction) { | |
| 1058 if ((IsLwRegFpOffset(lw_instr) || | |
| 1059 IsLwRegFpNegOffset(lw_instr))) { | |
| 1060 if ((mem_write_instr & kRtMask) == | |
| 1061 (mem_read_instr & kRtMask)) { | |
| 1062 // Pattern: push & pop from/to same register, | |
| 1063 // with a fp+offset lw in between | |
| 1064 // | |
| 1065 // The following: | |
| 1066 // addiu sp, sp, -4 | |
| 1067 // sw rx, [sp, #0]! | |
| 1068 // lw rz, [fp, #-24] | |
| 1069 // lw rx, [sp, 0], | |
| 1070 // addiu sp, sp, 4 | |
| 1071 // | |
| 1072 // Becomes: | |
| 1073 // if(rx == rz) | |
| 1074 // delete all | |
| 1075 // else | |
| 1076 // lw rz, [fp, #-24] | |
| 1077 | |
| 1078 if ((mem_write_instr & kRtMask) == (lw_instr & kRtMask)) { | |
| 1079 pc_ -= 5 * kInstrSize; | |
| 1080 } else { | |
| 1081 pc_ -= 5 * kInstrSize; | |
| 1082 // Reinsert back the lw rz. | |
| 1083 emit(lw_instr); | |
| 1084 } | |
| 1085 if (FLAG_print_peephole_optimization) { | |
| 1086 PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset()); | |
| 1087 } | |
| 1088 } else { | |
| 1089 // Pattern: push & pop from/to different registers | |
| 1090 // with a fp+offset lw in between | |
| 1091 // | |
| 1092 // The following: | |
| 1093 // addiu sp, sp ,-4 | |
| 1094 // sw rx, [sp, 0] | |
| 1095 // lw rz, [fp, #-24] | |
| 1096 // lw ry, [sp, 0] | |
| 1097 // addiu sp, sp, 4 | |
| 1098 // | |
| 1099 // Becomes: | |
| 1100 // if(ry == rz) | |
| 1101 // mov ry, rx; | |
| 1102 // else if(rx != rz) | |
| 1103 // lw rz, [fp, #-24] | |
| 1104 // mov ry, rx | |
| 1105 // else if((ry != rz) || (rx == rz)) becomes: | |
| 1106 // mov ry, rx | |
| 1107 // lw rz, [fp, #-24] | |
| 1108 | |
| 1109 Register reg_pushed, reg_popped; | |
| 1110 if ((mem_read_instr & kRtMask) == (lw_instr & kRtMask)) { | |
| 1111 reg_pushed = GetRt(mem_write_instr); | |
| 1112 reg_popped = GetRt(mem_read_instr); | |
| 1113 pc_ -= 5 * kInstrSize; | |
| 1114 or_(reg_popped, reg_pushed, zero_reg); // move instruction; | |
| 1115 } else if ((mem_write_instr & kRtMask) | |
| 1116 != (lw_instr & kRtMask)) { | |
| 1117 reg_pushed = GetRt(mem_write_instr); | |
| 1118 reg_popped = GetRt(mem_read_instr); | |
| 1119 pc_ -= 5 * kInstrSize; | |
| 1120 emit(lw_instr); | |
| 1121 or_(reg_popped, reg_pushed, zero_reg); // move instruction | |
| 1122 } else if (((mem_read_instr & kRtMask) | |
| 1123 != (lw_instr & kRtMask)) || | |
| 1124 ((mem_write_instr & kRtMask) | |
| 1125 == (lw_instr & kRtMask)) ) { | |
| 1126 reg_pushed = GetRt(mem_write_instr); | |
| 1127 reg_popped = GetRt(mem_read_instr); | |
| 1128 pc_ -= 5 * kInstrSize; | |
| 1129 or_(reg_popped, reg_pushed, zero_reg); // move instruction | |
| 1130 emit(lw_instr); | |
| 1131 } | |
| 1132 if (FLAG_print_peephole_optimization) { | |
| 1133 PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset()); | |
| 1134 } | |
| 1135 } | |
| 1136 } | |
| 1137 } | |
| 1138 } | |
| 665 } | 1139 } |
| 666 | 1140 |
| 667 | 1141 |
| 668 void Assembler::addiu(Register rd, Register rs, int32_t j) { | |
| 669 GenInstrImmediate(ADDIU, rs, rd, j); | |
| 670 } | |
| 671 | |
| 672 | |
| 673 void Assembler::sub(Register rd, Register rs, Register rt) { | |
| 674 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUB); | |
| 675 } | |
| 676 | |
| 677 | |
| 678 void Assembler::subu(Register rd, Register rs, Register rt) { | 1142 void Assembler::subu(Register rd, Register rs, Register rt) { |
| 679 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU); | 1143 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU); |
| 680 } | 1144 } |
| 681 | 1145 |
| 682 | 1146 |
| 683 void Assembler::mul(Register rd, Register rs, Register rt) { | 1147 void Assembler::mul(Register rd, Register rs, Register rt) { |
| 684 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL); | 1148 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL); |
| 685 } | 1149 } |
| 686 | 1150 |
| 687 | 1151 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 736 GenInstrImmediate(XORI, rs, rt, j); | 1200 GenInstrImmediate(XORI, rs, rt, j); |
| 737 } | 1201 } |
| 738 | 1202 |
| 739 | 1203 |
| 740 void Assembler::nor(Register rd, Register rs, Register rt) { | 1204 void Assembler::nor(Register rd, Register rs, Register rt) { |
| 741 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR); | 1205 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR); |
| 742 } | 1206 } |
| 743 | 1207 |
| 744 | 1208 |
| 745 // Shifts. | 1209 // Shifts. |
| 746 void Assembler::sll(Register rd, Register rt, uint16_t sa) { | 1210 void Assembler::sll(Register rd, |
| 1211 Register rt, | |
| 1212 uint16_t sa, | |
| 1213 bool coming_from_nop) { | |
| 1214 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be | |
| 1215 // generated using the sll instruction. They must be generated using | |
| 1216 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo | |
| 1217 // instructions. | |
| 1218 ASSERT(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg))); | |
| 747 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL); | 1219 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL); |
| 748 } | 1220 } |
| 749 | 1221 |
| 750 | 1222 |
| 751 void Assembler::sllv(Register rd, Register rt, Register rs) { | 1223 void Assembler::sllv(Register rd, Register rt, Register rs) { |
| 752 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV); | 1224 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV); |
| 753 } | 1225 } |
| 754 | 1226 |
| 755 | 1227 |
| 756 void Assembler::srl(Register rd, Register rt, uint16_t sa) { | 1228 void Assembler::srl(Register rd, Register rt, uint16_t sa) { |
| 757 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL); | 1229 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL); |
| 758 } | 1230 } |
| 759 | 1231 |
| 760 | 1232 |
| 761 void Assembler::srlv(Register rd, Register rt, Register rs) { | 1233 void Assembler::srlv(Register rd, Register rt, Register rs) { |
| 762 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV); | 1234 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV); |
| 763 } | 1235 } |
| 764 | 1236 |
| 765 | 1237 |
| 766 void Assembler::sra(Register rd, Register rt, uint16_t sa) { | 1238 void Assembler::sra(Register rd, Register rt, uint16_t sa) { |
| 767 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA); | 1239 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA); |
| 768 } | 1240 } |
| 769 | 1241 |
| 770 | 1242 |
| 771 void Assembler::srav(Register rd, Register rt, Register rs) { | 1243 void Assembler::srav(Register rd, Register rt, Register rs) { |
| 772 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV); | 1244 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV); |
| 773 } | 1245 } |
| 774 | 1246 |
| 775 | 1247 |
| 1248 void Assembler::rotr(Register rd, Register rt, uint16_t sa) { | |
| 1249 ASSERT(rd.is_valid() && rt.is_valid() && is_uint5(sa)); | |
| 1250 if (mips32r2) { | |
| 1251 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift) | |
| 1252 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL; | |
| 1253 emit(instr); | |
| 1254 } else { | |
| 1255 // Just in case. You should generally use this through MacroAssembler::Ror. | |
| 1256 UNIMPLEMENTED_MIPS(); | |
| 1257 } | |
| 1258 } | |
| 1259 | |
| 1260 | |
| 1261 void Assembler::rotrv(Register rd, Register rt, Register rs) { | |
| 1262 ASSERT(rd.is_valid() && rt.is_valid() && rs.is_valid() ); | |
| 1263 if (mips32r2) { | |
| 1264 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift) | |
| 1265 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV; | |
| 1266 emit(instr); | |
| 1267 } else { | |
| 1268 // Just in case. You should generally use this through MacroAssembler::Ror. | |
| 1269 UNIMPLEMENTED_MIPS(); | |
| 1270 } | |
| 1271 } | |
| 1272 | |
| 1273 | |
| 776 //------------Memory-instructions------------- | 1274 //------------Memory-instructions------------- |
| 777 | 1275 |
| 778 void Assembler::lb(Register rd, const MemOperand& rs) { | 1276 void Assembler::lb(Register rd, const MemOperand& rs) { |
| 779 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_); | 1277 if (is_int16(rs.offset_)) { |
| 1278 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_); | |
| 1279 } else { // Offset > 16 bits, use multiple instructions to load. | |
| 1280 ASSERT(!rs.rm().is(at)); | |
| 1281 lui(at, rs.offset_ >> 16); | |
| 1282 ori(at, at, rs.offset_ & 0xffff); | |
| 1283 addu(at, at, rs.rm()); | |
| 1284 GenInstrImmediate(LB, at, rd, 0); // Equiv to lb(rd, MemOperand(at, 0)); | |
| 1285 } | |
| 780 } | 1286 } |
| 781 | 1287 |
| 782 | 1288 |
| 783 void Assembler::lbu(Register rd, const MemOperand& rs) { | 1289 void Assembler::lbu(Register rd, const MemOperand& rs) { |
| 784 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_); | 1290 if (is_int16(rs.offset_)) { |
| 1291 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_); | |
| 1292 } else { // Offset > 16 bits, use multiple instructions to load. | |
| 1293 ASSERT(!rs.rm().is(at)); | |
| 1294 lui(at, rs.offset_ >> 16); | |
| 1295 ori(at, at, rs.offset_ & 0xffff); | |
| 1296 addu(at, at, rs.rm()); | |
| 1297 GenInstrImmediate(LBU, at, rd, 0); // Equiv to lbu(rd, MemOperand(at, 0)); | |
| 1298 } | |
| 1299 } | |
| 1300 | |
| 1301 | |
| 1302 void Assembler::lh(Register rd, const MemOperand& rs) { | |
| 1303 if (is_int16(rs.offset_)) { | |
| 1304 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_); | |
| 1305 } else { // Offset > 16 bits, use multiple instructions to load. | |
| 1306 ASSERT(!rs.rm().is(at)); | |
| 1307 lui(at, rs.offset_ >> 16); | |
| 1308 ori(at, at, rs.offset_ & 0xffff); | |
| 1309 addu(at, at, rs.rm()); | |
| 1310 GenInstrImmediate(LH, at, rd, 0); // Equiv to lh(rd, MemOperand(at, 0)); | |
| 1311 } | |
| 1312 } | |
| 1313 | |
| 1314 | |
| 1315 void Assembler::lhu(Register rd, const MemOperand& rs) { | |
| 1316 if (is_int16(rs.offset_)) { | |
| 1317 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_); | |
| 1318 } else { // Offset > 16 bits, use multiple instructions to load. | |
| 1319 ASSERT(!rs.rm().is(at)); | |
| 1320 lui(at, rs.offset_ >> 16); | |
| 1321 ori(at, at, rs.offset_ & 0xffff); | |
| 1322 addu(at, at, rs.rm()); | |
| 1323 GenInstrImmediate(LHU, at, rd, 0); // Equiv to lhu(rd, MemOperand(at, 0)); | |
| 1324 } | |
| 785 } | 1325 } |
| 786 | 1326 |
| 787 | 1327 |
| 788 void Assembler::lw(Register rd, const MemOperand& rs) { | 1328 void Assembler::lw(Register rd, const MemOperand& rs) { |
| 789 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_); | 1329 if (is_int16(rs.offset_)) { |
| 1330 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_); | |
| 1331 } else { // Offset > 16 bits, use multiple instructions to load. | |
| 1332 ASSERT(!rs.rm().is(at)); | |
| 1333 lui(at, rs.offset_ >> 16); | |
| 1334 ori(at, at, rs.offset_ & 0xffff); | |
| 1335 addu(at, at, rs.rm()); | |
| 1336 GenInstrImmediate(LW, at, rd, 0); // Equiv to lw(rd, MemOperand(at, 0)); | |
| 1337 } | |
| 1338 | |
| 1339 if (can_peephole_optimize(2)) { | |
| 1340 Instr sw_instr = instr_at(pc_ - 2 * kInstrSize); | |
| 1341 Instr lw_instr = instr_at(pc_ - 1 * kInstrSize); | |
| 1342 | |
| 1343 if ((IsSwRegFpOffset(sw_instr) && | |
| 1344 IsLwRegFpOffset(lw_instr)) || | |
| 1345 (IsSwRegFpNegOffset(sw_instr) && | |
| 1346 IsLwRegFpNegOffset(lw_instr))) { | |
| 1347 if ((lw_instr & kLwSwInstrArgumentMask) == | |
| 1348 (sw_instr & kLwSwInstrArgumentMask)) { | |
| 1349 // Pattern: Lw/sw same fp+offset, same register. | |
| 1350 // | |
| 1351 // The following: | |
| 1352 // sw rx, [fp, #-12] | |
| 1353 // lw rx, [fp, #-12] | |
| 1354 // | |
| 1355 // Becomes: | |
| 1356 // sw rx, [fp, #-12] | |
| 1357 | |
| 1358 pc_ -= 1 * kInstrSize; | |
| 1359 if (FLAG_print_peephole_optimization) { | |
| 1360 PrintF("%x sw/lw (fp + same offset), same reg\n", pc_offset()); | |
| 1361 } | |
| 1362 } else if ((lw_instr & kLwSwOffsetMask) == | |
| 1363 (sw_instr & kLwSwOffsetMask)) { | |
| 1364 // Pattern: Lw/sw same fp+offset, different register. | |
| 1365 // | |
| 1366 // The following: | |
| 1367 // sw rx, [fp, #-12] | |
| 1368 // lw ry, [fp, #-12] | |
| 1369 // | |
| 1370 // Becomes: | |
| 1371 // sw rx, [fp, #-12] | |
| 1372 // mov ry, rx | |
| 1373 | |
| 1374 Register reg_stored, reg_loaded; | |
| 1375 reg_stored = GetRt(sw_instr); | |
| 1376 reg_loaded = GetRt(lw_instr); | |
| 1377 pc_ -= 1 * kInstrSize; | |
| 1378 // Insert a mov instruction, which is better than lw. | |
| 1379 or_(reg_loaded, reg_stored, zero_reg); // move instruction. | |
| 1380 if (FLAG_print_peephole_optimization) { | |
| 1381 PrintF("%x sw/lw (fp + same offset), diff reg \n", pc_offset()); | |
| 1382 } | |
| 1383 } | |
| 1384 } | |
| 1385 } | |
| 1386 } | |
| 1387 | |
| 1388 | |
| 1389 void Assembler::lwl(Register rd, const MemOperand& rs) { | |
| 1390 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_); | |
| 1391 } | |
| 1392 | |
| 1393 | |
| 1394 void Assembler::lwr(Register rd, const MemOperand& rs) { | |
| 1395 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_); | |
| 790 } | 1396 } |
| 791 | 1397 |
| 792 | 1398 |
| 793 void Assembler::sb(Register rd, const MemOperand& rs) { | 1399 void Assembler::sb(Register rd, const MemOperand& rs) { |
| 794 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_); | 1400 if (is_int16(rs.offset_)) { |
| 1401 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_); | |
| 1402 } else { // Offset > 16 bits, use multiple instructions to store. | |
| 1403 ASSERT(!rs.rm().is(at)); | |
| 1404 lui(at, rs.offset_ >> 16); | |
| 1405 ori(at, at, rs.offset_ & 0xffff); | |
| 1406 addu(at, at, rs.rm()); | |
| 1407 GenInstrImmediate(SB, at, rd, 0); // Equiv to sb(rd, MemOperand(at, 0)); | |
| 1408 } | |
| 1409 } | |
| 1410 | |
| 1411 | |
| 1412 void Assembler::sh(Register rd, const MemOperand& rs) { | |
| 1413 if (is_int16(rs.offset_)) { | |
| 1414 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_); | |
| 1415 } else { // Offset > 16 bits, use multiple instructions to store. | |
| 1416 ASSERT(!rs.rm().is(at)); | |
| 1417 lui(at, rs.offset_ >> 16); | |
| 1418 ori(at, at, rs.offset_ & 0xffff); | |
| 1419 addu(at, at, rs.rm()); | |
| 1420 GenInstrImmediate(SH, at, rd, 0); // Equiv to sh(rd, MemOperand(at, 0)); | |
| 1421 } | |
| 795 } | 1422 } |
| 796 | 1423 |
| 797 | 1424 |
| 798 void Assembler::sw(Register rd, const MemOperand& rs) { | 1425 void Assembler::sw(Register rd, const MemOperand& rs) { |
| 799 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_); | 1426 if (is_int16(rs.offset_)) { |
| 800 } | 1427 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_); |
| 801 | 1428 } else { // Offset > 16 bits, use multiple instructions to store. |
| 802 | 1429 ASSERT(!rs.rm().is(at)); |
| 1430 lui(at, rs.offset_ >> 16); | |
| 1431 ori(at, at, rs.offset_ & 0xffff); | |
| 1432 addu(at, at, rs.rm()); | |
| 1433 GenInstrImmediate(SW, at, rd, 0); // Equiv to sw(rd, MemOperand(at, 0)); | |
| 1434 } | |
| 1435 | |
| 1436 // Eliminate pattern: pop(), push(r) | |
| 1437 // addiu sp, sp, Operand(kPointerSize); | |
| 1438 // addiu sp, sp, Operand(-kPointerSize); | |
| 1439 // -> sw r, MemOpernad(sp, 0); | |
| 1440 if (can_peephole_optimize(3) && | |
| 1441 // Pattern. | |
| 1442 instr_at(pc_ - 1 * kInstrSize) == | |
| 1443 (kPushRegPattern | (rd.code() << kRtShift)) && | |
| 1444 instr_at(pc_ - 2 * kInstrSize) == kPushInstruction && | |
| 1445 instr_at(pc_ - 3 * kInstrSize) == kPopInstruction) { | |
| 1446 pc_ -= 3 * kInstrSize; | |
| 1447 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_); | |
| 1448 if (FLAG_print_peephole_optimization) { | |
| 1449 PrintF("%x pop()/push(reg) eliminated\n", pc_offset()); | |
| 1450 } | |
| 1451 } | |
| 1452 } | |
| 1453 | |
| 1454 | |
| 1455 void Assembler::swl(Register rd, const MemOperand& rs) { | |
| 1456 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_); | |
| 1457 } | |
| 1458 | |
| 1459 | |
| 1460 void Assembler::swr(Register rd, const MemOperand& rs) { | |
| 1461 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_); | |
| 1462 } | |
| 1463 | |
| 1464 | |
| 803 void Assembler::lui(Register rd, int32_t j) { | 1465 void Assembler::lui(Register rd, int32_t j) { |
| 804 GenInstrImmediate(LUI, zero_reg, rd, j); | 1466 GenInstrImmediate(LUI, zero_reg, rd, j); |
| 805 } | 1467 } |
| 806 | 1468 |
| 807 | 1469 |
| 808 //-------------Misc-instructions-------------- | 1470 //-------------Misc-instructions-------------- |
| 809 | 1471 |
| 810 // Break / Trap instructions. | 1472 // Break / Trap instructions. |
| 811 void Assembler::break_(uint32_t code) { | 1473 void Assembler::break_(uint32_t code) { |
| 812 ASSERT((code & ~0xfffff) == 0); | 1474 ASSERT((code & ~0xfffff) == 0); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 889 void Assembler::slti(Register rt, Register rs, int32_t j) { | 1551 void Assembler::slti(Register rt, Register rs, int32_t j) { |
| 890 GenInstrImmediate(SLTI, rs, rt, j); | 1552 GenInstrImmediate(SLTI, rs, rt, j); |
| 891 } | 1553 } |
| 892 | 1554 |
| 893 | 1555 |
| 894 void Assembler::sltiu(Register rt, Register rs, int32_t j) { | 1556 void Assembler::sltiu(Register rt, Register rs, int32_t j) { |
| 895 GenInstrImmediate(SLTIU, rs, rt, j); | 1557 GenInstrImmediate(SLTIU, rs, rt, j); |
| 896 } | 1558 } |
| 897 | 1559 |
| 898 | 1560 |
| 1561 // Conditional move. | |
| 1562 void Assembler::movz(Register rd, Register rs, Register rt) { | |
| 1563 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ); | |
| 1564 } | |
| 1565 | |
| 1566 | |
| 1567 void Assembler::movn(Register rd, Register rs, Register rt) { | |
| 1568 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN); | |
| 1569 } | |
| 1570 | |
| 1571 | |
| 1572 void Assembler::movt(Register rd, Register rs, uint16_t cc) { | |
| 1573 Register rt; | |
| 1574 rt.code_ = (cc & 0x0003)<<2 | 1; | |
| 1575 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI); | |
| 1576 } | |
| 1577 | |
| 1578 | |
| 1579 void Assembler::movf(Register rd, Register rs, uint16_t cc) { | |
| 1580 Register rt; | |
| 1581 rt.code_ = (cc & 0x0003)<<2 | 0; | |
| 1582 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI); | |
| 1583 } | |
| 1584 | |
| 1585 | |
| 1586 // Bit twiddling. | |
| 1587 void Assembler::clz(Register rd, Register rs) { | |
| 1588 // Clz instr requires same GPR number in 'rd' and 'rt' fields. | |
| 1589 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ); | |
| 1590 } | |
| 1591 | |
| 1592 | |
| 1593 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) { | |
| 1594 if (mips32r2) { | |
| 1595 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb | |
| 1596 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS); | |
| 1597 } else { | |
| 1598 // Just in case. This instruction should | |
| 1599 // be called through MacroAssembler::Ins. | |
| 1600 UNIMPLEMENTED_MIPS(); | |
| 1601 } | |
| 1602 } | |
| 1603 | |
| 1604 | |
| 1605 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) { | |
| 1606 if (mips32r2) { | |
| 1607 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb. | |
| 1608 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT); | |
| 1609 } else { | |
| 1610 // Just in case. This instruction should | |
| 1611 // be called through MacroAssembler::Ext. | |
| 1612 UNIMPLEMENTED_MIPS(); | |
| 1613 } | |
| 1614 } | |
| 1615 | |
| 1616 | |
| 899 //--------Coprocessor-instructions---------------- | 1617 //--------Coprocessor-instructions---------------- |
| 900 | 1618 |
| 901 // Load, store, move. | 1619 // Load, store, move. |
| 902 void Assembler::lwc1(FPURegister fd, const MemOperand& src) { | 1620 void Assembler::lwc1(FPURegister fd, const MemOperand& src) { |
| 903 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_); | 1621 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_); |
| 904 } | 1622 } |
| 905 | 1623 |
| 906 | 1624 |
| 907 void Assembler::ldc1(FPURegister fd, const MemOperand& src) { | 1625 void Assembler::ldc1(FPURegister fd, const MemOperand& src) { |
| 908 GenInstrImmediate(LDC1, src.rm(), fd, src.offset_); | 1626 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit |
| 1627 // load to two 32-bit loads. | |
| 1628 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_); | |
| 1629 FPURegister nextfpreg; | |
| 1630 nextfpreg.setcode(fd.code() + 1); | |
| 1631 GenInstrImmediate(LWC1, src.rm(), nextfpreg, src.offset_ + 4); | |
| 909 } | 1632 } |
| 910 | 1633 |
| 911 | 1634 |
| 912 void Assembler::swc1(FPURegister fd, const MemOperand& src) { | 1635 void Assembler::swc1(FPURegister fd, const MemOperand& src) { |
| 913 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_); | 1636 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_); |
| 914 } | 1637 } |
| 915 | 1638 |
| 916 | 1639 |
| 917 void Assembler::sdc1(FPURegister fd, const MemOperand& src) { | 1640 void Assembler::sdc1(FPURegister fd, const MemOperand& src) { |
| 918 GenInstrImmediate(SDC1, src.rm(), fd, src.offset_); | 1641 // Workaround for non-8-byte alignment of HeapNumber, convert 64-bit |
| 1642 // store to two 32-bit stores. | |
| 1643 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_); | |
| 1644 FPURegister nextfpreg; | |
| 1645 nextfpreg.setcode(fd.code() + 1); | |
| 1646 GenInstrImmediate(SWC1, src.rm(), nextfpreg, src.offset_ + 4); | |
| 919 } | 1647 } |
| 920 | 1648 |
| 921 | 1649 |
| 922 void Assembler::mtc1(FPURegister fs, Register rt) { | 1650 void Assembler::mtc1(Register rt, FPURegister fs) { |
| 923 GenInstrRegister(COP1, MTC1, rt, fs, f0); | 1651 GenInstrRegister(COP1, MTC1, rt, fs, f0); |
| 924 } | 1652 } |
| 925 | 1653 |
| 926 | 1654 |
| 927 void Assembler::mthc1(FPURegister fs, Register rt) { | 1655 void Assembler::mfc1(Register rt, FPURegister fs) { |
| 928 GenInstrRegister(COP1, MTHC1, rt, fs, f0); | |
| 929 } | |
| 930 | |
| 931 | |
| 932 void Assembler::mfc1(FPURegister fs, Register rt) { | |
| 933 GenInstrRegister(COP1, MFC1, rt, fs, f0); | 1656 GenInstrRegister(COP1, MFC1, rt, fs, f0); |
| 934 } | 1657 } |
| 935 | 1658 |
| 936 | 1659 |
| 937 void Assembler::mfhc1(FPURegister fs, Register rt) { | 1660 void Assembler::ctc1(Register rt, FPUControlRegister fs) { |
| 938 GenInstrRegister(COP1, MFHC1, rt, fs, f0); | 1661 GenInstrRegister(COP1, CTC1, rt, fs); |
| 939 } | 1662 } |
| 940 | 1663 |
| 941 | 1664 |
| 1665 void Assembler::cfc1(Register rt, FPUControlRegister fs) { | |
| 1666 GenInstrRegister(COP1, CFC1, rt, fs); | |
| 1667 } | |
| 1668 | |
| 1669 | |
| 1670 // Arithmetic. | |
| 1671 | |
| 1672 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) { | |
| 1673 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D); | |
| 1674 } | |
| 1675 | |
| 1676 | |
| 1677 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) { | |
| 1678 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D); | |
| 1679 } | |
| 1680 | |
| 1681 | |
| 1682 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) { | |
| 1683 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D); | |
| 1684 } | |
| 1685 | |
| 1686 | |
| 1687 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) { | |
| 1688 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D); | |
| 1689 } | |
| 1690 | |
| 1691 | |
| 1692 void Assembler::abs_d(FPURegister fd, FPURegister fs) { | |
| 1693 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D); | |
| 1694 } | |
| 1695 | |
| 1696 | |
| 1697 void Assembler::mov_d(FPURegister fd, FPURegister fs) { | |
| 1698 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D); | |
| 1699 } | |
| 1700 | |
| 1701 | |
| 1702 void Assembler::neg_d(FPURegister fd, FPURegister fs) { | |
| 1703 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D); | |
| 1704 } | |
| 1705 | |
| 1706 | |
| 1707 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) { | |
| 1708 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D); | |
| 1709 } | |
| 1710 | |
| 1711 | |
| 942 // Conversions. | 1712 // Conversions. |
| 943 | 1713 |
| 944 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) { | 1714 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) { |
| 945 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S); | 1715 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S); |
| 946 } | 1716 } |
| 947 | 1717 |
| 948 | 1718 |
| 949 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) { | 1719 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) { |
| 950 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D); | 1720 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D); |
| 951 } | 1721 } |
| 952 | 1722 |
| 953 | 1723 |
| 1724 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) { | |
| 1725 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S); | |
| 1726 } | |
| 1727 | |
| 1728 | |
| 1729 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) { | |
| 1730 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D); | |
| 1731 } | |
| 1732 | |
| 1733 | |
| 1734 void Assembler::round_w_s(FPURegister fd, FPURegister fs) { | |
| 1735 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S); | |
| 1736 } | |
| 1737 | |
| 1738 | |
| 1739 void Assembler::round_w_d(FPURegister fd, FPURegister fs) { | |
| 1740 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D); | |
| 1741 } | |
| 1742 | |
| 1743 | |
| 1744 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) { | |
| 1745 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S); | |
| 1746 } | |
| 1747 | |
| 1748 | |
| 1749 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) { | |
| 1750 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D); | |
| 1751 } | |
| 1752 | |
| 1753 | |
| 1754 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) { | |
| 1755 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S); | |
| 1756 } | |
| 1757 | |
| 1758 | |
| 1759 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) { | |
| 1760 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D); | |
| 1761 } | |
| 1762 | |
| 1763 | |
| 954 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) { | 1764 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) { |
| 955 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S); | 1765 if (mips32r2) { |
| 1766 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S); | |
| 1767 } else { | |
|
Søren Thygesen Gjesse
2011/03/21 16:05:19
Instead of UNIMPLEMENTED_MIPS() this should probab
Paul Lind
2011/03/23 01:55:43
Done.
| |
| 1768 UNIMPLEMENTED_MIPS(); | |
| 1769 } | |
| 956 } | 1770 } |
| 957 | 1771 |
| 958 | 1772 |
| 959 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) { | 1773 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) { |
| 960 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D); | 1774 if (mips32r2) { |
| 1775 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D); | |
| 1776 } else { | |
| 1777 UNIMPLEMENTED_MIPS(); | |
| 1778 } | |
| 961 } | 1779 } |
| 962 | 1780 |
| 963 | 1781 |
| 1782 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) { | |
| 1783 if (mips32r2) { | |
| 1784 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S); | |
| 1785 } else { | |
| 1786 UNIMPLEMENTED_MIPS(); | |
| 1787 } | |
| 1788 } | |
| 1789 | |
| 1790 | |
| 1791 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) { | |
| 1792 if (mips32r2) { | |
| 1793 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D); | |
| 1794 } else { | |
| 1795 UNIMPLEMENTED_MIPS(); | |
| 1796 } | |
| 1797 } | |
| 1798 | |
| 1799 | |
| 1800 void Assembler::round_l_s(FPURegister fd, FPURegister fs) { | |
| 1801 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S); | |
| 1802 } | |
| 1803 | |
| 1804 | |
| 1805 void Assembler::round_l_d(FPURegister fd, FPURegister fs) { | |
| 1806 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D); | |
| 1807 } | |
| 1808 | |
| 1809 | |
| 1810 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) { | |
| 1811 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S); | |
| 1812 } | |
| 1813 | |
| 1814 | |
| 1815 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) { | |
| 1816 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D); | |
| 1817 } | |
| 1818 | |
| 1819 | |
| 1820 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) { | |
| 1821 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S); | |
| 1822 } | |
| 1823 | |
| 1824 | |
| 1825 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) { | |
| 1826 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D); | |
| 1827 } | |
| 1828 | |
| 1829 | |
| 964 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) { | 1830 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) { |
| 965 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W); | 1831 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W); |
| 966 } | 1832 } |
| 967 | 1833 |
| 968 | 1834 |
| 969 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) { | 1835 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) { |
| 970 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L); | 1836 if (mips32r2) { |
| 1837 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L); | |
| 1838 } else { | |
| 1839 UNIMPLEMENTED_MIPS(); | |
| 1840 } | |
| 971 } | 1841 } |
| 972 | 1842 |
| 973 | 1843 |
| 974 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) { | 1844 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) { |
| 975 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D); | 1845 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D); |
| 976 } | 1846 } |
| 977 | 1847 |
| 978 | 1848 |
| 979 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) { | 1849 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) { |
| 980 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W); | 1850 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W); |
| 981 } | 1851 } |
| 982 | 1852 |
| 983 | 1853 |
| 984 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) { | 1854 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) { |
| 985 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L); | 1855 if (mips32r2) { |
| 1856 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L); | |
| 1857 } else { | |
| 1858 UNIMPLEMENTED_MIPS(); | |
| 1859 } | |
| 986 } | 1860 } |
| 987 | 1861 |
| 988 | 1862 |
| 989 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) { | 1863 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) { |
| 990 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S); | 1864 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S); |
| 991 } | 1865 } |
| 992 | 1866 |
| 993 | 1867 |
| 994 // Conditions. | 1868 // Conditions. |
| 995 void Assembler::c(FPUCondition cond, SecondaryField fmt, | 1869 void Assembler::c(FPUCondition cond, SecondaryField fmt, |
| 996 FPURegister ft, FPURegister fs, uint16_t cc) { | 1870 FPURegister fs, FPURegister ft, uint16_t cc) { |
| 997 ASSERT(is_uint3(cc)); | 1871 ASSERT(is_uint3(cc)); |
| 998 ASSERT((fmt & ~(31 << kRsShift)) == 0); | 1872 ASSERT((fmt & ~(31 << kRsShift)) == 0); |
| 999 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift | 1873 Instr instr = COP1 | fmt | ft.code() << 16 | fs.code() << kFsShift |
| 1000 | cc << 8 | 3 << 4 | cond; | 1874 | cc << 8 | 3 << 4 | cond; |
| 1001 emit(instr); | 1875 emit(instr); |
| 1002 } | 1876 } |
| 1003 | 1877 |
| 1004 | 1878 |
| 1879 void Assembler::fcmp(FPURegister src1, const double src2, | |
| 1880 FPUCondition cond) { | |
| 1881 ASSERT(CpuFeatures::IsSupported(FPU)); | |
| 1882 ASSERT(src2 == 0.0); | |
| 1883 mtc1(zero_reg, f14); | |
| 1884 cvt_d_w(f14, f14); | |
| 1885 c(cond, D, src1, f14, 0); | |
| 1886 } | |
| 1887 | |
| 1888 | |
| 1005 void Assembler::bc1f(int16_t offset, uint16_t cc) { | 1889 void Assembler::bc1f(int16_t offset, uint16_t cc) { |
| 1006 ASSERT(is_uint3(cc)); | 1890 ASSERT(is_uint3(cc)); |
| 1007 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask); | 1891 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask); |
| 1008 emit(instr); | 1892 emit(instr); |
| 1009 } | 1893 } |
| 1010 | 1894 |
| 1011 | 1895 |
| 1012 void Assembler::bc1t(int16_t offset, uint16_t cc) { | 1896 void Assembler::bc1t(int16_t offset, uint16_t cc) { |
| 1013 ASSERT(is_uint3(cc)); | 1897 ASSERT(is_uint3(cc)); |
| 1014 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask); | 1898 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask); |
| 1015 emit(instr); | 1899 emit(instr); |
| 1016 } | 1900 } |
| 1017 | 1901 |
| 1018 | 1902 |
| 1019 // Debugging. | 1903 // Debugging. |
| 1020 void Assembler::RecordJSReturn() { | 1904 void Assembler::RecordJSReturn() { |
| 1021 WriteRecordedPositions(); | 1905 positions_recorder()->WriteRecordedPositions(); |
| 1022 CheckBuffer(); | 1906 CheckBuffer(); |
| 1023 RecordRelocInfo(RelocInfo::JS_RETURN); | 1907 RecordRelocInfo(RelocInfo::JS_RETURN); |
| 1024 } | 1908 } |
| 1025 | 1909 |
| 1026 | 1910 |
| 1911 void Assembler::RecordDebugBreakSlot() { | |
| 1912 positions_recorder()->WriteRecordedPositions(); | |
| 1913 CheckBuffer(); | |
| 1914 RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT); | |
| 1915 } | |
| 1916 | |
| 1917 | |
| 1027 void Assembler::RecordComment(const char* msg) { | 1918 void Assembler::RecordComment(const char* msg) { |
| 1028 if (FLAG_debug_code) { | 1919 if (FLAG_code_comments) { |
| 1029 CheckBuffer(); | 1920 CheckBuffer(); |
| 1030 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); | 1921 RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg)); |
| 1031 } | 1922 } |
| 1032 } | 1923 } |
| 1033 | 1924 |
| 1034 | 1925 |
| 1035 void Assembler::RecordPosition(int pos) { | |
| 1036 if (pos == RelocInfo::kNoPosition) return; | |
| 1037 ASSERT(pos >= 0); | |
| 1038 current_position_ = pos; | |
| 1039 } | |
| 1040 | |
| 1041 | |
| 1042 void Assembler::RecordStatementPosition(int pos) { | |
| 1043 if (pos == RelocInfo::kNoPosition) return; | |
| 1044 ASSERT(pos >= 0); | |
| 1045 current_statement_position_ = pos; | |
| 1046 } | |
| 1047 | |
| 1048 | |
| 1049 bool Assembler::WriteRecordedPositions() { | |
| 1050 bool written = false; | |
| 1051 | |
| 1052 // Write the statement position if it is different from what was written last | |
| 1053 // time. | |
| 1054 if (current_statement_position_ != written_statement_position_) { | |
| 1055 CheckBuffer(); | |
| 1056 RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_); | |
| 1057 written_statement_position_ = current_statement_position_; | |
| 1058 written = true; | |
| 1059 } | |
| 1060 | |
| 1061 // Write the position if it is different from what was written last time and | |
| 1062 // also different from the written statement position. | |
| 1063 if (current_position_ != written_position_ && | |
| 1064 current_position_ != written_statement_position_) { | |
| 1065 CheckBuffer(); | |
| 1066 RecordRelocInfo(RelocInfo::POSITION, current_position_); | |
| 1067 written_position_ = current_position_; | |
| 1068 written = true; | |
| 1069 } | |
| 1070 | |
| 1071 // Return whether something was written. | |
| 1072 return written; | |
| 1073 } | |
| 1074 | |
| 1075 | |
| 1076 void Assembler::GrowBuffer() { | 1926 void Assembler::GrowBuffer() { |
| 1077 if (!own_buffer_) FATAL("external code buffer is too small"); | 1927 if (!own_buffer_) FATAL("external code buffer is too small"); |
| 1078 | 1928 |
| 1079 // Compute new buffer size. | 1929 // Compute new buffer size. |
| 1080 CodeDesc desc; // the new buffer | 1930 CodeDesc desc; // the new buffer |
| 1081 if (buffer_size_ < 4*KB) { | 1931 if (buffer_size_ < 4*KB) { |
| 1082 desc.buffer_size = 4*KB; | 1932 desc.buffer_size = 4*KB; |
| 1083 } else if (buffer_size_ < 1*MB) { | 1933 } else if (buffer_size_ < 1*MB) { |
| 1084 desc.buffer_size = 2*buffer_size_; | 1934 desc.buffer_size = 2*buffer_size_; |
| 1085 } else { | 1935 } else { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1110 | 1960 |
| 1111 | 1961 |
| 1112 // On ia32 and ARM pc relative addressing is used, and we thus need to apply a | 1962 // On ia32 and ARM pc relative addressing is used, and we thus need to apply a |
| 1113 // shift by pc_delta. But on MIPS the target address it directly loaded, so | 1963 // shift by pc_delta. But on MIPS the target address it directly loaded, so |
| 1114 // we do not need to relocate here. | 1964 // we do not need to relocate here. |
| 1115 | 1965 |
| 1116 ASSERT(!overflow()); | 1966 ASSERT(!overflow()); |
| 1117 } | 1967 } |
| 1118 | 1968 |
| 1119 | 1969 |
| 1970 void Assembler::db(uint8_t data) { | |
| 1971 CheckBuffer(); | |
| 1972 *reinterpret_cast<uint8_t*>(pc_) = data; | |
| 1973 pc_ += sizeof(uint8_t); | |
| 1974 } | |
| 1975 | |
| 1976 | |
| 1977 void Assembler::dd(uint32_t data) { | |
| 1978 CheckBuffer(); | |
| 1979 *reinterpret_cast<uint32_t*>(pc_) = data; | |
| 1980 pc_ += sizeof(uint32_t); | |
| 1981 } | |
| 1982 | |
| 1983 | |
| 1120 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { | 1984 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
| 1121 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants | 1985 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants |
| 1122 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::STATEMENT_POSITION) { | 1986 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { |
| 1123 // Adjust code for new modes. | 1987 // Adjust code for new modes. |
| 1124 ASSERT(RelocInfo::IsJSReturn(rmode) | 1988 ASSERT(RelocInfo::IsDebugBreakSlot(rmode) |
| 1989 || RelocInfo::IsJSReturn(rmode) | |
| 1125 || RelocInfo::IsComment(rmode) | 1990 || RelocInfo::IsComment(rmode) |
| 1126 || RelocInfo::IsPosition(rmode)); | 1991 || RelocInfo::IsPosition(rmode)); |
| 1127 // These modes do not need an entry in the constant pool. | 1992 // These modes do not need an entry in the constant pool. |
| 1128 } | 1993 } |
| 1129 if (rinfo.rmode() != RelocInfo::NONE) { | 1994 if (rinfo.rmode() != RelocInfo::NONE) { |
| 1130 // Don't record external references unless the heap will be serialized. | 1995 // Don't record external references unless the heap will be serialized. |
| 1131 if (rmode == RelocInfo::EXTERNAL_REFERENCE && | 1996 if (rmode == RelocInfo::EXTERNAL_REFERENCE && |
| 1132 !Serializer::enabled() && | 1997 !Serializer::enabled() && |
| 1133 !FLAG_debug_code) { | 1998 !FLAG_debug_code) { |
| 1134 return; | 1999 return; |
| 1135 } | 2000 } |
| 1136 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here | 2001 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here |
| 1137 reloc_info_writer.Write(&rinfo); | 2002 reloc_info_writer.Write(&rinfo); |
| 1138 } | 2003 } |
| 1139 } | 2004 } |
| 1140 | 2005 |
| 1141 | 2006 |
| 2007 void Assembler::BlockTrampolinePoolFor(int instructions) { | |
| 2008 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize); | |
| 2009 } | |
| 2010 | |
| 2011 | |
| 2012 void Assembler::CheckTrampolinePool(bool force_emit) { | |
| 2013 // Calculate the offset of the next check. | |
| 2014 next_buffer_check_ = pc_offset() + kCheckConstInterval; | |
| 2015 | |
| 2016 int dist = pc_offset() - last_trampoline_pool_end_; | |
| 2017 | |
| 2018 if (dist <= kMaxDistBetweenPools && !force_emit) { | |
| 2019 return; | |
| 2020 } | |
| 2021 | |
| 2022 // Some small sequences of instructions must not be broken up by the | |
| 2023 // insertion of a trampoline pool; such sequences are protected by setting | |
| 2024 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_, | |
| 2025 // which are both checked here. Also, recursive calls to CheckTrampolinePool | |
| 2026 // are blocked by trampoline_pool_blocked_nesting_. | |
| 2027 if ((trampoline_pool_blocked_nesting_ > 0) || | |
| 2028 (pc_offset() < no_trampoline_pool_before_)) { | |
| 2029 // Emission is currently blocked; make sure we try again as soon as | |
| 2030 // possible. | |
| 2031 if (trampoline_pool_blocked_nesting_ > 0) { | |
| 2032 next_buffer_check_ = pc_offset() + kInstrSize; | |
| 2033 } else { | |
| 2034 next_buffer_check_ = no_trampoline_pool_before_; | |
| 2035 } | |
| 2036 return; | |
| 2037 } | |
| 2038 | |
| 2039 // First we emit jump (2 instructions), then we emit trampoline pool. | |
| 2040 { BlockTrampolinePoolScope block_trampoline_pool(this); | |
| 2041 Label after_pool; | |
| 2042 b(&after_pool); | |
| 2043 nop(); | |
| 2044 | |
| 2045 int pool_start = pc_offset(); | |
| 2046 for (int i = 0; i < kSlotsPerTrampoline; i++) { | |
| 2047 b(&after_pool); | |
| 2048 nop(); | |
| 2049 } | |
| 2050 for (int i = 0; i < kLabelsPerTrampoline; i++) { | |
| 2051 emit(0); | |
| 2052 } | |
| 2053 last_trampoline_pool_end_ = pc_offset() - kInstrSize; | |
| 2054 bind(&after_pool); | |
| 2055 trampolines_.Add(Trampoline(pool_start, | |
| 2056 kSlotsPerTrampoline, | |
| 2057 kLabelsPerTrampoline)); | |
| 2058 | |
| 2059 // Since a trampoline pool was just emitted, | |
| 2060 // move the check offset forward by the standard interval. | |
| 2061 next_buffer_check_ = last_trampoline_pool_end_ + kMaxDistBetweenPools; | |
| 2062 } | |
| 2063 return; | |
| 2064 } | |
| 2065 | |
| 2066 | |
| 1142 Address Assembler::target_address_at(Address pc) { | 2067 Address Assembler::target_address_at(Address pc) { |
| 1143 Instr instr1 = instr_at(pc); | 2068 Instr instr1 = instr_at(pc); |
| 1144 Instr instr2 = instr_at(pc + kInstrSize); | 2069 Instr instr2 = instr_at(pc + kInstrSize); |
| 1145 // Check we have 2 instructions generated by li. | 2070 // Check we have 2 instructions generated by li. |
| 2071 | |
| 2072 // if ( ! (((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) || | |
|
Søren Thygesen Gjesse
2011/03/21 16:05:19
Code in comments.
Paul Lind
2011/03/23 01:55:43
Done.
| |
| 2073 // ((instr1 == nopInstr) && ((instr2 & kOpcodeMask) == ADDI || | |
| 2074 // (instr2 & kOpcodeMask) == ORI || | |
| 2075 // (instr2 & kOpcodeMask) == LUI)))) { | |
| 2076 // PrintF("target_address_at(): adr: %08x i1: %08x, i2: %08x\n", | |
| 2077 // pc, instr1, instr2); | |
| 2078 // } | |
| 2079 | |
| 1146 ASSERT(((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) || | 2080 ASSERT(((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) || |
| 1147 ((instr1 == nopInstr) && ((instr2 & kOpcodeMask) == ADDI || | 2081 ((instr1 == nopInstr) && ((instr2 & kOpcodeMask) == ADDI || |
| 1148 (instr2 & kOpcodeMask) == ORI || | 2082 (instr2 & kOpcodeMask) == ORI || |
| 1149 (instr2 & kOpcodeMask) == LUI))); | 2083 (instr2 & kOpcodeMask) == LUI))); |
| 1150 // Interpret these 2 instructions. | 2084 // Interpret these 2 instructions. |
| 1151 if (instr1 == nopInstr) { | 2085 if (instr1 == nopInstr) { |
| 1152 if ((instr2 & kOpcodeMask) == ADDI) { | 2086 if ((instr2 & kOpcodeMask) == ADDI) { |
| 1153 return reinterpret_cast<Address>(((instr2 & kImm16Mask) << 16) >> 16); | 2087 return reinterpret_cast<Address>(((instr2 & kImm16Mask) << 16) >> 16); |
| 1154 } else if ((instr2 & kOpcodeMask) == ORI) { | 2088 } else if ((instr2 & kOpcodeMask) == ORI) { |
| 1155 return reinterpret_cast<Address>(instr2 & kImm16Mask); | 2089 return reinterpret_cast<Address>(instr2 & kImm16Mask); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1169 | 2103 |
| 1170 | 2104 |
| 1171 void Assembler::set_target_address_at(Address pc, Address target) { | 2105 void Assembler::set_target_address_at(Address pc, Address target) { |
| 1172 // On MIPS we need to patch the code to generate. | 2106 // On MIPS we need to patch the code to generate. |
| 1173 | 2107 |
| 1174 // First check we have a li. | 2108 // First check we have a li. |
| 1175 Instr instr2 = instr_at(pc + kInstrSize); | 2109 Instr instr2 = instr_at(pc + kInstrSize); |
| 1176 #ifdef DEBUG | 2110 #ifdef DEBUG |
| 1177 Instr instr1 = instr_at(pc); | 2111 Instr instr1 = instr_at(pc); |
| 1178 | 2112 |
| 1179 // Check we have indeed the result from a li with MustUseAt true. | 2113 // Check we have indeed the result from a li with MustUseReg true. |
| 1180 CHECK(((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) || | 2114 CHECK(((instr1 & kOpcodeMask) == LUI && (instr2 & kOpcodeMask) == ORI) || |
| 1181 ((instr1 == 0) && ((instr2 & kOpcodeMask)== ADDIU || | 2115 ((instr1 == 0) && ((instr2 & kOpcodeMask)== ADDIU || |
| 1182 (instr2 & kOpcodeMask)== ORI || | 2116 (instr2 & kOpcodeMask)== ORI || |
| 1183 (instr2 & kOpcodeMask)== LUI))); | 2117 (instr2 & kOpcodeMask)== LUI))); |
| 1184 #endif | 2118 #endif |
| 1185 | 2119 |
| 1186 | 2120 |
| 1187 uint32_t rt_code = (instr2 & kRtFieldMask); | 2121 uint32_t rt_code = (instr2 & kRtFieldMask); |
| 1188 uint32_t* p = reinterpret_cast<uint32_t*>(pc); | 2122 uint32_t* p = reinterpret_cast<uint32_t*>(pc); |
| 1189 uint32_t itarget = reinterpret_cast<uint32_t>(target); | 2123 uint32_t itarget = reinterpret_cast<uint32_t>(target); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1210 *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & LOMask); | 2144 *(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & LOMask); |
| 1211 } | 2145 } |
| 1212 | 2146 |
| 1213 CPU::FlushICache(pc, 2 * sizeof(int32_t)); | 2147 CPU::FlushICache(pc, 2 * sizeof(int32_t)); |
| 1214 } | 2148 } |
| 1215 | 2149 |
| 1216 | 2150 |
| 1217 } } // namespace v8::internal | 2151 } } // namespace v8::internal |
| 1218 | 2152 |
| 1219 #endif // V8_TARGET_ARCH_MIPS | 2153 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |