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 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. | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
This comment about f2 does not seems to be what th
Paul Lind
2011/03/26 18:39:17
Removed bogus comments.
| |
| 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 | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
Start comment with uppercase and end with full sto
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 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 | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
arg -> arg 0? Start comment with uppercase and end
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 250 const FPURegister f13 = { 13 }; | |
| 251 const FPURegister f14 = { 14 }; // arg in hard float mode | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
arg -> arg 1? Start comment with uppercase and end
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 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 |
| 270 class Assembler : public Malloced { | 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 { | |
| 349 public: | |
| 350 // Detect features of the target CPU. Set safe defaults if the serializer | |
| 351 // is enabled (snapshots must be portable). | |
| 352 void Probe(bool portable); | |
| 353 | |
| 354 // Check whether a feature is supported by the target CPU. | |
| 355 bool IsSupported(CpuFeature f) const { | |
| 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 bool IsEnabled(CpuFeature f) const { | |
| 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 : cpu_features_(Isolate::Current()->cpu_features()), | |
| 371 isolate_(Isolate::Current()) { | |
| 372 ASSERT(cpu_features_->IsSupported(f)); | |
| 373 ASSERT(!Serializer::enabled() || | |
| 374 (cpu_features_->found_by_runtime_probing_ & (1u << f)) == 0); | |
| 375 old_enabled_ = cpu_features_->enabled_; | |
| 376 cpu_features_->enabled_ |= 1u << f; | |
| 377 } | |
| 378 ~Scope() { | |
| 379 ASSERT_EQ(Isolate::Current(), isolate_); | |
| 380 cpu_features_->enabled_ = old_enabled_; | |
| 381 } | |
| 382 private: | |
| 383 unsigned old_enabled_; | |
| 384 CpuFeatures* cpu_features_; | |
| 385 Isolate* isolate_; | |
| 386 #else | |
| 387 public: | |
| 388 explicit Scope(CpuFeature f) {} | |
| 389 #endif | |
| 390 }; | |
| 391 | |
| 392 private: | |
| 393 CpuFeatures(); | |
| 394 | |
| 395 unsigned supported_; | |
| 396 unsigned enabled_; | |
| 397 unsigned found_by_runtime_probing_; | |
| 398 | |
| 399 friend class Isolate; | |
| 400 | |
| 401 DISALLOW_COPY_AND_ASSIGN(CpuFeatures); | |
| 402 }; | |
| 403 | |
| 404 | |
| 405 class Assembler : public AssemblerBase { | |
| 271 public: | 406 public: |
| 272 // Create an assembler. Instructions and relocation information are emitted | 407 // Create an assembler. Instructions and relocation information are emitted |
| 273 // into a buffer, with the instructions starting from the beginning and the | 408 // into a buffer, with the instructions starting from the beginning and the |
| 274 // relocation information starting from the end of the buffer. See CodeDesc | 409 // relocation information starting from the end of the buffer. See CodeDesc |
| 275 // for a detailed comment on the layout (globals.h). | 410 // for a detailed comment on the layout (globals.h). |
| 276 // | 411 // |
| 277 // If the provided buffer is NULL, the assembler allocates and grows its own | 412 // 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 | 413 // buffer, and buffer_size determines the initial buffer size. The buffer is |
| 279 // owned by the assembler and deallocated upon destruction of the assembler. | 414 // owned by the assembler and deallocated upon destruction of the assembler. |
| 280 // | 415 // |
| 281 // If the provided buffer is not NULL, the assembler uses the provided buffer | 416 // 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 | 417 // 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 | 418 // is too small, a fatal error occurs. No deallocation of the buffer is done |
| 284 // upon destruction of the assembler. | 419 // upon destruction of the assembler. |
| 285 Assembler(void* buffer, int buffer_size); | 420 Assembler(void* buffer, int buffer_size); |
| 286 ~Assembler(); | 421 ~Assembler(); |
| 287 | 422 |
| 423 // Overrides the default provided by FLAG_debug_code. | |
| 424 void set_emit_debug_code(bool value) { emit_debug_code_ = value; } | |
| 425 | |
| 288 // GetCode emits any pending (non-emitted) code and fills the descriptor | 426 // GetCode emits any pending (non-emitted) code and fills the descriptor |
| 289 // desc. GetCode() is idempotent; it returns the same result if no other | 427 // desc. GetCode() is idempotent; it returns the same result if no other |
| 290 // Assembler functions are invoked in between GetCode() calls. | 428 // Assembler functions are invoked in between GetCode() calls. |
| 291 void GetCode(CodeDesc* desc); | 429 void GetCode(CodeDesc* desc); |
| 292 | 430 |
| 293 // Label operations & relative jumps (PPUM Appendix D). | 431 // Label operations & relative jumps (PPUM Appendix D). |
| 294 // | 432 // |
| 295 // Takes a branch opcode (cc) and a label (L) and generates | 433 // Takes a branch opcode (cc) and a label (L) and generates |
| 296 // either a backward branch or a forward branch and links it | 434 // either a backward branch or a forward branch and links it |
| 297 // to the label fixup chain. Usage: | 435 // 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) { | 451 int32_t shifted_branch_offset(Label* L, bool jump_elimination_allowed) { |
| 314 int32_t o = branch_offset(L, jump_elimination_allowed); | 452 int32_t o = branch_offset(L, jump_elimination_allowed); |
| 315 ASSERT((o & 3) == 0); // Assert the offset is aligned. | 453 ASSERT((o & 3) == 0); // Assert the offset is aligned. |
| 316 return o >> 2; | 454 return o >> 2; |
| 317 } | 455 } |
| 318 | 456 |
| 319 // Puts a labels target address at the given position. | 457 // Puts a labels target address at the given position. |
| 320 // The high 8 bits are set to zero. | 458 // The high 8 bits are set to zero. |
| 321 void label_at_put(Label* L, int at_offset); | 459 void label_at_put(Label* L, int at_offset); |
| 322 | 460 |
| 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. | 461 // Read/Modify the code target address in the branch/call instruction at pc. |
| 330 static Address target_address_at(Address pc); | 462 static Address target_address_at(Address pc); |
| 331 static void set_target_address_at(Address pc, Address target); | 463 static void set_target_address_at(Address pc, Address target); |
| 332 | 464 |
| 333 // This sets the branch destination (which gets loaded at the call address). | 465 // This sets the branch destination (which gets loaded at the call address). |
| 334 // This is for calls and branches within generated code. | 466 // This is for calls and branches within generated code. |
| 335 inline static void set_target_at(Address instruction_payload, | 467 inline static void set_target_at(Address instruction_payload, |
| 336 Address target) { | 468 Address target) { |
| 337 set_target_address_at(instruction_payload, target); | 469 set_target_address_at(instruction_payload, target); |
| 338 } | 470 } |
| 339 | 471 |
| 340 // This sets the branch destination. | 472 // This sets the branch destination. |
| 341 // This is for calls and branches to runtime code. | 473 // This is for calls and branches to runtime code. |
| 342 inline static void set_external_target_at(Address instruction_payload, | 474 inline static void set_external_target_at(Address instruction_payload, |
| 343 Address target) { | 475 Address target) { |
| 344 set_target_address_at(instruction_payload, target); | 476 set_target_address_at(instruction_payload, target); |
| 345 } | 477 } |
| 346 | 478 |
| 347 static const int kCallTargetSize = 3 * kPointerSize; | 479 // Size of an instruction. |
| 348 static const int kExternalTargetSize = 3 * kPointerSize; | 480 static const int kInstrSize = sizeof(Instr); |
| 481 | |
| 482 // Difference between address of current opcode and target address offset. | |
| 483 static const int kBranchPCOffset = 4; | |
| 484 | |
| 485 // Here we are patching the address in the LUI/ORI instruction pair. | |
| 486 // These values are used in serialization process and must be zero for | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
in -> in the
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 487 // MIPS platform, as Code, Embedded Object or External-reference pointers | |
| 488 // are split across two consecutive instructions and don't exist separately | |
| 489 // in the code, so the serializer should not step forwards in memory after | |
| 490 // a target is resolved and written. | |
| 491 static const int kCallTargetSize = 0 * kInstrSize; | |
| 492 static const int kExternalTargetSize = 0 * kInstrSize; | |
| 493 | |
| 494 // Number of consecutive instructions used to store 32bit constant. | |
| 495 // Used in RelocInfo::target_address_address() function to tell serializer | |
| 496 // address of the instruction that follows LUI/ORI instruction pair. | |
| 497 static const int kInstructionsFor32BitConstant = 2; | |
| 349 | 498 |
| 350 // Distance between the instruction referring to the address of the call | 499 // Distance between the instruction referring to the address of the call |
| 351 // target and the return address. | 500 // target and the return address. |
| 352 static const int kCallTargetAddressOffset = 4 * kInstrSize; | 501 static const int kCallTargetAddressOffset = 4 * kInstrSize; |
| 353 | 502 |
| 354 // Distance between start of patched return sequence and the emitted address | 503 // Distance between start of patched return sequence and the emitted address |
| 355 // to jump to. | 504 // to jump to. |
| 356 static const int kPatchReturnSequenceAddressOffset = kInstrSize; | 505 static const int kPatchReturnSequenceAddressOffset = 0; |
| 357 | 506 |
| 358 // Distance between start of patched debug break slot and the emitted address | 507 // Distance between start of patched debug break slot and the emitted address |
| 359 // to jump to. | 508 // to jump to. |
| 360 static const int kPatchDebugBreakSlotAddressOffset = kInstrSize; | 509 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize; |
| 510 | |
| 511 // Difference between address of current opcode and value read from pc | |
| 512 // register. | |
| 513 static const int kPcLoadDelta = 4; | |
| 514 | |
| 515 // Number of instructions used for the JS return sequence. The constant is | |
| 516 // used by the debugger to patch the JS return sequence. | |
| 517 static const int kJSReturnSequenceInstructions = 7; | |
| 518 static const int kDebugBreakSlotInstructions = 4; | |
| 519 static const int kDebugBreakSlotLength = | |
| 520 kDebugBreakSlotInstructions * kInstrSize; | |
| 521 | |
| 361 | 522 |
| 362 // --------------------------------------------------------------------------- | 523 // --------------------------------------------------------------------------- |
| 363 // Code generation. | 524 // Code generation. |
| 364 | 525 |
| 365 void nop() { sll(zero_reg, zero_reg, 0); } | 526 // Insert the smallest number of nop instructions |
| 527 // possible to align the pc offset to a multiple | |
| 528 // of m. m must be a power of 2 (>= 4). | |
| 529 void Align(int m); | |
| 530 // Aligns code to something that's optimal for a jump target for the platform. | |
| 531 void CodeTargetAlign(); | |
| 532 | |
| 533 // Different nop operations are used by the code generator to detect certain | |
| 534 // states of the generated code. | |
| 535 enum NopMarkerTypes { | |
| 536 NON_MARKING_NOP = 0, | |
| 537 DEBUG_BREAK_NOP, | |
| 538 // IC markers. | |
| 539 PROPERTY_ACCESS_INLINED, | |
| 540 PROPERTY_ACCESS_INLINED_CONTEXT, | |
| 541 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, | |
| 542 // Helper values. | |
| 543 LAST_CODE_MARKER, | |
| 544 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED | |
| 545 }; | |
| 546 | |
| 547 // type == 0 is the default non-marking type. | |
| 548 void nop(unsigned int type = 0) { | |
| 549 ASSERT(type < 32); | |
| 550 sll(zero_reg, zero_reg, type, true); | |
| 551 } | |
| 366 | 552 |
| 367 | 553 |
| 368 //------- Branch and jump instructions -------- | 554 //------- Branch and jump instructions -------- |
| 369 // We don't use likely variant of instructions. | 555 // We don't use likely variant of instructions. |
| 370 void b(int16_t offset); | 556 void b(int16_t offset); |
| 371 void b(Label* L) { b(branch_offset(L, false)>>2); } | 557 void b(Label* L) { b(branch_offset(L, false)>>2); } |
| 372 void bal(int16_t offset); | 558 void bal(int16_t offset); |
| 373 void bal(Label* L) { bal(branch_offset(L, false)>>2); } | 559 void bal(Label* L) { bal(branch_offset(L, false)>>2); } |
| 374 | 560 |
| 375 void beq(Register rs, Register rt, int16_t offset); | 561 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. | 579 // Jump targets must be in the current 256 MB-aligned region. ie 28 bits. |
| 394 void j(int32_t target); | 580 void j(int32_t target); |
| 395 void jal(int32_t target); | 581 void jal(int32_t target); |
| 396 void jalr(Register rs, Register rd = ra); | 582 void jalr(Register rs, Register rd = ra); |
| 397 void jr(Register target); | 583 void jr(Register target); |
| 398 | 584 |
| 399 | 585 |
| 400 //-------Data-processing-instructions--------- | 586 //-------Data-processing-instructions--------- |
| 401 | 587 |
| 402 // Arithmetic. | 588 // Arithmetic. |
| 403 void add(Register rd, Register rs, Register rt); | |
| 404 void addu(Register rd, Register rs, Register rt); | 589 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); | 590 void subu(Register rd, Register rs, Register rt); |
| 407 void mult(Register rs, Register rt); | 591 void mult(Register rs, Register rt); |
| 408 void multu(Register rs, Register rt); | 592 void multu(Register rs, Register rt); |
| 409 void div(Register rs, Register rt); | 593 void div(Register rs, Register rt); |
| 410 void divu(Register rs, Register rt); | 594 void divu(Register rs, Register rt); |
| 411 void mul(Register rd, Register rs, Register rt); | 595 void mul(Register rd, Register rs, Register rt); |
| 412 | 596 |
| 413 void addi(Register rd, Register rs, int32_t j); | |
| 414 void addiu(Register rd, Register rs, int32_t j); | 597 void addiu(Register rd, Register rs, int32_t j); |
| 415 | 598 |
| 416 // Logical. | 599 // Logical. |
| 417 void and_(Register rd, Register rs, Register rt); | 600 void and_(Register rd, Register rs, Register rt); |
| 418 void or_(Register rd, Register rs, Register rt); | 601 void or_(Register rd, Register rs, Register rt); |
| 419 void xor_(Register rd, Register rs, Register rt); | 602 void xor_(Register rd, Register rs, Register rt); |
| 420 void nor(Register rd, Register rs, Register rt); | 603 void nor(Register rd, Register rs, Register rt); |
| 421 | 604 |
| 422 void andi(Register rd, Register rs, int32_t j); | 605 void andi(Register rd, Register rs, int32_t j); |
| 423 void ori(Register rd, Register rs, int32_t j); | 606 void ori(Register rd, Register rs, int32_t j); |
| 424 void xori(Register rd, Register rs, int32_t j); | 607 void xori(Register rd, Register rs, int32_t j); |
| 425 void lui(Register rd, int32_t j); | 608 void lui(Register rd, int32_t j); |
| 426 | 609 |
| 427 // Shifts. | 610 // Shifts. |
| 428 void sll(Register rd, Register rt, uint16_t sa); | 611 // Please note: sll(zero_reg, zero_reg, x) instructions are reserved as nop |
| 612 // and may cause problems in normal code. coming_from_nop makes sure this | |
| 613 // doesn't happen. | |
| 614 void sll(Register rd, Register rt, uint16_t sa, bool coming_from_nop = false); | |
| 429 void sllv(Register rd, Register rt, Register rs); | 615 void sllv(Register rd, Register rt, Register rs); |
| 430 void srl(Register rd, Register rt, uint16_t sa); | 616 void srl(Register rd, Register rt, uint16_t sa); |
| 431 void srlv(Register rd, Register rt, Register rs); | 617 void srlv(Register rd, Register rt, Register rs); |
| 432 void sra(Register rt, Register rd, uint16_t sa); | 618 void sra(Register rt, Register rd, uint16_t sa); |
| 433 void srav(Register rt, Register rd, Register rs); | 619 void srav(Register rt, Register rd, Register rs); |
| 620 void rotr(Register rd, Register rt, uint16_t sa); | |
| 621 void rotrv(Register rd, Register rt, Register rs); | |
| 434 | 622 |
| 435 | 623 |
| 436 //------------Memory-instructions------------- | 624 //------------Memory-instructions------------- |
| 437 | 625 |
| 438 void lb(Register rd, const MemOperand& rs); | 626 void lb(Register rd, const MemOperand& rs); |
| 439 void lbu(Register rd, const MemOperand& rs); | 627 void lbu(Register rd, const MemOperand& rs); |
| 628 void lh(Register rd, const MemOperand& rs); | |
| 629 void lhu(Register rd, const MemOperand& rs); | |
| 440 void lw(Register rd, const MemOperand& rs); | 630 void lw(Register rd, const MemOperand& rs); |
| 631 void lwl(Register rd, const MemOperand& rs); | |
| 632 void lwr(Register rd, const MemOperand& rs); | |
| 441 void sb(Register rd, const MemOperand& rs); | 633 void sb(Register rd, const MemOperand& rs); |
| 634 void sh(Register rd, const MemOperand& rs); | |
| 442 void sw(Register rd, const MemOperand& rs); | 635 void sw(Register rd, const MemOperand& rs); |
| 636 void swl(Register rd, const MemOperand& rs); | |
| 637 void swr(Register rd, const MemOperand& rs); | |
| 443 | 638 |
| 444 | 639 |
| 445 //-------------Misc-instructions-------------- | 640 //-------------Misc-instructions-------------- |
| 446 | 641 |
| 447 // Break / Trap instructions. | 642 // Break / Trap instructions. |
| 448 void break_(uint32_t code); | 643 void break_(uint32_t code); |
| 449 void tge(Register rs, Register rt, uint16_t code); | 644 void tge(Register rs, Register rt, uint16_t code); |
| 450 void tgeu(Register rs, Register rt, uint16_t code); | 645 void tgeu(Register rs, Register rt, uint16_t code); |
| 451 void tlt(Register rs, Register rt, uint16_t code); | 646 void tlt(Register rs, Register rt, uint16_t code); |
| 452 void tltu(Register rs, Register rt, uint16_t code); | 647 void tltu(Register rs, Register rt, uint16_t code); |
| 453 void teq(Register rs, Register rt, uint16_t code); | 648 void teq(Register rs, Register rt, uint16_t code); |
| 454 void tne(Register rs, Register rt, uint16_t code); | 649 void tne(Register rs, Register rt, uint16_t code); |
| 455 | 650 |
| 456 // Move from HI/LO register. | 651 // Move from HI/LO register. |
| 457 void mfhi(Register rd); | 652 void mfhi(Register rd); |
| 458 void mflo(Register rd); | 653 void mflo(Register rd); |
| 459 | 654 |
| 460 // Set on less than. | 655 // Set on less than. |
| 461 void slt(Register rd, Register rs, Register rt); | 656 void slt(Register rd, Register rs, Register rt); |
| 462 void sltu(Register rd, Register rs, Register rt); | 657 void sltu(Register rd, Register rs, Register rt); |
| 463 void slti(Register rd, Register rs, int32_t j); | 658 void slti(Register rd, Register rs, int32_t j); |
| 464 void sltiu(Register rd, Register rs, int32_t j); | 659 void sltiu(Register rd, Register rs, int32_t j); |
| 465 | 660 |
| 661 // Conditional move. | |
| 662 void movz(Register rd, Register rs, Register rt); | |
| 663 void movn(Register rd, Register rs, Register rt); | |
| 664 void movt(Register rd, Register rs, uint16_t cc = 0); | |
| 665 void movf(Register rd, Register rs, uint16_t cc = 0); | |
| 666 | |
| 667 // Bit twiddling. | |
| 668 void clz(Register rd, Register rs); | |
| 669 void ins_(Register rt, Register rs, uint16_t pos, uint16_t size); | |
| 670 void ext_(Register rt, Register rs, uint16_t pos, uint16_t size); | |
| 466 | 671 |
| 467 //--------Coprocessor-instructions---------------- | 672 //--------Coprocessor-instructions---------------- |
| 468 | 673 |
| 469 // Load, store, and move. | 674 // Load, store, and move. |
| 470 void lwc1(FPURegister fd, const MemOperand& src); | 675 void lwc1(FPURegister fd, const MemOperand& src); |
| 471 void ldc1(FPURegister fd, const MemOperand& src); | 676 void ldc1(FPURegister fd, const MemOperand& src); |
| 472 | 677 |
| 473 void swc1(FPURegister fs, const MemOperand& dst); | 678 void swc1(FPURegister fs, const MemOperand& dst); |
| 474 void sdc1(FPURegister fs, const MemOperand& dst); | 679 void sdc1(FPURegister fs, const MemOperand& dst); |
| 475 | 680 |
| 476 // When paired with MTC1 to write a value to a 64-bit FPR, the MTC1 must be | 681 void mtc1(Register rt, FPURegister fs); |
| 477 // executed first, followed by the MTHC1. | 682 void mfc1(Register rt, FPURegister fs); |
| 478 void mtc1(FPURegister fs, Register rt); | 683 |
| 479 void mthc1(FPURegister fs, Register rt); | 684 void ctc1(Register rt, FPUControlRegister fs); |
| 480 void mfc1(FPURegister fs, Register rt); | 685 void cfc1(Register rt, FPUControlRegister fs); |
| 481 void mfhc1(FPURegister fs, Register rt); | 686 |
| 687 // Arithmetic. | |
| 688 void add_d(FPURegister fd, FPURegister fs, FPURegister ft); | |
| 689 void sub_d(FPURegister fd, FPURegister fs, FPURegister ft); | |
| 690 void mul_d(FPURegister fd, FPURegister fs, FPURegister ft); | |
| 691 void div_d(FPURegister fd, FPURegister fs, FPURegister ft); | |
| 692 void abs_d(FPURegister fd, FPURegister fs); | |
| 693 void mov_d(FPURegister fd, FPURegister fs); | |
| 694 void neg_d(FPURegister fd, FPURegister fs); | |
| 695 void sqrt_d(FPURegister fd, FPURegister fs); | |
| 482 | 696 |
| 483 // Conversion. | 697 // Conversion. |
| 484 void cvt_w_s(FPURegister fd, FPURegister fs); | 698 void cvt_w_s(FPURegister fd, FPURegister fs); |
| 485 void cvt_w_d(FPURegister fd, FPURegister fs); | 699 void cvt_w_d(FPURegister fd, FPURegister fs); |
| 700 void trunc_w_s(FPURegister fd, FPURegister fs); | |
| 701 void trunc_w_d(FPURegister fd, FPURegister fs); | |
| 702 void round_w_s(FPURegister fd, FPURegister fs); | |
| 703 void round_w_d(FPURegister fd, FPURegister fs); | |
| 704 void floor_w_s(FPURegister fd, FPURegister fs); | |
| 705 void floor_w_d(FPURegister fd, FPURegister fs); | |
| 706 void ceil_w_s(FPURegister fd, FPURegister fs); | |
| 707 void ceil_w_d(FPURegister fd, FPURegister fs); | |
| 486 | 708 |
| 487 void cvt_l_s(FPURegister fd, FPURegister fs); | 709 void cvt_l_s(FPURegister fd, FPURegister fs); |
| 488 void cvt_l_d(FPURegister fd, FPURegister fs); | 710 void cvt_l_d(FPURegister fd, FPURegister fs); |
| 711 void trunc_l_s(FPURegister fd, FPURegister fs); | |
| 712 void trunc_l_d(FPURegister fd, FPURegister fs); | |
| 713 void round_l_s(FPURegister fd, FPURegister fs); | |
| 714 void round_l_d(FPURegister fd, FPURegister fs); | |
| 715 void floor_l_s(FPURegister fd, FPURegister fs); | |
| 716 void floor_l_d(FPURegister fd, FPURegister fs); | |
| 717 void ceil_l_s(FPURegister fd, FPURegister fs); | |
| 718 void ceil_l_d(FPURegister fd, FPURegister fs); | |
| 489 | 719 |
| 490 void cvt_s_w(FPURegister fd, FPURegister fs); | 720 void cvt_s_w(FPURegister fd, FPURegister fs); |
| 491 void cvt_s_l(FPURegister fd, FPURegister fs); | 721 void cvt_s_l(FPURegister fd, FPURegister fs); |
| 492 void cvt_s_d(FPURegister fd, FPURegister fs); | 722 void cvt_s_d(FPURegister fd, FPURegister fs); |
| 493 | 723 |
| 494 void cvt_d_w(FPURegister fd, FPURegister fs); | 724 void cvt_d_w(FPURegister fd, FPURegister fs); |
| 495 void cvt_d_l(FPURegister fd, FPURegister fs); | 725 void cvt_d_l(FPURegister fd, FPURegister fs); |
| 496 void cvt_d_s(FPURegister fd, FPURegister fs); | 726 void cvt_d_s(FPURegister fd, FPURegister fs); |
| 497 | 727 |
| 498 // Conditions and branches. | 728 // Conditions and branches. |
| 499 void c(FPUCondition cond, SecondaryField fmt, | 729 void c(FPUCondition cond, SecondaryField fmt, |
| 500 FPURegister ft, FPURegister fs, uint16_t cc = 0); | 730 FPURegister ft, FPURegister fs, uint16_t cc = 0); |
| 501 | 731 |
| 502 void bc1f(int16_t offset, uint16_t cc = 0); | 732 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); } | 733 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); | 734 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); } | 735 void bc1t(Label* L, uint16_t cc = 0) { bc1t(branch_offset(L, false)>>2, cc); } |
| 506 | 736 void fcmp(FPURegister src1, const double src2, FPUCondition cond); |
| 507 | 737 |
| 508 // Check the code size generated from label to here. | 738 // Check the code size generated from label to here. |
| 509 int InstructionsGeneratedSince(Label* l) { | 739 int InstructionsGeneratedSince(Label* l) { |
| 510 return (pc_offset() - l->pos()) / kInstrSize; | 740 return (pc_offset() - l->pos()) / kInstrSize; |
| 511 } | 741 } |
| 512 | 742 |
| 743 // Class for scoping postponing the trampoline pool generation. | |
| 744 class BlockTrampolinePoolScope { | |
| 745 public: | |
| 746 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) { | |
| 747 assem_->StartBlockTrampolinePool(); | |
| 748 } | |
| 749 ~BlockTrampolinePoolScope() { | |
| 750 assem_->EndBlockTrampolinePool(); | |
| 751 } | |
| 752 | |
| 753 private: | |
| 754 Assembler* assem_; | |
| 755 | |
| 756 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope); | |
| 757 }; | |
| 758 | |
| 513 // Debugging. | 759 // Debugging. |
| 514 | 760 |
| 515 // Mark address of the ExitJSFrame code. | 761 // Mark address of the ExitJSFrame code. |
| 516 void RecordJSReturn(); | 762 void RecordJSReturn(); |
| 517 | 763 |
| 764 // Mark address of a debug break slot. | |
| 765 void RecordDebugBreakSlot(); | |
| 766 | |
| 518 // Record a comment relocation entry that can be used by a disassembler. | 767 // Record a comment relocation entry that can be used by a disassembler. |
| 519 // Use --debug_code to enable. | 768 // Use --code-comments to enable. |
| 520 void RecordComment(const char* msg); | 769 void RecordComment(const char* msg); |
| 521 | 770 |
| 522 void RecordPosition(int pos); | 771 // Writes a single byte or word of data in the code stream. Used for |
| 523 void RecordStatementPosition(int pos); | 772 // inline tables, e.g., jump-tables. |
| 524 bool WriteRecordedPositions(); | 773 void db(uint8_t data); |
| 774 void dd(uint32_t data); | |
| 525 | 775 |
| 526 int32_t pc_offset() const { return pc_ - buffer_; } | 776 int32_t pc_offset() const { return pc_ - buffer_; } |
| 527 int32_t current_position() const { return current_position_; } | 777 |
| 528 int32_t current_statement_position() const { | 778 PositionsRecorder* positions_recorder() { return &positions_recorder_; } |
| 529 return current_statement_position_; | 779 |
| 780 bool can_peephole_optimize(int instructions) { | |
| 781 if (!allow_peephole_optimization_) return false; | |
| 782 if (last_bound_pos_ > pc_offset() - instructions * kInstrSize) return false; | |
| 783 return reloc_info_writer.last_pc() <= pc_ - instructions * kInstrSize; | |
| 530 } | 784 } |
| 531 | 785 |
| 786 // Postpone the generation of the trampoline pool for the specified number of | |
| 787 // instructions. | |
| 788 void BlockTrampolinePoolFor(int instructions); | |
| 789 | |
| 532 // Check if there is less than kGap bytes available in the buffer. | 790 // 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 | 791 // If this is the case, we need to grow the buffer before emitting |
| 534 // an instruction or relocation information. | 792 // an instruction or relocation information. |
| 535 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } | 793 inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; } |
| 536 | 794 |
| 537 // Get the number of bytes available in the buffer. | 795 // Get the number of bytes available in the buffer. |
| 538 inline int available_space() const { return reloc_info_writer.pos() - pc_; } | 796 inline int available_space() const { return reloc_info_writer.pos() - pc_; } |
| 539 | 797 |
| 540 protected: | |
| 541 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } | |
| 542 | |
| 543 // Read/patch instructions. | 798 // Read/patch instructions. |
| 544 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } | 799 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); } |
| 545 void instr_at_put(byte* pc, Instr instr) { | 800 static void instr_at_put(byte* pc, Instr instr) { |
| 546 *reinterpret_cast<Instr*>(pc) = instr; | 801 *reinterpret_cast<Instr*>(pc) = instr; |
| 547 } | 802 } |
| 548 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } | 803 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } |
| 549 void instr_at_put(int pos, Instr instr) { | 804 void instr_at_put(int pos, Instr instr) { |
| 550 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; | 805 *reinterpret_cast<Instr*>(buffer_ + pos) = instr; |
| 551 } | 806 } |
| 552 | 807 |
| 553 // Check if an instruction is a branch of some kind. | 808 // Check if an instruction is a branch of some kind. |
| 554 bool is_branch(Instr instr); | 809 static bool IsBranch(Instr instr); |
| 810 | |
| 811 static bool IsNop(Instr instr, unsigned int type); | |
| 812 static bool IsPop(Instr instr); | |
| 813 static bool IsPush(Instr instr); | |
| 814 static bool IsLwRegFpOffset(Instr instr); | |
| 815 static bool IsSwRegFpOffset(Instr instr); | |
| 816 static bool IsLwRegFpNegOffset(Instr instr); | |
| 817 static bool IsSwRegFpNegOffset(Instr instr); | |
| 818 | |
| 819 static Register GetRt(Instr instr); | |
| 820 | |
| 821 static int32_t GetBranchOffset(Instr instr); | |
| 822 static bool IsLw(Instr instr); | |
| 823 static int16_t GetLwOffset(Instr instr); | |
| 824 static Instr SetLwOffset(Instr instr, int16_t offset); | |
| 825 | |
| 826 static bool IsSw(Instr instr); | |
| 827 static Instr SetSwOffset(Instr instr, int16_t offset); | |
| 828 static bool IsAddImmediate(Instr instr); | |
| 829 static Instr SetAddImmediateOffset(Instr instr, int16_t offset); | |
| 830 | |
| 831 void CheckTrampolinePool(bool force_emit = false); | |
| 832 | |
| 833 protected: | |
| 834 bool emit_debug_code() const { return emit_debug_code_; } | |
| 835 | |
| 836 int32_t buffer_space() const { return reloc_info_writer.pos() - pc_; } | |
| 555 | 837 |
| 556 // Decode branch instruction at pos and return branch target pos. | 838 // Decode branch instruction at pos and return branch target pos. |
| 557 int target_at(int32_t pos); | 839 int target_at(int32_t pos); |
| 558 | 840 |
| 559 // Patch branch instruction at pos to branch to given branch target pos. | 841 // Patch branch instruction at pos to branch to given branch target pos. |
| 560 void target_at_put(int32_t pos, int32_t target_pos); | 842 void target_at_put(int32_t pos, int32_t target_pos); |
| 561 | 843 |
| 562 // Say if we need to relocate with this mode. | 844 // Say if we need to relocate with this mode. |
| 563 bool MustUseAt(RelocInfo::Mode rmode); | 845 bool MustUseReg(RelocInfo::Mode rmode); |
| 564 | 846 |
| 565 // Record reloc info for current pc_. | 847 // Record reloc info for current pc_. |
| 566 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); | 848 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); |
| 567 | 849 |
| 850 // Block the emission of the trampoline pool before pc_offset. | |
| 851 void BlockTrampolinePoolBefore(int pc_offset) { | |
| 852 if (no_trampoline_pool_before_ < pc_offset) | |
| 853 no_trampoline_pool_before_ = pc_offset; | |
| 854 } | |
| 855 | |
| 856 void StartBlockTrampolinePool() { | |
| 857 trampoline_pool_blocked_nesting_++; | |
| 858 } | |
| 859 void EndBlockTrampolinePool() { | |
| 860 trampoline_pool_blocked_nesting_--; | |
| 861 } | |
| 862 | |
| 863 bool is_trampoline_pool_blocked() const { | |
| 864 return trampoline_pool_blocked_nesting_ > 0; | |
| 865 } | |
| 866 | |
| 568 private: | 867 private: |
| 569 // Code buffer: | 868 // Code buffer: |
| 570 // The buffer into which code and relocation info are generated. | 869 // The buffer into which code and relocation info are generated. |
| 571 byte* buffer_; | 870 byte* buffer_; |
| 572 int buffer_size_; | 871 int buffer_size_; |
| 573 // True if the assembler owns the buffer, false if buffer is external. | 872 // True if the assembler owns the buffer, false if buffer is external. |
| 574 bool own_buffer_; | 873 bool own_buffer_; |
| 575 | 874 |
| 576 // Buffer size and constant pool distance are checked together at regular | 875 // Buffer size and constant pool distance are checked together at regular |
| 577 // intervals of kBufferCheckInterval emitted bytes. | 876 // intervals of kBufferCheckInterval emitted bytes. |
| 578 static const int kBufferCheckInterval = 1*KB/2; | 877 static const int kBufferCheckInterval = 1*KB/2; |
| 579 | 878 |
| 580 // Code generation. | 879 // Code generation. |
| 581 // The relocation writer's position is at least kGap bytes below the end of | 880 // 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 | 881 // 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 | 882 // not have to check for overflow. The same is true for writes of large |
| 584 // relocation info entries. | 883 // relocation info entries. |
| 585 static const int kGap = 32; | 884 static const int kGap = 32; |
| 586 byte* pc_; // The program counter - moves forward. | 885 byte* pc_; // The program counter - moves forward. |
| 587 | 886 |
| 887 | |
| 888 // Repeated checking whether the trampoline pool should be emitted is rather | |
| 889 // expensive. By default we only check again once a number of instructions | |
| 890 // has been generated. | |
| 891 static const int kCheckConstIntervalInst = 32; | |
| 892 static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize; | |
| 893 | |
| 894 int next_buffer_check_; // pc offset of next buffer check. | |
| 895 | |
| 896 // Emission of the trampoline pool may be blocked in some code sequences. | |
| 897 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero. | |
| 898 int no_trampoline_pool_before_; // Block emission before this pc offset. | |
| 899 | |
| 900 // Keep track of the last emitted pool to guarantee a maximal distance. | |
| 901 int last_trampoline_pool_end_; // pc offset of the end of the last pool. | |
| 902 | |
| 588 // Relocation information generation. | 903 // Relocation information generation. |
| 589 // Each relocation is encoded as a variable size value. | 904 // Each relocation is encoded as a variable size value. |
| 590 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; | 905 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
| 591 RelocInfoWriter reloc_info_writer; | 906 RelocInfoWriter reloc_info_writer; |
| 592 | 907 |
| 593 // The bound position, before this we cannot do instruction elimination. | 908 // The bound position, before this we cannot do instruction elimination. |
| 594 int last_bound_pos_; | 909 int last_bound_pos_; |
| 595 | 910 |
| 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. | 911 // Code emission. |
| 603 inline void CheckBuffer(); | 912 inline void CheckBuffer(); |
| 604 void GrowBuffer(); | 913 void GrowBuffer(); |
| 605 inline void emit(Instr x); | 914 inline void emit(Instr x); |
| 915 inline void CheckTrampolinePoolQuick(); | |
| 606 | 916 |
| 607 // Instruction generation. | 917 // Instruction generation. |
| 608 // We have 3 different kind of encoding layout on MIPS. | 918 // We have 3 different kind of encoding layout on MIPS. |
| 609 // However due to many different types of objects encoded in the same fields | 919 // However due to many different types of objects encoded in the same fields |
| 610 // we have quite a few aliases for each mode. | 920 // we have quite a few aliases for each mode. |
| 611 // Using the same structure to refer to Register and FPURegister would spare a | 921 // 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. | 922 // few aliases, but mixing both does not look clean to me. |
| 613 // Anyway we could surely implement this differently. | 923 // Anyway we could surely implement this differently. |
| 614 | 924 |
| 615 void GenInstrRegister(Opcode opcode, | 925 void GenInstrRegister(Opcode opcode, |
| 616 Register rs, | 926 Register rs, |
| 617 Register rt, | 927 Register rt, |
| 618 Register rd, | 928 Register rd, |
| 619 uint16_t sa = 0, | 929 uint16_t sa = 0, |
| 620 SecondaryField func = NULLSF); | 930 SecondaryField func = NULLSF); |
| 621 | 931 |
| 622 void GenInstrRegister(Opcode opcode, | 932 void GenInstrRegister(Opcode opcode, |
| 933 Register rs, | |
| 934 Register rt, | |
| 935 uint16_t msb, | |
| 936 uint16_t lsb, | |
| 937 SecondaryField func); | |
| 938 | |
| 939 void GenInstrRegister(Opcode opcode, | |
| 623 SecondaryField fmt, | 940 SecondaryField fmt, |
| 624 FPURegister ft, | 941 FPURegister ft, |
| 625 FPURegister fs, | 942 FPURegister fs, |
| 626 FPURegister fd, | 943 FPURegister fd, |
| 627 SecondaryField func = NULLSF); | 944 SecondaryField func = NULLSF); |
| 628 | 945 |
| 629 void GenInstrRegister(Opcode opcode, | 946 void GenInstrRegister(Opcode opcode, |
| 630 SecondaryField fmt, | 947 SecondaryField fmt, |
| 631 Register rt, | 948 Register rt, |
| 632 FPURegister fs, | 949 FPURegister fs, |
| 633 FPURegister fd, | 950 FPURegister fd, |
| 634 SecondaryField func = NULLSF); | 951 SecondaryField func = NULLSF); |
| 635 | 952 |
| 953 void GenInstrRegister(Opcode opcode, | |
| 954 SecondaryField fmt, | |
| 955 Register rt, | |
| 956 FPUControlRegister fs, | |
| 957 SecondaryField func = NULLSF); | |
| 958 | |
| 636 | 959 |
| 637 void GenInstrImmediate(Opcode opcode, | 960 void GenInstrImmediate(Opcode opcode, |
| 638 Register rs, | 961 Register rs, |
| 639 Register rt, | 962 Register rt, |
| 640 int32_t j); | 963 int32_t j); |
| 641 void GenInstrImmediate(Opcode opcode, | 964 void GenInstrImmediate(Opcode opcode, |
| 642 Register rs, | 965 Register rs, |
| 643 SecondaryField SF, | 966 SecondaryField SF, |
| 644 int32_t j); | 967 int32_t j); |
| 645 void GenInstrImmediate(Opcode opcode, | 968 void GenInstrImmediate(Opcode opcode, |
| 646 Register r1, | 969 Register r1, |
| 647 FPURegister r2, | 970 FPURegister r2, |
| 648 int32_t j); | 971 int32_t j); |
| 649 | 972 |
| 650 | 973 |
| 651 void GenInstrJump(Opcode opcode, | 974 void GenInstrJump(Opcode opcode, |
| 652 uint32_t address); | 975 uint32_t address); |
| 653 | 976 |
| 654 | 977 |
| 655 // Labels. | 978 // Labels. |
| 656 void print(Label* L); | 979 void print(Label* L); |
| 657 void bind_to(Label* L, int pos); | 980 void bind_to(Label* L, int pos); |
| 658 void link_to(Label* L, Label* appendix); | 981 void link_to(Label* L, Label* appendix); |
| 659 void next(Label* L); | 982 void next(Label* L); |
| 660 | 983 |
| 984 // One trampoline consists of: | |
| 985 // - space for trampoline slots, | |
| 986 // - space for labels. | |
| 987 // | |
| 988 // Space for trampoline slots is equal to slot_count * 2*kInstrSize. | |
| 989 // Space for trampoline slots preceeds space for labels. Each label is of one | |
| 990 // instruction size, so total amount for labels is equal to | |
| 991 // label_count * kInstrSize. | |
| 992 class Trampoline { | |
| 993 public: | |
| 994 Trampoline(int start, int slot_count, int label_count) { | |
| 995 start_ = start; | |
| 996 next_slot_ = start; | |
| 997 free_slot_count_ = slot_count; | |
| 998 next_label_ = start + slot_count*2*kInstrSize; | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
Spaces between binary operations (more below).
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 999 free_label_count_ = label_count; | |
| 1000 end_ = next_label_ + (label_count-1)*kInstrSize; | |
| 1001 } | |
| 1002 int bound() { | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
If this function is just an accessor for next_slot
Paul Lind
2011/03/26 18:39:17
This accessor was unused. I deleted it.
| |
| 1003 return next_slot_; | |
| 1004 } | |
| 1005 int start() { | |
| 1006 return start_; | |
| 1007 } | |
| 1008 int end() { | |
| 1009 return end_; | |
| 1010 } | |
| 1011 int take_slot() { | |
| 1012 int trampoline_slot = next_slot_; | |
| 1013 ASSERT(free_slot_count_ > 0); | |
| 1014 free_slot_count_--; | |
| 1015 next_slot_ += 2*kInstrSize; | |
| 1016 return trampoline_slot; | |
| 1017 } | |
| 1018 int take_label() { | |
| 1019 int label_pos = next_label_; | |
| 1020 ASSERT(free_label_count_ > 0); | |
| 1021 free_label_count_--; | |
| 1022 next_label_ += kInstrSize; | |
| 1023 return label_pos; | |
| 1024 } | |
| 1025 private: | |
| 1026 int start_; | |
| 1027 int end_; | |
| 1028 int next_slot_; | |
| 1029 int free_slot_count_; | |
| 1030 int next_label_; | |
| 1031 int free_label_count_; | |
| 1032 }; | |
| 1033 | |
| 1034 int32_t get_label_entry(int32_t pos, bool next_pool = true); | |
| 1035 int32_t get_trampoline_entry(int32_t pos, bool next_pool = true); | |
| 1036 | |
| 1037 static const int kSlotsPerTrampoline = 2304; | |
| 1038 static const int kLabelsPerTrampoline = 8; | |
| 1039 static const int kTrampolineInst = | |
|
Søren Thygesen Gjesse
2011/03/23 23:38:42
Only 4 space indent of line starting with "2 *".
Paul Lind
2011/03/26 18:39:17
Done.
| |
| 1040 2*kSlotsPerTrampoline + kLabelsPerTrampoline; | |
| 1041 static const int kTrampolineSize = kTrampolineInst*kInstrSize; | |
| 1042 static const int kMaxBranchOffset = (1 << (18-1)) - 1; | |
| 1043 static const int kMaxDistBetweenPools = kMaxBranchOffset - 2*kTrampolineSize; | |
| 1044 | |
| 1045 List<Trampoline> trampolines_; | |
| 1046 | |
| 661 friend class RegExpMacroAssemblerMIPS; | 1047 friend class RegExpMacroAssemblerMIPS; |
| 662 friend class RelocInfo; | 1048 friend class RelocInfo; |
| 1049 friend class CodePatcher; | |
| 1050 friend class BlockTrampolinePoolScope; | |
| 1051 | |
| 1052 PositionsRecorder positions_recorder_; | |
| 1053 bool allow_peephole_optimization_; | |
| 1054 bool emit_debug_code_; | |
| 1055 friend class PositionsRecorder; | |
| 1056 friend class EnsureSpace; | |
| 1057 }; | |
| 1058 | |
| 1059 | |
| 1060 class EnsureSpace BASE_EMBEDDED { | |
| 1061 public: | |
| 1062 explicit EnsureSpace(Assembler* assembler) { | |
| 1063 assembler->CheckBuffer(); | |
| 1064 } | |
| 663 }; | 1065 }; |
| 664 | 1066 |
| 665 } } // namespace v8::internal | 1067 } } // namespace v8::internal |
| 666 | 1068 |
| 667 #endif // V8_ARM_ASSEMBLER_MIPS_H_ | 1069 #endif // V8_ARM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |