| 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 23 matching lines...) Expand all Loading... |
| 34 | 34 |
| 35 | 35 |
| 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ | 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_H_ |
| 37 #define V8_MIPS_ASSEMBLER_MIPS_H_ | 37 #define V8_MIPS_ASSEMBLER_MIPS_H_ |
| 38 | 38 |
| 39 #include <stdio.h> | 39 #include <stdio.h> |
| 40 #include "assembler.h" | 40 #include "assembler.h" |
| 41 #include "constants-mips.h" | 41 #include "constants-mips.h" |
| 42 #include "serialize.h" | 42 #include "serialize.h" |
| 43 | 43 |
| 44 using namespace assembler::mips; | |
| 45 | |
| 46 namespace v8 { | 44 namespace v8 { |
| 47 namespace internal { | 45 namespace internal { |
| 48 | 46 |
| 49 // CPU Registers. | 47 // CPU Registers. |
| 50 // | 48 // |
| 51 // 1) We would prefer to use an enum, but enum values are assignment- | 49 // 1) We would prefer to use an enum, but enum values are assignment- |
| 52 // compatible with int, which has caused code-generation bugs. | 50 // compatible with int, which has caused code-generation bugs. |
| 53 // | 51 // |
| 54 // 2) We would prefer to use a class instead of a struct but we don't like | 52 // 2) We would prefer to use a class instead of a struct but we don't like |
| 55 // the register initialization to depend on the particular initialization | 53 // the register initialization to depend on the particular initialization |
| (...skipping 10 matching lines...) Expand all Loading... |
| 66 // such that we use an enum in optimized mode, and the struct in debug | 64 // such that we use an enum in optimized mode, and the struct in debug |
| 67 // mode. This way we get the compile-time error checking in debug mode | 65 // mode. This way we get the compile-time error checking in debug mode |
| 68 // and best performance in optimized code. | 66 // and best performance in optimized code. |
| 69 | 67 |
| 70 | 68 |
| 71 // ----------------------------------------------------------------------------- | 69 // ----------------------------------------------------------------------------- |
| 72 // Implementation of Register and FPURegister | 70 // Implementation of Register and FPURegister |
| 73 | 71 |
| 74 // Core register. | 72 // Core register. |
| 75 struct Register { | 73 struct Register { |
| 74 static const int kNumRegisters = v8::internal::kNumRegisters; |
| 75 static const int kNumAllocatableRegisters = 14; // v0 through t7 |
| 76 |
| 77 static int ToAllocationIndex(Register reg) { |
| 78 return reg.code() - 2; // zero_reg and 'at' are skipped. |
| 79 } |
| 80 |
| 81 static Register FromAllocationIndex(int index) { |
| 82 ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| 83 return from_code(index + 2); // zero_reg and 'at' are skipped. |
| 84 } |
| 85 |
| 86 static const char* AllocationIndexToString(int index) { |
| 87 ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| 88 const char* const names[] = { |
| 89 "v0", |
| 90 "v1", |
| 91 "a0", |
| 92 "a1", |
| 93 "a2", |
| 94 "a3", |
| 95 "t0", |
| 96 "t1", |
| 97 "t2", |
| 98 "t3", |
| 99 "t4", |
| 100 "t5", |
| 101 "t6", |
| 102 "t7", |
| 103 }; |
| 104 return names[index]; |
| 105 } |
| 106 |
| 107 static Register from_code(int code) { |
| 108 Register r = { code }; |
| 109 return r; |
| 110 } |
| 111 |
| 76 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } | 112 bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; } |
| 77 bool is(Register reg) const { return code_ == reg.code_; } | 113 bool is(Register reg) const { return code_ == reg.code_; } |
| 78 int code() const { | 114 int code() const { |
| 79 ASSERT(is_valid()); | 115 ASSERT(is_valid()); |
| 80 return code_; | 116 return code_; |
| 81 } | 117 } |
| 82 int bit() const { | 118 int bit() const { |
| 83 ASSERT(is_valid()); | 119 ASSERT(is_valid()); |
| 84 return 1 << code_; | 120 return 1 << code_; |
| 85 } | 121 } |
| 86 | 122 |
| 87 // Unfortunately we can't make this private in a struct. | 123 // Unfortunately we can't make this private in a struct. |
| 88 int code_; | 124 int code_; |
| 89 }; | 125 }; |
| 90 | 126 |
| 91 extern const Register no_reg; | 127 const Register no_reg = { -1 }; |
| 92 | 128 |
| 93 extern const Register zero_reg; | 129 const Register zero_reg = { 0 }; |
| 94 extern const Register at; | 130 const Register at = { 1 }; |
| 95 extern const Register v0; | 131 const Register v0 = { 2 }; |
| 96 extern const Register v1; | 132 const Register v1 = { 3 }; |
| 97 extern const Register a0; | 133 const Register a0 = { 4 }; |
| 98 extern const Register a1; | 134 const Register a1 = { 5 }; |
| 99 extern const Register a2; | 135 const Register a2 = { 6 }; |
| 100 extern const Register a3; | 136 const Register a3 = { 7 }; |
| 101 extern const Register t0; | 137 const Register t0 = { 8 }; |
| 102 extern const Register t1; | 138 const Register t1 = { 9 }; |
| 103 extern const Register t2; | 139 const Register t2 = { 10 }; |
| 104 extern const Register t3; | 140 const Register t3 = { 11 }; |
| 105 extern const Register t4; | 141 const Register t4 = { 12 }; |
| 106 extern const Register t5; | 142 const Register t5 = { 13 }; |
| 107 extern const Register t6; | 143 const Register t6 = { 14 }; |
| 108 extern const Register t7; | 144 const Register t7 = { 15 }; |
| 109 extern const Register s0; | 145 const Register s0 = { 16 }; |
| 110 extern const Register s1; | 146 const Register s1 = { 17 }; |
| 111 extern const Register s2; | 147 const Register s2 = { 18 }; |
| 112 extern const Register s3; | 148 const Register s3 = { 19 }; |
| 113 extern const Register s4; | 149 const Register s4 = { 20 }; |
| 114 extern const Register s5; | 150 const Register s5 = { 21 }; |
| 115 extern const Register s6; | 151 const Register s6 = { 22 }; |
| 116 extern const Register s7; | 152 const Register s7 = { 23 }; |
| 117 extern const Register t8; | 153 const Register t8 = { 24 }; |
| 118 extern const Register t9; | 154 const Register t9 = { 25 }; |
| 119 extern const Register k0; | 155 const Register k0 = { 26 }; |
| 120 extern const Register k1; | 156 const Register k1 = { 27 }; |
| 121 extern const Register gp; | 157 const Register gp = { 28 }; |
| 122 extern const Register sp; | 158 const Register sp = { 29 }; |
| 123 extern const Register s8_fp; | 159 const Register s8_fp = { 30 }; |
| 124 extern const Register ra; | 160 const Register ra = { 31 }; |
| 161 |
| 125 | 162 |
| 126 int ToNumber(Register reg); | 163 int ToNumber(Register reg); |
| 127 | 164 |
| 128 Register ToRegister(int num); | 165 Register ToRegister(int num); |
| 129 | 166 |
| 130 // Coprocessor register. | 167 // Coprocessor register. |
| 131 struct FPURegister { | 168 struct FPURegister { |
| 132 bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegister ; } | 169 static const int kNumRegisters = v8::internal::kNumFPURegisters; |
| 170 // f0 has been excluded from allocation. This is following ia32 |
| 171 // where xmm0 is excluded. This should be revisited. |
| 172 // Currently f0 is used as a scratch register. |
| 173 // f2 has also been excluded from allocation to be used as a scratch |
| 174 // register as well. |
| 175 static const int kNumAllocatableRegisters = 15; |
| 176 |
| 177 static int ToAllocationIndex(FPURegister reg) { |
| 178 ASSERT(reg.code() != 0); |
| 179 ASSERT(reg.code() % 2 == 0); |
| 180 return (reg.code() / 2) - 1; |
| 181 } |
| 182 |
| 183 static FPURegister FromAllocationIndex(int index) { |
| 184 ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| 185 return from_code((index + 1) * 2); |
| 186 } |
| 187 |
| 188 static const char* AllocationIndexToString(int index) { |
| 189 ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| 190 const char* const names[] = { |
| 191 "f2", |
| 192 "f4", |
| 193 "f6", |
| 194 "f8", |
| 195 "f10", |
| 196 "f12", |
| 197 "f14", |
| 198 "f16", |
| 199 "f18", |
| 200 "f20", |
| 201 "f22", |
| 202 "f24", |
| 203 "f26", |
| 204 "f28", |
| 205 "f30" |
| 206 }; |
| 207 return names[index]; |
| 208 } |
| 209 |
| 210 static FPURegister from_code(int code) { |
| 211 FPURegister r = { code }; |
| 212 return r; |
| 213 } |
| 214 |
| 215 bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; } |
| 133 bool is(FPURegister creg) const { return code_ == creg.code_; } | 216 bool is(FPURegister creg) const { return code_ == creg.code_; } |
| 134 int code() const { | 217 int code() const { |
| 135 ASSERT(is_valid()); | 218 ASSERT(is_valid()); |
| 136 return code_; | 219 return code_; |
| 137 } | 220 } |
| 138 int bit() const { | 221 int bit() const { |
| 139 ASSERT(is_valid()); | 222 ASSERT(is_valid()); |
| 140 return 1 << code_; | 223 return 1 << code_; |
| 141 } | 224 } |
| 142 | 225 void setcode(int f) { |
| 226 code_ = f; |
| 227 ASSERT(is_valid()); |
| 228 } |
| 143 // Unfortunately we can't make this private in a struct. | 229 // Unfortunately we can't make this private in a struct. |
| 144 int code_; | 230 int code_; |
| 145 }; | 231 }; |
| 146 | 232 |
| 147 extern const FPURegister no_creg; | 233 typedef FPURegister DoubleRegister; |
| 148 | 234 |
| 149 extern const FPURegister f0; | 235 const FPURegister no_creg = { -1 }; |
| 150 extern const FPURegister f1; | |
| 151 extern const FPURegister f2; | |
| 152 extern const FPURegister f3; | |
| 153 extern const FPURegister f4; | |
| 154 extern const FPURegister f5; | |
| 155 extern const FPURegister f6; | |
| 156 extern const FPURegister f7; | |
| 157 extern const FPURegister f8; | |
| 158 extern const FPURegister f9; | |
| 159 extern const FPURegister f10; | |
| 160 extern const FPURegister f11; | |
| 161 extern const FPURegister f12; // arg | |
| 162 extern const FPURegister f13; | |
| 163 extern const FPURegister f14; // arg | |
| 164 extern const FPURegister f15; | |
| 165 extern const FPURegister f16; | |
| 166 extern const FPURegister f17; | |
| 167 extern const FPURegister f18; | |
| 168 extern const FPURegister f19; | |
| 169 extern const FPURegister f20; | |
| 170 extern const FPURegister f21; | |
| 171 extern const FPURegister f22; | |
| 172 extern const FPURegister f23; | |
| 173 extern const FPURegister f24; | |
| 174 extern const FPURegister f25; | |
| 175 extern const FPURegister f26; | |
| 176 extern const FPURegister f27; | |
| 177 extern const FPURegister f28; | |
| 178 extern const FPURegister f29; | |
| 179 extern const FPURegister f30; | |
| 180 extern const FPURegister f31; | |
| 181 | 236 |
| 237 const FPURegister f0 = { 0 }; // return value in hard float mode |
| 238 const FPURegister f1 = { 1 }; |
| 239 const FPURegister f2 = { 2 }; |
| 240 const FPURegister f3 = { 3 }; |
| 241 const FPURegister f4 = { 4 }; |
| 242 const FPURegister f5 = { 5 }; |
| 243 const FPURegister f6 = { 6 }; |
| 244 const FPURegister f7 = { 7 }; |
| 245 const FPURegister f8 = { 8 }; |
| 246 const FPURegister f9 = { 9 }; |
| 247 const FPURegister f10 = { 10 }; |
| 248 const FPURegister f11 = { 11 }; |
| 249 const FPURegister f12 = { 12 }; // arg in hard float mode |
| 250 const FPURegister f13 = { 13 }; |
| 251 const FPURegister f14 = { 14 }; // arg in hard float mode |
| 252 const FPURegister f15 = { 15 }; |
| 253 const FPURegister f16 = { 16 }; |
| 254 const FPURegister f17 = { 17 }; |
| 255 const FPURegister f18 = { 18 }; |
| 256 const FPURegister f19 = { 19 }; |
| 257 const FPURegister f20 = { 20 }; |
| 258 const FPURegister f21 = { 21 }; |
| 259 const FPURegister f22 = { 22 }; |
| 260 const FPURegister f23 = { 23 }; |
| 261 const FPURegister f24 = { 24 }; |
| 262 const FPURegister f25 = { 25 }; |
| 263 const FPURegister f26 = { 26 }; |
| 264 const FPURegister f27 = { 27 }; |
| 265 const FPURegister f28 = { 28 }; |
| 266 const FPURegister f29 = { 29 }; |
| 267 const FPURegister f30 = { 30 }; |
| 268 const FPURegister f31 = { 31 }; |
| 182 | 269 |
| 183 // Returns the equivalent of !cc. | 270 // FPU (coprocessor 1) control registers. |
| 184 // Negation of the default no_condition (-1) results in a non-default | 271 // Currently only FCSR (#31) is implemented. |
| 185 // no_condition value (-2). As long as tests for no_condition check | 272 struct FPUControlRegister { |
| 186 // for condition < 0, this will work as expected. | 273 static const int kFCSRRegister = 31; |
| 187 inline Condition NegateCondition(Condition cc); | 274 static const int kInvalidFPUControlRegister = -1; |
| 188 | 275 |
| 189 inline Condition ReverseCondition(Condition cc) { | 276 bool is_valid() const { return code_ == kFCSRRegister; } |
| 190 switch (cc) { | 277 bool is(FPUControlRegister creg) const { return code_ == creg.code_; } |
| 191 case Uless: | 278 int code() const { |
| 192 return Ugreater; | 279 ASSERT(is_valid()); |
| 193 case Ugreater: | 280 return code_; |
| 194 return Uless; | 281 } |
| 195 case Ugreater_equal: | 282 int bit() const { |
| 196 return Uless_equal; | 283 ASSERT(is_valid()); |
| 197 case Uless_equal: | 284 return 1 << code_; |
| 198 return Ugreater_equal; | 285 } |
| 199 case less: | 286 void setcode(int f) { |
| 200 return greater; | 287 code_ = f; |
| 201 case greater: | 288 ASSERT(is_valid()); |
| 202 return less; | 289 } |
| 203 case greater_equal: | 290 // Unfortunately we can't make this private in a struct. |
| 204 return less_equal; | 291 int code_; |
| 205 case less_equal: | |
| 206 return greater_equal; | |
| 207 default: | |
| 208 return cc; | |
| 209 }; | |
| 210 } | |
| 211 | |
| 212 | |
| 213 enum Hint { | |
| 214 no_hint = 0 | |
| 215 }; | 292 }; |
| 216 | 293 |
| 217 inline Hint NegateHint(Hint hint) { | 294 const FPUControlRegister no_fpucreg = { -1 }; |
| 218 return no_hint; | 295 const FPUControlRegister FCSR = { kFCSRRegister }; |
| 219 } | |
| 220 | 296 |
| 221 | 297 |
| 222 // ----------------------------------------------------------------------------- | 298 // ----------------------------------------------------------------------------- |
| 223 // Machine instruction Operands. | 299 // Machine instruction Operands. |
| 224 | 300 |
| 225 // Class Operand represents a shifter operand in data processing instructions. | 301 // Class Operand represents a shifter operand in data processing instructions. |
| 226 class Operand BASE_EMBEDDED { | 302 class Operand BASE_EMBEDDED { |
| 227 public: | 303 public: |
| 228 // Immediate. | 304 // Immediate. |
| 229 INLINE(explicit Operand(int32_t immediate, | 305 INLINE(explicit Operand(int32_t immediate, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 251 friend class Assembler; | 327 friend class Assembler; |
| 252 friend class MacroAssembler; | 328 friend class MacroAssembler; |
| 253 }; | 329 }; |
| 254 | 330 |
| 255 | 331 |
| 256 // On MIPS we have only one adressing mode with base_reg + offset. | 332 // On MIPS we have only one adressing mode with base_reg + offset. |
| 257 // Class MemOperand represents a memory operand in load and store instructions. | 333 // Class MemOperand represents a memory operand in load and store instructions. |
| 258 class MemOperand : public Operand { | 334 class MemOperand : public Operand { |
| 259 public: | 335 public: |
| 260 | 336 |
| 261 explicit MemOperand(Register rn, int16_t offset = 0); | 337 explicit MemOperand(Register rn, int32_t offset = 0); |
| 262 | 338 |
| 263 private: | 339 private: |
| 264 int16_t offset_; | 340 int32_t offset_; |
| 265 | 341 |
| 266 friend class Assembler; | 342 friend class Assembler; |
| 267 }; | 343 }; |
| 268 | 344 |
| 269 | 345 |
| 346 // CpuFeatures keeps track of which features are supported by the target CPU. |
| 347 // Supported features must be enabled by a Scope before use. |
| 348 class CpuFeatures : public AllStatic { |
| 349 public: |
| 350 // Detect features of the target CPU. Set safe defaults if the serializer |
| 351 // is enabled (snapshots must be portable). |
| 352 static void Probe(bool portable); |
| 353 |
| 354 // Check whether a feature is supported by the target CPU. |
| 355 static bool IsSupported(CpuFeature f) { |
| 356 if (f == FPU && !FLAG_enable_fpu) return false; |
| 357 return (supported_ & (1u << f)) != 0; |
| 358 } |
| 359 |
| 360 // Check whether a feature is currently enabled. |
| 361 static bool IsEnabled(CpuFeature f) { |
| 362 return (enabled_ & (1u << f)) != 0; |
| 363 } |
| 364 |
| 365 // Enable a specified feature within a scope. |
| 366 class Scope BASE_EMBEDDED { |
| 367 #ifdef DEBUG |
| 368 public: |
| 369 explicit Scope(CpuFeature f) { |
| 370 ASSERT(CpuFeatures::IsSupported(f)); |
| 371 ASSERT(!Serializer::enabled() || |
| 372 (found_by_runtime_probing_ & (1u << f)) == 0); |
| 373 old_enabled_ = CpuFeatures::enabled_; |
| 374 CpuFeatures::enabled_ |= 1u << f; |
| 375 } |
| 376 ~Scope() { CpuFeatures::enabled_ = old_enabled_; } |
| 377 private: |
| 378 unsigned old_enabled_; |
| 379 #else |
| 380 public: |
| 381 explicit Scope(CpuFeature f) {} |
| 382 #endif |
| 383 }; |
| 384 |
| 385 private: |
| 386 static unsigned supported_; |
| 387 static unsigned enabled_; |
| 388 static unsigned found_by_runtime_probing_; |
| 389 }; |
| 390 |
| 270 class Assembler : public Malloced { | 391 class Assembler : public Malloced { |
| 271 public: | 392 public: |
| 272 // Create an assembler. Instructions and relocation information are emitted | 393 // Create an assembler. Instructions and relocation information are emitted |
| 273 // into a buffer, with the instructions starting from the beginning and the | 394 // into a buffer, with the instructions starting from the beginning and the |
| 274 // relocation information starting from the end of the buffer. See CodeDesc | 395 // relocation information starting from the end of the buffer. See CodeDesc |
| 275 // for a detailed comment on the layout (globals.h). | 396 // for a detailed comment on the layout (globals.h). |
| 276 // | 397 // |
| 277 // If the provided buffer is NULL, the assembler allocates and grows its own | 398 // If the provided buffer is NULL, the assembler allocates and grows its own |
| 278 // buffer, and buffer_size determines the initial buffer size. The buffer is | 399 // buffer, and buffer_size determines the initial buffer size. The buffer is |
| 279 // owned by the assembler and deallocated upon destruction of the assembler. | 400 // owned by the assembler and deallocated upon destruction of the assembler. |
| 280 // | 401 // |
| 281 // If the provided buffer is not NULL, the assembler uses the provided buffer | 402 // If the provided buffer is not NULL, the assembler uses the provided buffer |
| 282 // for code generation and assumes its size to be buffer_size. If the buffer | 403 // for code generation and assumes its size to be buffer_size. If the buffer |
| 283 // is too small, a fatal error occurs. No deallocation of the buffer is done | 404 // is too small, a fatal error occurs. No deallocation of the buffer is done |
| 284 // upon destruction of the assembler. | 405 // upon destruction of the assembler. |
| 285 Assembler(void* buffer, int buffer_size); | 406 Assembler(void* buffer, int buffer_size); |
| 286 ~Assembler(); | 407 ~Assembler(); |
| 287 | 408 |
| 409 // Overrides the default provided by FLAG_debug_code. |
| 410 void set_emit_debug_code(bool value) { emit_debug_code_ = value; } |
| 411 |
| 288 // GetCode emits any pending (non-emitted) code and fills the descriptor | 412 // GetCode emits any pending (non-emitted) code and fills the descriptor |
| 289 // desc. GetCode() is idempotent; it returns the same result if no other | 413 // desc. GetCode() is idempotent; it returns the same result if no other |
| 290 // Assembler functions are invoked in between GetCode() calls. | 414 // Assembler functions are invoked in between GetCode() calls. |
| 291 void GetCode(CodeDesc* desc); | 415 void GetCode(CodeDesc* desc); |
| 292 | 416 |
| 293 // Label operations & relative jumps (PPUM Appendix D). | 417 // Label operations & relative jumps (PPUM Appendix D). |
| 294 // | 418 // |
| 295 // Takes a branch opcode (cc) and a label (L) and generates | 419 // Takes a branch opcode (cc) and a label (L) and generates |
| 296 // either a backward branch or a forward branch and links it | 420 // either a backward branch or a forward branch and links it |
| 297 // to the label fixup chain. Usage: | 421 // to the label fixup chain. Usage: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 313 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { | 437 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { |
| 314 int32_t o = branch_offset(L, jump_elimination_allowed); | 438 int32_t o = branch_offset(L, jump_elimination_allowed); |
| 315 ASSERT((o & 3) == 0); // Assert the offset is aligned. | 439 ASSERT((o & 3) == 0); // Assert the offset is aligned. |
| 316 return o >> 2; | 440 return o >> 2; |
| 317 } | 441 } |
| 318 | 442 |
| 319 // Puts a labels target address at the given position. | 443 // Puts a labels target address at the given position. |
| 320 // The high 8 bits are set to zero. | 444 // The high 8 bits are set to zero. |
| 321 void label_at_put(Label* L, int at_offset); | 445 void label_at_put(Label* L, int at_offset); |
| 322 | 446 |
| 323 // Size of an instruction. | |
| 324 static const int kInstrSize = sizeof(Instr); | |
| 325 | |
| 326 // Difference between address of current opcode and target address offset. | |
| 327 static const int kBranchPCOffset = 4; | |
| 328 | |
| 329 // Read/Modify the code target address in the branch/call instruction at pc. | 447 // Read/Modify the code target address in the branch/call instruction at pc. |
| 330 static Address target_address_at(Address pc); | 448 static Address target_address_at(Address pc); |
| 331 static void set_target_address_at(Address pc, Address target); | 449 static void set_target_address_at(Address pc, Address target); |
| 332 | 450 |
| 333 // This sets the branch destination (which gets loaded at the call address). | 451 // This sets the branch destination (which gets loaded at the call address). |
| 334 // This is for calls and branches within generated code. | 452 // This is for calls and branches within generated code. |
| 335 inline static void set_target_at(Address instruction_payload, | 453 inline static void set_target_at(Address instruction_payload, |
| 336 Address target) { | 454 Address target) { |
| 337 set_target_address_at(instruction_payload, target); | 455 set_target_address_at(instruction_payload, target); |
| 338 } | 456 } |
| 339 | 457 |
| 340 // This sets the branch destination. | 458 // This sets the branch destination. |
| 341 // This is for calls and branches to runtime code. | 459 // This is for calls and branches to runtime code. |
| 342 inline static void set_external_target_at(Address instruction_payload, | 460 inline static void set_external_target_at(Address instruction_payload, |
| 343 Address target) { | 461 Address target) { |
| 344 set_target_address_at(instruction_payload, target); | 462 set_target_address_at(instruction_payload, target); |
| 345 } | 463 } |
| 346 | 464 |
| 347 static const int kCallTargetSize = 3 * kPointerSize; | 465 // Size of an instruction. |
| 348 static const int kExternalTargetSize = 3 * kPointerSize; | 466 static const int kInstrSize = sizeof(Instr); |
| 467 |
| 468 // Difference between address of current opcode and target address offset. |
| 469 static const int kBranchPCOffset = 4; |
| 470 |
| 471 // Here we are patching the address in the LUI/ORI instruction pair. |
| 472 // These values are used in serialization process and must be zero for |
| 473 // MIPS platform, as Code, Embedded Object or External-reference pointers |
| 474 // are split across two consecutive instructions and don't exist separately |
| 475 // in the code, so the serializer should not step forwards in memory after |
| 476 // a target is resolved and written. |
| 477 static const int kCallTargetSize = 0 * kInstrSize; |
| 478 static const int kExternalTargetSize = 0 * kInstrSize; |
| 479 |
| 480 // Number of consecutive instructions used to store 32bit constant. |
| 481 // Used in RelocInfo::target_address_address() function to tell serializer |
| 482 // address of the instruction that follows LUI/ORI instruction pair. |
| 483 static const int kInstructionsFor32BitConstant = 2; |
| 349 | 484 |
| 350 // Distance between the instruction referring to the address of the call | 485 // Distance between the instruction referring to the address of the call |
| 351 // target and the return address. | 486 // target and the return address. |
| 352 static const int kCallTargetAddressOffset = 4 * kInstrSize; | 487 static const int kCallTargetAddressOffset = 4 * kInstrSize; |
| 353 | 488 |
| 354 // Distance between start of patched return sequence and the emitted address | 489 // Distance between start of patched return sequence and the emitted address |
| 355 // to jump to. | 490 // to jump to. |
| 356 static const int kPatchReturnSequenceAddressOffset = kInstrSize; | 491 static const int kPatchReturnSequenceAddressOffset = 0; |
| 357 | 492 |
| 358 // Distance between start of patched debug break slot and the emitted address | 493 // Distance between start of patched debug break slot and the emitted address |
| 359 // to jump to. | 494 // to jump to. |
| 360 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize; | 495 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize; |
| 496 |
| 497 // Difference between address of current opcode and value read from pc |
| 498 // register. |
| 499 static const int kPcLoadDelta = 4; |
| 500 |
| 501 // Number of instructions used for the JS return sequence. The constant is |
| 502 // used by the debugger to patch the JS return sequence. |
| 503 static const int kJSReturnSequenceInstructions = 7; |
| 504 static const int kDebugBreakSlotInstructions = 4; |
| 505 static const int kDebugBreakSlotLength = |
| 506 kDebugBreakSlotInstructions * kInstrSize; |
| 507 |
| 361 | 508 |
| 362 // --------------------------------------------------------------------------- | 509 // --------------------------------------------------------------------------- |
| 363 // Code generation. | 510 // Code generation. |
| 364 | 511 |
| 365 void nop() { sll(zero_reg, zero_reg, 0); } | 512 // Insert the smallest number of nop instructions |
| 513 // possible to align the pc offset to a multiple |
| 514 // of m. m must be a power of 2 (>= 4). |
| 515 void Align(int m); |
| 516 // Aligns code to something that's optimal for a jump target for the platform. |
| 517 void CodeTargetAlign(); |
| 518 |
| 519 // Different nop operations are used by the code generator to detect certain |
| 520 // states of the generated code. |
| 521 enum NopMarkerTypes { |
| 522 NON_MARKING_NOP = 0, |
| 523 DEBUG_BREAK_NOP, |
| 524 // IC markers. |
| 525 PROPERTY_ACCESS_INLINED, |
| 526 PROPERTY_ACCESS_INLINED_CONTEXT, |
| 527 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, |
| 528 // Helper values. |
| 529 LAST_CODE_MARKER, |
| 530 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED |
| 531 }; |
| 532 |
| 533 // type == 0 is the default non-marking type. |
| 534 void nop(unsigned int type = 0) { |
| 535 ASSERT(type < 32); |
| 536 sll(zero_reg, zero_reg, type, true); |
| 537 } |
| 366 | 538 |
| 367 | 539 |
| 368 //------- Branch and jump instructions -------- | 540 //------- Branch and jump instructions -------- |
| 369 // We don't use likely variant of instructions. | 541 // We don't use likely variant of instructions. |
| 370 void b(int16_t offset); | 542 void b(int16_t offset); |
| 371 void b(Label* L) { b(branch_offset(L, false)>>2); } | 543 void b(Label* L) { b(branch_offset(L, false)>>2); } |
| 372 void bal(int16_t offset); | 544 void bal(int16_t offset); |
| 373 void bal(Label* L) { bal(branch_offset(L, false)>>2); } | 545 void bal(Label* L) { bal(branch_offset(L, false)>>2); } |
| 374 | 546 |
| 375 void beq(Register rs, Register rt, int16_t offset); | 547 void beq(Register rs, Register rt, int16_t offset); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 393 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. | 565 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. |
| 394 void j(int32_t target); | 566 void j(int32_t target); |
| 395 void jal(int32_t target); | 567 void jal(int32_t target); |
| 396 void jalr(Register rs, Register rd = ra); | 568 void jalr(Register rs, Register rd = ra); |
| 397 void jr(Register target); | 569 void jr(Register target); |
| 398 | 570 |
| 399 | 571 |
| 400 //-------Data-processing-instructions--------- | 572 //-------Data-processing-instructions--------- |
| 401 | 573 |
| 402 // Arithmetic. | 574 // Arithmetic. |
| 403 void add(Register rd, Register rs, Register rt); | |
| 404 void addu(Register rd, Register rs, Register rt); | 575 void addu(Register rd, Register rs, Register rt); |
| 405 void sub(Register rd, Register rs, Register rt); | |
| 406 void subu(Register rd, Register rs, Register rt); | 576 void subu(Register rd, Register rs, Register rt); |
| 407 void mult(Register rs, Register rt); | 577 void mult(Register rs, Register rt); |
| 408 void multu(Register rs, Register rt); | 578 void multu(Register rs, Register rt); |
| 409 void div(Register rs, Register rt); | 579 void div(Register rs, Register rt); |
| 410 void divu(Register rs, Register rt); | 580 void divu(Register rs, Register rt); |
| 411 void mul(Register rd, Register rs, Register rt); | 581 void mul(Register rd, Register rs, Register rt); |
| 412 | 582 |
| 413 void addi(Register rd, Register rs, int32_t j); | |
| 414 void addiu(Register rd, Register rs, int32_t j); | 583 void addiu(Register rd, Register rs, int32_t j); |
| 415 | 584 |
| 416 // Logical. | 585 // Logical. |
| 417 void and_(Register rd, Register rs, Register rt); | 586 void and_(Register rd, Register rs, Register rt); |
| 418 void or_(Register rd, Register rs, Register rt); | 587 void or_(Register rd, Register rs, Register rt); |
| 419 void xor_(Register rd, Register rs, Register rt); | 588 void xor_(Register rd, Register rs, Register rt); |
| 420 void nor(Register rd, Register rs, Register rt); | 589 void nor(Register rd, Register rs, Register rt); |
| 421 | 590 |
| 422 void andi(Register rd, Register rs, int32_t j); | 591 void andi(Register rd, Register rs, int32_t j); |
| 423 void ori(Register rd, Register rs, int32_t j); | 592 void ori(Register rd, Register rs, int32_t j); |
| 424 void xori(Register rd, Register rs, int32_t j); | 593 void xori(Register rd, Register rs, int32_t j); |
| 425 void lui(Register rd, int32_t j); | 594 void lui(Register rd, int32_t j); |
| 426 | 595 |
| 427 // Shifts. | 596 // Shifts. |
| 428 void sll(Register rd, Register rt, uint16_t sa); | 597 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop |
| 598 // and may cause problems in normal code. coming_from_nop makes sure this |
| 599 // doesn't happen. |
| 600 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false); |
| 429 void sllv(Register rd, Register rt, Register rs); | 601 void sllv(Register rd, Register rt, Register rs); |
| 430 void srl(Register rd, Register rt, uint16_t sa); | 602 void srl(Register rd, Register rt, uint16_t sa); |
| 431 void srlv(Register rd, Register rt, Register rs); | 603 void srlv(Register rd, Register rt, Register rs); |
| 432 void sra(Register rt, Register rd, uint16_t sa); | 604 void sra(Register rt, Register rd, uint16_t sa); |
| 433 void srav(Register rt, Register rd, Register rs); | 605 void srav(Register rt, Register rd, Register rs); |
| 606 void rotr(Register rd, Register rt, uint16_t sa); |
| 607 void rotrv(Register rd, Register rt, Register rs); |
| 434 | 608 |
| 435 | 609 |
| 436 //------------Memory-instructions------------- | 610 //------------Memory-instructions------------- |
| 437 | 611 |
| 438 void lb(Register rd, const MemOperand& rs); | 612 void lb(Register rd, const MemOperand& rs); |
| 439 void lbu(Register rd, const MemOperand& rs); | 613 void lbu(Register rd, const MemOperand& rs); |
| 614 void lh(Register rd, const MemOperand& rs); |
| 615 void lhu(Register rd, const MemOperand& rs); |
| 440 void lw(Register rd, const MemOperand& rs); | 616 void lw(Register rd, const MemOperand& rs); |
| 617 void lwl(Register rd, const MemOperand& rs); |
| 618 void lwr(Register rd, const MemOperand& rs); |
| 441 void sb(Register rd, const MemOperand& rs); | 619 void sb(Register rd, const MemOperand& rs); |
| 620 void sh(Register rd, const MemOperand& rs); |
| 442 void sw(Register rd, const MemOperand& rs); | 621 void sw(Register rd, const MemOperand& rs); |
| 622 void swl(Register rd, const MemOperand& rs); |
| 623 void swr(Register rd, const MemOperand& rs); |
| 443 | 624 |
| 444 | 625 |
| 445 //-------------Misc-instructions-------------- | 626 //-------------Misc-instructions-------------- |
| 446 | 627 |
| 447 // Break / Trap instructions. | 628 // Break / Trap instructions. |
| 448 void break_(uint32_t code); | 629 void break_(uint32_t code); |
| 449 void tge(Register rs, Register rt, uint16_t code); | 630 void tge(Register rs, Register rt, uint16_t code); |
| 450 void tgeu(Register rs, Register rt, uint16_t code); | 631 void tgeu(Register rs, Register rt, uint16_t code); |
| 451 void tlt(Register rs, Register rt, uint16_t code); | 632 void tlt(Register rs, Register rt, uint16_t code); |
| 452 void tltu(Register rs, Register rt, uint16_t code); | 633 void tltu(Register rs, Register rt, uint16_t code); |
| 453 void teq(Register rs, Register rt, uint16_t code); | 634 void teq(Register rs, Register rt, uint16_t code); |
| 454 void tne(Register rs, Register rt, uint16_t code); | 635 void tne(Register rs, Register rt, uint16_t code); |
| 455 | 636 |
| 456 // Move from HI/LO register. | 637 // Move from HI/LO register. |
| 457 void mfhi(Register rd); | 638 void mfhi(Register rd); |
| 458 void mflo(Register rd); | 639 void mflo(Register rd); |
| 459 | 640 |
| 460 // Set on less than. | 641 // Set on less than. |
| 461 void slt(Register rd, Register rs, Register rt); | 642 void slt(Register rd, Register rs, Register rt); |
| 462 void sltu(Register rd, Register rs, Register rt); | 643 void sltu(Register rd, Register rs, Register rt); |
| 463 void slti(Register rd, Register rs, int32_t j); | 644 void slti(Register rd, Register rs, int32_t j); |
| 464 void sltiu(Register rd, Register rs, int32_t j); | 645 void sltiu(Register rd, Register rs, int32_t j); |
| 465 | 646 |
| 647 // Conditional move. |
| 648 void movz(Register rd, Register rs, Register rt); |
| 649 void movn(Register rd, Register rs, Register rt); |
| 650 void movt(Register rd, Register rs, uint16_t cc = 0); |
| 651 void movf(Register rd, Register rs, uint16_t cc = 0); |
| 652 |
| 653 // Bit twiddling. |
| 654 void clz(Register rd, Register rs); |
| 655 void ins_(Register rt, Register rs, uint16_t pos, uint16_t size); |
| 656 void ext_(Register rt, Register rs, uint16_t pos, uint16_t size); |
| 466 | 657 |
| 467 //--------Coprocessor-instructions---------------- | 658 //--------Coprocessor-instructions---------------- |
| 468 | 659 |
| 469 // Load, store, and move. | 660 // Load, store, and move. |
| 470 void lwc1(FPURegister fd, const MemOperand& src); | 661 void lwc1(FPURegister fd, const MemOperand& src); |
| 471 void ldc1(FPURegister fd, const MemOperand& src); | 662 void ldc1(FPURegister fd, const MemOperand& src); |
| 472 | 663 |
| 473 void swc1(FPURegister fs, const MemOperand& dst); | 664 void swc1(FPURegister fs, const MemOperand& dst); |
| 474 void sdc1(FPURegister fs, const MemOperand& dst); | 665 void sdc1(FPURegister fs, const MemOperand& dst); |
| 475 | 666 |
| 476 // When paired with MTC1 to write a value to a 64-bit FPR, the MTC1 must be | 667 void mtc1(Register rt, FPURegister fs); |
| 477 // executed first, followed by the MTHC1. | 668 void mfc1(Register rt, FPURegister fs); |
| 478 void mtc1(FPURegister fs, Register rt); | 669 |
| 479 void mthc1(FPURegister fs, Register rt); | 670 void ctc1(Register rt, FPUControlRegister fs); |
| 480 void mfc1(FPURegister fs, Register rt); | 671 void cfc1(Register rt, FPUControlRegister fs); |
| 481 void mfhc1(FPURegister fs, Register rt); | 672 |
| 673 // Arithmetic. |
| 674 void add_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 675 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 676 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 677 void div_d(FPURegister fd, FPURegister fs, FPURegister ft); |
| 678 void abs_d(FPURegister fd, FPURegister fs); |
| 679 void mov_d(FPURegister fd, FPURegister fs); |
| 680 void neg_d(FPURegister fd, FPURegister fs); |
| 681 void sqrt_d(FPURegister fd, FPURegister fs); |
| 482 | 682 |
| 483 // Conversion. | 683 // Conversion. |
| 484 void cvt_w_s(FPURegister fd, FPURegister fs); | 684 void cvt_w_s(FPURegister fd, FPURegister fs); |
| 485 void cvt_w_d(FPURegister fd, FPURegister fs); | 685 void cvt_w_d(FPURegister fd, FPURegister fs); |
| 686 void trunc_w_s(FPURegister fd, FPURegister fs); |
| 687 void trunc_w_d(FPURegister fd, FPURegister fs); |
| 688 void round_w_s(FPURegister fd, FPURegister fs); |
| 689 void round_w_d(FPURegister fd, FPURegister fs); |
| 690 void floor_w_s(FPURegister fd, FPURegister fs); |
| 691 void floor_w_d(FPURegister fd, FPURegister fs); |
| 692 void ceil_w_s(FPURegister fd, FPURegister fs); |
| 693 void ceil_w_d(FPURegister fd, FPURegister fs); |
| 486 | 694 |
| 487 void cvt_l_s(FPURegister fd, FPURegister fs); | 695 void cvt_l_s(FPURegister fd, FPURegister fs); |
| 488 void cvt_l_d(FPURegister fd, FPURegister fs); | 696 void cvt_l_d(FPURegister fd, FPURegister fs); |
| 697 void trunc_l_s(FPURegister fd, FPURegister fs); |
| 698 void trunc_l_d(FPURegister fd, FPURegister fs); |
| 699 void round_l_s(FPURegister fd, FPURegister fs); |
| 700 void round_l_d(FPURegister fd, FPURegister fs); |
| 701 void floor_l_s(FPURegister fd, FPURegister fs); |
| 702 void floor_l_d(FPURegister fd, FPURegister fs); |
| 703 void ceil_l_s(FPURegister fd, FPURegister fs); |
| 704 void ceil_l_d(FPURegister fd, FPURegister fs); |
| 489 | 705 |
| 490 void cvt_s_w(FPURegister fd, FPURegister fs); | 706 void cvt_s_w(FPURegister fd, FPURegister fs); |
| 491 void cvt_s_l(FPURegister fd, FPURegister fs); | 707 void cvt_s_l(FPURegister fd, FPURegister fs); |
| 492 void cvt_s_d(FPURegister fd, FPURegister fs); | 708 void cvt_s_d(FPURegister fd, FPURegister fs); |
| 493 | 709 |
| 494 void cvt_d_w(FPURegister fd, FPURegister fs); | 710 void cvt_d_w(FPURegister fd, FPURegister fs); |
| 495 void cvt_d_l(FPURegister fd, FPURegister fs); | 711 void cvt_d_l(FPURegister fd, FPURegister fs); |
| 496 void cvt_d_s(FPURegister fd, FPURegister fs); | 712 void cvt_d_s(FPURegister fd, FPURegister fs); |
| 497 | 713 |
| 498 // Conditions and branches. | 714 // Conditions and branches. |
| 499 void c(FPUCondition cond, SecondaryField fmt, | 715 void c(FPUCondition cond, SecondaryField fmt, |
| 500 FPURegister ft, FPURegister fs, uint16_t cc = 0); | 716 FPURegister ft, FPURegister fs, uint16_t cc = 0); |
| 501 | 717 |
| 502 void bc1f(int16_t offset, uint16_t cc = 0); | 718 void bc1f(int16_t offset, uint16_t cc = 0); |
| 503 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); } | 719 void bc1f(Label* L, uint16_t cc = 0) { bc1f(branch_offset(L, false)>>2, cc); } |
| 504 void bc1t(int16_t offset, uint16_t cc = 0); | 720 void bc1t(int16_t offset, uint16_t cc = 0); |
| 505 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } | 721 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } |
| 506 | 722 void fcmp(FPURegister src1, const double src2, FPUCondition cond); |
| 507 | 723 |
| 508 // Check the code size generated from label to here. | 724 // Check the code size generated from label to here. |
| 509 int InstructionsGeneratedSince(Label* l) { | 725 int InstructionsGeneratedSince(Label* l) { |
| 510 return (pc_offset() - l->pos()) / kInstrSize; | 726 return (pc_offset() - l->pos()) / kInstrSize; |
| 511 } | 727 } |
| 512 | 728 |
| 729 // Class for scoping postponing the trampoline pool generation. |
| 730 class BlockTrampolinePoolScope { |
| 731 public: |
| 732 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) { |
| 733 assem_->StartBlockTrampolinePool(); |
| 734 } |
| 735 ~BlockTrampolinePoolScope() { |
| 736 assem_->EndBlockTrampolinePool(); |
| 737 } |
| 738 |
| 739 private: |
| 740 Assembler* assem_; |
| 741 |
| 742 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope); |
| 743 }; |
| 744 |
| 513 // Debugging. | 745 // Debugging. |
| 514 | 746 |
| 515 // Mark address of the ExitJSFrame code. | 747 // Mark address of the ExitJSFrame code. |
| 516 void RecordJSReturn(); | 748 void RecordJSReturn(); |
| 517 | 749 |
| 750 // Mark address of a debug break slot. |
| 751 void RecordDebugBreakSlot(); |
| 752 |
| 518 // Record a comment relocation entry that can be used by a disassembler. | 753 // Record a comment relocation entry that can be used by a disassembler. |
| 519 // Use --debug_code to enable. | 754 // Use --code-comments to enable. |
| 520 void RecordComment(const char* msg); | 755 void RecordComment(const char* msg); |
| 521 | 756 |
| 522 void RecordPosition(int pos); | 757 // Writes a single byte or word of data in the code stream. Used for |
| 523 void RecordStatementPosition(int pos); | 758 // inline tables, e.g., jump-tables. |
| 524 bool WriteRecordedPositions(); | 759 void db(uint8_t data); |
| 760 void dd(uint32_t data); |
| 525 | 761 |
| 526 int32_t pc_offset() const { return pc_ - buffer_; } | 762 int32_t pc_offset() const { return pc_ - buffer_; } |
| 527 int32_t current_position() const { return current_position_; } | 763 |
| 528 int32_t current_statement_position() const { | 764 PositionsRecorder* positions_recorder() { return &positions_recorder_; } |
| 529 return current_statement_position_; | 765 |
| 766 bool can_peephole_optimize(int instructions) { |
| 767 if (!allow_peephole_optimization_) return false; |
| 768 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false; |
| 769 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize; |
| 530 } | 770 } |
| 531 | 771 |
| 772 // Postpone the generation of the trampoline pool for the specified number of |
| 773 // instructions. |
| 774 void BlockTrampolinePoolFor(int instructions); |
| 775 |
| 532 // Check if there is less than kGap bytes available in the buffer. | 776 // Check if there is less than kGap bytes available in the buffer. |
| 533 // If this is the case, we need to grow the buffer before emitting | 777 // If this is the case, we need to grow the buffer before emitting |
| 534 // an instruction or relocation information. | 778 // an instruction or relocation information. |
| 535 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } | 779 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } |
| 536 | 780 |
| 537 // Get the number of bytes available in the buffer. | 781 // Get the number of bytes available in the buffer. |
| 538 inline int available_space() const { return reloc_info_writer.pos() - pc_; } | 782 inline int available_space() const { return reloc_info_writer.pos() - pc_; } |
| 539 | 783 |
| 540 protected: | |
| 541 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } | |
| 542 | |
| 543 // Read/patch instructions. | 784 // Read/patch instructions. |
| 544 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } | 785 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } |
| 545 void instr_at_put(byte* pc, Instr instr) { | 786 static void instr_at_put(byte* pc, Instr instr) { |
| 546 *reinterpret_cast<Instr*>(pc) = instr; | 787 *reinterpret_cast<Instr*>(pc) = instr; |
| 547 } | 788 } |
| 548 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } | 789 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } |
| 549 void instr_at_put(int pos, Instr instr) { | 790 void instr_at_put(int pos, Instr instr) { |
| 550 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; | 791 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; |
| 551 } | 792 } |
| 552 | 793 |
| 553 // Check if an instruction is a branch of some kind. | 794 // Check if an instruction is a branch of some kind. |
| 554 bool is_branch(Instr instr); | 795 static bool IsBranch(Instr instr); |
| 796 |
| 797 static bool IsNop(Instr instr, unsigned int type); |
| 798 static bool IsPop(Instr instr); |
| 799 static bool IsPush(Instr instr); |
| 800 static bool IsLwRegFpOffset(Instr instr); |
| 801 static bool IsSwRegFpOffset(Instr instr); |
| 802 static bool IsLwRegFpNegOffset(Instr instr); |
| 803 static bool IsSwRegFpNegOffset(Instr instr); |
| 804 |
| 805 static Register GetRt(Instr instr); |
| 806 |
| 807 static int32_t GetBranchOffset(Instr instr); |
| 808 static bool IsLw(Instr instr); |
| 809 static int16_t GetLwOffset(Instr instr); |
| 810 static Instr SetLwOffset(Instr instr, int16_t offset); |
| 811 |
| 812 static bool IsSw(Instr instr); |
| 813 static Instr SetSwOffset(Instr instr, int16_t offset); |
| 814 static bool IsAddImmediate(Instr instr); |
| 815 static Instr SetAddImmediateOffset(Instr instr, int16_t offset); |
| 816 |
| 817 void CheckTrampolinePool(bool force_emit = false); |
| 818 |
| 819 protected: |
| 820 bool emit_debug_code() const { return emit_debug_code_; } |
| 821 |
| 822 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } |
| 555 | 823 |
| 556 // Decode branch instruction at pos and return branch target pos. | 824 // Decode branch instruction at pos and return branch target pos. |
| 557 int target_at(int32_t pos); | 825 int target_at(int32_t pos); |
| 558 | 826 |
| 559 // Patch branch instruction at pos to branch to given branch target pos. | 827 // Patch branch instruction at pos to branch to given branch target pos. |
| 560 void target_at_put(int32_t pos, int32_t target_pos); | 828 void target_at_put(int32_t pos, int32_t target_pos); |
| 561 | 829 |
| 562 // Say if we need to relocate with this mode. | 830 // Say if we need to relocate with this mode. |
| 563 bool MustUseAt(RelocInfo::Mode rmode); | 831 bool MustUseReg(RelocInfo::Mode rmode); |
| 564 | 832 |
| 565 // Record reloc info for current pc_. | 833 // Record reloc info for current pc_. |
| 566 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); | 834 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); |
| 567 | 835 |
| 836 // Block the emission of the trampoline pool before pc_offset. |
| 837 void BlockTrampolinePoolBefore(int pc_offset) { |
| 838 if (no_trampoline_pool_before_ < pc_offset) |
| 839 no_trampoline_pool_before_ = pc_offset; |
| 840 } |
| 841 |
| 842 void StartBlockTrampolinePool() { |
| 843 trampoline_pool_blocked_nesting_++; |
| 844 } |
| 845 void EndBlockTrampolinePool() { |
| 846 trampoline_pool_blocked_nesting_--; |
| 847 } |
| 848 |
| 849 bool is_trampoline_pool_blocked() const { |
| 850 return trampoline_pool_blocked_nesting_ > 0; |
| 851 } |
| 852 |
| 568 private: | 853 private: |
| 569 // Code buffer: | 854 // Code buffer: |
| 570 // The buffer into which code and relocation info are generated. | 855 // The buffer into which code and relocation info are generated. |
| 571 byte* buffer_; | 856 byte* buffer_; |
| 572 int buffer_size_; | 857 int buffer_size_; |
| 573 // True if the assembler owns the buffer, false if buffer is external. | 858 // True if the assembler owns the buffer, false if buffer is external. |
| 574 bool own_buffer_; | 859 bool own_buffer_; |
| 575 | 860 |
| 576 // Buffer size and constant pool distance are checked together at regular | 861 // Buffer size and constant pool distance are checked together at regular |
| 577 // intervals of kBufferCheckInterval emitted bytes. | 862 // intervals of kBufferCheckInterval emitted bytes. |
| 578 static const int kBufferCheckInterval = 1*KB/2; | 863 static const int kBufferCheckInterval = 1*KB/2; |
| 579 | 864 |
| 580 // Code generation. | 865 // Code generation. |
| 581 // The relocation writer's position is at least kGap bytes below the end of | 866 // The relocation writer's position is at least kGap bytes below the end of |
| 582 // the generated instructions. This is so that multi-instruction sequences do | 867 // the generated instructions. This is so that multi-instruction sequences do |
| 583 // not have to check for overflow. The same is true for writes of large | 868 // not have to check for overflow. The same is true for writes of large |
| 584 // relocation info entries. | 869 // relocation info entries. |
| 585 static const int kGap = 32; | 870 static const int kGap = 32; |
| 586 byte* pc_; // The program counter - moves forward. | 871 byte* pc_; // The program counter - moves forward. |
| 587 | 872 |
| 873 |
| 874 // Repeated checking whether the trampoline pool should be emitted is rather |
| 875 // expensive. By default we only check again once a number of instructions |
| 876 // has been generated. |
| 877 static const int kCheckConstIntervalInst = 32; |
| 878 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize; |
| 879 |
| 880 int next_buffer_check_; // pc offset of next buffer check. |
| 881 |
| 882 // Emission of the trampoline pool may be blocked in some code sequences. |
| 883 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero. |
| 884 int no_trampoline_pool_before_; // Block emission before this pc offset. |
| 885 |
| 886 // Keep track of the last emitted pool to guarantee a maximal distance. |
| 887 int last_trampoline_pool_end_; // pc offset of the end of the last pool. |
| 888 |
| 588 // Relocation information generation. | 889 // Relocation information generation. |
| 589 // Each relocation is encoded as a variable size value. | 890 // Each relocation is encoded as a variable size value. |
| 590 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 891 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
| 591 RelocInfoWriter reloc_info_writer; | 892 RelocInfoWriter reloc_info_writer; |
| 592 | 893 |
| 593 // The bound position, before this we cannot do instruction elimination. | 894 // The bound position, before this we cannot do instruction elimination. |
| 594 int last_bound_pos_; | 895 int last_bound_pos_; |
| 595 | 896 |
| 596 // Source position information. | |
| 597 int current_position_; | |
| 598 int current_statement_position_; | |
| 599 int written_position_; | |
| 600 int written_statement_position_; | |
| 601 | |
| 602 // Code emission. | 897 // Code emission. |
| 603 inline void CheckBuffer(); | 898 inline void CheckBuffer(); |
| 604 void GrowBuffer(); | 899 void GrowBuffer(); |
| 605 inline void emit(Instr x); | 900 inline void emit(Instr x); |
| 901 inline void CheckTrampolinePoolQuick(); |
| 606 | 902 |
| 607 // Instruction generation. | 903 // Instruction generation. |
| 608 // We have 3 different kind of encoding layout on MIPS. | 904 // We have 3 different kind of encoding layout on MIPS. |
| 609 // However due to many different types of objects encoded in the same fields | 905 // However due to many different types of objects encoded in the same fields |
| 610 // we have quite a few aliases for each mode. | 906 // we have quite a few aliases for each mode. |
| 611 // Using the same structure to refer to Register and FPURegister would spare a | 907 // Using the same structure to refer to Register and FPURegister would spare a |
| 612 // few aliases, but mixing both does not look clean to me. | 908 // few aliases, but mixing both does not look clean to me. |
| 613 // Anyway we could surely implement this differently. | 909 // Anyway we could surely implement this differently. |
| 614 | 910 |
| 615 void GenInstrRegister(Opcode opcode, | 911 void GenInstrRegister(Opcode opcode, |
| 616 Register rs, | 912 Register rs, |
| 617 Register rt, | 913 Register rt, |
| 618 Register rd, | 914 Register rd, |
| 619 uint16_t sa = 0, | 915 uint16_t sa = 0, |
| 620 SecondaryField func = NULLSF); | 916 SecondaryField func = NULLSF); |
| 621 | 917 |
| 622 void GenInstrRegister(Opcode opcode, | 918 void GenInstrRegister(Opcode opcode, |
| 919 Register rs, |
| 920 Register rt, |
| 921 uint16_t msb, |
| 922 uint16_t lsb, |
| 923 SecondaryField func); |
| 924 |
| 925 void GenInstrRegister(Opcode opcode, |
| 623 SecondaryField fmt, | 926 SecondaryField fmt, |
| 624 FPURegister ft, | 927 FPURegister ft, |
| 625 FPURegister fs, | 928 FPURegister fs, |
| 626 FPURegister fd, | 929 FPURegister fd, |
| 627 SecondaryField func = NULLSF); | 930 SecondaryField func = NULLSF); |
| 628 | 931 |
| 629 void GenInstrRegister(Opcode opcode, | 932 void GenInstrRegister(Opcode opcode, |
| 630 SecondaryField fmt, | 933 SecondaryField fmt, |
| 631 Register rt, | 934 Register rt, |
| 632 FPURegister fs, | 935 FPURegister fs, |
| 633 FPURegister fd, | 936 FPURegister fd, |
| 634 SecondaryField func = NULLSF); | 937 SecondaryField func = NULLSF); |
| 635 | 938 |
| 939 void GenInstrRegister(Opcode opcode, |
| 940 SecondaryField fmt, |
| 941 Register rt, |
| 942 FPUControlRegister fs, |
| 943 SecondaryField func = NULLSF); |
| 944 |
| 636 | 945 |
| 637 void GenInstrImmediate(Opcode opcode, | 946 void GenInstrImmediate(Opcode opcode, |
| 638 Register rs, | 947 Register rs, |
| 639 Register rt, | 948 Register rt, |
| 640 int32_t j); | 949 int32_t j); |
| 641 void GenInstrImmediate(Opcode opcode, | 950 void GenInstrImmediate(Opcode opcode, |
| 642 Register rs, | 951 Register rs, |
| 643 SecondaryField SF, | 952 SecondaryField SF, |
| 644 int32_t j); | 953 int32_t j); |
| 645 void GenInstrImmediate(Opcode opcode, | 954 void GenInstrImmediate(Opcode opcode, |
| 646 Register r1, | 955 Register r1, |
| 647 FPURegister r2, | 956 FPURegister r2, |
| 648 int32_t j); | 957 int32_t j); |
| 649 | 958 |
| 650 | 959 |
| 651 void GenInstrJump(Opcode opcode, | 960 void GenInstrJump(Opcode opcode, |
| 652 uint32_t address); | 961 uint32_t address); |
| 653 | 962 |
| 654 | 963 |
| 655 // Labels. | 964 // Labels. |
| 656 void print(Label* L); | 965 void print(Label* L); |
| 657 void bind_to(Label* L, int pos); | 966 void bind_to(Label* L, int pos); |
| 658 void link_to(Label* L, Label* appendix); | 967 void link_to(Label* L, Label* appendix); |
| 659 void next(Label* L); | 968 void next(Label* L); |
| 660 | 969 |
| 970 // One trampoline consists of: |
| 971 // - space for trampoline slots, |
| 972 // - space for labels. |
| 973 // |
| 974 // Space for trampoline slots is equal to slot_count * 2*kInstrSize. |
| 975 // Space for trampoline slots preceeds space for labels. Each label is of one |
| 976 // instruction size, so total amount for labels is equal to |
| 977 // label_count * kInstrSize. |
| 978 class Trampoline { |
| 979 public: |
| 980 Trampoline(int start, int slot_count, int label_count) { |
| 981 start_ = start; |
| 982 next_slot_ = start; |
| 983 free_slot_count_ = slot_count; |
| 984 next_label_ = start + slot_count*2*kInstrSize; |
| 985 free_label_count_ = label_count; |
| 986 end_ = next_label_ + (label_count-1)*kInstrSize; |
| 987 } |
| 988 int bound() { |
| 989 return next_slot_; |
| 990 } |
| 991 int start() { |
| 992 return start_; |
| 993 } |
| 994 int end() { |
| 995 return end_; |
| 996 } |
| 997 int take_slot() { |
| 998 int trampoline_slot = next_slot_; |
| 999 ASSERT(free_slot_count_ > 0); |
| 1000 free_slot_count_--; |
| 1001 next_slot_ += 2*kInstrSize; |
| 1002 return trampoline_slot; |
| 1003 } |
| 1004 int take_label() { |
| 1005 int label_pos = next_label_; |
| 1006 ASSERT(free_label_count_ > 0); |
| 1007 free_label_count_--; |
| 1008 next_label_ += kInstrSize; |
| 1009 return label_pos; |
| 1010 } |
| 1011 private: |
| 1012 int start_; |
| 1013 int end_; |
| 1014 int next_slot_; |
| 1015 int free_slot_count_; |
| 1016 int next_label_; |
| 1017 int free_label_count_; |
| 1018 }; |
| 1019 |
| 1020 int32_t get_label_entry(int32_t pos, bool next_pool = true); |
| 1021 int32_t get_trampoline_entry(int32_t pos, bool next_pool = true); |
| 1022 |
| 1023 static const int kSlotsPerTrampoline = 2304; |
| 1024 static const int kLabelsPerTrampoline = 8; |
| 1025 static const int kTrampolineInst = |
| 1026 2*kSlotsPerTrampoline + kLabelsPerTrampoline; |
| 1027 static const int kTrampolineSize = kTrampolineInst*kInstrSize; |
| 1028 static const int kMaxBranchOffset = (1 << (18-1)) - 1; |
| 1029 static const int kMaxDistBetweenPools = kMaxBranchOffset - 2*kTrampolineSize; |
| 1030 |
| 1031 List<Trampoline> trampolines_; |
| 1032 |
| 661 friend class RegExpMacroAssemblerMIPS; | 1033 friend class RegExpMacroAssemblerMIPS; |
| 662 friend class RelocInfo; | 1034 friend class RelocInfo; |
| 1035 friend class CodePatcher; |
| 1036 friend class BlockTrampolinePoolScope; |
| 1037 |
| 1038 PositionsRecorder positions_recorder_; |
| 1039 bool allow_peephole_optimization_; |
| 1040 bool emit_debug_code_; |
| 1041 friend class PositionsRecorder; |
| 1042 friend class EnsureSpace; |
| 1043 }; |
| 1044 |
| 1045 |
| 1046 class EnsureSpace BASE_EMBEDDED { |
| 1047 public: |
| 1048 explicit EnsureSpace(Assembler* assembler) { |
| 1049 assembler->CheckBuffer(); |
| 1050 } |
| 663 }; | 1051 }; |
| 664 | 1052 |
| 665 } } // namespace v8::internal | 1053 } } // namespace v8::internal |
| 666 | 1054 |
| 667 #endif // V8_ARM_ASSEMBLER_MIPS_H_ | 1055 #endif // V8_ARM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |