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