Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: runtime/vm/assembler_x64.h

Issue 8747023: Initial revision of assembler for x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/assembler_x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #ifndef VM_ASSEMBLER_X64_H_ 5 #ifndef VM_ASSEMBLER_X64_H_
6 #define VM_ASSEMBLER_X64_H_ 6 #define VM_ASSEMBLER_X64_H_
7 7
8 #ifndef VM_ASSEMBLER_H_ 8 #ifndef VM_ASSEMBLER_H_
9 #error Do not include assembler_x64.h directly; use assembler.h instead. 9 #error Do not include assembler_x64.h directly; use assembler.h instead.
10 #endif 10 #endif
11 11
12 #include "vm/assert.h" 12 #include "vm/assert.h"
13 #include "vm/constants_x64.h" 13 #include "vm/constants_x64.h"
14 #include "vm/utils.h"
14 15
15 namespace dart { 16 namespace dart {
16 17
18 // Forward declarations.
19 class RuntimeEntry;
20
21
17 #if defined(TESTING) || defined(DEBUG) 22 #if defined(TESTING) || defined(DEBUG)
18 23
19 #define CHECK_STACK_ALIGNMENT { \ 24 #define CHECK_STACK_ALIGNMENT { \
20 UNIMPLEMENTED(); \ 25 UNIMPLEMENTED(); \
21 } 26 }
22 27
23 #else 28 #else
24 29
25 #define CHECK_STACK_ALIGNMENT { } 30 #define CHECK_STACK_ALIGNMENT { }
26 31
27 #endif 32 #endif
28 33
29 34
35 class Immediate : public ValueObject {
36 public:
37 explicit Immediate(int64_t value) : value_(value) { }
38
39 int64_t value() const { return value_; }
40
41 bool is_int8() const { return Utils::IsInt(8, value_); }
42 bool is_uint8() const { return Utils::IsUint(8, value_); }
43 bool is_uint16() const { return Utils::IsUint(16, value_); }
44 bool is_int32() const { return Utils::IsInt(32, value_); }
45
46 private:
47 const int64_t value_;
48
49 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac
50 // build issue is resolved.
51 };
52
53
54 class Operand : public ValueObject {
55 public:
56 uint8_t rex() const {
57 return rex_;
58 }
59
60 uint8_t mod() const {
61 return (encoding_at(0) >> 6) & 3;
62 }
63
64 Register rm() const {
65 int rm_rex = (rex_ & 1) << 3;
66 return static_cast<Register>(rm_rex + (encoding_at(0) & 7));
67 }
68
69 ScaleFactor scale() const {
70 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
71 }
72
73 Register index() const {
74 int index_rex = (rex_ & 2) << 2;
75 return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7));
76 }
77
78 Register base() const {
79 int base_rex = (rex_ & 1) << 3;
80 return static_cast<Register>(base_rex + (encoding_at(1) & 7));
81 }
82
83 int8_t disp8() const {
84 ASSERT(length_ >= 2);
85 return static_cast<int8_t>(encoding_[length_ - 1]);
86 }
87
88 int32_t disp32() const {
89 ASSERT(length_ >= 5);
90 return bit_copy<int32_t>(encoding_[length_ - 4]);
91 }
92
93 protected:
94 Operand() : length_(0), rex_(0) { }
95
96 void SetModRM(int mod, Register rm) {
97 ASSERT((mod & ~3) == 0);
98 if (rm > 7) rex_ |= 1;
99 encoding_[0] = (mod << 6) | (rm & 7);
100 length_ = 1;
101 }
102
103 void SetSIB(ScaleFactor scale, Register index, Register base) {
104 ASSERT(length_ == 1);
105 ASSERT((scale & ~3) == 0);
106 if (base > 7) {
107 ASSERT((rex_ & 1) == 0); // Must not have REX.B already set.
108 rex_ |= 1;
109 }
110 if (index > 7) rex_ |= 2;
111 encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7);
112 length_ = 2;
113 }
114
115 void SetDisp8(int8_t disp) {
116 ASSERT(length_ == 1 || length_ == 2);
117 encoding_[length_++] = static_cast<uint8_t>(disp);
118 }
119
120 void SetDisp32(int32_t disp) {
121 ASSERT(length_ == 1 || length_ == 2);
122 memmove(&encoding_[length_], &disp, sizeof(disp));
123 length_ += sizeof(disp);
124 }
125
126 private:
127 uint8_t length_;
128 uint8_t rex_;
129 uint8_t encoding_[6];
130
131 explicit Operand(Register reg) : rex_(0) { SetModRM(3, reg); }
132
133 // Get the operand encoding byte at the given index.
134 uint8_t encoding_at(int index) const {
135 ASSERT(index >= 0 && index < length_);
136 return encoding_[index];
137 }
138
139 // Returns whether or not this operand is really the given register in
140 // disguise. Used from the assembler to generate better encodings.
141 bool IsRegister(Register reg) const {
142 return ((reg > 7 ? 1 : 0) == (rex_ & 1)) // REX.B match.
143 && ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register.
144 && ((encoding_at(0) & 0x07) == reg); // Register codes match.
145 }
146
147
148 friend class Assembler;
149
150 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Operand) once the mac
151 // build issue is resolved.
152 };
153
154
155 class Address : public Operand {
156 public:
157 Address(Register base, int32_t disp) {
158 if (disp == 0 && base != RBP) {
159 SetModRM(0, base);
160 if (base == RSP) SetSIB(TIMES_1, RSP, base);
161 } else if (Utils::IsInt(8, disp)) {
162 SetModRM(1, base);
163 if (base == RSP) SetSIB(TIMES_1, RSP, base);
164 SetDisp8(disp);
165 } else {
166 SetModRM(2, base);
167 if (base == RSP) SetSIB(TIMES_1, RSP, base);
168 SetDisp32(disp);
169 }
170 }
171
172 Address(Register index, ScaleFactor scale, int32_t disp) {
173 ASSERT(index != RSP); // Illegal addressing mode.
174 SetModRM(0, RSP);
175 SetSIB(scale, index, RBP);
176 SetDisp32(disp);
177 }
178
179 Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
180 ASSERT(index != RSP); // Illegal addressing mode.
181 if (disp == 0 && base != RBP) {
182 SetModRM(0, RSP);
183 SetSIB(scale, index, base);
184 } else if (Utils::IsInt(8, disp)) {
185 SetModRM(1, RSP);
186 SetSIB(scale, index, base);
187 SetDisp8(disp);
188 } else {
189 SetModRM(2, RSP);
190 SetSIB(scale, index, base);
191 SetDisp32(disp);
192 }
193 }
194
195 static Address Absolute(const uword addr) {
196 UNIMPLEMENTED();
197 Address result;
198 result.SetModRM(0, RBP);
199 result.SetDisp32(addr);
200 return result;
201 }
202
203 private:
204 Address() {}
205
206 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Address) once the mac
207 // build issue is resolved.
208 };
209
210
211 class FieldAddress : public Address {
212 public:
213 FieldAddress(Register base, int32_t disp)
214 : Address(base, disp - kHeapObjectTag) {}
215 FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp)
216 : Address(base, index, scale, disp - kHeapObjectTag) {}
217 };
218
219
30 class Label : public ValueObject { 220 class Label : public ValueObject {
31 public: 221 public:
32 Label() : position_(0) { } 222 Label() : position_(0), unresolved_(0) {
223 #ifdef DEBUG
224 for (int i = 0; i < kMaxUnresolvedBranches; i++) {
225 unresolved_near_positions_[i] = -1;
226 }
227 #endif // DEBUG
228 }
33 229
34 ~Label() { 230 ~Label() {
35 // Assert if label is being destroyed with unresolved branches pending. 231 // Assert if label is being destroyed with unresolved branches pending.
36 ASSERT(!IsLinked()); 232 ASSERT(!IsLinked());
37 } 233 ASSERT(!HasNear());
38 234 }
39 // Returns the position for bound and linked labels. Cannot be used 235
40 // for unused labels. 236 // Returns the position for bound labels. Cannot be used for unused or linked
237 // labels.
41 int Position() const { 238 int Position() const {
42 ASSERT(!IsUnused()); 239 ASSERT(IsBound());
43 return IsBound() ? -position_ - kWordSize : position_ - kWordSize; 240 return -position_ - kWordSize;
241 }
242
243 int LinkPosition() const {
244 ASSERT(IsLinked());
245 return position_ - kWordSize;
246 }
247
248 int NearPosition() {
249 ASSERT(HasNear());
250 return unresolved_near_positions_[--unresolved_];
44 } 251 }
45 252
46 bool IsBound() const { return position_ < 0; } 253 bool IsBound() const { return position_ < 0; }
47 bool IsUnused() const { return position_ == 0; } 254 bool IsUnused() const { return (position_ == 0) && (unresolved_ == 0); }
48 bool IsLinked() const { return position_ > 0; } 255 bool IsLinked() const { return position_ > 0; }
49 256 bool HasNear() const { return unresolved_ != 0; }
50 private: 257
51 int position_; 258 private:
52
53 void Reinitialize() {
54 position_ = 0;
55 }
56
57 void BindTo(int position) { 259 void BindTo(int position) {
58 ASSERT(!IsBound()); 260 ASSERT(!IsBound());
261 ASSERT(!HasNear());
59 position_ = -position - kWordSize; 262 position_ = -position - kWordSize;
60 ASSERT(IsBound()); 263 ASSERT(IsBound());
61 } 264 }
62 265
63 void LinkTo(int position) { 266 void LinkTo(int position) {
64 ASSERT(!IsBound()); 267 ASSERT(!IsBound());
65 position_ = position + kWordSize; 268 position_ = position + kWordSize;
66 ASSERT(IsLinked()); 269 ASSERT(IsLinked());
67 } 270 }
68 271
272 void NearLinkTo(int position) {
273 ASSERT(!IsBound());
274 ASSERT(unresolved_ < kMaxUnresolvedBranches);
275 unresolved_near_positions_[unresolved_++] = position;
276 }
277
278 static const int kMaxUnresolvedBranches = 20;
279
280 int position_;
281 int unresolved_;
282 int unresolved_near_positions_[kMaxUnresolvedBranches];
283
69 friend class Assembler; 284 friend class Assembler;
70 DISALLOW_COPY_AND_ASSIGN(Label); 285 DISALLOW_COPY_AND_ASSIGN(Label);
71 }; 286 };
72 287
73 288
74 class Assembler { 289 class Assembler : public ValueObject {
75 public: 290 public:
76 Assembler() { } 291 Assembler() : buffer_(), prolog_offset_(-1) { }
77 ~Assembler() { } 292 ~Assembler() { }
78 293
79 // Macros for High-level operations. 294 static const bool kNearJump = true;
80 void AddConstant(Register reg, int value) { 295 static const bool kFarJump = false;
81 UNIMPLEMENTED(); 296
82 } 297 /*
83 298 * Emit Machine Instructions.
84 // Misc. functionality 299 */
85 int CodeSize() const { 300 void call(Register reg);
86 UNIMPLEMENTED(); 301 void call(const Address& address);
87 return 0; 302 void call(Label* label);
88 } 303 void call(const ExternalLabel* label);
89 int prolog_offset() const { 304
90 UNIMPLEMENTED(); 305 static const intptr_t kCallExternalLabelSize = 5;
91 return 0; 306
92 } 307 void pushq(Register reg);
308 void pushq(const Address& address);
309
310 void popq(Register reg);
311 void popq(const Address& address);
312
313 void movl(Register dst, Register src);
314 void movl(Register dst, const Immediate& imm);
315 void movl(Register dst, const Address& src);
316 void movl(const Address& dst, Register src);
317
318 void movzxb(Register dst, Register src);
319 void movzxb(Register dst, const Address& src);
320 void movsxb(Register dst, Register src);
321 void movsxb(Register dst, const Address& src);
322 void movb(Register dst, const Address& src);
323 void movb(const Address& dst, Register src);
324 void movb(const Address& dst, const Immediate& imm);
325
326 void movzxw(Register dst, Register src);
327 void movzxw(Register dst, const Address& src);
328 void movsxw(Register dst, Register src);
329 void movsxw(Register dst, const Address& src);
330 void movw(Register dst, const Address& src);
331 void movw(const Address& dst, Register src);
332
333 void movq(Register dst, const Immediate& imm);
334 void movq(Register dst, Register src);
335 void movq(Register dst, const Address& src);
336 void movq(const Address& dst, Register src);
337 void movq(const Address& dst, const Immediate& imm);
338
339 void movsxl(Register dst, const Address& src);
340
341 void leaq(Register dst, const Address& src);
342
343 void movss(XmmRegister dst, const Address& src);
344 void movss(const Address& dst, XmmRegister src);
345 void movss(XmmRegister dst, XmmRegister src);
346
347 void movd(XmmRegister dst, Register src);
348 void movd(Register dst, XmmRegister src);
349
350 void addss(XmmRegister dst, XmmRegister src);
351 void subss(XmmRegister dst, XmmRegister src);
352 void mulss(XmmRegister dst, XmmRegister src);
353 void divss(XmmRegister dst, XmmRegister src);
354
355 void movsd(XmmRegister dst, const Address& src);
356 void movsd(const Address& dst, XmmRegister src);
357 void movsd(XmmRegister dst, XmmRegister src);
358
359 void addsd(XmmRegister dst, XmmRegister src);
360 void subsd(XmmRegister dst, XmmRegister src);
361 void mulsd(XmmRegister dst, XmmRegister src);
362 void divsd(XmmRegister dst, XmmRegister src);
363
364 void xchgl(Register dst, Register src);
365 void xchgq(Register dst, Register src);
366
367 void cmpl(Register reg, const Immediate& imm);
368 void cmpl(Register reg0, Register reg1);
369 void cmpl(Register reg, const Address& address);
370 void cmpl(const Address& address, const Immediate& imm);
371
372 void cmpq(Register reg, const Immediate& imm);
373 void cmpq(const Address& address, const Immediate& imm);
374 void cmpq(Register reg0, Register reg1);
375 void cmpq(Register reg, const Address& address);
376
377 void testl(Register reg1, Register reg2);
378 void testl(Register reg, const Immediate& imm);
379
380 void testq(Register reg1, Register reg2);
381 void testq(Register reg, const Immediate& imm);
382
383 void andl(Register dst, Register src);
384 void andl(Register dst, const Immediate& imm);
385
386 void orl(Register dst, Register src);
387 void orl(Register dst, const Immediate& imm);
388
389 void xorl(Register dst, Register src);
390
391 void andq(Register dst, Register src);
392 void andq(Register dst, const Immediate& imm);
393
394 void orq(Register dst, Register src);
395 void orq(Register dst, const Immediate& imm);
396
397 void xorq(Register dst, Register src);
398
399 void addl(Register dst, Register src);
400 void addl(const Address& address, const Immediate& imm);
401
402 void addq(Register dst, Register src);
403 void addq(Register reg, const Immediate& imm);
404 void addq(const Address& address, const Immediate& imm);
405
406 void subl(Register dst, Register src);
407
408 void cdq();
409 void cqo();
410
411 void idivl(Register reg);
412 void idivq(Register reg);
413
414 void imull(Register dst, Register src);
415 void imull(Register reg, const Immediate& imm);
416
417 void imulq(Register dst, Register src);
418
419 void subq(Register dst, Register src);
420 void subq(Register reg, const Immediate& imm);
421
422 void shll(Register reg, const Immediate& imm);
423 void shll(Register operand, Register shifter);
424 void shrl(Register reg, const Immediate& imm);
425 void shrl(Register operand, Register shifter);
426 void sarl(Register reg, const Immediate& imm);
427 void sarl(Register operand, Register shifter);
428
429 void shlq(Register reg, const Immediate& imm);
430 void shlq(Register operand, Register shifter);
431 void shrq(Register reg, const Immediate& imm);
432 void shrq(Register operand, Register shifter);
433 void sarq(Register reg, const Immediate& imm);
434 void sarq(Register operand, Register shifter);
435
436 void incl(const Address& address);
437 void decl(const Address& address);
438
439 void incq(Register reg);
440 void incq(const Address& address);
441 void decq(Register reg);
442 void decq(const Address& address);
443
444 void negl(Register reg);
445 void negq(Register reg);
446
447 void enter(const Immediate& imm);
448 void leave();
449
450 void ret();
451 void nop();
452 void int3();
453 void hlt();
454
455 void j(Condition condition, Label* label, bool near = kFarJump);
456
457 void jmp(Register reg);
458 void jmp(Label* label, bool near = kFarJump);
459 void jmp(const ExternalLabel* label);
460
461 void lock();
462 void cmpxchgl(const Address& address, Register reg);
463 void lock_cmpxchgl(const Address& address, Register reg) {
464 lock();
465 cmpxchgl(address, reg);
466 }
467
468 void cmpxchgq(const Address& address, Register reg);
469 void lock_cmpxchgq(const Address& address, Register reg) {
470 lock();
471 cmpxchgq(address, reg);
472 }
473
474 /*
475 * Macros for High-level operations.
476 */
477 void AddImmediate(Register reg, const Immediate& imm);
478
479 void LoadObject(Register dst, const Object& object);
480 void PushObject(const Object& object);
481 void CompareObject(Register reg, const Object& object);
482 void LoadDoubleConstant(XmmRegister dst, double value);
483
484 void StoreIntoObject(Register object, // Object we are storing into.
485 const FieldAddress& dest, // Where we are storing into.
486 Register value); // Value we are storing.
487
488 void DoubleNegate(XmmRegister d);
489 void FloatNegate(XmmRegister f);
490
491 void DoubleAbs(XmmRegister reg);
492
493 void LockCmpxchgl(const Address& address, Register reg) {
494 lock();
495 cmpxchgl(address, reg);
496 }
497
498 void EnterFrame(intptr_t frame_space);
499 void LeaveFrame();
500
501 void CallRuntimeFromDart(const RuntimeEntry& entry);
502 void CallRuntimeFromStub(const RuntimeEntry& entry);
503
504 /*
505 * Misc. functionality.
506 */
507 void SmiTag(Register reg) {
508 addl(reg, reg);
509 }
510
511 void SmiUntag(Register reg) {
512 sarl(reg, Immediate(kSmiTagSize));
513 }
514
515 int PreferredLoopAlignment() { return 16; }
516 void Align(int alignment, int offset);
517 void Bind(Label* label);
518
519 int CodeSize() const { return buffer_.Size(); }
520 int prolog_offset() const { return prolog_offset_; }
93 const ZoneGrowableArray<int>& GetPointerOffsets() const { 521 const ZoneGrowableArray<int>& GetPointerOffsets() const {
94 UNIMPLEMENTED(); 522 return buffer_.pointer_offsets();
95 return *pointer_offsets_; 523 }
96 } 524
97 void FinalizeInstructions(const MemoryRegion& region) { 525 void FinalizeInstructions(const MemoryRegion& region) {
98 UNIMPLEMENTED(); 526 buffer_.FinalizeInstructions(region);
99 } 527 }
100 528
101 // Debugging and bringup support. 529 // Debugging and bringup support.
102 void Stop(const char* message) { UNIMPLEMENTED(); } 530 void Stop(const char* message);
103 void Unimplemented(const char* message); 531 void Unimplemented(const char* message);
104 void Untested(const char* message); 532 void Untested(const char* message);
105 void Unreachable(const char* message); 533 void Unreachable(const char* message);
106 534
107 static void InitializeMemoryWithBreakpoints(uword data, int length) { 535 static void InitializeMemoryWithBreakpoints(uword data, int length);
108 UNIMPLEMENTED();
109 }
110 536
111 private: 537 private:
112 ZoneGrowableArray<int>* pointer_offsets_; 538 AssemblerBuffer buffer_;
539 int prolog_offset_;
540
541 inline void EmitUint8(uint8_t value);
542 inline void EmitInt32(int32_t value);
543 inline void EmitInt64(int64_t value);
544
545 inline void EmitRegisterREX(Register reg, uint8_t rex);
546 inline void EmitRegisterOperand(int rm, int reg);
547 inline void EmitOperandREX(int rm, const Operand& operand, uint8_t rex);
548 inline void EmitXmmRegisterOperand(int rm, XmmRegister reg);
549 inline void EmitFixup(AssemblerFixup* fixup);
550 inline void EmitOperandSizeOverride();
551
552 void EmitOperand(int rm, const Operand& operand);
553 void EmitImmediate(const Immediate& imm);
554 void EmitComplex(int rm, const Operand& operand, const Immediate& immediate);
555 void EmitLabel(Label* label, int instruction_size);
556 void EmitLabelLink(Label* label);
557 void EmitNearLabelLink(Label* label);
558
559 void EmitGenericShift(bool wide, int rm, Register reg, const Immediate& imm);
560 void EmitGenericShift(bool wide, int rm, Register operand, Register shifter);
561
113 DISALLOW_ALLOCATION(); 562 DISALLOW_ALLOCATION();
114 DISALLOW_COPY_AND_ASSIGN(Assembler); 563 DISALLOW_COPY_AND_ASSIGN(Assembler);
115 }; 564 };
116 565
566
567 enum {
568 REX_NONE = 0,
569 REX_B = 1 << 0,
570 REX_X = 1 << 1,
571 REX_R = 1 << 2,
572 REX_W = 1 << 3
573 };
574
575
576 inline void Assembler::EmitUint8(uint8_t value) {
577 buffer_.Emit<uint8_t>(value);
578 }
579
580
581 inline void Assembler::EmitInt32(int32_t value) {
582 buffer_.Emit<int32_t>(value);
583 }
584
585
586 inline void Assembler::EmitInt64(int64_t value) {
587 buffer_.Emit<int64_t>(value);
588 }
589
590
591 inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) {
592 ASSERT(reg != kNoRegister);
593 rex |= (reg > 7 ? REX_B : REX_NONE);
594 if (rex != 0) EmitUint8(0x40 | rex);
595 }
596
597
598 inline void Assembler::EmitOperandREX(int rm,
599 const Operand& operand,
600 uint8_t rex) {
601 rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex();
602 if (rex != 0) EmitUint8(0x40 | rex);
603 }
604
605
606 inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
607 buffer_.EmitFixup(fixup);
608 }
609
610
611 inline void Assembler::EmitOperandSizeOverride() {
612 EmitUint8(0x66);
613 }
614
117 } // namespace dart 615 } // namespace dart
118 616
119 #endif // VM_ASSEMBLER_X64_H_ 617 #endif // VM_ASSEMBLER_X64_H_
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/assembler_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698